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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +14 -0
- package/.changeset/flat-clouds-camp.md +5 -0
- package/.eslintrc.js +36 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/ISSUE_TEMPLATE/BUG_REPORT.md +36 -0
- package/.github/ISSUE_TEMPLATE/ENHANCEMENT.md +9 -0
- package/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md +9 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +34 -0
- package/.github/dependabot.yml +9 -0
- package/.github/workflows/changelog.yml +30 -0
- package/.github/workflows/ci.yml +22 -0
- package/.github/workflows/cla.yml +22 -0
- package/.github/workflows/close-waiting-for-response-issues.yml +20 -0
- package/.github/workflows/main-release.yml +36 -0
- package/.github/workflows/markdown_link_check.yml +14 -0
- package/.github/workflows/markdown_link_checker_config.json +9 -0
- package/.github/workflows/publish-experimental-build.yml +30 -0
- package/.github/workflows/release-candidate.yml +35 -0
- package/.github/workflows/remove-labels-on-activity.yml +16 -0
- package/.github/workflows/stale.yml +26 -0
- package/.prettierignore +5 -0
- package/.prettierrc +1 -0
- package/CODE_OF_CONDUCT.md +46 -0
- package/CONTRIBUTING.md +39 -0
- package/LICENSE.md +9 -0
- package/README.md +62 -3
- package/RELEASING.md +142 -0
- package/loom.config.ts +115 -0
- package/package.json +44 -3
- package/packages/.prettierrc +1 -0
- package/packages/shopify-app-express/CHANGELOG.md +316 -0
- package/packages/shopify-app-express/LICENSE.md +9 -0
- package/packages/shopify-app-express/README.md +93 -0
- package/packages/shopify-app-express/docs/reference/README.md +3 -0
- package/packages/shopify-app-express/docs/reference/auth.md +76 -0
- package/packages/shopify-app-express/docs/reference/cspHeaders.md +24 -0
- package/packages/shopify-app-express/docs/reference/ensureInstalledOnShop.md +17 -0
- package/packages/shopify-app-express/docs/reference/migrating-app-v6-api-lib-to-express-lib.md +345 -0
- package/packages/shopify-app-express/docs/reference/processWebhooks.md +67 -0
- package/packages/shopify-app-express/docs/reference/redirectOutOfApp.md +77 -0
- package/packages/shopify-app-express/docs/reference/redirectToShopifyOrAppRoot.md +20 -0
- package/packages/shopify-app-express/docs/reference/shopifyApp.md +148 -0
- package/packages/shopify-app-express/docs/reference/validateAuthenticatedSession.md +30 -0
- package/packages/shopify-app-express/loom.config.ts +27 -0
- package/packages/shopify-app-express/package.json +54 -0
- package/packages/shopify-app-express/src/__tests__/index.test.ts +100 -0
- package/packages/shopify-app-express/src/__tests__/integration/oauth.test.ts +445 -0
- package/packages/shopify-app-express/src/__tests__/integration/responses.ts +135 -0
- package/packages/shopify-app-express/src/__tests__/integration/types.ts +22 -0
- package/packages/shopify-app-express/src/__tests__/integration/utils.ts +68 -0
- package/packages/shopify-app-express/src/__tests__/integration/webhooks.test.ts +208 -0
- package/packages/shopify-app-express/src/__tests__/redirect-to-auth.test.ts +103 -0
- package/packages/shopify-app-express/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-express/src/__tests__/test-helper.ts +204 -0
- package/packages/shopify-app-express/src/app-installations.ts +42 -0
- package/packages/shopify-app-express/src/auth/__tests__/auth.test.ts +303 -0
- package/packages/shopify-app-express/src/auth/auth-callback.ts +131 -0
- package/packages/shopify-app-express/src/auth/index.ts +32 -0
- package/packages/shopify-app-express/src/auth/types.ts +13 -0
- package/packages/shopify-app-express/src/config-types.ts +38 -0
- package/packages/shopify-app-express/src/error.ts +8 -0
- package/packages/shopify-app-express/src/index.ts +171 -0
- package/packages/shopify-app-express/src/middlewares/__tests__/csp-headers.test.ts +69 -0
- package/packages/shopify-app-express/src/middlewares/__tests__/ensure-installed-on-shop.test.ts +193 -0
- package/packages/shopify-app-express/src/middlewares/__tests__/redirect-to-shopify-or-app-root.test.ts +59 -0
- package/packages/shopify-app-express/src/middlewares/__tests__/validate-authenticated-session.test.ts +319 -0
- package/packages/shopify-app-express/src/middlewares/csp-headers.ts +31 -0
- package/packages/shopify-app-express/src/middlewares/ensure-installed-on-shop.ts +176 -0
- package/packages/shopify-app-express/src/middlewares/has-valid-access-token.ts +25 -0
- package/packages/shopify-app-express/src/middlewares/index.ts +15 -0
- package/packages/shopify-app-express/src/middlewares/redirect-to-shopify-or-app-root.ts +39 -0
- package/packages/shopify-app-express/src/middlewares/types.ts +6 -0
- package/packages/shopify-app-express/src/middlewares/validate-authenticated-session.ts +142 -0
- package/packages/shopify-app-express/src/redirect-out-of-app.ts +80 -0
- package/packages/shopify-app-express/src/redirect-to-auth.ts +70 -0
- package/packages/shopify-app-express/src/types.ts +26 -0
- package/packages/shopify-app-express/src/version.ts +1 -0
- package/packages/shopify-app-express/src/webhooks/__tests__/process.test.ts +138 -0
- package/packages/shopify-app-express/src/webhooks/index.ts +54 -0
- package/packages/shopify-app-express/src/webhooks/process.ts +22 -0
- package/packages/shopify-app-express/src/webhooks/types.ts +24 -0
- package/packages/shopify-app-express/tsconfig.json +10 -0
- package/packages/shopify-app-remix/.eslintrc.js +3 -0
- package/packages/shopify-app-remix/CHANGELOG.md +569 -0
- package/packages/shopify-app-remix/LICENSE.md +9 -0
- package/packages/shopify-app-remix/README.md +223 -0
- package/packages/shopify-app-remix/docs/build-docs.sh +11 -0
- package/packages/shopify-app-remix/docs/generated/generated_docs_data.json +18650 -0
- package/packages/shopify-app-remix/docs/generated/generated_static_pages.json +540 -0
- package/packages/shopify-app-remix/docs/staticPages/admin.doc.ts +130 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/auth-cors.example.tsx +11 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/auth.example.tsx +19 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/graphql.example.tsx +29 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/headers.example.tsx +10 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/rest-resources.example.tsx +9 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/admin/rest.example.tsx +17 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/future-flags/config.example.ts +8 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/future-flags/unstable.example.ts +9 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/.graphqlrc.ts +16 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/install.npm.example.sh +2 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/install.pnpm.example.sh +2 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/install.yarn.example.sh +2 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/package.json +5 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/run.npm.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/run.pnpm.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/graphql-types/run.yarn.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/webhooks/config.example.ts +19 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/guides/webhooks/endpoint.example.ts +24 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/app-provider.example.ts +30 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/boundaries.example.ts +9 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/create.npm.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/create.pnpm.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/create.yarn.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/embedded-app-auth-strategy-config.example.ts +10 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/entry-server.example.ts +12 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/install.npm.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/install.pnpm.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/install.yarn.example.sh +1 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/shopify-app.example.ts +14 -0
- package/packages/shopify-app-remix/docs/staticPages/examples/index/splat-route.example.ts +11 -0
- package/packages/shopify-app-remix/docs/staticPages/future-flags.doc.ts +94 -0
- package/packages/shopify-app-remix/docs/staticPages/graphql-types.doc.ts +148 -0
- package/packages/shopify-app-remix/docs/staticPages/index.doc.ts +227 -0
- package/packages/shopify-app-remix/docs/staticPages/webhooks.doc.ts +64 -0
- package/packages/shopify-app-remix/docs/tsconfig.docs.json +9 -0
- package/packages/shopify-app-remix/docs/typeOverride.json +1 -0
- package/packages/shopify-app-remix/docs/upcoming_changes.md +153 -0
- package/packages/shopify-app-remix/loom.config.ts +57 -0
- package/packages/shopify-app-remix/package.json +93 -0
- package/packages/shopify-app-remix/src/react/.eslintrc.js +16 -0
- package/packages/shopify-app-remix/src/react/__tests__/test-helper.ts +22 -0
- package/packages/shopify-app-remix/src/react/components/AppProvider/AppProvider.doc.ts +34 -0
- package/packages/shopify-app-remix/src/react/components/AppProvider/AppProvider.tsx +121 -0
- package/packages/shopify-app-remix/src/react/components/AppProvider/__tests__/AppProvider.test.tsx +68 -0
- package/packages/shopify-app-remix/src/react/components/AppProvider/index.ts +1 -0
- package/packages/shopify-app-remix/src/react/components/RemixPolarisLink.tsx +14 -0
- package/packages/shopify-app-remix/src/react/components/index.ts +1 -0
- package/packages/shopify-app-remix/src/react/const.ts +2 -0
- package/packages/shopify-app-remix/src/react/index.ts +1 -0
- package/packages/shopify-app-remix/src/server/.eslintrc.js +16 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/__tests__/request-mock.test.ts +171 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/const.ts +11 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/expect-admin-api-client.ts +119 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/expect-begin-auth-redirect.ts +22 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/expect-document-request-headers.ts +25 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/expect-exit-iframe.ts +37 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/expect-login-redirect.ts +8 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/expect-storefront-api-client.ts +50 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/get-hmac.ts +10 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/get-jwt.ts +31 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/get-thrown-response.ts +17 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/index.ts +14 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/request-mock.ts +169 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/setup-valid-session.ts +45 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/sign-request-cookie.ts +21 -0
- package/packages/shopify-app-remix/src/server/__test-helpers/test-config.ts +112 -0
- package/packages/shopify-app-remix/src/server/__tests__/override-logger.test.ts +101 -0
- package/packages/shopify-app-remix/src/server/__tests__/shopify-app.test.ts +119 -0
- package/packages/shopify-app-remix/src/server/adapters/__tests__/node-app-bridge-url.test.ts +18 -0
- package/packages/shopify-app-remix/src/server/adapters/__tests__/node.test.ts +28 -0
- package/packages/shopify-app-remix/src/server/adapters/node/__tests__/setup-jest.ts +10 -0
- package/packages/shopify-app-remix/src/server/adapters/node/index.ts +20 -0
- package/packages/shopify-app-remix/src/server/adapters/vercel/__tests__/setup-jest.ts +12 -0
- package/packages/shopify-app-remix/src/server/adapters/vercel/index.ts +13 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/admin-client.test.ts +181 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/doc-request-path.test.ts +151 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/exit-i-frame-path.test.ts +99 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/patch-session-token-path.test.ts +58 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/reject-bot.test.ts +23 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/respond-to-options.test.ts +50 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/__tests__/session-token-header-path.test.ts +91 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/authenticate.admin.doc.ts +37 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/authenticate.ts +201 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/cancel.test.ts +258 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/check.test.ts +254 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/mock-responses.ts +65 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/request.test.ts +373 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/__tests__/require.test.ts +316 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/authenticate.admin.billing.doc.ts +28 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/cancel.ts +37 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/check.ts +38 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/index.ts +4 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/request.ts +101 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/require.ts +56 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/billing/types.ts +383 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/__tests__/redirect.test.ts +313 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/__tests__/validate-redirect-url.test.ts +84 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/begin-auth.ts +17 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/create-admin-api-context.ts +22 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.ts +18 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.ts +25 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/handle-client-error.ts +43 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/index.ts +14 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-to-auth-page.ts +28 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-to-bounce-page.ts +23 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.ts +21 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-with-app-bridge-headers.ts +13 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect-with-exitiframe.ts +28 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/redirect.ts +83 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/render-app-bridge.ts +46 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/trigger-after-auth-hook.ts +28 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/validate-redirect-url.ts +67 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/helpers/validate-shop-and-host-params.ts +28 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/admin-client.test.ts +222 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/auth-callback-path.test.ts +395 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/auth-path.test.ts +83 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/authenticate.test.ts +183 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/ensure-installed-on-shop.test.ts +234 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/auth-code-flow/session-token-header-path.test.ts +79 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/token-exchange/admin-client.test.ts +189 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/__tests__/token-exchange/authenticate.test.ts +310 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/auth-code-flow.ts +333 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/token-exchange.ts +169 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/strategies/types.ts +29 -0
- package/packages/shopify-app-remix/src/server/authenticate/admin/types.ts +199 -0
- package/packages/shopify-app-remix/src/server/authenticate/const.ts +15 -0
- package/packages/shopify-app-remix/src/server/authenticate/flow/__tests__/authenticate.test.ts +142 -0
- package/packages/shopify-app-remix/src/server/authenticate/flow/authenticate.flow.doc.ts +34 -0
- package/packages/shopify-app-remix/src/server/authenticate/flow/authenticate.ts +71 -0
- package/packages/shopify-app-remix/src/server/authenticate/flow/types.ts +90 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/__tests__/add-response-headers.test.ts +25 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/__tests__/app-bridge-url.test.ts +21 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/__tests__/idempotent-promise-handler.test.ts +104 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/add-response-headers.ts +43 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/app-bridge-url.ts +10 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/ensure-cors-headers.ts +38 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/get-session-token-header.ts +11 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/idempotent-promise-handler.ts +45 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/index.ts +8 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/reject-bot-request.ts +13 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/respond-to-invalid-session-token.ts +29 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/respond-to-options-request.ts +26 -0
- package/packages/shopify-app-remix/src/server/authenticate/helpers/validate-session-token.ts +32 -0
- package/packages/shopify-app-remix/src/server/authenticate/login/__tests__/login.test.ts +157 -0
- package/packages/shopify-app-remix/src/server/authenticate/login/login.ts +53 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/__tests__/factory.test.ts +224 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/__tests__/authenticate.test.ts +282 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.ts +36 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/authenticate.ts +90 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/appProxy/types.ts +164 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/checkout/__tests__/authenticate.test.ts +142 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/checkout/authenticate.public.checkout.doc.ts +23 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/checkout/authenticate.ts +45 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/checkout/types.ts +65 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/factory.ts +49 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/index.ts +1 -0
- package/packages/shopify-app-remix/src/server/authenticate/public/types.ts +77 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/__tests__/authenticate.test.ts +207 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/__tests__/mock-responses.ts +45 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/__tests__/register.test.ts +210 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/authenticate.ts +113 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/authenticate.webhooks.doc.ts +28 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/index.ts +1 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/register.ts +48 -0
- package/packages/shopify-app-remix/src/server/authenticate/webhooks/types.ts +246 -0
- package/packages/shopify-app-remix/src/server/boundary/__tests__/error.test.tsx +36 -0
- package/packages/shopify-app-remix/src/server/boundary/__tests__/headers.test.ts +66 -0
- package/packages/shopify-app-remix/src/server/boundary/error.tsx +14 -0
- package/packages/shopify-app-remix/src/server/boundary/headers.ts +15 -0
- package/packages/shopify-app-remix/src/server/boundary/index.ts +39 -0
- package/packages/shopify-app-remix/src/server/boundary/types.ts +4 -0
- package/packages/shopify-app-remix/src/server/clients/admin/authenticate.admin.api.doc.ts +34 -0
- package/packages/shopify-app-remix/src/server/clients/admin/factory.ts +30 -0
- package/packages/shopify-app-remix/src/server/clients/admin/graphql.ts +39 -0
- package/packages/shopify-app-remix/src/server/clients/admin/index.ts +2 -0
- package/packages/shopify-app-remix/src/server/clients/admin/rest.ts +157 -0
- package/packages/shopify-app-remix/src/server/clients/admin/types.ts +178 -0
- package/packages/shopify-app-remix/src/server/clients/index.ts +2 -0
- package/packages/shopify-app-remix/src/server/clients/storefront/authenticate.storefront.api.doc.ts +34 -0
- package/packages/shopify-app-remix/src/server/clients/storefront/factory.ts +32 -0
- package/packages/shopify-app-remix/src/server/clients/storefront/index.ts +2 -0
- package/packages/shopify-app-remix/src/server/clients/storefront/types.ts +31 -0
- package/packages/shopify-app-remix/src/server/clients/types.ts +27 -0
- package/packages/shopify-app-remix/src/server/config-types.ts +293 -0
- package/packages/shopify-app-remix/src/server/errors.ts +3 -0
- package/packages/shopify-app-remix/src/server/future/flags.ts +57 -0
- package/packages/shopify-app-remix/src/server/index.ts +20 -0
- package/packages/shopify-app-remix/src/server/override-logger.ts +42 -0
- package/packages/shopify-app-remix/src/server/shopify-app.doc.ts +45 -0
- package/packages/shopify-app-remix/src/server/shopify-app.ts +198 -0
- package/packages/shopify-app-remix/src/server/types.ts +509 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/admin/__tests__/factory.test.ts +30 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/admin/factory.ts +29 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/admin/index.ts +1 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/admin/types.ts +117 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/admin/unauthenticated.admin.doc.ts +40 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/helpers/get-offline-session.ts +13 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/helpers/index.ts +1 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/storefront/__tests__/factory.test.ts +30 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/storefront/factory.ts +28 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/storefront/index.ts +1 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/storefront/types.ts +39 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/storefront/unauthenticated.storefront.doc.ts +40 -0
- package/packages/shopify-app-remix/src/server/unauthenticated/types.ts +68 -0
- package/packages/shopify-app-remix/src/server/version.ts +1 -0
- package/packages/shopify-app-remix/tsconfig.json +11 -0
- package/packages/shopify-app-session-storage/CHANGELOG.md +149 -0
- package/packages/shopify-app-session-storage/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage/README.md +5 -0
- package/packages/shopify-app-session-storage/implementing-session-storage.md +214 -0
- package/packages/shopify-app-session-storage/loom.config.ts +45 -0
- package/packages/shopify-app-session-storage/package.json +44 -0
- package/packages/shopify-app-session-storage/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage/src/abstract-migration-engine.ts +53 -0
- package/packages/shopify-app-session-storage/src/index.ts +3 -0
- package/packages/shopify-app-session-storage/src/rdbms-session-storage-migrator.ts +59 -0
- package/packages/shopify-app-session-storage/src/types.ts +174 -0
- package/packages/shopify-app-session-storage/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-dynamodb/CHANGELOG.md +150 -0
- package/packages/shopify-app-session-storage-dynamodb/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-dynamodb/README.md +75 -0
- package/packages/shopify-app-session-storage-dynamodb/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-dynamodb/package.json +51 -0
- package/packages/shopify-app-session-storage-dynamodb/src/__tests__/dynamodb.test.ts +93 -0
- package/packages/shopify-app-session-storage-dynamodb/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-dynamodb/src/dynamodb.ts +126 -0
- package/packages/shopify-app-session-storage-dynamodb/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-kv/CHANGELOG.md +204 -0
- package/packages/shopify-app-session-storage-kv/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-kv/README.md +41 -0
- package/packages/shopify-app-session-storage-kv/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-kv/package.json +52 -0
- package/packages/shopify-app-session-storage-kv/src/__tests__/kv-namespace-dummy-worker.ts +8 -0
- package/packages/shopify-app-session-storage-kv/src/__tests__/kv.test.ts +22 -0
- package/packages/shopify-app-session-storage-kv/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-kv/src/kv.ts +87 -0
- package/packages/shopify-app-session-storage-kv/tsconfig.json +11 -0
- package/packages/shopify-app-session-storage-memory/CHANGELOG.md +190 -0
- package/packages/shopify-app-session-storage-memory/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-memory/README.md +19 -0
- package/packages/shopify-app-session-storage-memory/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-memory/package.json +46 -0
- package/packages/shopify-app-session-storage-memory/src/__tests__/memory.test.ts +12 -0
- package/packages/shopify-app-session-storage-memory/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-memory/src/memory.ts +34 -0
- package/packages/shopify-app-session-storage-memory/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-mongodb/CHANGELOG.md +208 -0
- package/packages/shopify-app-session-storage-mongodb/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-mongodb/README.md +30 -0
- package/packages/shopify-app-session-storage-mongodb/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-mongodb/package.json +49 -0
- package/packages/shopify-app-session-storage-mongodb/src/__tests__/mongodb.test.ts +54 -0
- package/packages/shopify-app-session-storage-mongodb/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-mongodb/src/mongodb.ts +120 -0
- package/packages/shopify-app-session-storage-mongodb/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-mysql/CHANGELOG.md +220 -0
- package/packages/shopify-app-session-storage-mysql/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-mysql/README.md +41 -0
- package/packages/shopify-app-session-storage-mysql/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-mysql/package.json +50 -0
- package/packages/shopify-app-session-storage-mysql/src/__tests__/mysql.test.ts +137 -0
- package/packages/shopify-app-session-storage-mysql/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-mysql/src/migrations.ts +18 -0
- package/packages/shopify-app-session-storage-mysql/src/mysql-connection.ts +108 -0
- package/packages/shopify-app-session-storage-mysql/src/mysql-migrator.ts +53 -0
- package/packages/shopify-app-session-storage-mysql/src/mysql.ts +178 -0
- package/packages/shopify-app-session-storage-mysql/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-postgresql/CHANGELOG.md +210 -0
- package/packages/shopify-app-session-storage-postgresql/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-postgresql/README.md +39 -0
- package/packages/shopify-app-session-storage-postgresql/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-postgresql/package.json +52 -0
- package/packages/shopify-app-session-storage-postgresql/src/__tests__/migrate-to-case-sensitivity.test.ts +344 -0
- package/packages/shopify-app-session-storage-postgresql/src/__tests__/postgresql.test.ts +136 -0
- package/packages/shopify-app-session-storage-postgresql/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-postgresql/src/migrations.ts +70 -0
- package/packages/shopify-app-session-storage-postgresql/src/postgres-connection.ts +94 -0
- package/packages/shopify-app-session-storage-postgresql/src/postgres-migrator.ts +27 -0
- package/packages/shopify-app-session-storage-postgresql/src/postgresql.ts +178 -0
- package/packages/shopify-app-session-storage-postgresql/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-prisma/CHANGELOG.md +148 -0
- package/packages/shopify-app-session-storage-prisma/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-prisma/README.md +68 -0
- package/packages/shopify-app-session-storage-prisma/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-prisma/package.json +51 -0
- package/packages/shopify-app-session-storage-prisma/prisma/migrations/20230425184828_init/migration.sql +11 -0
- package/packages/shopify-app-session-storage-prisma/prisma/migrations/20230906155758_mySession/migration.sql +11 -0
- package/packages/shopify-app-session-storage-prisma/prisma/migrations/migration_lock.toml +3 -0
- package/packages/shopify-app-session-storage-prisma/prisma/schema.prisma +30 -0
- package/packages/shopify-app-session-storage-prisma/src/__tests__/prisma.test.ts +66 -0
- package/packages/shopify-app-session-storage-prisma/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-prisma/src/prisma.ts +145 -0
- package/packages/shopify-app-session-storage-prisma/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-redis/CHANGELOG.md +200 -0
- package/packages/shopify-app-session-storage-redis/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-redis/README.md +38 -0
- package/packages/shopify-app-session-storage-redis/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-redis/package.json +50 -0
- package/packages/shopify-app-session-storage-redis/src/__tests__/migration-test-data.ts +46 -0
- package/packages/shopify-app-session-storage-redis/src/__tests__/redis.conf +2 -0
- package/packages/shopify-app-session-storage-redis/src/__tests__/redis.test.ts +236 -0
- package/packages/shopify-app-session-storage-redis/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-redis/src/migrations.ts +36 -0
- package/packages/shopify-app-session-storage-redis/src/redis-connection.ts +64 -0
- package/packages/shopify-app-session-storage-redis/src/redis-migrator.ts +58 -0
- package/packages/shopify-app-session-storage-redis/src/redis.ts +167 -0
- package/packages/shopify-app-session-storage-redis/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-sqlite/CHANGELOG.md +202 -0
- package/packages/shopify-app-session-storage-sqlite/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-sqlite/README.md +25 -0
- package/packages/shopify-app-session-storage-sqlite/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-sqlite/package.json +51 -0
- package/packages/shopify-app-session-storage-sqlite/src/__tests__/setup-jest.ts +8 -0
- package/packages/shopify-app-session-storage-sqlite/src/__tests__/sqlite.test.ts +44 -0
- package/packages/shopify-app-session-storage-sqlite/src/migrations.ts +54 -0
- package/packages/shopify-app-session-storage-sqlite/src/sqlite-connection.ts +80 -0
- package/packages/shopify-app-session-storage-sqlite/src/sqlite-migrator.ts +34 -0
- package/packages/shopify-app-session-storage-sqlite/src/sqlite.ts +147 -0
- package/packages/shopify-app-session-storage-sqlite/tsconfig.json +10 -0
- package/packages/shopify-app-session-storage-test-utils/CHANGELOG.md +185 -0
- package/packages/shopify-app-session-storage-test-utils/LICENSE.md +9 -0
- package/packages/shopify-app-session-storage-test-utils/loom.config.ts +27 -0
- package/packages/shopify-app-session-storage-test-utils/package.json +48 -0
- package/packages/shopify-app-session-storage-test-utils/src/__tests__/session-test-utils.test.ts +273 -0
- package/packages/shopify-app-session-storage-test-utils/src/battery-of-tests.ts +250 -0
- package/packages/shopify-app-session-storage-test-utils/src/index.ts +2 -0
- package/packages/shopify-app-session-storage-test-utils/src/session-test-utils.ts +24 -0
- package/packages/shopify-app-session-storage-test-utils/src/utils.ts +71 -0
- package/packages/shopify-app-session-storage-test-utils/tsconfig.json +10 -0
- package/tests/setup/build.js +1 -0
- package/tests/setup/setup-jest.ts +8 -0
- package/tsconfig.base.json +41 -0
- 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,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
|
+
}
|