@shopify/cli-kit 3.33.0 → 3.35.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 (212) hide show
  1. package/dist/git.js +3 -3
  2. package/dist/git.js.map +1 -1
  3. package/dist/http/fetch.js +1 -1
  4. package/dist/http/fetch.js.map +1 -1
  5. package/dist/http.js +2 -2
  6. package/dist/http.js.map +1 -1
  7. package/dist/index.d.ts +0 -7
  8. package/dist/index.js +0 -7
  9. package/dist/index.js.map +1 -1
  10. package/dist/metadata.js +1 -1
  11. package/dist/metadata.js.map +1 -1
  12. package/dist/npm.js +3 -3
  13. package/dist/npm.js.map +1 -1
  14. package/dist/output.js +4 -4
  15. package/dist/output.js.map +1 -1
  16. package/dist/path.d.ts +1 -1
  17. package/dist/path.js +5 -3
  18. package/dist/path.js.map +1 -1
  19. package/dist/private/node/analytics.js +6 -9
  20. package/dist/private/node/analytics.js.map +1 -1
  21. package/dist/private/node/api/graphql.js +2 -1
  22. package/dist/private/node/api/graphql.js.map +1 -1
  23. package/dist/private/node/api/headers.d.ts +2 -2
  24. package/dist/private/node/api/headers.js +4 -4
  25. package/dist/private/node/api/headers.js.map +1 -1
  26. package/dist/private/node/api/rest.d.ts +6 -4
  27. package/dist/private/node/api/rest.js +8 -7
  28. package/dist/private/node/api/rest.js.map +1 -1
  29. package/dist/private/node/constants.d.ts +42 -0
  30. package/dist/private/node/constants.js +58 -0
  31. package/dist/private/node/constants.js.map +1 -0
  32. package/dist/private/node/environment/service.d.ts +18 -0
  33. package/dist/private/node/environment/service.js +32 -0
  34. package/dist/private/node/environment/service.js.map +1 -0
  35. package/dist/{environment → private/node/environment}/spin-cache.d.ts +0 -0
  36. package/dist/{environment → private/node/environment}/spin-cache.js +0 -0
  37. package/dist/private/node/environment/spin-cache.js.map +1 -0
  38. package/dist/{environment → private/node/environment}/utilities.d.ts +0 -0
  39. package/dist/{environment → private/node/environment}/utilities.js +0 -0
  40. package/dist/private/node/environment/utilities.js.map +1 -0
  41. package/dist/{session → private/node/session}/authorize.d.ts +1 -5
  42. package/dist/{session → private/node/session}/authorize.js +9 -9
  43. package/dist/private/node/session/authorize.js.map +1 -0
  44. package/dist/{session → private/node/session}/device-authorization.d.ts +0 -0
  45. package/dist/{session → private/node/session}/device-authorization.js +7 -9
  46. package/dist/private/node/session/device-authorization.js.map +1 -0
  47. package/dist/{session → private/node/session}/exchange.d.ts +2 -2
  48. package/dist/{session → private/node/session}/exchange.js +5 -5
  49. package/dist/private/node/session/exchange.js.map +1 -0
  50. package/dist/{session → private/node/session}/identity-token-validation.d.ts +0 -0
  51. package/dist/{session → private/node/session}/identity-token-validation.js +4 -4
  52. package/dist/private/node/session/identity-token-validation.js.map +1 -0
  53. package/dist/{session → private/node/session}/identity.d.ts +1 -1
  54. package/dist/{session → private/node/session}/identity.js +2 -3
  55. package/dist/private/node/session/identity.js.map +1 -0
  56. package/dist/{session → private/node/session}/post-auth.d.ts +1 -1
  57. package/dist/{session → private/node/session}/post-auth.js +10 -10
  58. package/dist/private/node/session/post-auth.js.map +1 -0
  59. package/dist/{session → private/node/session}/redirect-listener.d.ts +0 -0
  60. package/dist/{session → private/node/session}/redirect-listener.js +2 -2
  61. package/dist/private/node/session/redirect-listener.js.map +1 -0
  62. package/dist/{session → private/node/session}/schema.d.ts +1 -1
  63. package/dist/{session → private/node/session}/schema.js +1 -1
  64. package/dist/private/node/session/schema.js.map +1 -0
  65. package/dist/{session → private/node/session}/scopes.d.ts +1 -1
  66. package/dist/{session → private/node/session}/scopes.js +2 -2
  67. package/dist/private/node/session/scopes.js.map +1 -0
  68. package/dist/{session → private/node/session}/store.d.ts +0 -0
  69. package/dist/{session → private/node/session}/store.js +10 -10
  70. package/dist/private/node/session/store.js.map +1 -0
  71. package/dist/{session → private/node/session}/validate.d.ts +0 -0
  72. package/dist/{session → private/node/session}/validate.js +4 -4
  73. package/dist/private/node/session/validate.js.map +1 -0
  74. package/dist/private/node/session.d.ts +56 -0
  75. package/dist/{session.js → private/node/session.js} +98 -134
  76. package/dist/private/node/session.js.map +1 -0
  77. package/dist/private/node/ui/components/SelectPrompt.d.ts +2 -1
  78. package/dist/private/node/ui/components/SelectPrompt.js +2 -1
  79. package/dist/private/node/ui/components/SelectPrompt.js.map +1 -1
  80. package/dist/private/node/ui/components/Table/Column.d.ts +5 -0
  81. package/dist/private/node/ui/components/Table/Column.js +2 -0
  82. package/dist/private/node/ui/components/Table/Column.js.map +1 -0
  83. package/dist/private/node/ui/components/Table/Row.d.ts +12 -0
  84. package/dist/private/node/ui/components/Table/Row.js +24 -0
  85. package/dist/private/node/ui/components/Table/Row.js.map +1 -0
  86. package/dist/private/node/ui/components/Table/ScalarDict.d.ts +5 -0
  87. package/dist/private/node/ui/components/Table/ScalarDict.js +2 -0
  88. package/dist/private/node/ui/components/Table/ScalarDict.js.map +1 -0
  89. package/dist/private/node/ui/components/Table/Table.d.ts +12 -0
  90. package/dist/private/node/ui/components/Table/Table.js +30 -0
  91. package/dist/private/node/ui/components/Table/Table.js.map +1 -0
  92. package/dist/private/node/ui/components/Table/Table.test.d.ts +1 -0
  93. package/dist/private/node/ui/components/Table/Table.test.js +41 -0
  94. package/dist/private/node/ui/components/Table/Table.test.js.map +1 -0
  95. package/dist/private/node/ui.js +1 -1
  96. package/dist/private/node/ui.js.map +1 -1
  97. package/dist/public/common/string.d.ts +11 -0
  98. package/dist/public/common/string.js +21 -0
  99. package/dist/public/common/string.js.map +1 -1
  100. package/dist/public/common/version.d.ts +1 -0
  101. package/dist/public/common/version.js +2 -0
  102. package/dist/public/common/version.js.map +1 -0
  103. package/dist/public/node/analytics.js +5 -5
  104. package/dist/public/node/analytics.js.map +1 -1
  105. package/dist/public/node/api/admin.d.ts +5 -2
  106. package/dist/public/node/api/admin.js +4 -3
  107. package/dist/public/node/api/admin.js.map +1 -1
  108. package/dist/public/node/api/partners.js +1 -1
  109. package/dist/public/node/api/partners.js.map +1 -1
  110. package/dist/public/node/base-command.js +2 -2
  111. package/dist/public/node/base-command.js.map +1 -1
  112. package/dist/public/node/cli.d.ts +8 -0
  113. package/dist/public/node/cli.js +25 -8
  114. package/dist/public/node/cli.js.map +1 -1
  115. package/dist/public/node/dot-env.js +2 -2
  116. package/dist/public/node/dot-env.js.map +1 -1
  117. package/dist/public/node/environment/fqdn.d.ts +26 -0
  118. package/dist/{environment → public/node/environment}/fqdn.js +15 -31
  119. package/dist/public/node/environment/fqdn.js.map +1 -0
  120. package/dist/{environment → public/node/environment}/local.d.ts +62 -15
  121. package/dist/{environment → public/node/environment}/local.js +81 -36
  122. package/dist/public/node/environment/local.js.map +1 -0
  123. package/dist/public/node/environment/spin.d.ts +43 -0
  124. package/dist/{environment → public/node/environment}/spin.js +31 -38
  125. package/dist/public/node/environment/spin.js.map +1 -0
  126. package/dist/public/node/error-handler.js +6 -5
  127. package/dist/public/node/error-handler.js.map +1 -1
  128. package/dist/public/node/fs.d.ts +222 -3
  129. package/dist/public/node/fs.js +338 -2
  130. package/dist/public/node/fs.js.map +1 -1
  131. package/dist/public/node/git.d.ts +90 -0
  132. package/dist/public/node/git.js +174 -0
  133. package/dist/public/node/git.js.map +1 -0
  134. package/dist/public/node/liquid.js +6 -6
  135. package/dist/public/node/liquid.js.map +1 -1
  136. package/dist/public/node/node-package-manager.d.ts +0 -10
  137. package/dist/public/node/node-package-manager.js +3 -20
  138. package/dist/public/node/node-package-manager.js.map +1 -1
  139. package/dist/public/node/presets.js +2 -2
  140. package/dist/public/node/presets.js.map +1 -1
  141. package/dist/public/node/ruby.d.ts +1 -1
  142. package/dist/public/node/ruby.js +19 -20
  143. package/dist/public/node/ruby.js.map +1 -1
  144. package/dist/public/node/session.d.ts +53 -0
  145. package/dist/public/node/session.js +95 -0
  146. package/dist/public/node/session.js.map +1 -0
  147. package/dist/public/node/system.d.ts +44 -0
  148. package/dist/{system.js → public/node/system.js} +34 -54
  149. package/dist/public/node/system.js.map +1 -0
  150. package/dist/public/node/tcp.js +1 -1
  151. package/dist/public/node/tcp.js.map +1 -1
  152. package/dist/public/node/ui.d.ts +13 -0
  153. package/dist/public/node/ui.js +14 -0
  154. package/dist/public/node/ui.js.map +1 -1
  155. package/dist/public/node/vscode.js +5 -5
  156. package/dist/public/node/vscode.js.map +1 -1
  157. package/dist/secure-store.js +4 -4
  158. package/dist/secure-store.js.map +1 -1
  159. package/dist/store.d.ts +10 -10
  160. package/dist/store.js +21 -22
  161. package/dist/store.js.map +1 -1
  162. package/dist/testing/store.js +3 -3
  163. package/dist/testing/store.js.map +1 -1
  164. package/dist/testing/ui.js +1 -1
  165. package/dist/testing/ui.js.map +1 -1
  166. package/dist/tsconfig.tsbuildinfo +1 -1
  167. package/dist/ui.js +4 -4
  168. package/dist/ui.js.map +1 -1
  169. package/package.json +10 -7
  170. package/dist/cli.d.ts +0 -8
  171. package/dist/cli.js +0 -18
  172. package/dist/cli.js.map +0 -1
  173. package/dist/constants.d.ts +0 -51
  174. package/dist/constants.js +0 -70
  175. package/dist/constants.js.map +0 -1
  176. package/dist/environment/fqdn.d.ts +0 -29
  177. package/dist/environment/fqdn.js.map +0 -1
  178. package/dist/environment/local.js.map +0 -1
  179. package/dist/environment/service.d.ts +0 -4
  180. package/dist/environment/service.js +0 -19
  181. package/dist/environment/service.js.map +0 -1
  182. package/dist/environment/spin-cache.js.map +0 -1
  183. package/dist/environment/spin.d.ts +0 -50
  184. package/dist/environment/spin.js.map +0 -1
  185. package/dist/environment/utilities.js.map +0 -1
  186. package/dist/environment.d.ts +0 -7
  187. package/dist/environment.js +0 -8
  188. package/dist/environment.js.map +0 -1
  189. package/dist/file.d.ts +0 -98
  190. package/dist/file.js +0 -216
  191. package/dist/file.js.map +0 -1
  192. package/dist/network/service.d.ts +0 -14
  193. package/dist/network/service.js +0 -11
  194. package/dist/network/service.js.map +0 -1
  195. package/dist/session/authorize.js.map +0 -1
  196. package/dist/session/device-authorization.js.map +0 -1
  197. package/dist/session/exchange.js.map +0 -1
  198. package/dist/session/identity-token-validation.js.map +0 -1
  199. package/dist/session/identity.js.map +0 -1
  200. package/dist/session/post-auth.js.map +0 -1
  201. package/dist/session/redirect-listener.js.map +0 -1
  202. package/dist/session/schema.js.map +0 -1
  203. package/dist/session/scopes.js.map +0 -1
  204. package/dist/session/store.js.map +0 -1
  205. package/dist/session/token.d.ts +0 -40
  206. package/dist/session/token.js +0 -22
  207. package/dist/session/token.js.map +0 -1
  208. package/dist/session/validate.js.map +0 -1
  209. package/dist/session.d.ts +0 -96
  210. package/dist/session.js.map +0 -1
  211. package/dist/system.d.ts +0 -51
  212. package/dist/system.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { define } from '../schema.js';
