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,246 @@
1
+ import {Session, Shopify, ShopifyRestResources} from '@shopify/shopify-api';
2
+
3
+ import type {JSONValue} from '../../types';
4
+ import type {AdminApiContext} from '../../clients';
5
+ import type {FeatureEnabled, FutureFlagOptions} from '../../future/flags';
6
+
7
+ export interface RegisterWebhooksOptions {
8
+ /**
9
+ * The Shopify session used to register webhooks using the Admin API.
10
+ */
11
+ session: Session;
12
+ }
13
+
14
+ interface Context<Topics = string | number | symbol> {
15
+ /**
16
+ * The API version used for the webhook.
17
+ *
18
+ * @example
19
+ * <caption>Webhook API version.</caption>
20
+ * <description>Get the API version used for webhook request.</description>
21
+ * ```ts
22
+ * // /app/routes/webhooks.tsx
23
+ * import { ActionFunction } from "@remix-run/node";
24
+ * import { authenticate } from "../shopify.server";
25
+ *
26
+ * export const action: ActionFunction = async ({ request }) => {
27
+ * const { apiVersion } = await authenticate.webhook(request);
28
+ * return new Response();
29
+ * };
30
+ * ```
31
+ */
32
+ apiVersion: string;
33
+ /**
34
+ * The shop where the webhook was triggered.
35
+ *
36
+ * @example
37
+ * <caption>Webhook shop.</caption>
38
+ * <description>Get the shop that triggered a webhook.</description>
39
+ * ```ts
40
+ * // /app/routes/webhooks.tsx
41
+ * import { ActionFunction } from "@remix-run/node";
42
+ * import { authenticate } from "../shopify.server";
43
+ *
44
+ * export const action: ActionFunction = async ({ request }) => {
45
+ * const { shop } = await authenticate.webhook(request);
46
+ * return new Response();
47
+ * };
48
+ * ```
49
+ */
50
+ shop: string;
51
+ /**
52
+ * The topic of the webhook.
53
+ *
54
+ * @example
55
+ * <caption>Webhook topic.</caption>
56
+ * <description>Get the event topic for the webhook.</description>
57
+ * ```ts
58
+ * // /app/routes/webhooks.tsx
59
+ * import { ActionFunction } from "@remix-run/node";
60
+ * import { authenticate } from "../shopify.server";
61
+ *
62
+ * export const action: ActionFunction = async ({ request }) => {
63
+ * const { topic } = await authenticate.webhook(request);
64
+ *
65
+ * switch (topic) {
66
+ * case "APP_UNINSTALLED":
67
+ * // Do something when the app is uninstalled.
68
+ * break;
69
+ * }
70
+ *
71
+ * return new Response();
72
+ * };
73
+ * ```
74
+ */
75
+ topic: Topics;
76
+ /**
77
+ * A unique ID for the webhook. Useful to keep track of which events your app has already processed.
78
+ *
79
+ * @example
80
+ * <caption>Webhook ID.</caption>
81
+ * <description>Get the webhook ID.</description>
82
+ * ```ts
83
+ * // /app/routes/webhooks.tsx
84
+ * import { ActionFunction } from "@remix-run/node";
85
+ * import { authenticate } from "../shopify.server";
86
+ *
87
+ * export const action: ActionFunction = async ({ request }) => {
88
+ * const { webhookId } = await authenticate.webhook(request);
89
+ * return new Response();
90
+ * };
91
+ * ```
92
+ */
93
+ webhookId: string;
94
+ /**
95
+ * The payload from the webhook request.
96
+ *
97
+ * @example
98
+ * <caption>Webhook payload.</caption>
99
+ * <description>Get the request's POST payload.</description>
100
+ * ```ts
101
+ * // /app/routes/webhooks.tsx
102
+ * import { ActionFunction } from "@remix-run/node";
103
+ * import { authenticate } from "../shopify.server";
104
+ *
105
+ * export const action: ActionFunction = async ({ request }) => {
106
+ * const { payload } = await authenticate.webhook(request);
107
+ * return new Response();
108
+ * };
109
+ * ```
110
+ */
111
+ payload: JSONValue;
112
+ /**
113
+ * The sub-topic of the webhook. This is only available for certain webhooks.
114
+ *
115
+ * @example
116
+ * <caption>Webhook sub-topic.</caption>
117
+ * <description>Get the webhook sub-topic.</description>
118
+ * ```ts
119
+ * // /app/routes/webhooks.tsx
120
+ * import { ActionFunction } from "@remix-run/node";
121
+ * import { authenticate } from "../shopify.server";
122
+ *
123
+ * export const action: ActionFunction = async ({ request }) => {
124
+ * const { subTopic } = await authenticate.webhook(request);
125
+ * return new Response();
126
+ * };
127
+ * ```
128
+ *
129
+ */
130
+ subTopic?: string;
131
+ }
132
+
133
+ export interface WebhookContextWithoutSession<Topics = string | number | symbol>
134
+ extends Context<Topics> {
135
+ session: undefined;
136
+ admin: undefined;
137
+ }
138
+
139
+ export interface LegacyWebhookAdminApiContext<
140
+ Resources extends ShopifyRestResources,
141
+ > {
142
+ /** A REST client. */
143
+ rest: InstanceType<Shopify['clients']['Rest']> & Resources;
144
+ /** A GraphQL client. */
145
+ graphql: InstanceType<Shopify['clients']['Graphql']>;
146
+ }
147
+
148
+ export type WebhookAdminContext<
149
+ Future extends FutureFlagOptions,
150
+ Resources extends ShopifyRestResources,
151
+ > =
152
+ FeatureEnabled<Future, 'v3_webhookAdminContext'> extends true
153
+ ? AdminApiContext<Resources>
154
+ : LegacyWebhookAdminApiContext<Resources>;
155
+
156
+ export interface WebhookContextWithSession<
157
+ Future extends FutureFlagOptions,
158
+ Resources extends ShopifyRestResources,
159
+ Topics = string | number | symbol,
160
+ > extends Context<Topics> {
161
+ /**
162
+ * A session with an offline token for the shop.
163
+ *
164
+ * Returned only if there is a session for the shop.
165
+ */
166
+ session: Session;
167
+
168
+ /**
169
+ * An admin context for the webhook.
170
+ *
171
+ * Returned only if there is a session for the shop.
172
+ *
173
+ * @example
174
+ * <caption>[V3] Webhook admin context.</caption>
175
+ * <description>With the `v3_webhookAdminContext` future flag enabled, use the `admin` object in the context to interact with the Admin API.</description>
176
+ * ```ts
177
+ * // /app/routes/webhooks.tsx
178
+ * import { ActionFunctionArgs } from "@remix-run/node";
179
+ * import { authenticate } from "../shopify.server";
180
+ *
181
+ * export async function action({ request }: ActionFunctionArgs) {
182
+ * const { admin } = await authenticate.webhook(request);
183
+ *
184
+ * const response = await admin?.graphql(
185
+ * `#graphql
186
+ * mutation populateProduct($input: ProductInput!) {
187
+ * productCreate(input: $input) {
188
+ * product {
189
+ * id
190
+ * }
191
+ * }
192
+ * }`,
193
+ * { variables: { input: { title: "Product Name" } } }
194
+ * );
195
+ *
196
+ * const productData = await response.json();
197
+ * return json({ data: productData.data });
198
+ * }
199
+ * ```
200
+ *
201
+ * @example
202
+ * <caption>Webhook admin context.</caption>
203
+ * <description>Use the `admin` object in the context to interact with the Admin API. This format will be removed in V3 of the package.</description>
204
+ * ```ts
205
+ * // /app/routes/webhooks.tsx
206
+ * import { json, ActionFunctionArgs } from "@remix-run/node";
207
+ * import { authenticate } from "../shopify.server";
208
+ *
209
+ * export async function action({ request }: ActionFunctionArgs) {
210
+ * const { admin } = await authenticate.webhook(request);
211
+ *
212
+ * const response = await admin?.graphql.query<any>({
213
+ * data: {
214
+ * query: `#graphql
215
+ * mutation populateProduct($input: ProductInput!) {
216
+ * productCreate(input: $input) {
217
+ * product {
218
+ * id
219
+ * }
220
+ * }
221
+ * }`,
222
+ * variables: { input: { title: "Product Name" } },
223
+ * },
224
+ * });
225
+ *
226
+ * const productData = response?.body.data;
227
+ * return json({ data: productData.data });
228
+ * }
229
+ * ```
230
+ */
231
+ admin: WebhookAdminContext<Future, Resources>;
232
+ }
233
+
234
+ export type WebhookContext<
235
+ Future extends FutureFlagOptions,
236
+ Resources extends ShopifyRestResources,
237
+ Topics = string | number | symbol,
238
+ > =
239
+ | WebhookContextWithoutSession<Topics>
240
+ | WebhookContextWithSession<Future, Resources, Topics>;
241
+
242
+ export type AuthenticateWebhook<
243
+ Future extends FutureFlagOptions,
244
+ Resources extends ShopifyRestResources,
245
+ Topics = string | number | symbol,
246
+ > = (request: Request) => Promise<WebhookContext<Future, Resources, Topics>>;
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ import {boundary} from '../../index';
4
+
5
+ describe('Error boundary', () => {
6
+ it('returns a string when handling an ErrorResponse', () => {
7
+ // WHEN
8
+ const result = boundary.error(new ErrorResponse());
9
+
10
+ // THEN
11
+ expect(result).toEqual(
12
+ <div dangerouslySetInnerHTML={{__html: 'Handling response'}} />,
13
+ );
14
+ });
15
+
16
+ it('returns a string when handling an ErrorResponseImpl', () => {
17
+ // WHEN
18
+ const result = boundary.error(new ErrorResponseImpl());
19
+
20
+ // THEN
21
+ expect(result).toEqual(
22
+ <div dangerouslySetInnerHTML={{__html: 'Handling response'}} />,
23
+ );
24
+ });
25
+
26
+ it('throws an error when handling an unknown error', () => {
27
+ // WHEN
28
+ const result = () => boundary.error(new Error());
29
+
30
+ // THEN
31
+ expect(result).toThrowError();
32
+ });
33
+ });
34
+
35
+ class ErrorResponse extends Error {}
36
+ class ErrorResponseImpl extends Error {}
@@ -0,0 +1,66 @@
1
+ import {boundary} from '../index';
2
+ import {shopifyApp} from '../../index';
3
+ import {testConfig} from '../../__test-helpers';
4
+
5
+ describe('Headers boundary', () => {
6
+ it('returns only error headers if error headers are present', () => {
7
+ // GIVEN
8
+ const shopify = shopifyApp(testConfig());
9
+ const headers = {
10
+ parentHeaders: new Headers([['parent', 'header']]),
11
+ loaderHeaders: new Headers([['loader', 'header']]),
12
+ actionHeaders: new Headers([['action', 'header']]),
13
+ errorHeaders: new Headers([['error', 'header']]),
14
+ };
15
+
16
+ // WHEN
17
+ const result = boundary.headers(headers);
18
+
19
+ // THEN
20
+ expect(result.get('parent')).toBeNull();
21
+ expect(result.get('loader')).toBeNull();
22
+ expect(result.get('action')).toBeNull();
23
+ expect(result.get('error')).toEqual('header');
24
+ });
25
+
26
+ it('merges parent, loader & action headers if no error headers are present', () => {
27
+ // GIVEN
28
+ const shopify = shopifyApp(testConfig());
29
+ const headers = {
30
+ parentHeaders: new Headers([
31
+ ['parent', 'header'],
32
+ ['common', 'parent'],
33
+ ]),
34
+ loaderHeaders: new Headers([
35
+ ['loader', 'header'],
36
+ ['common', 'loader'],
37
+ ]),
38
+ actionHeaders: new Headers([
39
+ ['action', 'header'],
40
+ ['common', 'action'],
41
+ ]),
42
+ errorHeaders: new Headers(),
43
+ };
44
+
45
+ // WHEN
46
+ const result = boundary.headers(headers);
47
+
48
+ // THEN
49
+ expect(result.get('parent')).toEqual('header');
50
+ expect(result.get('loader')).toEqual('header');
51
+ expect(result.get('action')).toEqual('header');
52
+ expect(result.get('common')).toEqual('parent, loader, action');
53
+ });
54
+
55
+ it('returns an empty headers object if no headers are present', () => {
56
+ // GIVEN
57
+ const shopify = shopifyApp(testConfig());
58
+ const headers = {};
59
+
60
+ // WHEN
61
+ const result = boundary.headers(headers as any);
62
+
63
+ // THEN
64
+ expect(result.entries()).toEqual(new Headers().entries());
65
+ });
66
+ });
@@ -0,0 +1,14 @@
1
+ export function errorBoundary(error: any) {
2
+ if (
3
+ error.constructor.name === 'ErrorResponse' ||
4
+ error.constructor.name === 'ErrorResponseImpl'
5
+ ) {
6
+ return (
7
+ <div
8
+ dangerouslySetInnerHTML={{__html: error.data || 'Handling response'}}
9
+ />
10
+ );
11
+ }
12
+
13
+ throw error;
14
+ }
@@ -0,0 +1,15 @@
1
+ import {HeadersArgs} from '@remix-run/server-runtime';
2
+
3
+ export function headersBoundary(headers: HeadersArgs): Headers {
4
+ const {parentHeaders, loaderHeaders, actionHeaders, errorHeaders} = headers;
5
+
6
+ if (errorHeaders && Array.from(errorHeaders.entries()).length > 0) {
7
+ return errorHeaders;
8
+ }
9
+
10
+ return new Headers([
11
+ ...(parentHeaders ? Array.from(parentHeaders.entries()) : []),
12
+ ...(loaderHeaders ? Array.from(loaderHeaders.entries()) : []),
13
+ ...(actionHeaders ? Array.from(actionHeaders.entries()) : []),
14
+ ]);
15
+ }
@@ -0,0 +1,39 @@
1
+ import {headersBoundary} from './headers';
2
+ import {errorBoundary} from './error';
3
+
4
+ /**
5
+ * A collection of functions that handle the necessary code for error boundaries in routes using authenticate.admin.
6
+ */
7
+ export const boundary = {
8
+ /**
9
+ * A function that handles errors or thrown responses.
10
+ *
11
+ * @example
12
+ * <caption>Catching errors in a route</caption>
13
+ * ```ts
14
+ * // /app/routes/admin/widgets.ts
15
+ * import { boundary } from "@shopify/shopify-app-remix/server";
16
+ *
17
+ * export function ErrorBoundary() {
18
+ * return boundary.error(useRouteError());
19
+ * }
20
+ * ```
21
+ */
22
+ error: errorBoundary,
23
+
24
+ /**
25
+ * A function that sets the appropriate document repsonse headers.
26
+ *
27
+ * @example
28
+ * <caption>Catching errors in a route</caption>
29
+ * ```ts
30
+ * // /app/routes/admin/widgets.ts
31
+ * import { boundary } from "@shopify/shopify-app-remix/server";
32
+ *
33
+ * export const headers = (headersArgs) => {
34
+ * return boundary.headers(headersArgs);
35
+ * };
36
+ * ```
37
+ */
38
+ headers: headersBoundary,
39
+ };
@@ -0,0 +1,4 @@
1
+ import {HeadersArgs} from '@remix-run/server-runtime';
2
+
3
+ export type ErrorBoundary = (error: unknown) => string | never;
4
+ export type HeadersBoundary = (headers: HeadersArgs) => Headers;
@@ -0,0 +1,34 @@
1
+ import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs';
2
+
3
+ const data: ReferenceEntityTemplateSchema = {
4
+ name: 'Admin API',
5
+ description:
6
+ 'Contains objects used to interact with the Admin API.' +
7
+ '\n\nThis object is returned as part of different contexts, such as [`admin`](/docs/api/shopify-app-remix/authenticate/admin), [`unauthenticated.admin`](/docs/api/shopify-app-remix/unauthenticated/unauthenticated-admin), and [`webhook`](/docs/api/shopify-app-remix/authenticate/webhook).',
8
+ category: 'APIs',
9
+ type: 'object',
10
+ isVisualComponent: false,
11
+ definitions: [
12
+ {
13
+ title: 'admin',
14
+ description:
15
+ 'Provides utilities that apps can use to make requests to the Admin API.',
16
+ type: 'AdminApiContext',
17
+ },
18
+ ],
19
+ jsDocTypeExamples: ['AdminApiContext'],
20
+ related: [
21
+ {
22
+ name: 'Authenticated context',
23
+ subtitle: 'Authenticate requests from Shopify Admin.',
24
+ url: '/docs/api/shopify-app-remix/authenticate/admin',
25
+ },
26
+ {
27
+ name: 'Unauthenticated context',
28
+ subtitle: 'Interact with the Admin API on non-Shopify requests.',
29
+ url: '/docs/api/shopify-app-remix/unauthenticated/unauthenticated-admin',
30
+ },
31
+ ],
32
+ };
33
+
34
+ export default data;
@@ -0,0 +1,30 @@
1
+ import {Session, ShopifyRestResources} from '@shopify/shopify-api';
2
+
3
+ import {BasicParams} from '../../types';
4
+
5
+ import {graphqlClientFactory} from './graphql';
6
+ import {restClientFactory} from './rest';
7
+ import type {AdminApiContext} from './types';
8
+
9
+ interface RestClientOptions {
10
+ params: BasicParams;
11
+ session: Session;
12
+ handleClientError?: (error: any) => Promise<void>;
13
+ }
14
+
15
+ export function adminClientFactory<
16
+ Resources extends ShopifyRestResources = ShopifyRestResources,
17
+ >({
18
+ params,
19
+ handleClientError,
20
+ session,
21
+ }: RestClientOptions): AdminApiContext<Resources> {
22
+ return {
23
+ rest: restClientFactory<Resources>({
24
+ params,
25
+ session,
26
+ handleClientError,
27
+ }),
28
+ graphql: graphqlClientFactory({params, session, handleClientError}),
29
+ };
30
+ }
@@ -0,0 +1,39 @@
1
+ import {AdminOperations} from '@shopify/admin-api-client';
2
+
3
+ import {GraphQLClient} from '../types';
4
+
5
+ import {AdminClientOptions} from './types';
6
+
7
+ // eslint-disable-next-line no-warning-comments
8
+ // TODO: This is actually just a call through to the Shopify API client, but with a different API. We should eventually
9
+ // move this over to the library layer. While doing that, we should also allow the apiVersion to be passed into the REST
10
+ // client request calls.
11
+ export function graphqlClientFactory({
12
+ params,
13
+ handleClientError,
14
+ session,
15
+ }: AdminClientOptions): GraphQLClient<AdminOperations> {
16
+ return async function query(operation, options) {
17
+ const client = new params.api.clients.Graphql({
18
+ session,
19
+ apiVersion: options?.apiVersion,
20
+ });
21
+
22
+ try {
23
+ // We convert the incoming response to a Response object to bring this client closer to the Remix client.
24
+ const apiResponse = await client.request(operation, {
25
+ variables: options?.variables,
26
+ retries: options?.tries ? options.tries - 1 : 0,
27
+ headers: options?.headers,
28
+ });
29
+
30
+ return new Response(JSON.stringify(apiResponse));
31
+ } catch (error) {
32
+ if (handleClientError) {
33
+ throw await handleClientError({error, params, session});
34
+ }
35
+
36
+ throw error;
37
+ }
38
+ };
39
+ }
@@ -0,0 +1,2 @@
1
+ export * from './factory';
2
+ export * from './types';
@@ -0,0 +1,157 @@
1
+ import {
2
+ DeleteRequestParams,
3
+ GetRequestParams,
4
+ PostRequestParams,
5
+ PutRequestParams,
6
+ RequestParams,
7
+ Session,
8
+ Shopify,
9
+ ShopifyRestResources,
10
+ } from '@shopify/shopify-api';
11
+
12
+ import type {AdminClientOptions} from './types';
13
+
14
+ export type RestClientWithResources<Resources extends ShopifyRestResources> =
15
+ RemixRestClient & {resources: Resources};
16
+
17
+ export function restClientFactory<
18
+ Resources extends ShopifyRestResources = ShopifyRestResources,
19
+ >({
20
+ params,
21
+ handleClientError,
22
+ session,
23
+ }: AdminClientOptions): RestClientWithResources<Resources> {
24
+ const {api} = params;
25
+ const client = new RemixRestClient({
26
+ params,
27
+ handleClientError,
28
+ session,
29
+ }) as RestClientWithResources<Resources>;
30
+
31
+ if (api.rest) {
32
+ client.resources = {} as Resources;
33
+
34
+ const RestResourceClient = restResourceClientFactory({
35
+ params,
36
+ handleClientError,
37
+ session,
38
+ });
39
+
40
+ Object.entries(api.rest).forEach(([name, resource]) => {
41
+ class RemixResource extends resource {
42
+ public static Client = RestResourceClient;
43
+ }
44
+
45
+ Reflect.defineProperty(RemixResource, 'name', {
46
+ value: name,
47
+ });
48
+
49
+ Reflect.set(client.resources, name, RemixResource);
50
+ });
51
+ }
52
+
53
+ return client;
54
+ }
55
+
56
+ class RemixRestClient {
57
+ public session: Session;
58
+ private params: AdminClientOptions['params'];
59
+ private handleClientError: AdminClientOptions['handleClientError'];
60
+
61
+ constructor({params, session, handleClientError}: AdminClientOptions) {
62
+ this.params = params;
63
+ this.handleClientError = handleClientError;
64
+ this.session = session;
65
+ }
66
+
67
+ /**
68
+ * Performs a GET request on the given path.
69
+ */
70
+ public async get(params: GetRequestParams) {
71
+ return this.makeRequest({
72
+ method: 'GET' as RequestParams['method'],
73
+ ...params,
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Performs a POST request on the given path.
79
+ */
80
+ public async post(params: PostRequestParams) {
81
+ return this.makeRequest({
82
+ method: 'POST' as RequestParams['method'],
83
+ ...params,
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Performs a PUT request on the given path.
89
+ */
90
+ public async put(params: PutRequestParams) {
91
+ return this.makeRequest({
92
+ method: 'PUT' as RequestParams['method'],
93
+ ...params,
94
+ });
95
+ }
96
+
97
+ /**
98
+ * Performs a DELETE request on the given path.
99
+ */
100
+ public async delete(params: DeleteRequestParams) {
101
+ return this.makeRequest({
102
+ method: 'DELETE' as RequestParams['method'],
103
+ ...params,
104
+ });
105
+ }
106
+
107
+ protected async makeRequest(params: RequestParams): Promise<Response> {
108
+ const originalClient = new this.params.api.clients.Rest({
109
+ session: this.session,
110
+ });
111
+ const originalRequest = Reflect.get(originalClient, 'request');
112
+
113
+ try {
114
+ const apiResponse = await originalRequest.call(originalClient, params);
115
+
116
+ // We use a separate client for REST requests and REST resources because we want to override the API library
117
+ // client class to return a Response object instead.
118
+ return new Response(JSON.stringify(apiResponse.body), {
119
+ headers: apiResponse.headers,
120
+ });
121
+ } catch (error) {
122
+ if (this.handleClientError) {
123
+ throw await this.handleClientError({
124
+ error,
125
+ session: this.session,
126
+ params: this.params,
127
+ });
128
+ } else throw new Error(error);
129
+ }
130
+ }
131
+ }
132
+
133
+ function restResourceClientFactory({
134
+ params,
135
+ handleClientError,
136
+ session,
137
+ }: AdminClientOptions): Shopify['clients']['Rest'] {
138
+ const {api} = params;
139
+
140
+ const ApiClient = api.clients.Rest;
141
+ return class RestResourceClient extends ApiClient {
142
+ protected async request(requestParams: RequestParams) {
143
+ const originalClient = new api.clients.Rest({session});
144
+ const originalRequest = Reflect.get(originalClient, 'request');
145
+
146
+ try {
147
+ // We just call through to the API library client, and handle the error response here, so that data parsing
148
+ // behaves the same way.
149
+ return await originalRequest.call(originalClient, requestParams);
150
+ } catch (error) {
151
+ if (handleClientError) {
152
+ throw await handleClientError({error, params, session});
153
+ } else throw new Error(error);
154
+ }
155
+ }
156
+ };
157
+ }