shopify-app-js 0.0.1-security → 1.0.1

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.

Potentially problematic release.


This version of shopify-app-js might be problematic. Click here for more details.

Files changed (424) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +14 -0
  3. package/.changeset/flat-clouds-camp.md +5 -0
  4. package/.eslintrc.js +36 -0
  5. package/.github/CODEOWNERS +1 -0
  6. package/.github/ISSUE_TEMPLATE/BUG_REPORT.md +36 -0
  7. package/.github/ISSUE_TEMPLATE/ENHANCEMENT.md +9 -0
  8. package/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md +9 -0
  9. package/.github/PULL_REQUEST_TEMPLATE.md +34 -0
  10. package/.github/dependabot.yml +9 -0
  11. package/.github/workflows/changelog.yml +30 -0
  12. package/.github/workflows/ci.yml +22 -0
  13. package/.github/workflows/cla.yml +22 -0
  14. package/.github/workflows/close-waiting-for-response-issues.yml +20 -0
  15. package/.github/workflows/main-release.yml +36 -0
  16. package/.github/workflows/markdown_link_check.yml +14 -0
  17. package/.github/workflows/markdown_link_checker_config.json +9 -0
  18. package/.github/workflows/publish-experimental-build.yml +30 -0
  19. package/.github/workflows/release-candidate.yml +35 -0
  20. package/.github/workflows/remove-labels-on-activity.yml +16 -0
  21. package/.github/workflows/stale.yml +26 -0
  22. package/.prettierignore +5 -0
  23. package/.prettierrc +1 -0
  24. package/CODE_OF_CONDUCT.md +46 -0
  25. package/CONTRIBUTING.md +39 -0
  26. package/LICENSE.md +9 -0
  27. package/README.md +62 -3
  28. package/RELEASING.md +142 -0
  29. package/loom.config.ts +115 -0
  30. package/package.json +44 -3
  31. package/packages/.prettierrc +1 -0
  32. package/packages/shopify-app-express/CHANGELOG.md +316 -0
  33. package/packages/shopify-app-express/LICENSE.md +9 -0
  34. package/packages/shopify-app-express/README.md +93 -0
  35. package/packages/shopify-app-express/docs/reference/README.md +3 -0
  36. package/packages/shopify-app-express/docs/reference/auth.md +76 -0
  37. package/packages/shopify-app-express/docs/reference/cspHeaders.md +24 -0
  38. package/packages/shopify-app-express/docs/reference/ensureInstalledOnShop.md +17 -0
  39. package/packages/shopify-app-express/docs/reference/migrating-app-v6-api-lib-to-express-lib.md +345 -0
  40. package/packages/shopify-app-express/docs/reference/processWebhooks.md +67 -0
  41. package/packages/shopify-app-express/docs/reference/redirectOutOfApp.md +77 -0
  42. package/packages/shopify-app-express/docs/reference/redirectToShopifyOrAppRoot.md +20 -0
  43. package/packages/shopify-app-express/docs/reference/shopifyApp.md +148 -0
  44. package/packages/shopify-app-express/docs/reference/validateAuthenticatedSession.md +30 -0
  45. package/packages/shopify-app-express/loom.config.ts +27 -0
  46. package/packages/shopify-app-express/package.json +54 -0
  47. package/packages/shopify-app-express/src/__tests__/index.test.ts +100 -0
  48. package/packages/shopify-app-express/src/__tests__/integration/oauth.test.ts +445 -0
  49. package/packages/shopify-app-express/src/__tests__/integration/responses.ts +135 -0
  50. package/packages/shopify-app-express/src/__tests__/integration/types.ts +22 -0
  51. package/packages/shopify-app-express/src/__tests__/integration/utils.ts +68 -0
  52. package/packages/shopify-app-express/src/__tests__/integration/webhooks.test.ts +208 -0
  53. package/packages/shopify-app-express/src/__tests__/redirect-to-auth.test.ts +103 -0
  54. package/packages/shopify-app-express/src/__tests__/setup-jest.ts +8 -0
  55. package/packages/shopify-app-express/src/__tests__/test-helper.ts +204 -0
  56. package/packages/shopify-app-express/src/app-installations.ts +42 -0
  57. package/packages/shopify-app-express/src/auth/__tests__/auth.test.ts +303 -0
  58. package/packages/shopify-app-express/src/auth/auth-callback.ts +131 -0
  59. package/packages/shopify-app-express/src/auth/index.ts +32 -0
  60. package/packages/shopify-app-express/src/auth/types.ts +13 -0
  61. package/packages/shopify-app-express/src/config-types.ts +38 -0
  62. package/packages/shopify-app-express/src/error.ts +8 -0
  63. package/packages/shopify-app-express/src/index.ts +171 -0
  64. package/packages/shopify-app-express/src/middlewares/__tests__/csp-headers.test.ts +69 -0
  65. package/packages/shopify-app-express/src/middlewares/__tests__/ensure-installed-on-shop.test.ts +193 -0
  66. package/packages/shopify-app-express/src/middlewares/__tests__/redirect-to-shopify-or-app-root.test.ts +59 -0
  67. package/packages/shopify-app-express/src/middlewares/__tests__/validate-authenticated-session.test.ts +319 -0
  68. package/packages/shopify-app-express/src/middlewares/csp-headers.ts +31 -0
  69. package/packages/shopify-app-express/src/middlewares/ensure-installed-on-shop.ts +176 -0
  70. package/packages/shopify-app-express/src/middlewares/has-valid-access-token.ts +25 -0
  71. package/packages/shopify-app-express/src/middlewares/index.ts +15 -0
  72. package/packages/shopify-app-express/src/middlewares/redirect-to-shopify-or-app-root.ts +39 -0
  73. package/packages/shopify-app-express/src/middlewares/types.ts +6 -0
  74. package/packages/shopify-app-express/src/middlewares/validate-authenticated-session.ts +142 -0
  75. package/packages/shopify-app-express/src/redirect-out-of-app.ts +80 -0
  76. package/packages/shopify-app-express/src/redirect-to-auth.ts +70 -0
  77. package/packages/shopify-app-express/src/types.ts +26 -0
  78. package/packages/shopify-app-express/src/version.ts +1 -0
  79. package/packages/shopify-app-express/src/webhooks/__tests__/process.test.ts +138 -0
  80. package/packages/shopify-app-express/src/webhooks/index.ts +54 -0
  81. package/packages/shopify-app-express/src/webhooks/process.ts +22 -0
  82. package/packages/shopify-app-express/src/webhooks/types.ts +24 -0
  83. package/packages/shopify-app-express/tsconfig.json +10 -0
  84. package/packages/shopify-app-remix/.eslintrc.js +3 -0
  85. package/packages/shopify-app-remix/CHANGELOG.md +569 -0
  86. package/packages/shopify-app-remix/LICENSE.md +9 -0
  87. package/packages/shopify-app-remix/README.md +223 -0
  88. package/packages/shopify-app-remix/docs/build-docs.sh +11 -0
  89. package/packages/shopify-app-remix/docs/generated/generated_docs_data.json +18650 -0
  90. package/packages/shopify-app-remix/docs/generated/generated_static_pages.json +540 -0
  91. package/packages/shopify-app-remix/docs/staticPages/admin.doc.ts +130 -0
  92. package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/auth-cors.example.tsx +11 -0
  93. package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/auth.example.tsx +19 -0
  94. package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/graphql.example.tsx +29 -0
  95. package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/headers.example.tsx +10 -0
  96. package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/rest-resources.example.tsx +9 -0
  97. package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/rest.example.tsx +17 -0
  98. package/packages/shopify-app-remix/docs/staticPages/examples/guides/future-flags/config.example.ts +8 -0
  99. package/packages/shopify-app-remix/docs/staticPages/examples/guides/future-flags/unstable.example.ts +9 -0
  100. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/.graphqlrc.ts +16 -0
  101. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/install.npm.example.sh +2 -0
  102. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/install.pnpm.example.sh +2 -0
  103. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/install.yarn.example.sh +2 -0
  104. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/package.json +5 -0
  105. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/run.npm.example.sh +1 -0
  106. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/run.pnpm.example.sh +1 -0
  107. package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/run.yarn.example.sh +1 -0
  108. package/packages/shopify-app-remix/docs/staticPages/examples/guides/webhooks/config.example.ts +19 -0
  109. package/packages/shopify-app-remix/docs/staticPages/examples/guides/webhooks/endpoint.example.ts +24 -0
  110. package/packages/shopify-app-remix/docs/staticPages/examples/index/app-provider.example.ts +30 -0
  111. package/packages/shopify-app-remix/docs/staticPages/examples/index/boundaries.example.ts +9 -0
  112. package/packages/shopify-app-remix/docs/staticPages/examples/index/create.npm.example.sh +1 -0
  113. package/packages/shopify-app-remix/docs/staticPages/examples/index/create.pnpm.example.sh +1 -0
  114. package/packages/shopify-app-remix/docs/staticPages/examples/index/create.yarn.example.sh +1 -0
  115. package/packages/shopify-app-remix/docs/staticPages/examples/index/embedded-app-auth-strategy-config.example.ts +10 -0
  116. package/packages/shopify-app-remix/docs/staticPages/examples/index/entry-server.example.ts +12 -0
  117. package/packages/shopify-app-remix/docs/staticPages/examples/index/install.npm.example.sh +1 -0
  118. package/packages/shopify-app-remix/docs/staticPages/examples/index/install.pnpm.example.sh +1 -0
  119. package/packages/shopify-app-remix/docs/staticPages/examples/index/install.yarn.example.sh +1 -0
  120. package/packages/shopify-app-remix/docs/staticPages/examples/index/shopify-app.example.ts +14 -0
  121. package/packages/shopify-app-remix/docs/staticPages/examples/index/splat-route.example.ts +11 -0
  122. package/packages/shopify-app-remix/docs/staticPages/future-flags.doc.ts +94 -0
  123. package/packages/shopify-app-remix/docs/staticPages/graphql-types.doc.ts +148 -0
  124. package/packages/shopify-app-remix/docs/staticPages/index.doc.ts +227 -0
  125. package/packages/shopify-app-remix/docs/staticPages/webhooks.doc.ts +64 -0
  126. package/packages/shopify-app-remix/docs/tsconfig.docs.json +9 -0
  127. package/packages/shopify-app-remix/docs/typeOverride.json +1 -0
  128. package/packages/shopify-app-remix/docs/upcoming_changes.md +153 -0
  129. package/packages/shopify-app-remix/loom.config.ts +57 -0
  130. package/packages/shopify-app-remix/package.json +93 -0
  131. package/packages/shopify-app-remix/src/react/.eslintrc.js +16 -0
  132. package/packages/shopify-app-remix/src/react/__tests__/test-helper.ts +22 -0
  133. package/packages/shopify-app-remix/src/react/components/AppProvider/AppProvider.doc.ts +34 -0
  134. package/packages/shopify-app-remix/src/react/components/AppProvider/AppProvider.tsx +121 -0
  135. package/packages/shopify-app-remix/src/react/components/AppProvider/__tests__/AppProvider.test.tsx +68 -0
  136. package/packages/shopify-app-remix/src/react/components/AppProvider/index.ts +1 -0
  137. package/packages/shopify-app-remix/src/react/components/RemixPolarisLink.tsx +14 -0
  138. package/packages/shopify-app-remix/src/react/components/index.ts +1 -0
  139. package/packages/shopify-app-remix/src/react/const.ts +2 -0
  140. package/packages/shopify-app-remix/src/react/index.ts +1 -0
  141. package/packages/shopify-app-remix/src/server/.eslintrc.js +16 -0
  142. package/packages/shopify-app-remix/src/server/__test-helpers/__tests__/request-mock.test.ts +171 -0
  143. package/packages/shopify-app-remix/src/server/__test-helpers/const.ts +11 -0
  144. package/packages/shopify-app-remix/src/server/__test-helpers/expect-admin-api-client.ts +119 -0
  145. package/packages/shopify-app-remix/src/server/__test-helpers/expect-begin-auth-redirect.ts +22 -0
  146. package/packages/shopify-app-remix/src/server/__test-helpers/expect-document-request-headers.ts +25 -0
  147. package/packages/shopify-app-remix/src/server/__test-helpers/expect-exit-iframe.ts +37 -0
  148. package/packages/shopify-app-remix/src/server/__test-helpers/expect-login-redirect.ts +8 -0
  149. package/packages/shopify-app-remix/src/server/__test-helpers/expect-storefront-api-client.ts +50 -0
  150. package/packages/shopify-app-remix/src/server/__test-helpers/get-hmac.ts +10 -0
  151. package/packages/shopify-app-remix/src/server/__test-helpers/get-jwt.ts +31 -0
  152. package/packages/shopify-app-remix/src/server/__test-helpers/get-thrown-response.ts +17 -0
  153. package/packages/shopify-app-remix/src/server/__test-helpers/index.ts +14 -0
  154. package/packages/shopify-app-remix/src/server/__test-helpers/request-mock.ts +169 -0
  155. package/packages/shopify-app-remix/src/server/__test-helpers/setup-valid-session.ts +45 -0
  156. package/packages/shopify-app-remix/src/server/__test-helpers/sign-request-cookie.ts +21 -0
  157. package/packages/shopify-app-remix/src/server/__test-helpers/test-config.ts +112 -0
  158. package/packages/shopify-app-remix/src/server/__tests__/override-logger.test.ts +101 -0
  159. package/packages/shopify-app-remix/src/server/__tests__/shopify-app.test.ts +119 -0
  160. package/packages/shopify-app-remix/src/server/adapters/__tests__/node-app-bridge-url.test.ts +18 -0
  161. package/packages/shopify-app-remix/src/server/adapters/__tests__/node.test.ts +28 -0
  162. package/packages/shopify-app-remix/src/server/adapters/node/__tests__/setup-jest.ts +10 -0
  163. package/packages/shopify-app-remix/src/server/adapters/node/index.ts +20 -0
  164. package/packages/shopify-app-remix/src/server/adapters/vercel/__tests__/setup-jest.ts +12 -0
  165. package/packages/shopify-app-remix/src/server/adapters/vercel/index.ts +13 -0
  166. package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/admin-client.test.ts +181 -0
  167. package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/doc-request-path.test.ts +151 -0
  168. package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/exit-i-frame-path.test.ts +99 -0
  169. package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/patch-session-token-path.test.ts +58 -0
  170. package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/reject-bot.test.ts +23 -0
  171. package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/respond-to-options.test.ts +50 -0
  172. package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/session-token-header-path.test.ts +91 -0
  173. package/packages/shopify-app-remix/src/server/authenticate/admin/authenticate.admin.doc.ts +37 -0
  174. package/packages/shopify-app-remix/src/server/authenticate/admin/authenticate.ts +201 -0
  175. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/cancel.test.ts +258 -0
  176. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/check.test.ts +254 -0
  177. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/mock-responses.ts +65 -0
  178. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/request.test.ts +373 -0
  179. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/require.test.ts +316 -0
  180. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/authenticate.admin.billing.doc.ts +28 -0
  181. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/cancel.ts +37 -0
  182. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/check.ts +38 -0
  183. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/index.ts +4 -0
  184. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/request.ts +101 -0
  185. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/require.ts +56 -0
  186. package/packages/shopify-app-remix/src/server/authenticate/admin/billing/types.ts +383 -0
  187. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/__tests__/redirect.test.ts +313 -0
  188. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/__tests__/validate-redirect-url.test.ts +84 -0
  189. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/begin-auth.ts +17 -0
  190. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/create-admin-api-context.ts +22 -0
  191. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.ts +18 -0
  192. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.ts +25 -0
  193. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/handle-client-error.ts +43 -0
  194. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/index.ts +14 -0
  195. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-to-auth-page.ts +28 -0
  196. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-to-bounce-page.ts +23 -0
  197. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.ts +21 -0
  198. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-with-app-bridge-headers.ts +13 -0
  199. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-with-exitiframe.ts +28 -0
  200. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect.ts +83 -0
  201. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/render-app-bridge.ts +46 -0
  202. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/trigger-after-auth-hook.ts +28 -0
  203. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/validate-redirect-url.ts +67 -0
  204. package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/validate-shop-and-host-params.ts +28 -0
  205. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/admin-client.test.ts +222 -0
  206. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/auth-callback-path.test.ts +395 -0
  207. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/auth-path.test.ts +83 -0
  208. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/authenticate.test.ts +183 -0
  209. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/ensure-installed-on-shop.test.ts +234 -0
  210. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/session-token-header-path.test.ts +79 -0
  211. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/token-exchange/admin-client.test.ts +189 -0
  212. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/token-exchange/authenticate.test.ts +310 -0
  213. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/auth-code-flow.ts +333 -0
  214. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/token-exchange.ts +169 -0
  215. package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/types.ts +29 -0
  216. package/packages/shopify-app-remix/src/server/authenticate/admin/types.ts +199 -0
  217. package/packages/shopify-app-remix/src/server/authenticate/const.ts +15 -0
  218. package/packages/shopify-app-remix/src/server/authenticate/flow/__tests__/authenticate.test.ts +142 -0
  219. package/packages/shopify-app-remix/src/server/authenticate/flow/authenticate.flow.doc.ts +34 -0
  220. package/packages/shopify-app-remix/src/server/authenticate/flow/authenticate.ts +71 -0
  221. package/packages/shopify-app-remix/src/server/authenticate/flow/types.ts +90 -0
  222. package/packages/shopify-app-remix/src/server/authenticate/helpers/__tests__/add-response-headers.test.ts +25 -0
  223. package/packages/shopify-app-remix/src/server/authenticate/helpers/__tests__/app-bridge-url.test.ts +21 -0
  224. package/packages/shopify-app-remix/src/server/authenticate/helpers/__tests__/idempotent-promise-handler.test.ts +104 -0
  225. package/packages/shopify-app-remix/src/server/authenticate/helpers/add-response-headers.ts +43 -0
  226. package/packages/shopify-app-remix/src/server/authenticate/helpers/app-bridge-url.ts +10 -0
  227. package/packages/shopify-app-remix/src/server/authenticate/helpers/ensure-cors-headers.ts +38 -0
  228. package/packages/shopify-app-remix/src/server/authenticate/helpers/get-session-token-header.ts +11 -0
  229. package/packages/shopify-app-remix/src/server/authenticate/helpers/idempotent-promise-handler.ts +45 -0
  230. package/packages/shopify-app-remix/src/server/authenticate/helpers/index.ts +8 -0
  231. package/packages/shopify-app-remix/src/server/authenticate/helpers/reject-bot-request.ts +13 -0
  232. package/packages/shopify-app-remix/src/server/authenticate/helpers/respond-to-invalid-session-token.ts +29 -0
  233. package/packages/shopify-app-remix/src/server/authenticate/helpers/respond-to-options-request.ts +26 -0
  234. package/packages/shopify-app-remix/src/server/authenticate/helpers/validate-session-token.ts +32 -0
  235. package/packages/shopify-app-remix/src/server/authenticate/login/__tests__/login.test.ts +157 -0
  236. package/packages/shopify-app-remix/src/server/authenticate/login/login.ts +53 -0
  237. package/packages/shopify-app-remix/src/server/authenticate/public/__tests__/factory.test.ts +224 -0
  238. package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/__tests__/authenticate.test.ts +282 -0
  239. package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.ts +36 -0
  240. package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/authenticate.ts +90 -0
  241. package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/types.ts +164 -0
  242. package/packages/shopify-app-remix/src/server/authenticate/public/checkout/__tests__/authenticate.test.ts +142 -0
  243. package/packages/shopify-app-remix/src/server/authenticate/public/checkout/authenticate.public.checkout.doc.ts +23 -0
  244. package/packages/shopify-app-remix/src/server/authenticate/public/checkout/authenticate.ts +45 -0
  245. package/packages/shopify-app-remix/src/server/authenticate/public/checkout/types.ts +65 -0
  246. package/packages/shopify-app-remix/src/server/authenticate/public/factory.ts +49 -0
  247. package/packages/shopify-app-remix/src/server/authenticate/public/index.ts +1 -0
  248. package/packages/shopify-app-remix/src/server/authenticate/public/types.ts +77 -0
  249. package/packages/shopify-app-remix/src/server/authenticate/webhooks/__tests__/authenticate.test.ts +207 -0
  250. package/packages/shopify-app-remix/src/server/authenticate/webhooks/__tests__/mock-responses.ts +45 -0
  251. package/packages/shopify-app-remix/src/server/authenticate/webhooks/__tests__/register.test.ts +210 -0
  252. package/packages/shopify-app-remix/src/server/authenticate/webhooks/authenticate.ts +113 -0
  253. package/packages/shopify-app-remix/src/server/authenticate/webhooks/authenticate.webhooks.doc.ts +28 -0
  254. package/packages/shopify-app-remix/src/server/authenticate/webhooks/index.ts +1 -0
  255. package/packages/shopify-app-remix/src/server/authenticate/webhooks/register.ts +48 -0
  256. package/packages/shopify-app-remix/src/server/authenticate/webhooks/types.ts +246 -0
  257. package/packages/shopify-app-remix/src/server/boundary/__tests__/error.test.tsx +36 -0
  258. package/packages/shopify-app-remix/src/server/boundary/__tests__/headers.test.ts +66 -0
  259. package/packages/shopify-app-remix/src/server/boundary/error.tsx +14 -0
  260. package/packages/shopify-app-remix/src/server/boundary/headers.ts +15 -0
  261. package/packages/shopify-app-remix/src/server/boundary/index.ts +39 -0
  262. package/packages/shopify-app-remix/src/server/boundary/types.ts +4 -0
  263. package/packages/shopify-app-remix/src/server/clients/admin/authenticate.admin.api.doc.ts +34 -0
  264. package/packages/shopify-app-remix/src/server/clients/admin/factory.ts +30 -0
  265. package/packages/shopify-app-remix/src/server/clients/admin/graphql.ts +39 -0
  266. package/packages/shopify-app-remix/src/server/clients/admin/index.ts +2 -0
  267. package/packages/shopify-app-remix/src/server/clients/admin/rest.ts +157 -0
  268. package/packages/shopify-app-remix/src/server/clients/admin/types.ts +178 -0
  269. package/packages/shopify-app-remix/src/server/clients/index.ts +2 -0
  270. package/packages/shopify-app-remix/src/server/clients/storefront/authenticate.storefront.api.doc.ts +34 -0
  271. package/packages/shopify-app-remix/src/server/clients/storefront/factory.ts +32 -0
  272. package/packages/shopify-app-remix/src/server/clients/storefront/index.ts +2 -0
  273. package/packages/shopify-app-remix/src/server/clients/storefront/types.ts +31 -0
  274. package/packages/shopify-app-remix/src/server/clients/types.ts +27 -0
  275. package/packages/shopify-app-remix/src/server/config-types.ts +293 -0
  276. package/packages/shopify-app-remix/src/server/errors.ts +3 -0
  277. package/packages/shopify-app-remix/src/server/future/flags.ts +57 -0
  278. package/packages/shopify-app-remix/src/server/index.ts +20 -0
  279. package/packages/shopify-app-remix/src/server/override-logger.ts +42 -0
  280. package/packages/shopify-app-remix/src/server/shopify-app.doc.ts +45 -0
  281. package/packages/shopify-app-remix/src/server/shopify-app.ts +198 -0
  282. package/packages/shopify-app-remix/src/server/types.ts +509 -0
  283. package/packages/shopify-app-remix/src/server/unauthenticated/admin/__tests__/factory.test.ts +30 -0
  284. package/packages/shopify-app-remix/src/server/unauthenticated/admin/factory.ts +29 -0
  285. package/packages/shopify-app-remix/src/server/unauthenticated/admin/index.ts +1 -0
  286. package/packages/shopify-app-remix/src/server/unauthenticated/admin/types.ts +117 -0
  287. package/packages/shopify-app-remix/src/server/unauthenticated/admin/unauthenticated.admin.doc.ts +40 -0
  288. package/packages/shopify-app-remix/src/server/unauthenticated/helpers/get-offline-session.ts +13 -0
  289. package/packages/shopify-app-remix/src/server/unauthenticated/helpers/index.ts +1 -0
  290. package/packages/shopify-app-remix/src/server/unauthenticated/storefront/__tests__/factory.test.ts +30 -0
  291. package/packages/shopify-app-remix/src/server/unauthenticated/storefront/factory.ts +28 -0
  292. package/packages/shopify-app-remix/src/server/unauthenticated/storefront/index.ts +1 -0
  293. package/packages/shopify-app-remix/src/server/unauthenticated/storefront/types.ts +39 -0
  294. package/packages/shopify-app-remix/src/server/unauthenticated/storefront/unauthenticated.storefront.doc.ts +40 -0
  295. package/packages/shopify-app-remix/src/server/unauthenticated/types.ts +68 -0
  296. package/packages/shopify-app-remix/src/server/version.ts +1 -0
  297. package/packages/shopify-app-remix/tsconfig.json +11 -0
  298. package/packages/shopify-app-session-storage/CHANGELOG.md +149 -0
  299. package/packages/shopify-app-session-storage/LICENSE.md +9 -0
  300. package/packages/shopify-app-session-storage/README.md +5 -0
  301. package/packages/shopify-app-session-storage/implementing-session-storage.md +214 -0
  302. package/packages/shopify-app-session-storage/loom.config.ts +45 -0
  303. package/packages/shopify-app-session-storage/package.json +44 -0
  304. package/packages/shopify-app-session-storage/src/__tests__/setup-jest.ts +8 -0
  305. package/packages/shopify-app-session-storage/src/abstract-migration-engine.ts +53 -0
  306. package/packages/shopify-app-session-storage/src/index.ts +3 -0
  307. package/packages/shopify-app-session-storage/src/rdbms-session-storage-migrator.ts +59 -0
  308. package/packages/shopify-app-session-storage/src/types.ts +174 -0
  309. package/packages/shopify-app-session-storage/tsconfig.json +10 -0
  310. package/packages/shopify-app-session-storage-dynamodb/CHANGELOG.md +150 -0
  311. package/packages/shopify-app-session-storage-dynamodb/LICENSE.md +9 -0
  312. package/packages/shopify-app-session-storage-dynamodb/README.md +75 -0
  313. package/packages/shopify-app-session-storage-dynamodb/loom.config.ts +27 -0
  314. package/packages/shopify-app-session-storage-dynamodb/package.json +51 -0
  315. package/packages/shopify-app-session-storage-dynamodb/src/__tests__/dynamodb.test.ts +93 -0
  316. package/packages/shopify-app-session-storage-dynamodb/src/__tests__/setup-jest.ts +8 -0
  317. package/packages/shopify-app-session-storage-dynamodb/src/dynamodb.ts +126 -0
  318. package/packages/shopify-app-session-storage-dynamodb/tsconfig.json +10 -0
  319. package/packages/shopify-app-session-storage-kv/CHANGELOG.md +204 -0
  320. package/packages/shopify-app-session-storage-kv/LICENSE.md +9 -0
  321. package/packages/shopify-app-session-storage-kv/README.md +41 -0
  322. package/packages/shopify-app-session-storage-kv/loom.config.ts +27 -0
  323. package/packages/shopify-app-session-storage-kv/package.json +52 -0
  324. package/packages/shopify-app-session-storage-kv/src/__tests__/kv-namespace-dummy-worker.ts +8 -0
  325. package/packages/shopify-app-session-storage-kv/src/__tests__/kv.test.ts +22 -0
  326. package/packages/shopify-app-session-storage-kv/src/__tests__/setup-jest.ts +8 -0
  327. package/packages/shopify-app-session-storage-kv/src/kv.ts +87 -0
  328. package/packages/shopify-app-session-storage-kv/tsconfig.json +11 -0
  329. package/packages/shopify-app-session-storage-memory/CHANGELOG.md +190 -0
  330. package/packages/shopify-app-session-storage-memory/LICENSE.md +9 -0
  331. package/packages/shopify-app-session-storage-memory/README.md +19 -0
  332. package/packages/shopify-app-session-storage-memory/loom.config.ts +27 -0
  333. package/packages/shopify-app-session-storage-memory/package.json +46 -0
  334. package/packages/shopify-app-session-storage-memory/src/__tests__/memory.test.ts +12 -0
  335. package/packages/shopify-app-session-storage-memory/src/__tests__/setup-jest.ts +8 -0
  336. package/packages/shopify-app-session-storage-memory/src/memory.ts +34 -0
  337. package/packages/shopify-app-session-storage-memory/tsconfig.json +10 -0
  338. package/packages/shopify-app-session-storage-mongodb/CHANGELOG.md +208 -0
  339. package/packages/shopify-app-session-storage-mongodb/LICENSE.md +9 -0
  340. package/packages/shopify-app-session-storage-mongodb/README.md +30 -0
  341. package/packages/shopify-app-session-storage-mongodb/loom.config.ts +27 -0
  342. package/packages/shopify-app-session-storage-mongodb/package.json +49 -0
  343. package/packages/shopify-app-session-storage-mongodb/src/__tests__/mongodb.test.ts +54 -0
  344. package/packages/shopify-app-session-storage-mongodb/src/__tests__/setup-jest.ts +8 -0
  345. package/packages/shopify-app-session-storage-mongodb/src/mongodb.ts +120 -0
  346. package/packages/shopify-app-session-storage-mongodb/tsconfig.json +10 -0
  347. package/packages/shopify-app-session-storage-mysql/CHANGELOG.md +220 -0
  348. package/packages/shopify-app-session-storage-mysql/LICENSE.md +9 -0
  349. package/packages/shopify-app-session-storage-mysql/README.md +41 -0
  350. package/packages/shopify-app-session-storage-mysql/loom.config.ts +27 -0
  351. package/packages/shopify-app-session-storage-mysql/package.json +50 -0
  352. package/packages/shopify-app-session-storage-mysql/src/__tests__/mysql.test.ts +137 -0
  353. package/packages/shopify-app-session-storage-mysql/src/__tests__/setup-jest.ts +8 -0
  354. package/packages/shopify-app-session-storage-mysql/src/migrations.ts +18 -0
  355. package/packages/shopify-app-session-storage-mysql/src/mysql-connection.ts +108 -0
  356. package/packages/shopify-app-session-storage-mysql/src/mysql-migrator.ts +53 -0
  357. package/packages/shopify-app-session-storage-mysql/src/mysql.ts +178 -0
  358. package/packages/shopify-app-session-storage-mysql/tsconfig.json +10 -0
  359. package/packages/shopify-app-session-storage-postgresql/CHANGELOG.md +210 -0
  360. package/packages/shopify-app-session-storage-postgresql/LICENSE.md +9 -0
  361. package/packages/shopify-app-session-storage-postgresql/README.md +39 -0
  362. package/packages/shopify-app-session-storage-postgresql/loom.config.ts +27 -0
  363. package/packages/shopify-app-session-storage-postgresql/package.json +52 -0
  364. package/packages/shopify-app-session-storage-postgresql/src/__tests__/migrate-to-case-sensitivity.test.ts +344 -0
  365. package/packages/shopify-app-session-storage-postgresql/src/__tests__/postgresql.test.ts +136 -0
  366. package/packages/shopify-app-session-storage-postgresql/src/__tests__/setup-jest.ts +8 -0
  367. package/packages/shopify-app-session-storage-postgresql/src/migrations.ts +70 -0
  368. package/packages/shopify-app-session-storage-postgresql/src/postgres-connection.ts +94 -0
  369. package/packages/shopify-app-session-storage-postgresql/src/postgres-migrator.ts +27 -0
  370. package/packages/shopify-app-session-storage-postgresql/src/postgresql.ts +178 -0
  371. package/packages/shopify-app-session-storage-postgresql/tsconfig.json +10 -0
  372. package/packages/shopify-app-session-storage-prisma/CHANGELOG.md +148 -0
  373. package/packages/shopify-app-session-storage-prisma/LICENSE.md +9 -0
  374. package/packages/shopify-app-session-storage-prisma/README.md +68 -0
  375. package/packages/shopify-app-session-storage-prisma/loom.config.ts +27 -0
  376. package/packages/shopify-app-session-storage-prisma/package.json +51 -0
  377. package/packages/shopify-app-session-storage-prisma/prisma/migrations/20230425184828_init/migration.sql +11 -0
  378. package/packages/shopify-app-session-storage-prisma/prisma/migrations/20230906155758_mySession/migration.sql +11 -0
  379. package/packages/shopify-app-session-storage-prisma/prisma/migrations/migration_lock.toml +3 -0
  380. package/packages/shopify-app-session-storage-prisma/prisma/schema.prisma +30 -0
  381. package/packages/shopify-app-session-storage-prisma/src/__tests__/prisma.test.ts +66 -0
  382. package/packages/shopify-app-session-storage-prisma/src/__tests__/setup-jest.ts +8 -0
  383. package/packages/shopify-app-session-storage-prisma/src/prisma.ts +145 -0
  384. package/packages/shopify-app-session-storage-prisma/tsconfig.json +10 -0
  385. package/packages/shopify-app-session-storage-redis/CHANGELOG.md +200 -0
  386. package/packages/shopify-app-session-storage-redis/LICENSE.md +9 -0
  387. package/packages/shopify-app-session-storage-redis/README.md +38 -0
  388. package/packages/shopify-app-session-storage-redis/loom.config.ts +27 -0
  389. package/packages/shopify-app-session-storage-redis/package.json +50 -0
  390. package/packages/shopify-app-session-storage-redis/src/__tests__/migration-test-data.ts +46 -0
  391. package/packages/shopify-app-session-storage-redis/src/__tests__/redis.conf +2 -0
  392. package/packages/shopify-app-session-storage-redis/src/__tests__/redis.test.ts +236 -0
  393. package/packages/shopify-app-session-storage-redis/src/__tests__/setup-jest.ts +8 -0
  394. package/packages/shopify-app-session-storage-redis/src/migrations.ts +36 -0
  395. package/packages/shopify-app-session-storage-redis/src/redis-connection.ts +64 -0
  396. package/packages/shopify-app-session-storage-redis/src/redis-migrator.ts +58 -0
  397. package/packages/shopify-app-session-storage-redis/src/redis.ts +167 -0
  398. package/packages/shopify-app-session-storage-redis/tsconfig.json +10 -0
  399. package/packages/shopify-app-session-storage-sqlite/CHANGELOG.md +202 -0
  400. package/packages/shopify-app-session-storage-sqlite/LICENSE.md +9 -0
  401. package/packages/shopify-app-session-storage-sqlite/README.md +25 -0
  402. package/packages/shopify-app-session-storage-sqlite/loom.config.ts +27 -0
  403. package/packages/shopify-app-session-storage-sqlite/package.json +51 -0
  404. package/packages/shopify-app-session-storage-sqlite/src/__tests__/setup-jest.ts +8 -0
  405. package/packages/shopify-app-session-storage-sqlite/src/__tests__/sqlite.test.ts +44 -0
  406. package/packages/shopify-app-session-storage-sqlite/src/migrations.ts +54 -0
  407. package/packages/shopify-app-session-storage-sqlite/src/sqlite-connection.ts +80 -0
  408. package/packages/shopify-app-session-storage-sqlite/src/sqlite-migrator.ts +34 -0
  409. package/packages/shopify-app-session-storage-sqlite/src/sqlite.ts +147 -0
  410. package/packages/shopify-app-session-storage-sqlite/tsconfig.json +10 -0
  411. package/packages/shopify-app-session-storage-test-utils/CHANGELOG.md +185 -0
  412. package/packages/shopify-app-session-storage-test-utils/LICENSE.md +9 -0
  413. package/packages/shopify-app-session-storage-test-utils/loom.config.ts +27 -0
  414. package/packages/shopify-app-session-storage-test-utils/package.json +48 -0
  415. package/packages/shopify-app-session-storage-test-utils/src/__tests__/session-test-utils.test.ts +273 -0
  416. package/packages/shopify-app-session-storage-test-utils/src/battery-of-tests.ts +250 -0
  417. package/packages/shopify-app-session-storage-test-utils/src/index.ts +2 -0
  418. package/packages/shopify-app-session-storage-test-utils/src/session-test-utils.ts +24 -0
  419. package/packages/shopify-app-session-storage-test-utils/src/utils.ts +71 -0
  420. package/packages/shopify-app-session-storage-test-utils/tsconfig.json +10 -0
  421. package/tests/setup/build.js +1 -0
  422. package/tests/setup/setup-jest.ts +8 -0
  423. package/tsconfig.base.json +41 -0
  424. package/tsconfig.json +19 -0