1
+ import { define } from '../../../schema.js';
2
2
  /**
3
3
  * The schema represents an Identity token.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { define } from '../schema.js';
1
+ import { define } from '../../../schema.js';
2
2
  const DateSchema = define.preprocess((arg) => {
3
3
  if (typeof arg === 'string' || arg instanceof Date)
4
4
  return new Date(arg);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/private/node/session/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAA;AAEzC,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;;;;;;;;;;;;;;;;;;;;;;GAsBG;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 * {\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"]}
@@ -1,4 +1,4 @@
1
- import { API } from '../network/api.js';
1
+ import { API } from '../../../network/api.js';
2
2
  /**
3
3
  * Generate a flat array with all the default scopes for all the APIs plus
4
4
  * any custom scope defined by the user.
@@ -1,5 +1,5 @@
1
- import { Bug } from '../error.js';
2
- import { allAPIs } from '../network/api.js';
1
+ import { Bug } from '../../../error.js';
2
+ import { allAPIs } from '../../../network/api.js';
3
3
  /**
4
4
  * Generate a flat array with all the default scopes for all the APIs plus
5
5
  * any custom scope defined by the user.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../../../src/private/node/session/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,mBAAmB,CAAA;AACrC,OAAO,EAAC,OAAO,EAAM,MAAM,yBAAyB,CAAA;AAEpD;;;;;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"]}
@@ -1,9 +1,9 @@
1
1
  import { SessionSchema } from './schema.js';
2
- import constants from '../constants.js';
3
- import { platformAndArch } from '../public/node/os.js';
4
- import { store as secureStore, fetch as secureFetch, remove as secureRemove } from '../secure-store.js';
5
- import { content, debug } from '../output.js';
6
- import { getSession, removeSession, setSession, clearAllAppInfo } from '../store.js';
2
+ import { keychainConstants } from '../constants.js';
3
+ import { platformAndArch } from '../../../public/node/os.js';
4
+ import { store as secureStore, fetch as secureFetch, remove as secureRemove } from '../../../secure-store.js';
5
+ import { content, debug } from '../../../output.js';
6
+ import { getSession, removeSession, setSession, clearAllAppInfo } from '../../../store.js';
7
7
  /**
8
8
  * The identifier of the session in the secure store.
9
9
  */
@@ -19,7 +19,7 @@ export async function store(session) {
19
19
  await secureStore(identifier, jsonSession);
20
20
  }
21
21
  else {
22
- await setSession(jsonSession);
22
+ setSession(jsonSession);
23
23
  }
24
24
  }
25
25
  /**
@@ -36,7 +36,7 @@ export async function fetch() {
36
36
  content = await secureFetch(identifier);
37
37
  }
38
38
  else {
39
- content = await getSession();
39
+ content = getSession();
40
40
  }
41
41
  if (!content) {
42
42
  return undefined;
@@ -59,9 +59,9 @@ export async function remove() {
59
59
  await secureRemove(identifier);
60
60
  }
61
61
  else {
62
- await removeSession();
62
+ removeSession();
63
63
  }
64
- await clearAllAppInfo();
64
+ clearAllAppInfo();
65
65
  }
66
66
  /**
67
67
  * Returns true if the secure store is available on the system.
@@ -76,7 +76,7 @@ async function secureStoreAvailable() {
76
76
  return false;
77
77
  }
78
78
  const keytar = await import('keytar');
79
- await keytar.default.findCredentials(constants.keychain.service);
79
+ await keytar.default.findCredentials(keychainConstants.service);
80
80
  debug(content `Secure store is available`);
81
81
  return true;
82
82
  // eslint-disable-next-line no-catch-all/no-catch-all
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/private/node/session/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAC,eAAe,EAAC,MAAM,4BAA4B,CAAA;AAC1D,OAAO,EAAC,KAAK,IAAI,WAAW,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,IAAI,YAAY,EAAC,MAAM,0BAA0B,CAAA;AAC3G,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAC,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,mBAAmB,CAAA;AAGxF;;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,UAAU,CAAC,WAAW,CAAC,CAAA;KACxB;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,UAAU,EAAE,CAAA;KACvB;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,aAAa,EAAE,CAAA;KAChB;IAED,eAAe,EAAE,CAAA;AACnB,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,iBAAiB,CAAC,OAAO,CAAC,CAAA;QAC/D,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 {keychainConstants} from '../constants.js'\nimport {platformAndArch} from '../../../public/node/os.js'\nimport {store as secureStore, fetch as secureFetch, remove as secureRemove} from '../../../secure-store.js'\nimport {content, debug} from '../../../output.js'\nimport {getSession, removeSession, setSession, clearAllAppInfo} from '../../../store.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 - 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 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 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 = 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 removeSession()\n }\n\n clearAllAppInfo()\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(keychainConstants.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"]}
@@ -1,8 +1,8 @@
1
1
  import { applicationId } from './identity.js';
2
2
  import { validateIdentityToken } from './identity-token-validation.js';
3
- import constants from '../constants.js';
4
- import { debug } from '../output.js';
5
- import { firstPartyDev } from '../environment/local.js';
3
+ import { sessionConstants } from '../constants.js';
4
+ import { debug } from '../../../output.js';
5
+ import { firstPartyDev } from '../../../public/node/environment/local.js';
6
6
  /**
7
7
  * Validate if an identity token is valid for the requested scopes
8
8
  */
@@ -60,6 +60,6 @@ function isTokenExpired(token) {
60
60
  return token.expiresAt < expireThreshold();
61
61
  }
62
62
  function expireThreshold() {
63
- return new Date(Date.now() + constants.session.expirationTimeMarginInMinutes * 60 * 1000);
63
+ return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000);
64
64
  }
65
65
  //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/private/node/session/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAC,qBAAqB,EAAC,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAA;AACxC,OAAO,EAAC,aAAa,EAAC,MAAM,2CAA2C,CAAA;AAKvE;;GAEG;AACH,SAAS,cAAc,CAAC,eAAyB,EAAE,QAAuB;IACxE,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAA;IACrC,IAAI,aAAa,EAAE,KAAK,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAA;IACxE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;AACxE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAgB,EAChB,YAA+B,EAC/B,OAGC;IAED,IAAI,CAAC,OAAO;QAAE,OAAO,iBAAiB,CAAA;IACtC,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC/D,MAAM,eAAe,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IACjF,IAAI,CAAC,cAAc;QAAE,OAAO,iBAAiB,CAAA;IAC7C,IAAI,gBAAgB,GAAG,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAEvD,IAAI,YAAY,CAAC,WAAW,EAAE;QAC5B,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;QACvC,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAE,CAAA;QAC1C,gBAAgB,GAAG,gBAAgB,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;KAC7D;IAED,IAAI,YAAY,CAAC,qBAAqB,EAAE;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,qBAAqB,CAAC,CAAA;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAE,CAAA;QAC1C,gBAAgB,GAAG,gBAAgB,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;KAC7D;IAED,IAAI,YAAY,CAAC,QAAQ,EAAE;QACzB,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;QACpC,MAAM,SAAS,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,SAAS,IAAI,KAAK,EAAE,CAAA;QAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC,SAAS,CAAE,CAAA;QAC9C,gBAAgB,GAAG,gBAAgB,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;KAC7D;IAED,KAAK,CAAC;;kBAEU,gBAAgB;8BACJ,CAAC,eAAe;GAC3C,CAAC,CAAA;IAEF,IAAI,gBAAgB;QAAE,OAAO,eAAe,CAAA;IAC5C,IAAI,CAAC,eAAe;QAAE,OAAO,iBAAiB,CAAA;IAC9C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,cAAc,CAAC,KAAuB;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,KAAK,CAAC,SAAS,GAAG,eAAe,EAAE,CAAA;AAC5C,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,CAAC,6BAA6B,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;AAC1F,CAAC","sourcesContent":["import {applicationId} from './identity.js'\nimport {ApplicationToken, IdentityToken} from './schema.js'\nimport {validateIdentityToken} from './identity-token-validation.js'\nimport {sessionConstants} from '../constants.js'\nimport {debug} from '../../../output.js'\nimport {firstPartyDev} from '../../../public/node/environment/local.js'\nimport {OAuthApplications} from '../session.js'\n\ntype ValidationResult = 'needs_refresh' | 'needs_full_auth' | 'ok'\n\n/**\n * Validate if an identity token is valid for the requested scopes\n */\nfunction validateScopes(requestedScopes: string[], identity: IdentityToken) {\n const currentScopes = identity.scopes\n if (firstPartyDev() !== currentScopes.includes('employee')) return false\n return requestedScopes.every((scope) => currentScopes.includes(scope))\n}\n\n/**\n * Validate if the current session is valid or we need to refresh/re-authenticate\n * @param scopes - requested scopes to validate\n * @param applications - requested applications\n * @param session - current session with identity and application tokens\n * @returns 'ok' if the session is valid, 'needs_full_auth' if we need to re-authenticate, 'needs_refresh' if we need to refresh the session\n */\nexport async function validateSession(\n scopes: string[],\n applications: OAuthApplications,\n session: {\n identity: IdentityToken\n applications: {[x: string]: ApplicationToken}\n },\n): Promise<ValidationResult> {\n if (!session) return 'needs_full_auth'\n const scopesAreValid = validateScopes(scopes, session.identity)\n const identityIsValid = await validateIdentityToken(session.identity.accessToken)\n if (!scopesAreValid) return 'needs_full_auth'\n let tokensAreExpired = isTokenExpired(session.identity)\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n const token = session.applications[appId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = session.applications[realAppId]!\n tokensAreExpired = tokensAreExpired || isTokenExpired(token)\n }\n\n debug(`\nThe validation of the token for application/identity completed with the following results:\n- It's expired: ${tokensAreExpired}\n- It's invalid in identity: ${!identityIsValid}\n `)\n\n if (tokensAreExpired) return 'needs_refresh'\n if (!identityIsValid) return 'needs_full_auth'\n return 'ok'\n}\n\nfunction isTokenExpired(token: ApplicationToken): boolean {\n if (!token) return true\n return token.expiresAt < expireThreshold()\n}\n\nfunction expireThreshold(): Date {\n return new Date(Date.now() + sessionConstants.expirationTimeMarginInMinutes * 60 * 1000)\n}\n"]}