@@ -0,0 +1,37 @@
1
+ import {HttpResponseError, Session} from '@shopify/shopify-api';
2
+
3
+ import type {BasicParams} from '../../../types';
4
+ import {redirectToAuthPage} from '../helpers';
5
+
6
+ import type {CancelBillingOptions} from './types';
7
+
8
+ export function cancelBillingFactory(
9
+ params: BasicParams,
10
+ request: Request,
11
+ session: Session,
12
+ ) {
13
+ return async function cancelBilling(options: CancelBillingOptions) {
14
+ const {api, logger, config} = params;
15
+
16
+ logger.debug('Cancelling billing', {shop: session.shop, ...options});
17
+
18
+ try {
19
+ return await api.billing.cancel({
20
+ session,
21
+ subscriptionId: options.subscriptionId,
22
+ isTest: options.isTest,
23
+ prorate: options.prorate,
24
+ });
25
+ } catch (error) {
26
+ if (error instanceof HttpResponseError && error.response.code === 401) {
27
+ logger.debug('API token was invalid, redirecting to OAuth', {
28
+ shop: session.shop,
29
+ });
30
+ await config.sessionStorage.deleteSession(session.id);
31
+ throw await redirectToAuthPage(params, request, session.shop);
32
+ } else {
33
+ throw error;
34
+ }
35
+ }
36
+ };
37
+ }
@@ -0,0 +1,38 @@
1
+ import {HttpResponseError, Session} from '@shopify/shopify-api';
2
+
3
+ import type {BasicParams} from '../../../types';
4
+ import {redirectToAuthPage} from '../helpers';
5
+ import type {AppConfigArg} from '../../../config-types';
6
+
7
+ import type {CheckBillingOptions} from './types';
8
+
9
+ export function checkBillingFactory<Config extends AppConfigArg>(
10
+ params: BasicParams,
11
+ request: Request,
12
+ session: Session,
13
+ ) {
14
+ return async function checkBilling(options: CheckBillingOptions<Config>) {
15
+ const {api, logger, config} = params;
16
+
17
+ logger.debug('Checking billing plans', {shop: session.shop, ...options});
18
+
19
+ try {
20
+ return await api.billing.check({
21
+ session,
22
+ plans: options.plans as string[],
23
+ isTest: options.isTest,
24
+ returnObject: true,
25
+ });
26
+ } catch (error) {
27
+ if (error instanceof HttpResponseError && error.response.code === 401) {
28
+ logger.debug('API token was invalid, redirecting to OAuth', {
29
+ shop: session.shop,
30
+ });
31
+ await config.sessionStorage.deleteSession(session.id);
32
+ throw await redirectToAuthPage(params, request, session.shop);
33
+ } else {
34
+ throw error;
35
+ }
36
+ }
37
+ };
38
+ }
@@ -0,0 +1,4 @@
1
+ export {cancelBillingFactory} from './cancel';
2
+ export {requireBillingFactory} from './require';
3
+ export {requestBillingFactory} from './request';
4
+ export {checkBillingFactory} from './check';
@@ -0,0 +1,101 @@
1
+ import {
2
+ BillingRequestResponseObject,
3
+ HttpResponseError,
4
+ Session,
5
+ } from '@shopify/shopify-api';
6
+ import {redirect} from '@remix-run/server-runtime';
7
+
8
+ import {AppConfigArg} from '../../../config-types';
9
+ import {BasicParams} from '../../../types';
10
+ import {getAppBridgeHeaders, redirectToAuthPage} from '../helpers';
11
+
12
+ import type {RequestBillingOptions} from './types';
13
+
14
+ export function requestBillingFactory<Config extends AppConfigArg>(
15
+ params: BasicParams,
16
+ request: Request,
17
+ session: Session,
18
+ ) {
19
+ return async function requestBilling({
20
+ plan,
21
+ isTest,
22
+ returnUrl,
23
+ ...overrides
24
+ }: RequestBillingOptions<Config>): Promise<never> {
25
+ const {api, logger, config} = params;
26
+
27
+ logger.info('Requesting billing', {
28
+ shop: session.shop,
29
+ plan,
30
+ isTest,
31
+ returnUrl,
32
+ });
33
+
34
+ let result: BillingRequestResponseObject;
35
+ try {
36
+ result = await api.billing.request({
37
+ plan: plan as string,
38
+ session,
39
+ isTest,
40
+ returnUrl,
41
+ returnObject: true,
42
+ ...overrides,
43
+ });
44
+ } catch (error) {
45
+ if (error instanceof HttpResponseError && error.response.code === 401) {
46
+ logger.debug('API token was invalid, redirecting to OAuth', {
47
+ shop: session.shop,
48
+ });
49
+ await config.sessionStorage.deleteSession(session.id);
50
+ throw await redirectToAuthPage(params, request, session.shop);
51
+ } else {
52
+ throw error;
53
+ }
54
+ }
55
+
56
+ throw redirectOutOfApp(
57
+ params,
58
+ request,
59
+ result.confirmationUrl,
60
+ session.shop,
61
+ );
62
+ };
63
+ }
64
+
65
+ function redirectOutOfApp(
66
+ params: BasicParams,
67
+ request: Request,
68
+ url: string,
69
+ shop: string,
70
+ ): never {
71
+ const {config, logger} = params;
72
+
73
+ logger.debug('Redirecting out of app', {url});
74
+
75
+ const requestUrl = new URL(request.url);
76
+ const isEmbeddedRequest = requestUrl.searchParams.get('embedded') === '1';
77
+ const isXhrRequest = request.headers.get('authorization');
78
+
79
+ if (isXhrRequest) {
80
+ // eslint-disable-next-line no-warning-comments
81
+ // TODO Check this with the beta flag disabled (with the bounce page)
82
+ // Remix is not including the X-Shopify-API-Request-Failure-Reauthorize-Url when throwing a Response
83
+ // https://github.com/remix-run/remix/issues/5356
84
+ throw new Response(undefined, {
85
+ status: 401,
86
+ statusText: 'Unauthorized',
87
+ headers: getAppBridgeHeaders(url),
88
+ });
89
+ } else if (isEmbeddedRequest) {
90
+ const params = new URLSearchParams({
91
+ shop,
92
+ host: requestUrl.searchParams.get('host')!,
93
+ exitIframe: url,
94
+ });
95
+
96
+ throw redirect(`${config.auth.exitIframePath}?${params.toString()}`);
97
+ } else {
98
+ // This will only ever happen for non-embedded apps, because the authenticator will stop before reaching this point
99
+ throw redirect(url);
100
+ }
101
+ }
@@ -0,0 +1,56 @@
1
+ import {
2
+ BillingCheckResponseObject,
3
+ HttpResponseError,
4
+ Session,
5
+ } from '@shopify/shopify-api';
6
+
7
+ import type {BasicParams} from '../../../types';
8
+ import type {AppConfigArg} from '../../../config-types';
9
+ import {redirectToAuthPage} from '../helpers';
10
+
11
+ import type {RequireBillingOptions} from './types';
12
+
13
+ export function requireBillingFactory<Config extends AppConfigArg>(
14
+ params: BasicParams,
15
+ request: Request,
16
+ session: Session,
17
+ ) {
18
+ const {api, logger, config} = params;
19
+
20
+ return async function requireBilling(options: RequireBillingOptions<Config>) {
21
+ const logContext = {
22
+ shop: session.shop,
23
+ plans: options.plans,
24
+ isTest: options.isTest,
25
+ };
26
+
27
+ logger.debug('Checking billing for the shop', logContext);
28
+
29
+ let data: BillingCheckResponseObject;
30
+ try {
31
+ data = await api.billing.check({
32
+ session,
33
+ plans: options.plans as string[],
34
+ isTest: options.isTest,
35
+ returnObject: true,
36
+ });
37
+ } catch (error) {
38
+ if (error instanceof HttpResponseError && error.response.code === 401) {
39
+ logger.debug('API token was invalid, redirecting to OAuth', logContext);
40
+ await config.sessionStorage.deleteSession(session.id);
41
+ throw await redirectToAuthPage(params, request, session.shop);
42
+ } else {
43
+ throw error;
44
+ }
45
+ }
46
+
47
+ if (!data.hasActivePayment) {
48
+ logger.debug('Billing check failed', logContext);
49
+ throw await options.onFailure(new Error('Billing check failed'));
50
+ }
51
+
52
+ logger.debug('Billing check succeeded', logContext);
53
+
54
+ return data;
55
+ };
56
+ }
@@ -0,0 +1,383 @@
1
+ import {
2
+ AppSubscription,
3
+ BillingCheckParams,
4
+ BillingCheckResponseObject,
5
+ BillingRequestParams,
6
+ } from '@shopify/shopify-api';
7
+
8
+ import type {AppConfigArg} from '../../../config-types';
9
+
10
+ export interface RequireBillingOptions<Config extends AppConfigArg>
11
+ extends Omit<BillingCheckParams, 'session' | 'plans' | 'returnObject'> {
12
+ /**
13
+ * The plans to check for. Must be one of the values defined in the `billing` config option.
14
+ */
15
+ plans: (keyof Config['billing'])[];
16
+ /**
17
+ * How to handle the request if the shop doesn't have an active payment for any plan.
18
+ */
19
+ onFailure: (error: any) => Promise<Response>;
20
+ }
21
+
22
+ export interface CheckBillingOptions<Config extends AppConfigArg>
23
+ extends Omit<BillingCheckParams, 'session' | 'plans' | 'returnObject'> {
24
+ /**
25
+ * The plans to check for. Must be one of the values defined in the `billing` config option.
26
+ */
27
+ plans: (keyof Config['billing'])[];
28
+ }
29
+
30
+ export interface RequestBillingOptions<Config extends AppConfigArg>
31
+ extends Omit<BillingRequestParams, 'session' | 'plan' | 'returnObject'> {
32
+ /**
33
+ * The plan to request. Must be one of the values defined in the `billing` config option.
34
+ */
35
+ plan: keyof Config['billing'];
36
+ /**
37
+ * Whether to use the test mode. This prevents the credit card from being charged. Test shops and demo shops cannot be charged.
38
+ */
39
+ isTest?: boolean;
40
+ /**
41
+ * The URL to return to after the merchant approves the payment.
42
+ */
43
+ returnUrl?: string;
44
+ }
45
+
46
+ export interface CancelBillingOptions {
47
+ /**
48
+ * The ID of the subscription to cancel.
49
+ */
50
+ subscriptionId: string;
51
+ /**
52
+ * Whether to prorate the cancellation.
53
+ *
54
+ * {@link https://shopify.dev/docs/apps/billing/subscriptions/cancel-recurring-charges}
55
+ */
56
+ prorate?: boolean;
57
+ /*
58
+ * Whether to use the test mode. This prevents the credit card from being charged. Test shops and demo shops cannot be charged.
59
+ */
60
+ isTest?: boolean;
61
+ }
62
+
63
+ export interface BillingContext<Config extends AppConfigArg> {
64
+ /**
65
+ * Checks if the shop has an active payment for any plan defined in the `billing` config option.
66
+ *
67
+ * @returns A promise that resolves to an object containing the active purchases for the shop.
68
+ *
69
+ * @example
70
+ * <caption>Requesting billing right away.</caption>
71
+ * <description>Call `billing.request` in the `onFailure` callback to immediately redirect to the Shopify page to request payment.</description>
72
+ * ```ts
73
+ * // /app/routes/**\/*.ts
74
+ * import { LoaderFunctionArgs } from "@remix-run/node";
75
+ * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
76
+ *
77
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
78
+ * const { billing } = await authenticate.admin(request);
79
+ * await billing.require({
80
+ * plans: [MONTHLY_PLAN],
81
+ * isTest: true,
82
+ * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),
83
+ * });
84
+ *
85
+ * // App logic
86
+ * };
87
+ * ```
88
+ * ```ts
89
+ * // shopify.server.ts
90
+ * import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server";
91
+ *
92
+ * export const MONTHLY_PLAN = 'Monthly subscription';
93
+ * export const ANNUAL_PLAN = 'Annual subscription';
94
+ *
95
+ * const shopify = shopifyApp({
96
+ * // ...etc
97
+ * billing: {
98
+ * [MONTHLY_PLAN]: {
99
+ * amount: 5,
100
+ * currencyCode: 'USD',
101
+ * interval: BillingInterval.Every30Days,
102
+ * },
103
+ * [ANNUAL_PLAN]: {
104
+ * amount: 50,
105
+ * currencyCode: 'USD',
106
+ * interval: BillingInterval.Annual,
107
+ * },
108
+ * }
109
+ * });
110
+ * export default shopify;
111
+ * export const authenticate = shopify.authenticate;
112
+ * ```
113
+ *
114
+ * @example
115
+ * <caption>Redirect to a plan selection page.</caption>
116
+ * <description> When the app has multiple plans, create a page in your App that allows the merchant to select a plan. If a merchant does not have the required plan you can redirect them to page in your app to select one.</description>
117
+ * ```ts
118
+ * // /app/routes/**\/*.ts
119
+ * import { LoaderFunctionArgs, redirect } from "@remix-run/node";
120
+ * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from "../shopify.server";
121
+ *
122
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
123
+ * const { billing } = await authenticate.admin(request);
124
+ * const billingCheck = await billing.require({
125
+ * plans: [MONTHLY_PLAN, ANNUAL_PLAN],
126
+ * isTest: true,
127
+ * onFailure: () => redirect('/select-plan'),
128
+ * });
129
+ *
130
+ * const subscription = billingCheck.appSubscriptions[0];
131
+ * console.log(`Shop is on ${subscription.name} (id ${subscription.id})`);
132
+ *
133
+ * // App logic
134
+ * };
135
+ * ```
136
+ * ```ts
137
+ * // shopify.server.ts
138
+ * import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server";
139
+ *
140
+ * export const MONTHLY_PLAN = 'Monthly subscription';
141
+ * export const ANNUAL_PLAN = 'Annual subscription';
142
+ *
143
+ * const shopify = shopifyApp({
144
+ * // ...etc
145
+ * billing: {
146
+ * [MONTHLY_PLAN]: {
147
+ * amount: 5,
148
+ * currencyCode: 'USD',
149
+ * interval: BillingInterval.Every30Days,
150
+ * },
151
+ * [ANNUAL_PLAN]: {
152
+ * amount: 50,
153
+ * currencyCode: 'USD',
154
+ * interval: BillingInterval.Annual,
155
+ * },
156
+ * }
157
+ * });
158
+ * export default shopify;
159
+ * export const authenticate = shopify.authenticate;
160
+ * ```
161
+ * @example
162
+ * <caption>Requesting billing with line items</caption>
163
+ * <description>Call `billing.request` with the `v3_lineItemBilling` future flag enabled</description>
164
+ * ```ts
165
+ * // /app/routes/**\/*.ts
166
+ * import { LoaderFunctionArgs } from "@remix-run/node";
167
+ * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
168
+ *
169
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
170
+ * const { billing } = await authenticate.admin(request);
171
+ * await billing.require({
172
+ * plans: [MONTHLY_PLAN],
173
+ * isTest: true,
174
+ * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),
175
+ * });
176
+ *
177
+ * // App logic
178
+ * };
179
+ * ```
180
+ * ```ts
181
+ * // shopify.server.ts
182
+ * import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server";
183
+ *
184
+ * export const MONTHLY_PLAN = 'Monthly subscription';
185
+ * export const ANNUAL_PLAN = 'Annual subscription';
186
+ *
187
+ * const shopify = shopifyApp({
188
+ * // ...etc
189
+ * billing: {
190
+ * [MONTHLY_PLAN]: {
191
+ * lineItems: [
192
+ * {
193
+ * amount: 5,
194
+ * currencyCode: 'USD',
195
+ * interval: BillingInterval.Every30Days,
196
+ * },
197
+ * {
198
+ * amount: 1,
199
+ * currencyCode: 'USD',
200
+ * interval: BillingInterval.Usage.
201
+ * terms: '1 dollar per 1000 emails',
202
+ * },
203
+ * ],
204
+ * },
205
+ * }
206
+ * future: {v3_lineItemBilling: true}
207
+ * });
208
+ * export default shopify;
209
+ * export const authenticate = shopify.authenticate;
210
+ * ```
211
+ */
212
+ require: (
213
+ options: RequireBillingOptions<Config>,
214
+ ) => Promise<BillingCheckResponseObject>;
215
+
216
+ /**
217
+ * Checks if the shop has an active payment for any plan defined in the `billing` config option.
218
+ *
219
+ * @returns A promise that resolves to an object containing the active purchases for the shop.
220
+ *
221
+ * @example
222
+ * <caption>Check what billing plans a merchant is subscribed to.</caption>
223
+ * <description>Use billing.check if you want to determine which plans are in use. Unlike `require`, `check` does not
224
+ * throw an error if no active billing plans are present. </description>
225
+ * ```ts
226
+ * // /app/routes/**\/*.ts
227
+ * import { LoaderFunctionArgs } from "@remix-run/node";
228
+ * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
229
+ *
230
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
231
+ * const { billing } = await authenticate.admin(request);
232
+ * const { hasActivePayment, appSubscriptions } = await billing.check({
233
+ * plans: [MONTHLY_PLAN],
234
+ * isTest: false,
235
+ * });
236
+ * console.log(hasActivePayment)
237
+ * console.log(appSubscriptions)
238
+ * };
239
+ * ```
240
+ * ```ts
241
+ * // shopify.server.ts
242
+ * import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server";
243
+ *
244
+ * export const MONTHLY_PLAN = 'Monthly subscription';
245
+ * export const ANNUAL_PLAN = 'Annual subscription';
246
+ *
247
+ * const shopify = shopifyApp({
248
+ * // ...etc
249
+ * billing: {
250
+ * [MONTHLY_PLAN]: {
251
+ * amount: 5,
252
+ * currencyCode: 'USD',
253
+ * interval: BillingInterval.Every30Days,
254
+ * },
255
+ * [ANNUAL_PLAN]: {
256
+ * amount: 50,
257
+ * currencyCode: 'USD',
258
+ * interval: BillingInterval.Annual,
259
+ * },
260
+ * }
261
+ * });
262
+ * export default shopify;
263
+ * export const authenticate = shopify.authenticate;
264
+ * ```
265
+ *
266
+ */
267
+ check: (
268
+ options: CheckBillingOptions<Config>,
269
+ ) => Promise<BillingCheckResponseObject>;
270
+
271
+ /**
272
+ * Requests payment for the plan.
273
+ *
274
+ * @returns Redirects to the confirmation URL for the payment.
275
+ *
276
+ * @example
277
+ * <caption>Using a custom return URL.</caption>
278
+ * <description>Change where the merchant is returned to after approving the purchase using the `returnUrl` option.</description>
279
+ * ```ts
280
+ * // /app/routes/**\/*.ts
281
+ * import { LoaderFunctionArgs } from "@remix-run/node";
282
+ * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
283
+ *
284
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
285
+ * const { billing } = await authenticate.admin(request);
286
+ * await billing.require({
287
+ * plans: [MONTHLY_PLAN],
288
+ * onFailure: async () => billing.request({
289
+ * plan: MONTHLY_PLAN,
290
+ * isTest: true,
291
+ * returnUrl: 'https://admin.shopify.com/store/my-store/apps/my-app/billing-page',
292
+ * }),
293
+ * });
294
+ *
295
+ * // App logic
296
+ * };
297
+ * ```
298
+ * ```ts
299
+ * // shopify.server.ts
300
+ * import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server";
301
+ *
302
+ * export const MONTHLY_PLAN = 'Monthly subscription';
303
+ * export const ANNUAL_PLAN = 'Annual subscription';
304
+ *
305
+ * const shopify = shopifyApp({
306
+ * // ...etc
307
+ * billing: {
308
+ * [MONTHLY_PLAN]: {
309
+ * amount: 5,
310
+ * currencyCode: 'USD',
311
+ * interval: BillingInterval.Every30Days,
312
+ * },
313
+ * [ANNUAL_PLAN]: {
314
+ * amount: 50,
315
+ * currencyCode: 'USD',
316
+ * interval: BillingInterval.Annual,
317
+ * },
318
+ * }
319
+ * });
320
+ * export default shopify;
321
+ * export const authenticate = shopify.authenticate;
322
+ * ```
323
+ */
324
+ request: (options: RequestBillingOptions<Config>) => Promise<never>;
325
+
326
+ /**
327
+ * Cancels an ongoing subscription, given its ID.
328
+ *
329
+ * @returns The cancelled subscription.
330
+ *
331
+ * @example
332
+ * <caption>Cancelling a subscription.</caption>
333
+ * <description>Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.</description>
334
+ * ```ts
335
+ * // /app/routes/cancel-subscription.ts
336
+ * import { LoaderFunctionArgs } from "@remix-run/node";
337
+ * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
338
+ *
339
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
340
+ * const { billing } = await authenticate.admin(request);
341
+ * const billingCheck = await billing.require({
342
+ * plans: [MONTHLY_PLAN],
343
+ * onFailure: async () => billing.request({ plan: MONTHLY_PLAN }),
344
+ * });
345
+ *
346
+ * const subscription = billingCheck.appSubscriptions[0];
347
+ * const cancelledSubscription = await billing.cancel({
348
+ * subscriptionId: subscription.id,
349
+ * isTest: true,
350
+ * prorate: true,
351
+ * });
352
+ *
353
+ * // App logic
354
+ * };
355
+ * ```
356
+ * ```ts
357
+ * // shopify.server.ts
358
+ * import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server";
359
+ *
360
+ * export const MONTHLY_PLAN = 'Monthly subscription';
361
+ * export const ANNUAL_PLAN = 'Annual subscription';
362
+ *
363
+ * const shopify = shopifyApp({
364
+ * // ...etc
365
+ * billing: {
366
+ * [MONTHLY_PLAN]: {
367
+ * amount: 5,
368
+ * currencyCode: 'USD',
369
+ * interval: BillingInterval.Every30Days,
370
+ * },
371
+ * [ANNUAL_PLAN]: {
372
+ * amount: 50,
373
+ * currencyCode: 'USD',
374
+ * interval: BillingInterval.Annual,
375
+ * },
376
+ * }
377
+ * });
378
+ * export default shopify;
379
+ * export const authenticate = shopify.authenticate;
380
+ * ```
381
+ */
382
+ cancel: (options: CancelBillingOptions) => Promise<AppSubscription>;
383
+ }