@@ -0,0 +1,56 @@
1
+ /// <reference types="node" />
2
+ import { AdminSession } from '@shopify/cli-kit/node/session';
3
+ /**
4
+ * A scope supported by the Shopify Admin API.
5
+ */
6
+ declare type AdminAPIScope = 'graphql' | 'themes' | 'collaborator' | string;
7
+ /**
8
+ * It represents the options to authenticate against the Shopify Admin API.
9
+ */
10
+ interface AdminAPIOAuthOptions {
11
+ /** Store to request permissions for. */
12
+ storeFqdn: string;
13
+ /** List of scopes to request permissions for. */
14
+ scopes: AdminAPIScope[];
15
+ }
16
+ /**
17
+ * A scope supported by the Partners API.
18
+ */
19
+ declare type PartnersAPIScope = 'cli' | string;
20
+ interface PartnersAPIOAuthOptions {
21
+ /** List of scopes to request permissions for. */
22
+ scopes: PartnersAPIScope[];
23
+ }
24
+ /**
25
+ * A scope supported by the Storefront Renderer API.
26
+ */
27
+ declare type StorefrontRendererScope = 'devtools' | string;
28
+ interface StorefrontRendererAPIOAuthOptions {
29
+ /** List of scopes to request permissions for. */
30
+ scopes: StorefrontRendererScope[];
31
+ }
32
+ /**
33
+ * It represents the authentication requirements and
34
+ * is the input necessary to trigger the authentication
35
+ * flow.
36
+ */
37
+ export interface OAuthApplications {
38
+ adminApi?: AdminAPIOAuthOptions;
39
+ storefrontRendererApi?: StorefrontRendererAPIOAuthOptions;
40
+ partnersApi?: PartnersAPIOAuthOptions;
41
+ }
42
+ export interface OAuthSession {
43
+ admin?: AdminSession;
44
+ partners?: string;
45
+ storefront?: string;
46
+ }
47
+ /**
48
+ * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
49
+ *
50
+ * @param applications - An object containing the applications we need to be authenticated with.
51
+ * @param env - Optional environment variables to use.
52
+ * @param forceRefresh - Optional flag to force a refresh of the token.
53
+ * @returns An instance with the access tokens organized by application.
54
+ */
55
+ export declare function ensureAuthenticated(applications: OAuthApplications, env?: NodeJS.ProcessEnv, forceRefresh?: boolean): Promise<OAuthSession>;
56
+ export {};
@@ -1,107 +1,35 @@
1
1
  import { applicationId } from './session/identity.js';
2
- import { Abort, Bug } from './error.js';
3
2
  import { validateSession } from './session/validate.js';
4
3
  import { allDefaultScopes, apiScopes } from './session/scopes.js';
5
- import { identity as identityFqdn, normalizeStoreName, partners as partnersFqdn } from './environment/fqdn.js';
6
- import { open } from './system.js';
7
4
  import { exchangeAccessForApplicationTokens, exchangeCodeForAccessToken, exchangeCustomPartnerToken, refreshAccessToken, InvalidGrantError, InvalidRequestError, } from './session/exchange.js';
8
- import { content, token, debug } from './output.js';
9
- import { keypress } from './ui.js';
10
5
  import { authorize } from './session/authorize.js';
11
6
  import * as secureStore from './session/store.js';
12
- import constants from './constants.js';
13
- import * as output from './output.js';
14
- import { firstPartyDev, useDeviceAuth } from './environment/local.js';
15
7
  import { pollForDeviceAuthorization, requestDeviceAuthorization } from './session/device-authorization.js';
16
- import { AbortError } from './public/node/error.js';
17
- import { partnersRequest } from './public/node/api/partners.js';
18
- import { RequestClientError } from './private/node/api/headers.js';
8
+ import { RequestClientError } from './api/headers.js';
9
+ import { environmentVariables } from './constants.js';
10
+ import { content, token, debug } from '../../output.js';
11
+ import { keypress } from '../../ui.js';
12
+ import * as output from '../../output.js';
13
+ import { firstPartyDev, useDeviceAuth } from '../../public/node/environment/local.js';
14
+ import { AbortError } from '../../public/node/error.js';
15
+ import { partnersRequest } from '../../public/node/api/partners.js';
16
+ import { normalizeStoreFqdn, partnersFqdn, identityFqdn } from '../../public/node/environment/fqdn.js';
17
+ import { openURL } from '../../public/node/system.js';
18
+ import { Abort, Bug } from '../../error.js';
19
19
  import { gql } from 'graphql-request';
20
- const NoSessionError = new Bug('No session found after ensuring authenticated');
21
- const MissingPartnerTokenError = new Bug('No partners token found after ensuring authenticated');
22
- const MissingAdminTokenError = new Bug('No admin token found after ensuring authenticated');
23
- const MissingStorefrontTokenError = new Bug('No storefront token found after ensuring authenticated');
24
- /**
25
- * Ensure that we have a valid session to access the Partners API.
26
- * If SHOPIFY_CLI_PARTNERS_TOKEN exists, that token will be used to obtain a valid Partners Token
27
- * If SHOPIFY_CLI_PARTNERS_TOKEN exists, scopes will be ignored
28
- * @param scopes - Optional array of extra scopes to authenticate with.
29
- * @returns The access token for the Partners API.
30
- */
31
- export async function ensureAuthenticatedPartners(scopes = [], env = process.env) {
32
- debug(content `Ensuring that the user is authenticated with the Partners API with the following scopes:
33
- ${token.json(scopes)}
34
- `);
35
- const envToken = env[constants.environmentVariables.partnersToken];
36
- if (envToken) {
37
- return (await exchangeCustomPartnerToken(envToken)).accessToken;
38
- }
39
- const tokens = await ensureAuthenticated({ partnersApi: { scopes } });
40
- if (!tokens.partners) {
41
- throw MissingPartnerTokenError;
42
- }
43
- return tokens.partners;
44
- }
45
- /**
46
- * Ensure that we have a valid session to access the Storefront API.
47
- * @param scopes - Optional array of extra scopes to authenticate with.
48
- * @returns The access token for the Storefront API.
49
- */
50
- export async function ensureAuthenticatedStorefront(scopes = [], password = undefined) {
51
- if (password)
52
- return password;
53
- debug(content `Ensuring that the user is authenticated with the Storefront API with the following scopes:
54
- ${token.json(scopes)}
55
- `);
56
- const tokens = await ensureAuthenticated({ storefrontRendererApi: { scopes } });
57
- if (!tokens.storefront) {
58
- throw MissingStorefrontTokenError;
59
- }
60
- return tokens.storefront;
61
- }
62
- /**
63
- * Ensure that we have a valid Admin session for the given store.
64
- * @param store - Store fqdn to request auth for
65
- * @param scopes - Optional array of extra scopes to authenticate with.
66
- * @returns The access token for the Admin API
67
- */
68
- export async function ensureAuthenticatedAdmin(store, scopes = [], forceRefresh = false) {
69
- debug(content `Ensuring that the user is authenticated with the Admin API with the following scopes for the store ${token.raw(store)}:
70
- ${token.json(scopes)}
71
- `);
72
- const tokens = await ensureAuthenticated({ adminApi: { scopes, storeFqdn: store } }, process.env, forceRefresh);
73
- if (!tokens.admin) {
74
- throw MissingAdminTokenError;
75
- }
76
- return tokens.admin;
77
- }
78
- /**
79
- * Ensure that we have a valid session to access the Theme API.
80
- * If a password is provided, that token will be used against Theme Access API.
81
- * Otherwise, it will ensure that the user is authenticated with the Admin API.
82
- * @param store - Store fqdn to request auth for
83
- * @param password - Password generated from Theme Access app
84
- * @param scopes - Optional array of extra scopes to authenticate with.
85
- * @returns The access token and store
86
- */
87
- export async function ensureAuthenticatedThemes(store, password, scopes = [], forceRefresh = false) {
88
- debug(content `Ensuring that the user is authenticated with the Theme API with the following scopes:
89
- ${token.json(scopes)}
90
- `);
91
- if (password)
92
- return { token: password, storeFqdn: await normalizeStoreName(store) };
93
- return ensureAuthenticatedAdmin(store, scopes, forceRefresh);
94
- }
95
20
  /**
96
21
  * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.
22
+ *
97
23
  * @param applications - An object containing the applications we need to be authenticated with.
24
+ * @param env - Optional environment variables to use.
25
+ * @param forceRefresh - Optional flag to force a refresh of the token.
98
26
  * @returns An instance with the access tokens organized by application.
99
27
  */
100
28
  export async function ensureAuthenticated(applications, env = process.env, forceRefresh = false) {
101
29
  const fqdn = await identityFqdn();
102
30
  const previousStoreFqdn = applications.adminApi?.storeFqdn;
103
31
  if (previousStoreFqdn) {
104
- const normalizedStoreName = await normalizeStoreName(previousStoreFqdn);
32
+ const normalizedStoreName = await normalizeStoreFqdn(previousStoreFqdn);
105
33
  if (previousStoreFqdn === applications.adminApi?.storeFqdn) {
106
34
  applications.adminApi.storeFqdn = normalizedStoreName;
107
35
  }
@@ -142,7 +70,7 @@ ${token.json(applications)}
142
70
  await secureStore.store(completeSession);
143
71
  const tokens = await tokensFor(applications, completeSession, fqdn);
144
72
  // Overwrite partners token if using a custom CLI Token
145
- const envToken = env[constants.environmentVariables.partnersToken];
73
+ const envToken = env[environmentVariables.partnersToken];
146
74
  if (envToken && applications.partnersApi) {
147
75
  tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken;
148
76
  }
@@ -151,50 +79,12 @@ ${token.json(applications)}
151
79
  }
152
80
  return tokens;
153
81
  }
154
- export async function hasPartnerAccount(partnersToken) {
155
- try {
156
- await partnersRequest(gql `
157
- {
158
- organizations(first: 1) {
159
- nodes {
160
- id
161
- }
162
- }
163
- }
164
- `, partnersToken);
165
- return true;
166
- // eslint-disable-next-line no-catch-all/no-catch-all
167
- }
168
- catch (error) {
169
- if (error instanceof RequestClientError && error.statusCode === 404) {
170
- return false;
171
- }
172
- else {
173
- return true;
174
- }
175
- }
176
- }
177
82
  /**
178
- * If the user creates an account from the Identity website, the created
179
- * account won't get a Partner organization created. We need to detect that
180
- * and take the user to create a partner organization.
181
- * @param partnersToken - Partners token
83
+ * Execute the full authentication flow.
84
+ *
85
+ * @param applications - An object containing the applications we need to be authenticated with.
86
+ * @param identityFqdn - The identity FQDN.
182
87
  */
183
- export async function ensureUserHasPartnerAccount(partnersToken) {
184
- debug(content `Verifying that the user has a Partner organization`);
185
- if (!(await hasPartnerAccount(partnersToken))) {
186
- output.info(`\nA Shopify Partners organization is needed to proceed.`);
187
- output.info(`👉 Press any key to create one`);
188
- await keypress();
189
- await open(`https://${await partnersFqdn()}/signup`);
190
- output.info(output.content `👉 Press any key when you have ${output.token.cyan('created the organization')}`);
191
- output.warn(output.content `Make sure you've confirmed your Shopify and the Partner organization from the email`);
192
- await keypress();
193
- if (!(await hasPartnerAccount(partnersToken))) {
194
- throw new Abort(`Couldn't find your Shopify Partners organization`, `Have you confirmed your accounts from the emails you received?`);
195
- }
196
- }
197
- }
198
88
  async function executeCompleteFlow(applications, identityFqdn) {
199
89
  const scopes = getFlattenScopes(applications);
200
90
  const exchangeScopes = getExchangeScopes(applications);
@@ -232,6 +122,64 @@ async function executeCompleteFlow(applications, identityFqdn) {
232
122
  output.completed('Logged in.');
233
123
  return session;
234
124
  }
125
+ /**
126
+ * If the user creates an account from the Identity website, the created
127
+ * account won't get a Partner organization created. We need to detect that
128
+ * and take the user to create a partner organization.
129
+ *
130
+ * @param partnersToken - Partners token.
131
+ */
132
+ async function ensureUserHasPartnerAccount(partnersToken) {
133
+ debug(content `Verifying that the user has a Partner organization`);
134
+ if (!(await hasPartnerAccount(partnersToken))) {
135
+ output.info(`\nA Shopify Partners organization is needed to proceed.`);
136
+ output.info(`👉 Press any key to create one`);
137
+ await keypress();
138
+ await openURL(`https://${await partnersFqdn()}/signup`);
139
+ output.info(output.content `👉 Press any key when you have ${output.token.cyan('created the organization')}`);
140
+ output.warn(output.content `Make sure you've confirmed your Shopify and the Partner organization from the email`);
141
+ await keypress();
142
+ if (!(await hasPartnerAccount(partnersToken))) {
143
+ throw new Abort(`Couldn't find your Shopify Partners organization`, `Have you confirmed your accounts from the emails you received?`);
144
+ }
145
+ }
146
+ }
147
+ /**
148
+ * Validate if the current token is valid for partners API.
149
+ *
150
+ * @param partnersToken - Partners token.
151
+ * @returns A promise that resolves to true if the token is valid for partners API.
152
+ */
153
+ async function hasPartnerAccount(partnersToken) {
154
+ try {
155
+ await partnersRequest(gql `
156
+ {
157
+ organizations(first: 1) {
158
+ nodes {
159
+ id
160
+ }
161
+ }
162
+ }
163
+ `, partnersToken);
164
+ return true;
165
+ // eslint-disable-next-line no-catch-all/no-catch-all
166
+ }
167
+ catch (error) {
168
+ if (error instanceof RequestClientError && error.statusCode === 404) {
169
+ return false;
170
+ }
171
+ else {
172
+ return true;
173
+ }
174
+ }
175
+ }
176
+ /**
177
+ * Refresh the tokens for a given session.
178
+ *
179
+ * @param token - Identity token.
180
+ * @param applications - An object containing the applications we need to be authenticated with.
181
+ * @param fqdn - The identity FQDN.
182
+ */
235
183
  async function refreshTokens(token, applications, fqdn) {
236
184
  // Refresh Identity Token
237
185
  const identityToken = await refreshAccessToken(token);
@@ -245,10 +193,17 @@ async function refreshTokens(token, applications, fqdn) {
245
193
  },
246
194
  };
247
195
  }
196
+ /**
197
+ * Get the application tokens for a given session.
198
+ *
199
+ * @param applications - An object containing the applications we need the tokens for.
200
+ * @param session - The current session.
201
+ * @param fqdn - The identity FQDN.
202
+ */
248
203
  async function tokensFor(applications, session, fqdn) {
249
204
  const fqdnSession = session[fqdn];
250
205
  if (!fqdnSession) {
251
- throw NoSessionError;
206
+ throw new Bug('No session found after ensuring authenticated');
252
207
  }
253
208
  const tokens = {};
254
209
  if (applications.adminApi) {
@@ -270,6 +225,12 @@ async function tokensFor(applications, session, fqdn) {
270
225
  return tokens;
271
226
  }
272
227
  // Scope Helpers
228
+ /**
229
+ * Get a flattened array of scopes for the given applications.
230
+ *
231
+ * @param apps - An object containing the applications we need the scopes for.
232
+ * @returns A flattened array of scopes.
233
+ */
273
234
  function getFlattenScopes(apps) {
274
235
  const admin = apps.adminApi?.scopes || [];
275
236
  const partner = apps.partnersApi?.scopes || [];
@@ -277,6 +238,12 @@ function getFlattenScopes(apps) {
277
238
  const requestedScopes = [...admin, ...partner, ...storefront];
278
239
  return allDefaultScopes(requestedScopes);
279
240
  }
241
+ /**
242
+ * Get the scopes for the given applications.
243
+ *
244
+ * @param apps - An object containing the applications we need the scopes for.
245
+ * @returns An object containing the scopes for each application.
246
+ */
280
247
  function getExchangeScopes(apps) {
281
248
  const adminScope = apps.adminApi?.scopes || [];
282
249
  const partnerScope = apps.partnersApi?.scopes || [];
@@ -287,7 +254,4 @@ function getExchangeScopes(apps) {
287
254
  storefront: apiScopes('storefront-renderer', storefrontScopes),
288
255
  };
289
256
  }
290
- export function logout() {
291
- return secureStore.remove();
292
- }
293
257
  //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/private/node/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {applicationId} from './session/identity.js'\nimport {validateSession} from './session/validate.js'\nimport {allDefaultScopes, apiScopes} from './session/scopes.js'\nimport {\n exchangeAccessForApplicationTokens,\n exchangeCodeForAccessToken,\n exchangeCustomPartnerToken,\n ExchangeScopes,\n refreshAccessToken,\n InvalidGrantError,\n InvalidRequestError,\n} from './session/exchange.js'\nimport {authorize} from './session/authorize.js'\nimport {IdentityToken, Session} from './session/schema.js'\nimport * as secureStore from './session/store.js'\nimport {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'\nimport {RequestClientError} from './api/headers.js'\nimport {environmentVariables} from './constants.js'\nimport {content, token, debug} from '../../output.js'\nimport {keypress} from '../../ui.js'\nimport * as output from '../../output.js'\nimport {firstPartyDev, useDeviceAuth} from '../../public/node/environment/local.js'\nimport {AbortError} from '../../public/node/error.js'\nimport {partnersRequest} from '../../public/node/api/partners.js'\nimport {normalizeStoreFqdn, partnersFqdn, identityFqdn} from '../../public/node/environment/fqdn.js'\nimport {openURL} from '../../public/node/system.js'\nimport {Abort, Bug} from '../../error.js'\nimport {gql} from 'graphql-request'\nimport {AdminSession} from '@shopify/cli-kit/node/session'\n\n/**\n * A scope supported by the Shopify Admin API.\n */\ntype AdminAPIScope = 'graphql' | 'themes' | 'collaborator' | string\n\n/**\n * It represents the options to authenticate against the Shopify Admin API.\n */\n\ninterface AdminAPIOAuthOptions {\n /** Store to request permissions for. */\n storeFqdn: string\n /** List of scopes to request permissions for. */\n scopes: AdminAPIScope[]\n}\n\n/**\n * A scope supported by the Partners API.\n */\ntype PartnersAPIScope = 'cli' | string\ninterface PartnersAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: PartnersAPIScope[]\n}\n\n/**\n * A scope supported by the Storefront Renderer API.\n */\ntype StorefrontRendererScope = 'devtools' | string\ninterface StorefrontRendererAPIOAuthOptions {\n /** List of scopes to request permissions for. */\n scopes: StorefrontRendererScope[]\n}\n\n/**\n * It represents the authentication requirements and\n * is the input necessary to trigger the authentication\n * flow.\n */\nexport interface OAuthApplications {\n adminApi?: AdminAPIOAuthOptions\n storefrontRendererApi?: StorefrontRendererAPIOAuthOptions\n partnersApi?: PartnersAPIOAuthOptions\n}\n\nexport interface OAuthSession {\n admin?: AdminSession\n partners?: string\n storefront?: string\n}\n\n/**\n * This method ensures that we have a valid session to authenticate against the given applications using the provided scopes.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param env - Optional environment variables to use.\n * @param forceRefresh - Optional flag to force a refresh of the token.\n * @returns An instance with the access tokens organized by application.\n */\nexport async function ensureAuthenticated(\n applications: OAuthApplications,\n env = process.env,\n forceRefresh = false,\n): Promise<OAuthSession> {\n const fqdn = await identityFqdn()\n\n const previousStoreFqdn = applications.adminApi?.storeFqdn\n if (previousStoreFqdn) {\n const normalizedStoreName = await normalizeStoreFqdn(previousStoreFqdn)\n if (previousStoreFqdn === applications.adminApi?.storeFqdn) {\n applications.adminApi.storeFqdn = normalizedStoreName\n }\n }\n\n const currentSession = (await secureStore.fetch()) || {}\n const fqdnSession = currentSession[fqdn]!\n const scopes = getFlattenScopes(applications)\n\n debug(content`Validating existing session against the scopes:\n${token.json(scopes)}\nFor applications:\n${token.json(applications)}\n`)\n const validationResult = await validateSession(scopes, applications, fqdnSession)\n\n let newSession = {}\n\n if (validationResult === 'needs_full_auth') {\n debug(content`Initiating the full authentication flow...`)\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (validationResult === 'needs_refresh' || forceRefresh) {\n debug(content`The current session is valid but needs refresh. Refreshing...`)\n try {\n newSession = await refreshTokens(fqdnSession.identity, applications, fqdn)\n } catch (error) {\n if (error instanceof InvalidGrantError) {\n newSession = await executeCompleteFlow(applications, fqdn)\n } else if (error instanceof InvalidRequestError) {\n await secureStore.remove()\n throw new AbortError('\\nError validating auth session', \"We've cleared the current session, please try again\")\n } else {\n throw error\n }\n }\n }\n\n const completeSession: Session = {...currentSession, ...newSession}\n await secureStore.store(completeSession)\n const tokens = await tokensFor(applications, completeSession, fqdn)\n\n // Overwrite partners token if using a custom CLI Token\n const envToken = env[environmentVariables.partnersToken]\n if (envToken && applications.partnersApi) {\n tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken\n }\n if (!envToken && tokens.partners) {\n await ensureUserHasPartnerAccount(tokens.partners)\n }\n\n return tokens\n}\n\n/**\n * Execute the full authentication flow.\n *\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param identityFqdn - The identity FQDN.\n */\nasync function executeCompleteFlow(applications: OAuthApplications, identityFqdn: string): Promise<Session> {\n const scopes = getFlattenScopes(applications)\n const exchangeScopes = getExchangeScopes(applications)\n const store = applications.adminApi?.storeFqdn\n if (firstPartyDev()) {\n debug(content`Authenticating as Shopify Employee...`)\n scopes.push('employee')\n }\n\n let identityToken: IdentityToken\n if (useDeviceAuth()) {\n // Request a device code to authorize without a browser redirect.\n debug(content`Requesting device authorization code...`)\n const deviceAuth = await requestDeviceAuthorization(scopes)\n\n // Poll for the identity token\n debug(content`Starting polling for the identity token...`)\n identityToken = await pollForDeviceAuthorization(deviceAuth.deviceCode, deviceAuth.interval)\n } else {\n // Authorize user via browser\n debug(content`Authorizing through Identity's website...`)\n const code = await authorize(scopes)\n\n // Exchange code for identity token\n debug(content`Authorization code received. Exchanging it for a CLI token...`)\n identityToken = await exchangeCodeForAccessToken(code)\n }\n\n // Exchange identity token for application tokens\n debug(content`CLI token received. Exchanging it for application tokens...`)\n const result = await exchangeAccessForApplicationTokens(identityToken, exchangeScopes, store)\n\n const session: Session = {\n [identityFqdn]: {\n identity: identityToken,\n applications: result,\n },\n }\n\n output.completed('Logged in.')\n\n return session\n}\n\n/**\n * If the user creates an account from the Identity website, the created\n * account won't get a Partner organization created. We need to detect that\n * and take the user to create a partner organization.\n *\n * @param partnersToken - Partners token.\n */\nasync function ensureUserHasPartnerAccount(partnersToken: string) {\n debug(content`Verifying that the user has a Partner organization`)\n if (!(await hasPartnerAccount(partnersToken))) {\n output.info(`\\nA Shopify Partners organization is needed to proceed.`)\n output.info(`👉 Press any key to create one`)\n await keypress()\n await openURL(`https://${await partnersFqdn()}/signup`)\n output.info(output.content`👉 Press any key when you have ${output.token.cyan('created the organization')}`)\n output.warn(output.content`Make sure you've confirmed your Shopify and the Partner organization from the email`)\n await keypress()\n if (!(await hasPartnerAccount(partnersToken))) {\n throw new Abort(\n `Couldn't find your Shopify Partners organization`,\n `Have you confirmed your accounts from the emails you received?`,\n )\n }\n }\n}\n\n/**\n * Validate if the current token is valid for partners API.\n *\n * @param partnersToken - Partners token.\n * @returns A promise that resolves to true if the token is valid for partners API.\n */\nasync function hasPartnerAccount(partnersToken: string): Promise<boolean> {\n try {\n await partnersRequest(\n gql`\n {\n organizations(first: 1) {\n nodes {\n id\n }\n }\n }\n `,\n partnersToken,\n )\n return true\n // eslint-disable-next-line no-catch-all/no-catch-all\n } catch (error) {\n if (error instanceof RequestClientError && error.statusCode === 404) {\n return false\n } else {\n return true\n }\n }\n}\n\n/**\n * Refresh the tokens for a given session.\n *\n * @param token - Identity token.\n * @param applications - An object containing the applications we need to be authenticated with.\n * @param fqdn - The identity FQDN.\n */\nasync function refreshTokens(token: IdentityToken, applications: OAuthApplications, fqdn: string): Promise<Session> {\n // Refresh Identity Token\n const identityToken = await refreshAccessToken(token)\n // Exchange new identity token for application tokens\n const exchangeScopes = getExchangeScopes(applications)\n const applicationTokens = await exchangeAccessForApplicationTokens(\n identityToken,\n exchangeScopes,\n applications.adminApi?.storeFqdn,\n )\n\n return {\n [fqdn]: {\n identity: identityToken,\n applications: applicationTokens,\n },\n }\n}\n\n/**\n * Get the application tokens for a given session.\n *\n * @param applications - An object containing the applications we need the tokens for.\n * @param session - The current session.\n * @param fqdn - The identity FQDN.\n */\nasync function tokensFor(applications: OAuthApplications, session: Session, fqdn: string): Promise<OAuthSession> {\n const fqdnSession = session[fqdn]\n if (!fqdnSession) {\n throw new Bug('No session found after ensuring authenticated')\n }\n const tokens: OAuthSession = {}\n if (applications.adminApi) {\n const appId = applicationId('admin')\n const realAppId = `${applications.adminApi.storeFqdn}-${appId}`\n const token = fqdnSession.applications[realAppId]?.accessToken\n if (token) {\n tokens.admin = {token, storeFqdn: applications.adminApi.storeFqdn}\n }\n }\n\n if (applications.partnersApi) {\n const appId = applicationId('partners')\n tokens.partners = fqdnSession.applications[appId]?.accessToken\n }\n\n if (applications.storefrontRendererApi) {\n const appId = applicationId('storefront-renderer')\n tokens.storefront = fqdnSession.applications[appId]?.accessToken\n }\n return tokens\n}\n\n// Scope Helpers\n/**\n * Get a flattened array of scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns A flattened array of scopes.\n */\nfunction getFlattenScopes(apps: OAuthApplications): string[] {\n const admin = apps.adminApi?.scopes || []\n const partner = apps.partnersApi?.scopes || []\n const storefront = apps.storefrontRendererApi?.scopes || []\n const requestedScopes = [...admin, ...partner, ...storefront]\n return allDefaultScopes(requestedScopes)\n}\n\n/**\n * Get the scopes for the given applications.\n *\n * @param apps - An object containing the applications we need the scopes for.\n * @returns An object containing the scopes for each application.\n */\nfunction getExchangeScopes(apps: OAuthApplications): ExchangeScopes {\n const adminScope = apps.adminApi?.scopes || []\n const partnerScope = apps.partnersApi?.scopes || []\n const storefrontScopes = apps.storefrontRendererApi?.scopes || []\n return {\n admin: apiScopes('admin', adminScope),\n partners: apiScopes('partners', partnerScope),\n storefront: apiScopes('storefront-renderer', storefrontScopes),\n }\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  import { Props as SelectProps } from './SelectInput.js';
2
2
  import { Props as TableProps } from './Table.js';
3
+ import { TokenItem } from './TokenizedText.js';
3
4
  import React, { ReactElement } from 'react';
4
5
  export interface Props<T> {
5
- message: string;
6
+ message: TokenItem;
6
7
  choices: SelectProps<T>['items'];
7
8
  onSubmit: (value: T) => void;
8
9
  infoTable?: TableProps['table'];
@@ -1,5 +1,6 @@
1
1
  import SelectInput from './SelectInput.js';
2
2
  import Table from './Table.js';
3
+ import { TokenizedText } from './TokenizedText.js';
3
4
  import { handleCtrlC } from '../../ui.js';
4
5
  import React, { useCallback, useState } from 'react';
5
6
  import { Box, measureElement, Text, useApp, useInput, useStdout } from 'ink';
@@ -32,7 +33,7 @@ function SelectPrompt({ message, choices, infoTable, onSubmit, }) {
32
33
  React.createElement(Box, null,
33
34
  React.createElement(Box, { marginRight: 2 },
34
35
  React.createElement(Text, null, "?")),
35
- React.createElement(Text, null, message)),
36
+ React.createElement(TokenizedText, { item: message })),
36
37
  infoTable && !submitted && (React.createElement(Box, { marginLeft: 7 },
37
38
  React.createElement(Table, { table: infoTable }))),
38
39
  submitted ? (React.createElement(Box, null,
@@ -1 +1 @@
1
- {"version":3,"file":"SelectPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,WAA6D,MAAM,kBAAkB,CAAA;AAC5F,OAAO,KAA4B,MAAM,YAAY,CAAA;AACrD,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,EAAe,WAAW,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAChE,OAAO,EAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AAC1E,OAAO,EAAC,OAAO,EAAC,MAAM,QAAQ,CAAA;AAC9B,OAAO,WAAW,MAAM,cAAc,CAAA;AAStC,SAAS,YAAY,CAAI,EACvB,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,GAC0B;IAClC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAgB,OAAO,CAAC,CAAC,CAAE,CAAC,CAAA;IAChE,MAAM,EAAC,IAAI,EAAE,UAAU,EAAC,GAAG,MAAM,EAAE,CAAA;IACnC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACjD,MAAM,EAAC,MAAM,EAAC,GAAG,SAAS,EAAE,CAAA;IAC5B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;IAEvC,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE;QACvC,IAAI,IAAI,KAAK,IAAI,EAAE;YACjB,MAAM,EAAC,MAAM,EAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;YACrC,SAAS,CAAC,MAAM,CAAC,CAAA;SAClB;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,QAAQ,CACN,WAAW,CACT,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACb,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAEvB,IAAI,GAAG,CAAC,MAAM,EAAE;YACd,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE;gBACnC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,aAAa,CAAC,CAAA;aACxC;YACD,YAAY,CAAC,IAAI,CAAC,CAAA;YAClB,UAAU,EAAE,CAAA;YACZ,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;SACvB;IACH,CAAC,EACD,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAC3B,CACF,CAAA;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,WAAW;QAC3D,oBAAC,GAAG;YACF,oBAAC,GAAG,IAAC,WAAW,EAAE,CAAC;gBACjB,oBAAC,IAAI,YAAS,CACV;YACN,oBAAC,IAAI,QAAE,OAAO,CAAQ,CAClB;QACL,SAAS,IAAI,CAAC,SAAS,IAAI,CAC1B,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;YAChB,oBAAC,KAAK,IAAC,KAAK,EAAE,SAAS,GAAI,CACvB,CACP;QACA,SAAS,CAAC,CAAC,CAAC,CACX,oBAAC,GAAG;YACF,oBAAC,GAAG,IAAC,WAAW,EAAE,CAAC;gBACjB,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,OAAO,CAAC,IAAI,CAAQ,CACpC;YAEN,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,MAAM,CAAC,KAAK,CAAQ,CACpC,CACP,CAAC,CAAC,CAAC,CACF,oBAAC,WAAW,IACV,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,IAAa,EAAE,EAAE;gBAC1B,SAAS,CAAC,IAAI,CAAC,CAAA;YACjB,CAAC,GACD,CACH,CACG,CACP,CAAA;AACH,CAAC;AAED,OAAO,EAAC,YAAY,EAAC,CAAA","sourcesContent":["import SelectInput, {Props as SelectProps, Item as SelectItem, Item} from './SelectInput.js'\nimport Table, {Props as TableProps} from './Table.js'\nimport {handleCtrlC} from '../../ui.js'\nimport React, {ReactElement, useCallback, useState} from 'react'\nimport {Box, measureElement, Text, useApp, useInput, useStdout} from 'ink'\nimport {figures} from 'listr2'\nimport ansiEscapes from 'ansi-escapes'\n\nexport interface Props<T> {\n message: string\n choices: SelectProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: TableProps['table']\n}\n\nfunction SelectPrompt<T>({\n message,\n choices,\n infoTable,\n onSubmit,\n}: React.PropsWithChildren<Props<T>>): ReactElement | null {\n const [answer, setAnswer] = useState<SelectItem<T>>(choices[0]!)\n const {exit: unmountInk} = useApp()\n const [submitted, setSubmitted] = useState(false)\n const {stdout} = useStdout()\n const [height, setHeight] = useState(0)\n\n const measuredRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setHeight(height)\n }\n }, [])\n\n useInput(\n useCallback(\n (input, key) => {\n handleCtrlC(input, key)\n\n if (key.return) {\n if (stdout && height >= stdout.rows) {\n stdout.write(ansiEscapes.clearTerminal)\n }\n setSubmitted(true)\n unmountInk()\n onSubmit(answer.value)\n }\n },\n [answer, onSubmit, height],\n ),\n )\n\n return (\n <Box flexDirection=\"column\" marginBottom={1} ref={measuredRef}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <Text>{message}</Text>\n </Box>\n {infoTable && !submitted && (\n <Box marginLeft={7}>\n <Table table={infoTable} />\n </Box>\n )}\n {submitted ? (\n <Box>\n <Box marginRight={2}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Text color=\"cyan\">{answer.label}</Text>\n </Box>\n ) : (\n <SelectInput\n items={choices}\n onChange={(item: Item<T>) => {\n setAnswer(item)\n }}\n />\n )}\n </Box>\n )\n}\n\nexport {SelectPrompt}\n"]}
1
+ {"version":3,"file":"SelectPrompt.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectPrompt.tsx"],"names":[],"mappings":"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","sourcesContent":["import SelectInput, {Props as SelectProps, Item as SelectItem, Item} from './SelectInput.js'\nimport Table, {Props as TableProps} from './Table.js'\nimport {TokenItem, TokenizedText} from './TokenizedText.js'\nimport {handleCtrlC} from '../../ui.js'\nimport React, {ReactElement, useCallback, useState} from 'react'\nimport {Box, measureElement, Text, useApp, useInput, useStdout} from 'ink'\nimport {figures} from 'listr2'\nimport ansiEscapes from 'ansi-escapes'\n\nexport interface Props<T> {\n message: TokenItem\n choices: SelectProps<T>['items']\n onSubmit: (value: T) => void\n infoTable?: TableProps['table']\n}\n\nfunction SelectPrompt<T>({\n message,\n choices,\n infoTable,\n onSubmit,\n}: React.PropsWithChildren<Props<T>>): ReactElement | null {\n const [answer, setAnswer] = useState<SelectItem<T>>(choices[0]!)\n const {exit: unmountInk} = useApp()\n const [submitted, setSubmitted] = useState(false)\n const {stdout} = useStdout()\n const [height, setHeight] = useState(0)\n\n const measuredRef = useCallback((node) => {\n if (node !== null) {\n const {height} = measureElement(node)\n setHeight(height)\n }\n }, [])\n\n useInput(\n useCallback(\n (input, key) => {\n handleCtrlC(input, key)\n\n if (key.return) {\n if (stdout && height >= stdout.rows) {\n stdout.write(ansiEscapes.clearTerminal)\n }\n setSubmitted(true)\n unmountInk()\n onSubmit(answer.value)\n }\n },\n [answer, onSubmit, height],\n ),\n )\n\n return (\n <Box flexDirection=\"column\" marginBottom={1} ref={measuredRef}>\n <Box>\n <Box marginRight={2}>\n <Text>?</Text>\n </Box>\n <TokenizedText item={message} />\n </Box>\n {infoTable && !submitted && (\n <Box marginLeft={7}>\n <Table table={infoTable} />\n </Box>\n )}\n {submitted ? (\n <Box>\n <Box marginRight={2}>\n <Text color=\"cyan\">{figures.tick}</Text>\n </Box>\n\n <Text color=\"cyan\">{answer.label}</Text>\n </Box>\n ) : (\n <SelectInput\n items={choices}\n onChange={(item: Item<T>) => {\n setAnswer(item)\n }}\n />\n )}\n </Box>\n )\n}\n\nexport {SelectPrompt}\n"]}
@@ -0,0 +1,5 @@
1
+ export interface Column<T> {
2
+ name: keyof T;
3
+ width: number;
4
+ color?: string;
5
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Column.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Column.js","sourceRoot":"","sources":["../../../../../../src/private/node/ui/components/Table/Column.ts"],"names":[],"mappings":"","sourcesContent":["export interface Column<T> {\n name: keyof T\n width: number\n color?: string\n}\n"]}