@shopify/shopify-app-remix 4.1.1 → 4.2.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.
- package/dist/cjs/react/components/AppProvider/AppProvider.js.map +1 -1
- package/dist/cjs/react/components/AppProxyForm/AppProxyForm.js +4 -3
- package/dist/cjs/react/components/AppProxyForm/AppProxyForm.js.map +1 -1
- package/dist/cjs/react/components/AppProxyLink/AppProxyLink.js +4 -3
- package/dist/cjs/react/components/AppProxyLink/AppProxyLink.js.map +1 -1
- package/dist/cjs/react/components/AppProxyProvider/AppProxyProvider.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/helpers/redirect.js +2 -2
- package/dist/cjs/server/authenticate/admin/helpers/redirect.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/strategies/auth-code-flow.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/strategies/merchant-custom-app.js.map +1 -1
- package/dist/cjs/server/authenticate/admin/strategies/token-exchange.js.map +1 -1
- package/dist/cjs/server/authenticate/webhooks/authenticate.js +34 -10
- package/dist/cjs/server/authenticate/webhooks/authenticate.js.map +1 -1
- package/dist/cjs/server/future/flags.js.map +1 -1
- package/dist/cjs/server/shopify-app.js +1 -0
- package/dist/cjs/server/shopify-app.js.map +1 -1
- package/dist/cjs/server/version.js +1 -1
- package/dist/cjs/server/version.js.map +1 -1
- package/dist/esm/react/components/AppProvider/AppProvider.mjs.map +1 -1
- package/dist/esm/react/components/AppProxyForm/AppProxyForm.mjs +5 -4
- package/dist/esm/react/components/AppProxyForm/AppProxyForm.mjs.map +1 -1
- package/dist/esm/react/components/AppProxyLink/AppProxyLink.mjs +5 -4
- package/dist/esm/react/components/AppProxyLink/AppProxyLink.mjs.map +1 -1
- package/dist/esm/react/components/AppProxyProvider/AppProxyProvider.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/helpers/redirect.mjs +2 -2
- package/dist/esm/server/authenticate/admin/helpers/redirect.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/strategies/auth-code-flow.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/strategies/merchant-custom-app.mjs.map +1 -1
- package/dist/esm/server/authenticate/admin/strategies/token-exchange.mjs.map +1 -1
- package/dist/esm/server/authenticate/webhooks/authenticate.mjs +35 -11
- package/dist/esm/server/authenticate/webhooks/authenticate.mjs.map +1 -1
- package/dist/esm/server/future/flags.mjs.map +1 -1
- package/dist/esm/server/shopify-app.mjs +1 -0
- package/dist/esm/server/shopify-app.mjs.map +1 -1
- package/dist/esm/server/version.mjs +1 -1
- package/dist/esm/server/version.mjs.map +1 -1
- package/dist/ts/react/components/AppProvider/AppProvider.d.ts +5 -1
- package/dist/ts/react/components/AppProvider/AppProvider.d.ts.map +1 -1
- package/dist/ts/react/components/AppProxyForm/AppProxyForm.d.ts +2 -1
- package/dist/ts/react/components/AppProxyForm/AppProxyForm.d.ts.map +1 -1
- package/dist/ts/react/components/AppProxyLink/AppProxyLink.d.ts +2 -1
- package/dist/ts/react/components/AppProxyLink/AppProxyLink.d.ts.map +1 -1
- package/dist/ts/react/components/AppProxyProvider/AppProxyProvider.d.ts +5 -1
- package/dist/ts/react/components/AppProxyProvider/AppProxyProvider.d.ts.map +1 -1
- package/dist/ts/server/authenticate/admin/billing/types.d.ts +4 -0
- package/dist/ts/server/authenticate/admin/billing/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/admin/scope/types.d.ts +2 -1
- package/dist/ts/server/authenticate/admin/scope/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts.map +1 -1
- package/dist/ts/server/authenticate/admin/strategies/merchant-custom-app.d.ts.map +1 -1
- package/dist/ts/server/authenticate/admin/strategies/token-exchange.d.ts.map +1 -1
- package/dist/ts/server/authenticate/admin/types.d.ts +10 -0
- package/dist/ts/server/authenticate/admin/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/flow/types.d.ts +4 -0
- package/dist/ts/server/authenticate/flow/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/fulfillment-service/types.d.ts +4 -0
- package/dist/ts/server/authenticate/fulfillment-service/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/public/appProxy/types.d.ts +4 -0
- package/dist/ts/server/authenticate/public/appProxy/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/public/checkout/types.d.ts +4 -0
- package/dist/ts/server/authenticate/public/checkout/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/public/customer-account/types.d.ts +4 -0
- package/dist/ts/server/authenticate/public/customer-account/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/public/extension/types.d.ts.map +1 -1
- package/dist/ts/server/authenticate/webhooks/authenticate.d.ts.map +1 -1
- package/dist/ts/server/authenticate/webhooks/types.d.ts +36 -3
- package/dist/ts/server/authenticate/webhooks/types.d.ts.map +1 -1
- package/dist/ts/server/boundary/error.d.ts +1 -1
- package/dist/ts/server/boundary/error.d.ts.map +1 -1
- package/dist/ts/server/clients/admin/types.d.ts +4 -0
- package/dist/ts/server/clients/admin/types.d.ts.map +1 -1
- package/dist/ts/server/clients/storefront/types.d.ts +4 -0
- package/dist/ts/server/clients/storefront/types.d.ts.map +1 -1
- package/dist/ts/server/config-types.d.ts.map +1 -1
- package/dist/ts/server/future/flags.d.ts +6 -0
- package/dist/ts/server/future/flags.d.ts.map +1 -1
- package/dist/ts/server/shopify-app.d.ts +1 -0
- package/dist/ts/server/shopify-app.d.ts.map +1 -1
- package/dist/ts/server/unauthenticated/admin/types.d.ts +4 -0
- package/dist/ts/server/unauthenticated/admin/types.d.ts.map +1 -1
- package/dist/ts/server/unauthenticated/storefront/types.d.ts +4 -0
- package/dist/ts/server/unauthenticated/storefront/types.d.ts.map +1 -1
- package/dist/ts/server/version.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +19 -15
- package/src/react/components/AppProvider/AppProvider.tsx +151 -0
- package/src/react/components/AppProvider/index.ts +1 -0
- package/src/react/components/AppProxyForm/AppProxyForm.tsx +85 -0
- package/src/react/components/AppProxyForm/index.ts +1 -0
- package/src/react/components/AppProxyLink/AppProxyLink.tsx +61 -0
- package/src/react/components/AppProxyLink/index.ts +1 -0
- package/src/react/components/AppProxyProvider/AppProxyProvider.tsx +104 -0
- package/src/react/components/AppProxyProvider/index.ts +5 -0
- package/src/react/components/RemixPolarisLink.tsx +14 -0
- package/src/react/components/index.ts +4 -0
- package/src/react/const.ts +2 -0
- package/src/react/index.ts +1 -0
- package/src/server/__test-helpers/const.ts +14 -0
- package/src/server/__test-helpers/expect-admin-api-client.ts +51 -0
- package/src/server/__test-helpers/expect-begin-auth-redirect.ts +22 -0
- package/src/server/__test-helpers/expect-document-request-headers.ts +25 -0
- package/src/server/__test-helpers/expect-exit-iframe.ts +37 -0
- package/src/server/__test-helpers/expect-login-redirect.ts +8 -0
- package/src/server/__test-helpers/expect-storefront-api-client.ts +49 -0
- package/src/server/__test-helpers/expect-token-refresh.ts +188 -0
- package/src/server/__test-helpers/get-hmac.ts +7 -0
- package/src/server/__test-helpers/get-jwt.ts +10 -0
- package/src/server/__test-helpers/get-thrown-error.ts +19 -0
- package/src/server/__test-helpers/get-thrown-response.ts +17 -0
- package/src/server/__test-helpers/index.ts +21 -0
- package/src/server/__test-helpers/mock-graphql-request.ts +60 -0
- package/src/server/__test-helpers/request-mock.ts +169 -0
- package/src/server/__test-helpers/setup-embedded-flow.ts +30 -0
- package/src/server/__test-helpers/setup-fetch-flow.ts +29 -0
- package/src/server/__test-helpers/setup-non-embedded-flow.ts +31 -0
- package/src/server/__test-helpers/setup-valid-request.ts +78 -0
- package/src/server/__test-helpers/setup-valid-session.ts +28 -0
- package/src/server/__test-helpers/sign-request-cookie.ts +32 -0
- package/src/server/__test-helpers/test-config.ts +56 -0
- package/src/server/adapters/node/index.ts +13 -0
- package/src/server/adapters/vercel/index.ts +13 -0
- package/src/server/authenticate/admin/authenticate.admin.doc.example.ts +34 -0
- package/src/server/authenticate/admin/authenticate.ts +232 -0
- package/src/server/authenticate/admin/billing/cancel.ts +38 -0
- package/src/server/authenticate/admin/billing/check.ts +41 -0
- package/src/server/authenticate/admin/billing/create-usage-record.ts +36 -0
- package/src/server/authenticate/admin/billing/helpers.ts +42 -0
- package/src/server/authenticate/admin/billing/index.ts +6 -0
- package/src/server/authenticate/admin/billing/request.ts +64 -0
- package/src/server/authenticate/admin/billing/require.ts +58 -0
- package/src/server/authenticate/admin/billing/types.ts +617 -0
- package/src/server/authenticate/admin/billing/update-usage-subscription-capped-amount.ts +55 -0
- package/src/server/authenticate/admin/helpers/begin-auth.ts +17 -0
- package/src/server/authenticate/admin/helpers/create-admin-api-context.ts +20 -0
- package/src/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.ts +18 -0
- package/src/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.ts +25 -0
- package/src/server/authenticate/admin/helpers/handle-client-error.ts +45 -0
- package/src/server/authenticate/admin/helpers/index.ts +14 -0
- package/src/server/authenticate/admin/helpers/redirect-to-auth-page.ts +28 -0
- package/src/server/authenticate/admin/helpers/redirect-to-bounce-page.ts +23 -0
- package/src/server/authenticate/admin/helpers/redirect-to-install-page.ts +53 -0
- package/src/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.ts +21 -0
- package/src/server/authenticate/admin/helpers/redirect-with-app-bridge-headers.ts +13 -0
- package/src/server/authenticate/admin/helpers/redirect-with-exitiframe.ts +28 -0
- package/src/server/authenticate/admin/helpers/redirect.ts +164 -0
- package/src/server/authenticate/admin/helpers/render-app-bridge.ts +46 -0
- package/src/server/authenticate/admin/helpers/trigger-after-auth-hook.ts +29 -0
- package/src/server/authenticate/admin/helpers/validate-redirect-url.ts +67 -0
- package/src/server/authenticate/admin/helpers/validate-shop-and-host-params.ts +46 -0
- package/src/server/authenticate/admin/scope/client/fetch-scopes-details.ts +43 -0
- package/src/server/authenticate/admin/scope/client/revoke-scopes.ts +38 -0
- package/src/server/authenticate/admin/scope/factory.ts +21 -0
- package/src/server/authenticate/admin/scope/query.ts +51 -0
- package/src/server/authenticate/admin/scope/request.ts +32 -0
- package/src/server/authenticate/admin/scope/revoke.ts +48 -0
- package/src/server/authenticate/admin/scope/types.ts +127 -0
- package/src/server/authenticate/admin/strategies/auth-code-flow.ts +332 -0
- package/src/server/authenticate/admin/strategies/merchant-custom-app.ts +65 -0
- package/src/server/authenticate/admin/strategies/token-exchange.ts +188 -0
- package/src/server/authenticate/admin/strategies/types.ts +29 -0
- package/src/server/authenticate/admin/types.ts +226 -0
- package/src/server/authenticate/const.ts +15 -0
- package/src/server/authenticate/flow/authenticate.flow.doc.example.ts +39 -0
- package/src/server/authenticate/flow/authenticate.ts +68 -0
- package/src/server/authenticate/flow/types.ts +89 -0
- package/src/server/authenticate/fulfillment-service/authenticate.fulfillment-service.doc.example.ts +52 -0
- package/src/server/authenticate/fulfillment-service/authenticate.ts +82 -0
- package/src/server/authenticate/fulfillment-service/types.ts +86 -0
- package/src/server/authenticate/helpers/add-response-headers.ts +43 -0
- package/src/server/authenticate/helpers/app-bridge-url.ts +10 -0
- package/src/server/authenticate/helpers/ensure-cors-headers.ts +38 -0
- package/src/server/authenticate/helpers/get-session-token-header.ts +11 -0
- package/src/server/authenticate/helpers/get-shop-from-request.ts +4 -0
- package/src/server/authenticate/helpers/idempotent-promise-handler.ts +45 -0
- package/src/server/authenticate/helpers/index.ts +10 -0
- package/src/server/authenticate/helpers/invalidate-access-token.ts +17 -0
- package/src/server/authenticate/helpers/reject-bot-request.ts +27 -0
- package/src/server/authenticate/helpers/respond-to-invalid-session-token.ts +28 -0
- package/src/server/authenticate/helpers/respond-to-options-request.ts +26 -0
- package/src/server/authenticate/helpers/validate-session-token.ts +40 -0
- package/src/server/authenticate/login/login.ts +53 -0
- package/src/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.example.ts +27 -0
- package/src/server/authenticate/public/appProxy/authenticate.ts +150 -0
- package/src/server/authenticate/public/appProxy/types.ts +219 -0
- package/src/server/authenticate/public/checkout/authenticate.public.checkout.doc.example.offers.ts +21 -0
- package/src/server/authenticate/public/checkout/authenticate.public.checkout.doc.example.ts +17 -0
- package/src/server/authenticate/public/checkout/authenticate.ts +13 -0
- package/src/server/authenticate/public/checkout/types.ts +69 -0
- package/src/server/authenticate/public/customer-account/authenticate.public.customerAccount.doc.example.offers.ts +36 -0
- package/src/server/authenticate/public/customer-account/authenticate.public.customerAccount.doc.example.ts +18 -0
- package/src/server/authenticate/public/customer-account/authenticate.ts +13 -0
- package/src/server/authenticate/public/customer-account/types.ts +69 -0
- package/src/server/authenticate/public/extension/authenticate.ts +54 -0
- package/src/server/authenticate/public/extension/types.ts +11 -0
- package/src/server/authenticate/public/factory.ts +24 -0
- package/src/server/authenticate/public/index.ts +1 -0
- package/src/server/authenticate/public/pos/authenticate.ts +8 -0
- package/src/server/authenticate/public/pos/types.ts +65 -0
- package/src/server/authenticate/public/types.ts +96 -0
- package/src/server/authenticate/webhooks/authenticate.ts +105 -0
- package/src/server/authenticate/webhooks/authenticate.webhooks.doc.example.ts +43 -0
- package/src/server/authenticate/webhooks/index.ts +1 -0
- package/src/server/authenticate/webhooks/register.ts +48 -0
- package/src/server/authenticate/webhooks/types.ts +267 -0
- package/src/server/boundary/error.tsx +14 -0
- package/src/server/boundary/headers.ts +15 -0
- package/src/server/boundary/index.ts +39 -0
- package/src/server/boundary/types.ts +4 -0
- package/src/server/clients/admin/factory.ts +22 -0
- package/src/server/clients/admin/graphql.ts +39 -0
- package/src/server/clients/admin/index.ts +2 -0
- package/src/server/clients/admin/types.ts +124 -0
- package/src/server/clients/index.ts +2 -0
- package/src/server/clients/storefront/factory.ts +32 -0
- package/src/server/clients/storefront/index.ts +2 -0
- package/src/server/clients/storefront/types.ts +82 -0
- package/src/server/clients/types.ts +47 -0
- package/src/server/config-types.ts +309 -0
- package/src/server/errors.ts +3 -0
- package/src/server/future/flags.ts +68 -0
- package/src/server/helpers/create-or-load-offline-session.ts +19 -0
- package/src/server/helpers/ensure-offline-token-is-not-expired.ts +32 -0
- package/src/server/helpers/ensure-valid-offline-session.ts +15 -0
- package/src/server/helpers/index.ts +4 -0
- package/src/server/helpers/refresh-token.ts +35 -0
- package/src/server/index.ts +24 -0
- package/src/server/override-logger.ts +42 -0
- package/src/server/shopify-app.ts +216 -0
- package/src/server/test-helpers/index.ts +1 -0
- package/src/server/test-helpers/test-config.ts +79 -0
- package/src/server/types-contexts.ts +44 -0
- package/src/server/types.ts +507 -0
- package/src/server/unauthenticated/admin/factory.ts +23 -0
- package/src/server/unauthenticated/admin/index.ts +1 -0
- package/src/server/unauthenticated/admin/types.ts +83 -0
- package/src/server/unauthenticated/storefront/factory.ts +28 -0
- package/src/server/unauthenticated/storefront/index.ts +1 -0
- package/src/server/unauthenticated/storefront/types.ts +109 -0
- package/src/server/unauthenticated/types.ts +65 -0
- package/src/server/version.ts +1 -0
- package/dist/ts/react/components/AppProvider/AppProvider.doc.d.ts +0 -4
- package/dist/ts/react/components/AppProvider/AppProvider.doc.d.ts.map +0 -1
- package/dist/ts/react/components/AppProxyForm/AppProxyForm.doc.d.ts +0 -4
- package/dist/ts/react/components/AppProxyForm/AppProxyForm.doc.d.ts.map +0 -1
- package/dist/ts/react/components/AppProxyLink/AppProxyLink.doc.d.ts +0 -4
- package/dist/ts/react/components/AppProxyLink/AppProxyLink.doc.d.ts.map +0 -1
- package/dist/ts/react/components/AppProxyProvider/AppProxyProvider.doc.d.ts +0 -4
- package/dist/ts/react/components/AppProxyProvider/AppProxyProvider.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/admin/authenticate.admin.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/admin/authenticate.admin.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/admin/billing/authenticate.admin.billing.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/admin/billing/authenticate.admin.billing.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/admin/scope/authenticate.admin.scopes.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/admin/scope/authenticate.admin.scopes.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/flow/authenticate.flow.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/flow/authenticate.flow.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/fulfillment-service/authenticate.fulfillment-service.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/fulfillment-service/authenticate.fulfillment-service.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/public/checkout/authenticate.public.checkout.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/public/checkout/authenticate.public.checkout.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/public/customer-account/authenticate.public.customerAccount.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/public/customer-account/authenticate.public.customerAccount.doc.d.ts.map +0 -1
- package/dist/ts/server/authenticate/webhooks/authenticate.webhooks.doc.d.ts +0 -4
- package/dist/ts/server/authenticate/webhooks/authenticate.webhooks.doc.d.ts.map +0 -1
- package/dist/ts/server/clients/admin/authenticate.admin.api.doc.d.ts +0 -4
- package/dist/ts/server/clients/admin/authenticate.admin.api.doc.d.ts.map +0 -1
- package/dist/ts/server/clients/storefront/authenticate.storefront.api.doc.d.ts +0 -4
- package/dist/ts/server/clients/storefront/authenticate.storefront.api.doc.d.ts.map +0 -1
- package/dist/ts/server/shopify-app.doc.d.ts +0 -4
- package/dist/ts/server/shopify-app.doc.d.ts.map +0 -1
- package/dist/ts/server/unauthenticated/admin/unauthenticated.admin.doc.d.ts +0 -4
- package/dist/ts/server/unauthenticated/admin/unauthenticated.admin.doc.d.ts.map +0 -1
- package/dist/ts/server/unauthenticated/storefront/unauthenticated.storefront.doc.d.ts +0 -4
- package/dist/ts/server/unauthenticated/storefront/unauthenticated.storefront.doc.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppProvider.js","sources":["../../../../../../src/react/components/AppProvider/AppProvider.tsx"],"sourcesContent":["import {\n AppProvider as PolarisAppProvider,\n AppProviderProps as PolarisAppProviderProps,\n} from '@shopify/polaris';\n// This leads to some TS errors, but it does compile to something that works\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport englishI18n from '@shopify/polaris/locales/en.json' with {type: 'json'};\nimport {useNavigate} from '@remix-run/react';\nimport {useEffect} from 'react';\n\nimport {APP_BRIDGE_URL} from '../../const';\nimport {RemixPolarisLink} from '../RemixPolarisLink';\n\nexport interface AppProviderProps
|
|
1
|
+
{"version":3,"file":"AppProvider.js","sources":["../../../../../../src/react/components/AppProvider/AppProvider.tsx"],"sourcesContent":["import {\n AppProvider as PolarisAppProvider,\n AppProviderProps as PolarisAppProviderProps,\n} from '@shopify/polaris';\n// This leads to some TS errors, but it does compile to something that works\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport englishI18n from '@shopify/polaris/locales/en.json' with {type: 'json'};\nimport {useNavigate} from '@remix-run/react';\nimport {useEffect} from 'react';\n\nimport {APP_BRIDGE_URL} from '../../const';\nimport {RemixPolarisLink} from '../RemixPolarisLink';\n\n/**\n * Props for the `AppProvider` component.\n * @publicDocs\n */\nexport interface AppProviderProps extends Omit<\n PolarisAppProviderProps,\n 'linkComponent' | 'i18n'\n> {\n /**\n * The API key for your Shopify app. This is the `Client ID` from the Partner Dashboard.\n *\n * When using the Shopify CLI, this is the `SHOPIFY_API_KEY` environment variable. If you're using the environment\n * variable, then you need to pass it from the loader to the component.\n */\n apiKey: string;\n /**\n * Whether the app is loaded inside the Shopify Admin. Default is `true`.\n *\n * {@link https://shopify.dev/docs/apps/admin/embedded-app-home}\n */\n isEmbeddedApp?: boolean;\n /**\n * The internationalization (i18n) configuration for your Polaris provider.\n *\n * {@link https://polaris.shopify.com/components/utilities/app-provider}\n */\n i18n?: PolarisAppProviderProps['i18n'];\n /**\n * Used internally by Shopify. You don't need to set this.\n * @private\n */\n __APP_BRIDGE_URL?: string;\n}\n\n/**\n * Sets up the Polaris `AppProvider` and injects the App Bridge script.\n *\n * This component extends the [`AppProvider`](https://polaris.shopify.com/components/utilities/app-provider) component\n * from Polaris, and accepts all of its props except for `linkComponent`, which is overridden to use the Remix `Link`\n * component.\n *\n * {@link https://polaris.shopify.com/components/utilities/app-provider}\n * {@link https://shopify.dev/tools/app-bridge}\n *\n * @example\n * <caption>Set up AppProvider.</caption>\n * <description>Wrap your app in the `AppProvider` component and pass in your API key.</description>\n * ```ts\n * // /app/routes/**\\/*.ts\n * import {authenticate} from '~/shopify.server';\n * import {AppProvider} from '@shopify/shopify-app-remix/react';\n *\n * export async function loader({ request }) {\n * await authenticate.admin(request);\n *\n * return json({ apiKey: process.env.SHOPIFY_API_KEY });\n * }\n *\n * export default function App() {\n * const { apiKey } = useLoaderData();\n *\n * return (\n * <AppProvider isEmbeddedApp apiKey={apiKey}>\n * <Outlet />\n * </AppProvider>\n * );\n * }\n * ```\n *\n * @example\n * <caption>Localize Polaris components.</caption>\n * <description>Pass in a different locale for Polaris to translate its components.</description>\n * ```ts\n * // /app/routes/**\\/*.ts\n * import {authenticate} from '~/shopify.server';\n * import {AppProvider} from '@shopify/shopify-app-remix/react';\n *\n * export async function loader({ request }) {\n * await authenticate.admin(request);\n *\n * return json({\n * apiKey: process.env.SHOPIFY_API_KEY,\n * polarisTranslations: require(\"@shopify/polaris/locales/fr.json\"),\n * });\n * }\n *\n * export default function App() {\n * const { apiKey, polarisTranslations } = useLoaderData();\n *\n * return (\n * <AppProvider apiKey={apiKey} i18n={polarisTranslations}>\n * <Outlet />\n * </AppProvider>\n * );\n * }\n * ```\n */\nexport function AppProvider(props: AppProviderProps) {\n const {\n children,\n apiKey,\n i18n,\n isEmbeddedApp = true,\n __APP_BRIDGE_URL = APP_BRIDGE_URL,\n ...polarisProps\n } = props;\n\n const navigate = useNavigate();\n\n useEffect(() => {\n const handleNavigate = (event: Event) => {\n const href = (event.target as HTMLElement)?.getAttribute('href');\n if (href) {\n navigate(href);\n }\n };\n\n addEventListener('shopify:navigate', handleNavigate);\n\n return () => {\n removeEventListener('shopify:navigate', handleNavigate);\n };\n }, [navigate]);\n\n return (\n <>\n {isEmbeddedApp && <script src={__APP_BRIDGE_URL} data-api-key={apiKey} />}\n <PolarisAppProvider\n {...polarisProps}\n linkComponent={RemixPolarisLink}\n i18n={i18n || englishI18n}\n >\n {children}\n </PolarisAppProvider>\n </>\n );\n}\n"],"names":["APP_BRIDGE_URL","useNavigate","useEffect","_jsxs","_Fragment","_jsx","PolarisAppProvider","RemixPolarisLink"],"mappings":";;;;;;;;;;AAgDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DG;AACG,SAAU,WAAW,CAAC,KAAuB,EAAA;IACjD,MAAM,EACJ,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,aAAa,GAAG,IAAI,EACpB,gBAAgB,GAAGA,qBAAc,EACjC,GAAG,YAAY,EAChB,GAAG,KAAK;AAET,IAAA,MAAM,QAAQ,GAAGC,iBAAW,EAAE;IAE9BC,eAAS,CAAC,MAAK;AACb,QAAA,MAAM,cAAc,GAAG,CAAC,KAAY,KAAI;YACtC,MAAM,IAAI,GAAI,KAAK,CAAC,MAAsB,EAAE,YAAY,CAAC,MAAM,CAAC;YAChE,IAAI,IAAI,EAAE;gBACR,QAAQ,CAAC,IAAI,CAAC;YAChB;AACF,QAAA,CAAC;AAED,QAAA,gBAAgB,CAAC,kBAAkB,EAAE,cAAc,CAAC;AAEpD,QAAA,OAAO,MAAK;AACV,YAAA,mBAAmB,CAAC,kBAAkB,EAAE,cAAc,CAAC;AACzD,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;AAEd,IAAA,QACEC,eAAA,CAAAC,mBAAA,EAAA,EAAA,QAAA,EAAA,CACG,aAAa,IAAIC,cAAA,CAAA,QAAA,EAAA,EAAQ,GAAG,EAAE,gBAAgB,EAAA,cAAA,EAAgB,MAAM,EAAA,CAAI,EACzEA,eAACC,mBAAkB,EAAA,EAAA,GACb,YAAY,EAChB,aAAa,EAAEC,iCAAgB,EAC/B,IAAI,EAAE,IAAI,IAAI,WAAW,EAAA,QAAA,EAExB,QAAQ,EAAA,CACU,CAAA,EAAA,CACpB;AAEP;;;;"}
|
|
@@ -60,15 +60,16 @@ var AppProxyProvider = require('../AppProxyProvider/AppProxyProvider.js');
|
|
|
60
60
|
* );
|
|
61
61
|
* }
|
|
62
62
|
* ```
|
|
63
|
+
* @publicDocs
|
|
63
64
|
*/
|
|
64
|
-
function AppProxyForm(props) {
|
|
65
|
+
const AppProxyForm = React.forwardRef(function AppProxyForm(props, ref) {
|
|
65
66
|
const context = React.useContext(AppProxyProvider.AppProxyProviderContext);
|
|
66
67
|
if (!context) {
|
|
67
68
|
throw new Error('AppProxyForm must be used within an AppProxyProvider component');
|
|
68
69
|
}
|
|
69
70
|
const { children, action, ...otherProps } = props;
|
|
70
|
-
return (jsxRuntime.jsx(react.Form, { action: context.formatUrl(action, false), ...otherProps, children: children }));
|
|
71
|
-
}
|
|
71
|
+
return (jsxRuntime.jsx(react.Form, { action: context.formatUrl(action, false), ...otherProps, ref: ref, children: children }));
|
|
72
|
+
});
|
|
72
73
|
|
|
73
74
|
exports.AppProxyForm = AppProxyForm;
|
|
74
75
|
//# sourceMappingURL=AppProxyForm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppProxyForm.js","sources":["../../../../../../src/react/components/AppProxyForm/AppProxyForm.tsx"],"sourcesContent":["import {useContext} from 'react';\nimport {Form, type FormProps} from '@remix-run/react';\n\nimport {AppProxyProviderContext} from '../AppProxyProvider';\n\nexport interface AppProxyFormProps extends FormProps {\n action: string;\n}\n\n/**\n * Sets up a Remix `<Form>` component that works when rendered on an app proxy page.\n *\n * Supports any properties accepted by the `<Form>` component.\n *\n * Because Remix doesn't support URL rewriting, any route using this component should <b>match the pathname of the proxy\n * URL exactly</b>, and <b>end in a trailing slash</b> (e.g., `https://<shop>/apps/proxy/`), or set the Remix Form prop\n * `navigate` to `false`.\n *\n * @example\n * <caption>Render a form element in a proxied route.</caption>\n * <description>Use an `AppProxyForm` within an `AppProxy` to create a form.</description>\n * ```ts\n * // /app/routes/apps/appProxy.ts\n * import {\n * AppProxyProvider,\n * AppProxyForm,\n * } from \"@shopify/shopify-app-remix/react\";\n * import { authenticate } from \"~/shopify.server\";\n *\n * export async function loader({ request }) {\n * await authenticate.public.appProxy(request);\n *\n * return json({ appUrl: process.env.SHOPIFY_APP_URL });\n * }\n *\n * export async function action({ request }) {\n * await authenticate.public.appProxy(request);\n *\n * const formData = await request.formData();\n * const field = formData.get(\"field\")?.toString();\n *\n * // Perform actions\n * if (field) {\n * console.log(\"Field:\", field);\n * }\n *\n * // Return JSON to the client\n * return json({ message: \"Success!\" });\n * }\n *\n * export default function App() {\n * const { appUrl } = useLoaderData();\n *\n * return (\n * <AppProxyProvider appUrl={appUrl}>\n * <AppProxyForm action=\"/apps/appProxy\" method=\"post\">\n * <input type=\"text\" name=\"field\" />\n *\n * <input type=\"submit\" name=\"Submit\" />\n * </AppProxyForm>\n * </AppProxyProvider>\n * );\n * }\n * ```\n */\nexport function AppProxyForm(props
|
|
1
|
+
{"version":3,"file":"AppProxyForm.js","sources":["../../../../../../src/react/components/AppProxyForm/AppProxyForm.tsx"],"sourcesContent":["import {forwardRef, useContext} from 'react';\nimport {Form, type FormProps} from '@remix-run/react';\n\nimport {AppProxyProviderContext} from '../AppProxyProvider';\n\nexport interface AppProxyFormProps extends FormProps {\n action: string;\n}\n\n/**\n * Sets up a Remix `<Form>` component that works when rendered on an app proxy page.\n *\n * Supports any properties accepted by the `<Form>` component.\n *\n * Because Remix doesn't support URL rewriting, any route using this component should <b>match the pathname of the proxy\n * URL exactly</b>, and <b>end in a trailing slash</b> (e.g., `https://<shop>/apps/proxy/`), or set the Remix Form prop\n * `navigate` to `false`.\n *\n * @example\n * <caption>Render a form element in a proxied route.</caption>\n * <description>Use an `AppProxyForm` within an `AppProxy` to create a form.</description>\n * ```ts\n * // /app/routes/apps/appProxy.ts\n * import {\n * AppProxyProvider,\n * AppProxyForm,\n * } from \"@shopify/shopify-app-remix/react\";\n * import { authenticate } from \"~/shopify.server\";\n *\n * export async function loader({ request }) {\n * await authenticate.public.appProxy(request);\n *\n * return json({ appUrl: process.env.SHOPIFY_APP_URL });\n * }\n *\n * export async function action({ request }) {\n * await authenticate.public.appProxy(request);\n *\n * const formData = await request.formData();\n * const field = formData.get(\"field\")?.toString();\n *\n * // Perform actions\n * if (field) {\n * console.log(\"Field:\", field);\n * }\n *\n * // Return JSON to the client\n * return json({ message: \"Success!\" });\n * }\n *\n * export default function App() {\n * const { appUrl } = useLoaderData();\n *\n * return (\n * <AppProxyProvider appUrl={appUrl}>\n * <AppProxyForm action=\"/apps/appProxy\" method=\"post\">\n * <input type=\"text\" name=\"field\" />\n *\n * <input type=\"submit\" name=\"Submit\" />\n * </AppProxyForm>\n * </AppProxyProvider>\n * );\n * }\n * ```\n * @publicDocs\n */\nexport const AppProxyForm = forwardRef<HTMLFormElement, AppProxyFormProps>(\n function AppProxyForm(props, ref) {\n const context = useContext(AppProxyProviderContext);\n\n if (!context) {\n throw new Error(\n 'AppProxyForm must be used within an AppProxyProvider component',\n );\n }\n\n const {children, action, ...otherProps} = props;\n\n return (\n <Form action={context.formatUrl(action, false)} {...otherProps} ref={ref}>\n {children}\n </Form>\n );\n },\n);\n"],"names":["forwardRef","useContext","AppProxyProviderContext","_jsx","Form"],"mappings":";;;;;;;AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDG;AACI,MAAM,YAAY,GAAGA,gBAAU,CACpC,SAAS,YAAY,CAAC,KAAK,EAAE,GAAG,EAAA;AAC9B,IAAA,MAAM,OAAO,GAAGC,gBAAU,CAACC,wCAAuB,CAAC;IAEnD,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE;IACH;IAEA,MAAM,EAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,EAAC,GAAG,KAAK;IAE/C,QACEC,cAAA,CAACC,UAAI,EAAA,EAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,EAAA,GAAM,UAAU,EAAE,GAAG,EAAE,GAAG,EAAA,QAAA,EACrE,QAAQ,EAAA,CACJ;AAEX,CAAC;;;;"}
|
|
@@ -33,15 +33,16 @@ var AppProxyProvider = require('../AppProxyProvider/AppProxyProvider.js');
|
|
|
33
33
|
* );
|
|
34
34
|
* }
|
|
35
35
|
* ```
|
|
36
|
+
* @publicDocs
|
|
36
37
|
*/
|
|
37
|
-
function AppProxyLink(props) {
|
|
38
|
+
const AppProxyLink = React.forwardRef(function AppProxyLink(props, ref) {
|
|
38
39
|
const context = React.useContext(AppProxyProvider.AppProxyProviderContext);
|
|
39
40
|
if (!context) {
|
|
40
41
|
throw new Error('AppProxyLink must be used within an AppProxyProvider component');
|
|
41
42
|
}
|
|
42
43
|
const { children, href, ...otherProps } = props;
|
|
43
|
-
return (jsxRuntime.jsx("a", { href: context.formatUrl(href), ...otherProps, children: children }));
|
|
44
|
-
}
|
|
44
|
+
return (jsxRuntime.jsx("a", { href: context.formatUrl(href), ...otherProps, ref: ref, children: children }));
|
|
45
|
+
});
|
|
45
46
|
|
|
46
47
|
exports.AppProxyLink = AppProxyLink;
|
|
47
48
|
//# sourceMappingURL=AppProxyLink.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppProxyLink.js","sources":["../../../../../../src/react/components/AppProxyLink/AppProxyLink.tsx"],"sourcesContent":["import {useContext} from 'react';\n\nimport {AppProxyProviderContext} from '../AppProxyProvider';\n\nexport interface AppProxyLinkProps
|
|
1
|
+
{"version":3,"file":"AppProxyLink.js","sources":["../../../../../../src/react/components/AppProxyLink/AppProxyLink.tsx"],"sourcesContent":["import {forwardRef, useContext} from 'react';\n\nimport {AppProxyProviderContext} from '../AppProxyProvider';\n\nexport interface AppProxyLinkProps extends React.DetailedHTMLProps<\n React.AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> {\n href: string;\n}\n\n/**\n * Sets up an `<a />` HTML element that works when rendered behind an app proxy.\n *\n * Supports any properties accepted by the `<a />` HTML element.\n *\n * @example\n * <caption>Link to a different route.</caption>\n * <description>Use an `AppProxyLink` within an `AppProxyProvider` to link to a different proxied route.</description>\n * ```ts\n * // /app/routes/**\\/*.ts\n * import {authenticate} from '~/shopify.server';\n * import {AppProxyProvider, AppProxyLink} from '@shopify/shopify-app-remix/react';\n *\n * export async function loader({ request }) {\n * await authenticate.public.appProxy(request);\n *\n * return json({ appUrl: process.env.SHOPIFY_APP_URL });\n * }\n *\n * export default function App() {\n * const { appUrl } = useLoaderData();\n *\n * return (\n * <AppProxyProvider appUrl={appUrl}>\n * <AppProxyLink href=\"/other-proxy-route\">Link to another route</AppProxyLink>\n * </AppProxyProvider>\n * );\n * }\n * ```\n * @publicDocs\n */\nexport const AppProxyLink = forwardRef<HTMLAnchorElement, AppProxyLinkProps>(\n function AppProxyLink(props, ref) {\n const context = useContext(AppProxyProviderContext);\n\n if (!context) {\n throw new Error(\n 'AppProxyLink must be used within an AppProxyProvider component',\n );\n }\n\n const {children, href, ...otherProps} = props;\n\n return (\n <a href={context.formatUrl(href)} {...otherProps} ref={ref}>\n {children}\n </a>\n );\n },\n);\n"],"names":["forwardRef","useContext","AppProxyProviderContext","_jsx"],"mappings":";;;;;;AAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BG;AACI,MAAM,YAAY,GAAGA,gBAAU,CACpC,SAAS,YAAY,CAAC,KAAK,EAAE,GAAG,EAAA;AAC9B,IAAA,MAAM,OAAO,GAAGC,gBAAU,CAACC,wCAAuB,CAAC;IAEnD,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE;IACH;IAEA,MAAM,EAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,UAAU,EAAC,GAAG,KAAK;IAE7C,QACEC,sBAAG,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,KAAM,UAAU,EAAE,GAAG,EAAE,GAAG,YACvD,QAAQ,EAAA,CACP;AAER,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppProxyProvider.js","sources":["../../../../../../src/react/components/AppProxyProvider/AppProxyProvider.tsx"],"sourcesContent":["import {createContext, useEffect, useState} from 'react';\n\nexport interface AppProxyProviderProps {\n /**\n * The URL where the app is hosted. You can set this from the `SHOPIFY_APP_URL` environment variable.\n */\n appUrl: string;\n\n /**\n * The children to render.\n */\n children?: React.ReactNode;\n}\n\ntype FormatUrlFunction = (\n url: string | undefined,\n addOrigin?: boolean,\n) => string | undefined;\n\ninterface AppProxyProviderContextProps {\n appUrl: string;\n formatUrl: FormatUrlFunction;\n requestUrl?: URL;\n}\n\nexport const AppProxyProviderContext =\n createContext<AppProxyProviderContextProps | null>(null);\n\n/**\n * Sets up a page to render behind a Shopify app proxy, enabling JavaScript and CSS to be loaded from the app.\n *\n * Also provides components that enable using other components such as links and forms within proxies.\n *\n * > Caution:\n * Because Remix doesn't support URL rewriting, any route using this component should <b>match the pathname of the proxy\n * URL exactly</b>, and <b>end in a trailing slash</b> (e.g., `https://<shop>/apps/proxy/`).\n *\n * @example\n * <caption>Wrap a route with an AppProxyProvider component.</caption>\n * <description>Wrap your route component in the `AppProxyProvider` component and pass in your app URL.</description>\n * ```ts\n * // /app/routes/**\\/*.ts\n * import {authenticate} from '~/shopify.server';\n * import {AppProxyProvider} from '@shopify/shopify-app-remix/react';\n *\n * export async function loader({ request }) {\n * await authenticate.public.appProxy(request);\n *\n * return json({ appUrl: process.env.SHOPIFY_APP_URL });\n * }\n *\n * export default function App() {\n * const { appUrl } = useLoaderData();\n *\n * return (\n * <AppProxyProvider appUrl={appUrl}>\n * Page content\n * </AppProxyProvider>\n * );\n * }\n * ```\n */\nexport function AppProxyProvider(props: AppProxyProviderProps) {\n const {children, appUrl} = props;\n const [requestUrl, setRequestUrl] = useState<URL | undefined>();\n\n useEffect(\n () => setRequestUrl(new URL(window.location.href)),\n [setRequestUrl],\n );\n\n return (\n <AppProxyProviderContext.Provider\n value={{appUrl, requestUrl, formatUrl: formatProxyUrl(requestUrl)}}\n >\n <base href={appUrl} />\n\n {children}\n </AppProxyProviderContext.Provider>\n );\n}\n\nfunction formatProxyUrl(requestUrl: URL | undefined): FormatUrlFunction {\n return (url: string | undefined, addOrigin = true) => {\n if (!url) {\n return url;\n }\n\n let finalUrl = url;\n\n if (addOrigin && requestUrl && finalUrl.startsWith('/')) {\n finalUrl = new URL(`${requestUrl.origin}${url}`).href;\n }\n if (!finalUrl.endsWith('/')) {\n finalUrl = `${finalUrl}/`;\n }\n\n return finalUrl;\n };\n}\n"],"names":["createContext","useState","useEffect","_jsxs","_jsx"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"AppProxyProvider.js","sources":["../../../../../../src/react/components/AppProxyProvider/AppProxyProvider.tsx"],"sourcesContent":["import {createContext, useEffect, useState} from 'react';\n\n/**\n * Props for the `AppProxyProvider` component.\n * @publicDocs\n */\nexport interface AppProxyProviderProps {\n /**\n * The URL where the app is hosted. You can set this from the `SHOPIFY_APP_URL` environment variable.\n */\n appUrl: string;\n\n /**\n * The children to render.\n */\n children?: React.ReactNode;\n}\n\ntype FormatUrlFunction = (\n url: string | undefined,\n addOrigin?: boolean,\n) => string | undefined;\n\ninterface AppProxyProviderContextProps {\n appUrl: string;\n formatUrl: FormatUrlFunction;\n requestUrl?: URL;\n}\n\nexport const AppProxyProviderContext =\n createContext<AppProxyProviderContextProps | null>(null);\n\n/**\n * Sets up a page to render behind a Shopify app proxy, enabling JavaScript and CSS to be loaded from the app.\n *\n * Also provides components that enable using other components such as links and forms within proxies.\n *\n * > Caution:\n * Because Remix doesn't support URL rewriting, any route using this component should <b>match the pathname of the proxy\n * URL exactly</b>, and <b>end in a trailing slash</b> (e.g., `https://<shop>/apps/proxy/`).\n *\n * @example\n * <caption>Wrap a route with an AppProxyProvider component.</caption>\n * <description>Wrap your route component in the `AppProxyProvider` component and pass in your app URL.</description>\n * ```ts\n * // /app/routes/**\\/*.ts\n * import {authenticate} from '~/shopify.server';\n * import {AppProxyProvider} from '@shopify/shopify-app-remix/react';\n *\n * export async function loader({ request }) {\n * await authenticate.public.appProxy(request);\n *\n * return json({ appUrl: process.env.SHOPIFY_APP_URL });\n * }\n *\n * export default function App() {\n * const { appUrl } = useLoaderData();\n *\n * return (\n * <AppProxyProvider appUrl={appUrl}>\n * Page content\n * </AppProxyProvider>\n * );\n * }\n * ```\n */\nexport function AppProxyProvider(props: AppProxyProviderProps) {\n const {children, appUrl} = props;\n const [requestUrl, setRequestUrl] = useState<URL | undefined>();\n\n useEffect(\n () => setRequestUrl(new URL(window.location.href)),\n [setRequestUrl],\n );\n\n return (\n <AppProxyProviderContext.Provider\n value={{appUrl, requestUrl, formatUrl: formatProxyUrl(requestUrl)}}\n >\n <base href={appUrl} />\n\n {children}\n </AppProxyProviderContext.Provider>\n );\n}\n\nfunction formatProxyUrl(requestUrl: URL | undefined): FormatUrlFunction {\n return (url: string | undefined, addOrigin = true) => {\n if (!url) {\n return url;\n }\n\n let finalUrl = url;\n\n if (addOrigin && requestUrl && finalUrl.startsWith('/')) {\n finalUrl = new URL(`${requestUrl.origin}${url}`).href;\n }\n if (!finalUrl.endsWith('/')) {\n finalUrl = `${finalUrl}/`;\n }\n\n return finalUrl;\n };\n}\n"],"names":["createContext","useState","useEffect","_jsxs","_jsx"],"mappings":";;;;;MA6Ba,uBAAuB,GAClCA,mBAAa,CAAsC,IAAI;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;AACG,SAAU,gBAAgB,CAAC,KAA4B,EAAA;AAC3D,IAAA,MAAM,EAAC,QAAQ,EAAE,MAAM,EAAC,GAAG,KAAK;IAChC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAGC,cAAQ,EAAmB;IAE/DC,eAAS,CACP,MAAM,aAAa,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAClD,CAAC,aAAa,CAAC,CAChB;AAED,IAAA,QACEC,eAAA,CAAC,uBAAuB,CAAC,QAAQ,EAAA,EAC/B,KAAK,EAAE,EAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EAAC,EAAA,QAAA,EAAA,CAElEC,cAAA,CAAA,MAAA,EAAA,EAAM,IAAI,EAAE,MAAM,EAAA,CAAI,EAErB,QAAQ,CAAA,EAAA,CACwB;AAEvC;AAEA,SAAS,cAAc,CAAC,UAA2B,EAAA;AACjD,IAAA,OAAO,CAAC,GAAuB,EAAE,SAAS,GAAG,IAAI,KAAI;QACnD,IAAI,CAAC,GAAG,EAAE;AACR,YAAA,OAAO,GAAG;QACZ;QAEA,IAAI,QAAQ,GAAG,GAAG;QAElB,IAAI,SAAS,IAAI,UAAU,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AACvD,YAAA,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,UAAU,CAAC,MAAM,CAAA,EAAG,GAAG,CAAA,CAAE,CAAC,CAAC,IAAI;QACvD;QACA,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AAC3B,YAAA,QAAQ,GAAG,CAAA,EAAG,QAAQ,CAAA,CAAA,CAAG;QAC3B;AAEA,QAAA,OAAO,QAAQ;AACjB,IAAA,CAAC;AACH;;;;;"}
|
|
@@ -17,8 +17,8 @@ function redirectFactory(params, request, shop) {
|
|
|
17
17
|
init,
|
|
18
18
|
});
|
|
19
19
|
logger.debug('Redirecting', { shop, url: parsedUrl.toString() });
|
|
20
|
-
const isSameOrigin = parsedUrl.origin === config.appUrl;
|
|
21
|
-
if (isSameOrigin
|
|
20
|
+
const isSameOrigin = parsedUrl.origin === new URL(config.appUrl).origin;
|
|
21
|
+
if (isSameOrigin) {
|
|
22
22
|
searchParams.forEach((value, key) => {
|
|
23
23
|
if (!parsedUrl.searchParams.has(key)) {
|
|
24
24
|
parsedUrl.searchParams.set(key, value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirect.js","sources":["../../../../../../../src/server/authenticate/admin/helpers/redirect.ts"],"sourcesContent":["import {\n TypedResponse,\n redirect as remixRedirect,\n} from '@remix-run/server-runtime';\n\nimport {BasicParams} from '../../../types';\nimport {getSessionTokenHeader} from '../../helpers/get-session-token-header';\n\nimport {renderAppBridge} from './render-app-bridge';\nimport {redirectWithAppBridgeHeaders} from './redirect-with-app-bridge-headers';\n\nexport type RedirectTarget = '_self' | '_parent' | '_top' | '_blank';\nexport type RedirectInit = number | (ResponseInit & {target?: RedirectTarget});\nexport type RedirectFunction = (\n url: string,\n init?: RedirectInit,\n) => TypedResponse<never>;\n\ninterface ParseURLOptions {\n params: BasicParams;\n url: string;\n base: string;\n shop: string;\n init: RedirectInit;\n}\n\ninterface ParsedURL {\n url: URL;\n target: RedirectTarget;\n}\n\nexport function redirectFactory(\n params: BasicParams,\n request: Request,\n shop: string,\n): RedirectFunction {\n const {config, logger} = params;\n\n return function redirect(url, init: RedirectInit) {\n const {searchParams} = new URL(request.url);\n const {url: parsedUrl, target} = parseURL({\n params,\n url,\n base: config.appUrl,\n shop,\n init,\n });\n\n logger.debug('Redirecting', {shop, url: parsedUrl.toString()});\n\n const isSameOrigin = parsedUrl.origin === config.appUrl;\n if (isSameOrigin
|
|
1
|
+
{"version":3,"file":"redirect.js","sources":["../../../../../../../src/server/authenticate/admin/helpers/redirect.ts"],"sourcesContent":["import {\n TypedResponse,\n redirect as remixRedirect,\n} from '@remix-run/server-runtime';\n\nimport {BasicParams} from '../../../types';\nimport {getSessionTokenHeader} from '../../helpers/get-session-token-header';\n\nimport {renderAppBridge} from './render-app-bridge';\nimport {redirectWithAppBridgeHeaders} from './redirect-with-app-bridge-headers';\n\nexport type RedirectTarget = '_self' | '_parent' | '_top' | '_blank';\nexport type RedirectInit = number | (ResponseInit & {target?: RedirectTarget});\nexport type RedirectFunction = (\n url: string,\n init?: RedirectInit,\n) => TypedResponse<never>;\n\ninterface ParseURLOptions {\n params: BasicParams;\n url: string;\n base: string;\n shop: string;\n init: RedirectInit;\n}\n\ninterface ParsedURL {\n url: URL;\n target: RedirectTarget;\n}\n\nexport function redirectFactory(\n params: BasicParams,\n request: Request,\n shop: string,\n): RedirectFunction {\n const {config, logger} = params;\n\n return function redirect(url, init: RedirectInit) {\n const {searchParams} = new URL(request.url);\n const {url: parsedUrl, target} = parseURL({\n params,\n url,\n base: config.appUrl,\n shop,\n init,\n });\n\n logger.debug('Redirecting', {shop, url: parsedUrl.toString()});\n\n const isSameOrigin = parsedUrl.origin === new URL(config.appUrl).origin;\n if (isSameOrigin) {\n searchParams.forEach((value, key) => {\n if (!parsedUrl.searchParams.has(key)) {\n parsedUrl.searchParams.set(key, value);\n }\n });\n }\n\n if (target === '_self') {\n if (isBounceRequest(request)) {\n throw renderAppBridge(params, request, {\n url: parsedUrl.toString(),\n target,\n });\n } else {\n return remixRedirect(parsedUrl.toString(), init);\n }\n } else if (isDataRequest(request)) {\n throw redirectWithAppBridgeHeaders(parsedUrl.toString());\n } else if (isEmbeddedRequest(request)) {\n throw renderAppBridge(params, request, {\n url: parsedUrl.toString(),\n target,\n });\n }\n return remixRedirect(url, init);\n };\n}\n\nfunction isBounceRequest(request: Request) {\n return (\n Boolean(getSessionTokenHeader(request)) &&\n request.headers.has('X-Shopify-Bounce')\n );\n}\n\nfunction isDataRequest(request: Request) {\n const isGet = request.method === 'GET';\n const sessionTokenHeader = Boolean(getSessionTokenHeader(request));\n\n return (\n sessionTokenHeader &&\n !isBounceRequest(request) &&\n (!isEmbeddedRequest(request) || !isGet)\n );\n}\n\nfunction isEmbeddedRequest(request: Request) {\n const {searchParams} = new URL(request.url);\n\n return searchParams.get('embedded') === '1';\n}\n\nfunction parseURL({params, base, init, shop, url}: ParseURLOptions): ParsedURL {\n let target: RedirectTarget | undefined =\n typeof init !== 'number' && init?.target ? init.target : undefined;\n\n if (isAdminRemotePath(url)) {\n const {config} = params;\n\n const adminPath = getAdminRemotePath(url);\n const cleanShopName = shop.replace('.myshopify.com', '');\n\n if (!target) {\n target = config.isEmbeddedApp ? '_parent' : '_self';\n }\n\n return {\n url: new URL(\n `https://admin.shopify.com/store/${cleanShopName}${adminPath}`,\n ),\n target,\n };\n } else {\n return {\n url: new URL(url, base),\n target: target ?? '_self',\n };\n }\n}\n\nconst ADMIN_REGEX = /^shopify:\\/*admin\\//i;\n\nfunction isAdminRemotePath(url: string) {\n return ADMIN_REGEX.test(url);\n}\n\nfunction getAdminRemotePath(url: string | URL) {\n const parsedUrl = removeRestrictedParams(new URL(url)).href;\n return parsedUrl.replace(ADMIN_REGEX, '/');\n}\n\nconst embeddedFrameParamsToRemove = [\n 'hmac',\n 'locale',\n 'protocol',\n 'session',\n 'id_token',\n 'shop',\n 'timestamp',\n 'host',\n 'embedded',\n // sent when clicking rel=\"home\" nav item\n 'appLoadId',\n];\n\nfunction removeRestrictedParams(url: URL | string) {\n const newUrl = new URL(url);\n embeddedFrameParamsToRemove.forEach((param) =>\n newUrl.searchParams.delete(param),\n );\n return newUrl;\n}\n"],"names":["renderAppBridge","remixRedirect","redirectWithAppBridgeHeaders","getSessionTokenHeader"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-code-flow.js","sources":["../../../../../../../src/server/authenticate/admin/strategies/auth-code-flow.ts"],"sourcesContent":["import {\n CookieNotFound,\n GraphqlQueryError,\n HttpResponseError,\n InvalidHmacError,\n InvalidOAuthError,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n beginAuth,\n handleClientErrorFactory,\n redirectToAuthPage,\n redirectToShopifyOrAppRoot,\n redirectWithExitIframe,\n triggerAfterAuthHook,\n validateShopAndHostParams,\n} from '../helpers';\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {getSessionTokenHeader} from '../../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class AuthCodeFlowStrategy<Config extends AppConfigArg>\n implements AuthorizationStrategy\n{\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(request: Request): Promise<void | never> {\n const {api, config} = this;\n\n const url = new URL(request.url);\n const isAuthRequest = url.pathname === config.auth.path;\n const isAuthCallbackRequest = url.pathname === config.auth.callbackPath;\n\n if (isAuthRequest || isAuthCallbackRequest) {\n const shop = api.utils.sanitizeShop(url.searchParams.get('shop')!);\n if (!shop) throw new Response('Shop param is invalid', {status: 400});\n\n if (isAuthRequest) {\n throw await this.handleAuthBeginRequest(request, shop);\n } else {\n throw await this.handleAuthCallbackRequest(request, shop);\n }\n }\n\n if (!getSessionTokenHeader(request)) {\n // This is a document request that doesn't contain a session token. We check if the app is installed.\n // If the app isn't installed, we initiate the OAuth auth code flow.\n // Requests with a header can only happen after the app is installed.\n await this.ensureInstalledOnShop(request);\n }\n }\n\n public async authenticate(\n request: Request,\n sessionContext: SessionContext,\n ): Promise<Session | never> {\n const {api, config, logger} = this;\n\n const {shop, session} = sessionContext;\n\n if (!session) {\n logger.debug('No session found, redirecting to OAuth', {shop});\n await redirectToAuthPage({config, logger, api}, request, shop);\n } else if (!session.isActive(config.scopes)) {\n logger.debug(\n 'Found a session, but it has expired, redirecting to OAuth',\n {shop},\n );\n await redirectToAuthPage({config, logger, api}, request, shop);\n }\n\n logger.debug('Found a valid session', {shop});\n\n return session!;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n const {api, config, logger} = this;\n return handleClientErrorFactory({\n request,\n onError: async ({session, error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n throw await redirectToAuthPage(\n {api, config, logger},\n request,\n session.shop,\n );\n }\n },\n });\n }\n\n private async ensureInstalledOnShop(request: Request) {\n const {api, config, logger} = this;\n\n validateShopAndHostParams({api, config, logger}, request);\n\n const url = new URL(request.url);\n let shop = url.searchParams.get('shop');\n\n // Ensure app is installed\n logger.debug('Ensuring app is installed on shop', {shop});\n\n if (!(await this.hasValidOfflineId(request))) {\n logger.info(\"Could not find a shop, can't authenticate request\");\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n const offlineSession = await this.getOfflineSession(request);\n const isEmbedded = url.searchParams.get('embedded') === '1';\n\n if (!offlineSession) {\n logger.info(\"Shop hasn't installed app yet, redirecting to OAuth\", {\n shop,\n });\n if (isEmbedded) {\n redirectWithExitIframe({api, config, logger}, request, shop!);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop!);\n }\n }\n\n shop = shop || offlineSession.shop;\n\n if (config.isEmbeddedApp && !isEmbedded) {\n try {\n logger.debug('Ensuring offline session is valid before embedding', {\n shop,\n });\n await this.testSession(offlineSession);\n\n logger.debug('Offline session is still valid, embedding app', {shop});\n } catch (error) {\n await this.handleInvalidOfflineSession(error, request, shop);\n }\n }\n }\n\n private async handleAuthBeginRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth begin request', {shop});\n\n // If we're loading from an iframe, we need to break out of it\n if (\n config.isEmbeddedApp &&\n request.headers.get('Sec-Fetch-Dest') === 'iframe'\n ) {\n logger.debug('Auth request in iframe detected, exiting iframe', {shop});\n throw redirectWithExitIframe({api, config, logger}, request, shop);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop);\n }\n }\n\n private async handleAuthCallbackRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth callback request', {shop});\n\n try {\n const {session, headers: responseHeaders} = await api.auth.callback({\n rawRequest: request,\n expiring: config.future.expiringOfflineAccessTokens,\n });\n\n await config.sessionStorage!.storeSession(session);\n\n if (config.useOnlineTokens && !session.isOnline) {\n logger.info('Requesting online access token for offline session', {\n shop,\n });\n await beginAuth({api, config, logger}, request, true, shop);\n }\n\n logger.debug('Request is valid, loaded session from OAuth callback', {\n shop: session.shop,\n isOnline: session.isOnline,\n });\n\n await triggerAfterAuthHook({api, config, logger}, session, request, this);\n\n throw await redirectToShopifyOrAppRoot(\n request,\n {api, config, logger},\n responseHeaders,\n );\n } catch (error) {\n if (error instanceof Response) throw error;\n\n throw await this.oauthCallbackError(error, request, shop);\n }\n }\n\n private async getOfflineSession(\n request: Request,\n ): Promise<Session | undefined> {\n const offlineId = await this.getOfflineSessionId(request);\n return this.config.sessionStorage!.loadSession(offlineId!);\n }\n\n private async hasValidOfflineId(request: Request) {\n return Boolean(await this.getOfflineSessionId(request));\n }\n\n private async getOfflineSessionId(\n request: Request,\n ): Promise<string | undefined> {\n const {api} = this;\n const url = new URL(request.url);\n const shop = url.searchParams.get('shop');\n\n return shop\n ? api.session.getOfflineId(shop)\n : api.session.getCurrentId({isOnline: false, rawRequest: request});\n }\n\n private async testSession(session: Session): Promise<void> {\n const {api} = this;\n\n const client = new api.clients.Graphql({\n session,\n });\n\n await client.request(`#graphql\n query shopifyAppShopName {\n shop {\n name\n }\n }\n `);\n }\n\n private async oauthCallbackError(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {logger} = this;\n logger.error('Error during OAuth callback', {shop, error: error.message});\n\n if (error instanceof CookieNotFound) {\n return this.handleAuthBeginRequest(request, shop);\n }\n\n if (\n error instanceof InvalidHmacError ||\n error instanceof InvalidOAuthError\n ) {\n return new Response(undefined, {\n status: 400,\n statusText: 'Invalid OAuth Request',\n });\n }\n\n return new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n\n private async handleInvalidOfflineSession(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {api, logger, config} = this;\n if (error instanceof HttpResponseError) {\n if (error.response.code === 401) {\n logger.info('Shop session is no longer valid, redirecting to OAuth', {\n shop,\n });\n throw await beginAuth({api, config, logger}, request, false, shop);\n } else {\n const message = JSON.stringify(error.response.body, null, 2);\n logger.error(`Unexpected error during session validation: ${message}`, {\n shop,\n });\n\n throw new Response(undefined, {\n status: error.response.code,\n statusText: error.response.statusText,\n });\n }\n } else if (error instanceof GraphqlQueryError) {\n const context: Record<string, string> = {shop};\n if (error.response) {\n context.response = JSON.stringify(error.body);\n }\n\n logger.error(\n `Unexpected error during session validation: ${error.message}`,\n context,\n );\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n }\n}\n"],"names":["getSessionTokenHeader","redirectToAuthPage","handleClientErrorFactory","validateShopAndHostParams","redirectWithExitIframe","beginAuth","triggerAfterAuthHook","redirectToShopifyOrAppRoot","CookieNotFound","InvalidHmacError","InvalidOAuthError","HttpResponseError","GraphqlQueryError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth-code-flow.js","sources":["../../../../../../../src/server/authenticate/admin/strategies/auth-code-flow.ts"],"sourcesContent":["import {\n CookieNotFound,\n GraphqlQueryError,\n HttpResponseError,\n InvalidHmacError,\n InvalidOAuthError,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../../types';\nimport {\n beginAuth,\n handleClientErrorFactory,\n redirectToAuthPage,\n redirectToShopifyOrAppRoot,\n redirectWithExitIframe,\n triggerAfterAuthHook,\n validateShopAndHostParams,\n} from '../helpers';\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {getSessionTokenHeader} from '../../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class AuthCodeFlowStrategy<\n Config extends AppConfigArg,\n> implements AuthorizationStrategy {\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(request: Request): Promise<void | never> {\n const {api, config} = this;\n\n const url = new URL(request.url);\n const isAuthRequest = url.pathname === config.auth.path;\n const isAuthCallbackRequest = url.pathname === config.auth.callbackPath;\n\n if (isAuthRequest || isAuthCallbackRequest) {\n const shop = api.utils.sanitizeShop(url.searchParams.get('shop')!);\n if (!shop) throw new Response('Shop param is invalid', {status: 400});\n\n if (isAuthRequest) {\n throw await this.handleAuthBeginRequest(request, shop);\n } else {\n throw await this.handleAuthCallbackRequest(request, shop);\n }\n }\n\n if (!getSessionTokenHeader(request)) {\n // This is a document request that doesn't contain a session token. We check if the app is installed.\n // If the app isn't installed, we initiate the OAuth auth code flow.\n // Requests with a header can only happen after the app is installed.\n await this.ensureInstalledOnShop(request);\n }\n }\n\n public async authenticate(\n request: Request,\n sessionContext: SessionContext,\n ): Promise<Session | never> {\n const {api, config, logger} = this;\n\n const {shop, session} = sessionContext;\n\n if (!session) {\n logger.debug('No session found, redirecting to OAuth', {shop});\n await redirectToAuthPage({config, logger, api}, request, shop);\n } else if (!session.isActive(config.scopes)) {\n logger.debug(\n 'Found a session, but it has expired, redirecting to OAuth',\n {shop},\n );\n await redirectToAuthPage({config, logger, api}, request, shop);\n }\n\n logger.debug('Found a valid session', {shop});\n\n return session!;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n const {api, config, logger} = this;\n return handleClientErrorFactory({\n request,\n onError: async ({session, error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n throw await redirectToAuthPage(\n {api, config, logger},\n request,\n session.shop,\n );\n }\n },\n });\n }\n\n private async ensureInstalledOnShop(request: Request) {\n const {api, config, logger} = this;\n\n validateShopAndHostParams({api, config, logger}, request);\n\n const url = new URL(request.url);\n let shop = url.searchParams.get('shop');\n\n // Ensure app is installed\n logger.debug('Ensuring app is installed on shop', {shop});\n\n if (!(await this.hasValidOfflineId(request))) {\n logger.info(\"Could not find a shop, can't authenticate request\");\n throw new Response(undefined, {\n status: 400,\n statusText: 'Bad Request',\n });\n }\n\n const offlineSession = await this.getOfflineSession(request);\n const isEmbedded = url.searchParams.get('embedded') === '1';\n\n if (!offlineSession) {\n logger.info(\"Shop hasn't installed app yet, redirecting to OAuth\", {\n shop,\n });\n if (isEmbedded) {\n redirectWithExitIframe({api, config, logger}, request, shop!);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop!);\n }\n }\n\n shop = shop || offlineSession.shop;\n\n if (config.isEmbeddedApp && !isEmbedded) {\n try {\n logger.debug('Ensuring offline session is valid before embedding', {\n shop,\n });\n await this.testSession(offlineSession);\n\n logger.debug('Offline session is still valid, embedding app', {shop});\n } catch (error) {\n await this.handleInvalidOfflineSession(error, request, shop);\n }\n }\n }\n\n private async handleAuthBeginRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth begin request', {shop});\n\n // If we're loading from an iframe, we need to break out of it\n if (\n config.isEmbeddedApp &&\n request.headers.get('Sec-Fetch-Dest') === 'iframe'\n ) {\n logger.debug('Auth request in iframe detected, exiting iframe', {shop});\n throw redirectWithExitIframe({api, config, logger}, request, shop);\n } else {\n throw await beginAuth({api, config, logger}, request, false, shop);\n }\n }\n\n private async handleAuthCallbackRequest(\n request: Request,\n shop: string,\n ): Promise<never> {\n const {api, config, logger} = this;\n\n logger.info('Handling OAuth callback request', {shop});\n\n try {\n const {session, headers: responseHeaders} = await api.auth.callback({\n rawRequest: request,\n expiring: config.future.expiringOfflineAccessTokens,\n });\n\n await config.sessionStorage!.storeSession(session);\n\n if (config.useOnlineTokens && !session.isOnline) {\n logger.info('Requesting online access token for offline session', {\n shop,\n });\n await beginAuth({api, config, logger}, request, true, shop);\n }\n\n logger.debug('Request is valid, loaded session from OAuth callback', {\n shop: session.shop,\n isOnline: session.isOnline,\n });\n\n await triggerAfterAuthHook({api, config, logger}, session, request, this);\n\n throw await redirectToShopifyOrAppRoot(\n request,\n {api, config, logger},\n responseHeaders,\n );\n } catch (error) {\n if (error instanceof Response) throw error;\n\n throw await this.oauthCallbackError(error, request, shop);\n }\n }\n\n private async getOfflineSession(\n request: Request,\n ): Promise<Session | undefined> {\n const offlineId = await this.getOfflineSessionId(request);\n return this.config.sessionStorage!.loadSession(offlineId!);\n }\n\n private async hasValidOfflineId(request: Request) {\n return Boolean(await this.getOfflineSessionId(request));\n }\n\n private async getOfflineSessionId(\n request: Request,\n ): Promise<string | undefined> {\n const {api} = this;\n const url = new URL(request.url);\n const shop = url.searchParams.get('shop');\n\n return shop\n ? api.session.getOfflineId(shop)\n : api.session.getCurrentId({isOnline: false, rawRequest: request});\n }\n\n private async testSession(session: Session): Promise<void> {\n const {api} = this;\n\n const client = new api.clients.Graphql({\n session,\n });\n\n await client.request(`#graphql\n query shopifyAppShopName {\n shop {\n name\n }\n }\n `);\n }\n\n private async oauthCallbackError(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {logger} = this;\n logger.error('Error during OAuth callback', {shop, error: error.message});\n\n if (error instanceof CookieNotFound) {\n return this.handleAuthBeginRequest(request, shop);\n }\n\n if (\n error instanceof InvalidHmacError ||\n error instanceof InvalidOAuthError\n ) {\n return new Response(undefined, {\n status: 400,\n statusText: 'Invalid OAuth Request',\n });\n }\n\n return new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n\n private async handleInvalidOfflineSession(\n error: Error,\n request: Request,\n shop: string,\n ) {\n const {api, logger, config} = this;\n if (error instanceof HttpResponseError) {\n if (error.response.code === 401) {\n logger.info('Shop session is no longer valid, redirecting to OAuth', {\n shop,\n });\n throw await beginAuth({api, config, logger}, request, false, shop);\n } else {\n const message = JSON.stringify(error.response.body, null, 2);\n logger.error(`Unexpected error during session validation: ${message}`, {\n shop,\n });\n\n throw new Response(undefined, {\n status: error.response.code,\n statusText: error.response.statusText,\n });\n }\n } else if (error instanceof GraphqlQueryError) {\n const context: Record<string, string> = {shop};\n if (error.response) {\n context.response = JSON.stringify(error.body);\n }\n\n logger.error(\n `Unexpected error during session validation: ${error.message}`,\n context,\n );\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n }\n}\n"],"names":["getSessionTokenHeader","redirectToAuthPage","handleClientErrorFactory","validateShopAndHostParams","redirectWithExitIframe","beginAuth","triggerAfterAuthHook","redirectToShopifyOrAppRoot","CookieNotFound","InvalidHmacError","InvalidOAuthError","HttpResponseError","GraphqlQueryError"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merchant-custom-app.js","sources":["../../../../../../../src/server/authenticate/admin/strategies/merchant-custom-app.ts"],"sourcesContent":["import {Session, Shopify, ShopifyError} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {ApiConfigWithFutureFlags, ApiFutureFlags} from '../../../future/flags';\nimport {HandleAdminClientError} from '../../../clients';\nimport {handleClientErrorFactory} from '../helpers';\nimport {getShopFromRequest} from '../../helpers';\n\nimport {AuthorizationStrategy, OnErrorOptions, SessionContext} from './types';\n\nexport class MerchantCustomAuth
|
|
1
|
+
{"version":3,"file":"merchant-custom-app.js","sources":["../../../../../../../src/server/authenticate/admin/strategies/merchant-custom-app.ts"],"sourcesContent":["import {Session, Shopify, ShopifyError} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {ApiConfigWithFutureFlags, ApiFutureFlags} from '../../../future/flags';\nimport {HandleAdminClientError} from '../../../clients';\nimport {handleClientErrorFactory} from '../helpers';\nimport {getShopFromRequest} from '../../helpers';\n\nimport {AuthorizationStrategy, OnErrorOptions, SessionContext} from './types';\n\nexport class MerchantCustomAuth<\n Config extends AppConfigArg,\n> implements AuthorizationStrategy {\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams<Config['future']>) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(request: Request): Promise<void> {\n this.logger.debug('Skipping OAuth request for merchant custom app', {\n shop: getShopFromRequest(request),\n });\n }\n\n public async authenticate(\n _request: Request,\n sessionContext: SessionContext,\n ): Promise<Session | never> {\n const {shop} = sessionContext;\n\n this.logger.debug(\n 'Building session from configured access token for merchant custom app',\n {shop},\n );\n const session = this.api.session.customAppSession(shop);\n\n return session;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n return handleClientErrorFactory({\n request,\n onError: async ({error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n this.logger.info(\n 'Request failed with 401. Review your API credentials or generate new tokens. https://shopify.dev/docs/apps/build/authentication-authorization/access-token-types/generate-app-access-tokens-admin#rotating-api-credentials-for-admin-created-apps ',\n );\n throw new ShopifyError(\n 'Unauthorized: Access token has been revoked.',\n );\n }\n },\n });\n }\n}\n"],"names":["getShopFromRequest","handleClientErrorFactory","ShopifyError"],"mappings":";;;;;;;;MAWa,kBAAkB,CAAA;AAGnB,IAAA,GAAG;AAKH,IAAA,MAAM;AACN,IAAA,MAAM;AAEhB,IAAA,WAAA,CAAmB,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAgC,EAAA;AACrE,QAAA,IAAI,CAAC,GAAG,GAAG,GAAG;AACd,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;AACpB,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;IACtB;IAEO,MAAM,sBAAsB,CAAC,OAAgB,EAAA;AAClD,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gDAAgD,EAAE;AAClE,YAAA,IAAI,EAAEA,qCAAkB,CAAC,OAAO,CAAC;AAClC,SAAA,CAAC;IACJ;AAEO,IAAA,MAAM,YAAY,CACvB,QAAiB,EACjB,cAA8B,EAAA;AAE9B,QAAA,MAAM,EAAC,IAAI,EAAC,GAAG,cAAc;QAE7B,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,uEAAuE,EACvE,EAAC,IAAI,EAAC,CACP;AACD,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC;AAEvD,QAAA,OAAO,OAAO;IAChB;AAEO,IAAA,iBAAiB,CAAC,OAAgB,EAAA;AACvC,QAAA,OAAOC,0CAAwB,CAAC;YAC9B,OAAO;AACP,YAAA,OAAO,EAAE,OAAO,EAAC,KAAK,EAAiB,KAAI;gBACzC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,GAAG,EAAE;AAC/B,oBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,oPAAoP,CACrP;AACD,oBAAA,MAAM,IAAIC,uBAAY,CACpB,8CAA8C,CAC/C;gBACH;YACF,CAAC;AACF,SAAA,CAAC;IACJ;AACD;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-exchange.js","sources":["../../../../../../../src/server/authenticate/admin/strategies/token-exchange.ts"],"sourcesContent":["import {\n HttpResponseError,\n InvalidJwtError,\n RequestedTokenType,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {\n respondToInvalidSessionToken,\n invalidateAccessToken,\n getShopFromRequest,\n} from '../../helpers';\nimport {handleClientErrorFactory, triggerAfterAuthHook} from '../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\nimport {WITHIN_MILLISECONDS_OF_EXPIRY} from '../../../helpers';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class TokenExchangeStrategy
|
|
1
|
+
{"version":3,"file":"token-exchange.js","sources":["../../../../../../../src/server/authenticate/admin/strategies/token-exchange.ts"],"sourcesContent":["import {\n HttpResponseError,\n InvalidJwtError,\n RequestedTokenType,\n Session,\n Shopify,\n} from '@shopify/shopify-api';\n\nimport {AppConfig, AppConfigArg} from '../../../config-types';\nimport {BasicParams} from '../../../types';\nimport {\n respondToInvalidSessionToken,\n invalidateAccessToken,\n getShopFromRequest,\n} from '../../helpers';\nimport {handleClientErrorFactory, triggerAfterAuthHook} from '../helpers';\nimport {HandleAdminClientError} from '../../../clients';\nimport type {\n ApiConfigWithFutureFlags,\n ApiFutureFlags,\n} from '../../../future/flags';\nimport {WITHIN_MILLISECONDS_OF_EXPIRY} from '../../../helpers';\n\nimport {AuthorizationStrategy, SessionContext, OnErrorOptions} from './types';\n\nexport class TokenExchangeStrategy<\n Config extends AppConfigArg,\n> implements AuthorizationStrategy {\n protected api: Shopify<\n ApiConfigWithFutureFlags<Config['future']>,\n ApiFutureFlags<Config['future']>\n >;\n\n protected config: AppConfig;\n protected logger: Shopify['logger'];\n\n public constructor({api, config, logger}: BasicParams<Config['future']>) {\n this.api = api;\n this.config = config;\n this.logger = logger;\n }\n\n public async respondToOAuthRequests(_request: Request): Promise<void> {}\n\n public async authenticate(\n request: Request,\n sessionContext: SessionContext,\n ): Promise<Session> {\n const {api, config, logger} = this;\n const {shop, session, sessionToken} = sessionContext;\n\n if (!sessionToken) throw new InvalidJwtError();\n\n if (\n !session ||\n !session.isActive(undefined, WITHIN_MILLISECONDS_OF_EXPIRY)\n ) {\n logger.info('No valid session found', {shop});\n logger.info('Requesting offline access token', {shop});\n const {session: offlineSession} = await this.exchangeToken({\n request,\n sessionToken,\n shop,\n requestedTokenType: RequestedTokenType.OfflineAccessToken,\n });\n\n await config.sessionStorage!.storeSession(offlineSession);\n\n let newSession = offlineSession;\n\n if (config.useOnlineTokens) {\n logger.info('Requesting online access token', {shop});\n const {session: onlineSession} = await this.exchangeToken({\n request,\n sessionToken,\n shop,\n requestedTokenType: RequestedTokenType.OnlineAccessToken,\n });\n\n await config.sessionStorage!.storeSession(onlineSession);\n newSession = onlineSession;\n }\n\n logger.debug('Request is valid, loaded session from session token', {\n shop: newSession.shop,\n isOnline: newSession.isOnline,\n });\n\n try {\n await this.handleAfterAuthHook(\n {api, config, logger},\n newSession,\n request,\n sessionToken,\n );\n } catch (errorOrResponse) {\n if (errorOrResponse instanceof Response) {\n throw errorOrResponse;\n }\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n\n return newSession;\n }\n\n return session!;\n }\n\n public handleClientError(request: Request): HandleAdminClientError {\n const {api, config, logger} = this;\n return handleClientErrorFactory({\n request,\n onError: async ({session, error}: OnErrorOptions) => {\n if (error.response.code === 401) {\n logger.debug('Responding to invalid access token', {\n shop: getShopFromRequest(request),\n });\n await invalidateAccessToken({config, api, logger}, session);\n\n respondToInvalidSessionToken({\n params: {config, api, logger},\n request,\n });\n }\n },\n });\n }\n\n private async exchangeToken({\n request,\n shop,\n sessionToken,\n requestedTokenType,\n }: {\n request: Request;\n shop: string;\n sessionToken: string;\n requestedTokenType: RequestedTokenType;\n }): Promise<{session: Session}> {\n const {api, config, logger} = this;\n\n try {\n return await api.auth.tokenExchange({\n sessionToken,\n shop,\n requestedTokenType,\n expiring: config.future.expiringOfflineAccessTokens,\n });\n } catch (error) {\n if (\n error instanceof InvalidJwtError ||\n (error instanceof HttpResponseError &&\n error.response.code === 400 &&\n error.response.body?.error === 'invalid_subject_token')\n ) {\n throw respondToInvalidSessionToken({\n params: {api, config, logger},\n request,\n retryRequest: true,\n });\n }\n\n throw new Response(undefined, {\n status: 500,\n statusText: 'Internal Server Error',\n });\n }\n }\n\n private async handleAfterAuthHook(\n params: BasicParams,\n session: Session,\n request: Request,\n sessionToken: string,\n ) {\n const {config} = params;\n await config.idempotentPromiseHandler.handlePromise({\n promiseFunction: () => {\n return triggerAfterAuthHook(params, session, request, this);\n },\n identifier: sessionToken,\n });\n }\n}\n"],"names":["InvalidJwtError","WITHIN_MILLISECONDS_OF_EXPIRY","RequestedTokenType","handleClientErrorFactory","getShopFromRequest","invalidateAccessToken","respondToInvalidSessionToken","HttpResponseError","triggerAfterAuthHook"],"mappings":";;;;;;;;;;;;;MAyBa,qBAAqB,CAAA;AAGtB,IAAA,GAAG;AAKH,IAAA,MAAM;AACN,IAAA,MAAM;AAEhB,IAAA,WAAA,CAAmB,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAgC,EAAA;AACrE,QAAA,IAAI,CAAC,GAAG,GAAG,GAAG;AACd,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;AACpB,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;IACtB;AAEO,IAAA,MAAM,sBAAsB,CAAC,QAAiB,IAAkB;AAEhE,IAAA,MAAM,YAAY,CACvB,OAAgB,EAChB,cAA8B,EAAA;QAE9B,MAAM,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAC,GAAG,IAAI;QAClC,MAAM,EAAC,IAAI,EAAE,OAAO,EAAE,YAAY,EAAC,GAAG,cAAc;AAEpD,QAAA,IAAI,CAAC,YAAY;YAAE,MAAM,IAAIA,0BAAe,EAAE;AAE9C,QAAA,IACE,CAAC,OAAO;YACR,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAEC,4DAA6B,CAAC,EAC3D;YACA,MAAM,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAC,IAAI,EAAC,CAAC;YAC7C,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAC,IAAI,EAAC,CAAC;YACtD,MAAM,EAAC,OAAO,EAAE,cAAc,EAAC,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC;gBACzD,OAAO;gBACP,YAAY;gBACZ,IAAI;gBACJ,kBAAkB,EAAEC,6BAAkB,CAAC,kBAAkB;AAC1D,aAAA,CAAC;YAEF,MAAM,MAAM,CAAC,cAAe,CAAC,YAAY,CAAC,cAAc,CAAC;YAEzD,IAAI,UAAU,GAAG,cAAc;AAE/B,YAAA,IAAI,MAAM,CAAC,eAAe,EAAE;gBAC1B,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE,EAAC,IAAI,EAAC,CAAC;gBACrD,MAAM,EAAC,OAAO,EAAE,aAAa,EAAC,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC;oBACxD,OAAO;oBACP,YAAY;oBACZ,IAAI;oBACJ,kBAAkB,EAAEA,6BAAkB,CAAC,iBAAiB;AACzD,iBAAA,CAAC;gBAEF,MAAM,MAAM,CAAC,cAAe,CAAC,YAAY,CAAC,aAAa,CAAC;gBACxD,UAAU,GAAG,aAAa;YAC5B;AAEA,YAAA,MAAM,CAAC,KAAK,CAAC,qDAAqD,EAAE;gBAClE,IAAI,EAAE,UAAU,CAAC,IAAI;gBACrB,QAAQ,EAAE,UAAU,CAAC,QAAQ;AAC9B,aAAA,CAAC;AAEF,YAAA,IAAI;AACF,gBAAA,MAAM,IAAI,CAAC,mBAAmB,CAC5B,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAC,EACrB,UAAU,EACV,OAAO,EACP,YAAY,CACb;YACH;YAAE,OAAO,eAAe,EAAE;AACxB,gBAAA,IAAI,eAAe,YAAY,QAAQ,EAAE;AACvC,oBAAA,MAAM,eAAe;gBACvB;AAEA,gBAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,oBAAA,MAAM,EAAE,GAAG;AACX,oBAAA,UAAU,EAAE,uBAAuB;AACpC,iBAAA,CAAC;YACJ;AAEA,YAAA,OAAO,UAAU;QACnB;AAEA,QAAA,OAAO,OAAQ;IACjB;AAEO,IAAA,iBAAiB,CAAC,OAAgB,EAAA;QACvC,MAAM,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAC,GAAG,IAAI;AAClC,QAAA,OAAOC,0CAAwB,CAAC;YAC9B,OAAO;YACP,OAAO,EAAE,OAAO,EAAC,OAAO,EAAE,KAAK,EAAiB,KAAI;gBAClD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,GAAG,EAAE;AAC/B,oBAAA,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE;AACjD,wBAAA,IAAI,EAAEC,qCAAkB,CAAC,OAAO,CAAC;AAClC,qBAAA,CAAC;AACF,oBAAA,MAAMC,2CAAqB,CAAC,EAAC,MAAM,EAAO,MAAM,EAAC,EAAE,OAAO,CAAC;AAE3D,oBAAAC,yDAA4B,CAAC;AAC3B,wBAAA,MAAM,EAAE,EAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAC;wBAC7B,OAAO;AACR,qBAAA,CAAC;gBACJ;YACF,CAAC;AACF,SAAA,CAAC;IACJ;IAEQ,MAAM,aAAa,CAAC,EAC1B,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,kBAAkB,GAMnB,EAAA;QACC,MAAM,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAC,GAAG,IAAI;AAElC,QAAA,IAAI;AACF,YAAA,OAAO,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC;gBAClC,YAAY;gBACZ,IAAI;gBACJ,kBAAkB;AAClB,gBAAA,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,2BAA2B;AACpD,aAAA,CAAC;QACJ;QAAE,OAAO,KAAK,EAAE;YACd,IACE,KAAK,YAAYN,0BAAe;iBAC/B,KAAK,YAAYO,4BAAiB;AACjC,oBAAA,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,GAAG;oBAC3B,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,KAAK,uBAAuB,CAAC,EACzD;AACA,gBAAA,MAAMD,yDAA4B,CAAC;AACjC,oBAAA,MAAM,EAAE,EAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAC;oBAC7B,OAAO;AACP,oBAAA,YAAY,EAAE,IAAI;AACnB,iBAAA,CAAC;YACJ;AAEA,YAAA,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE;AAC5B,gBAAA,MAAM,EAAE,GAAG;AACX,gBAAA,UAAU,EAAE,uBAAuB;AACpC,aAAA,CAAC;QACJ;IACF;IAEQ,MAAM,mBAAmB,CAC/B,MAAmB,EACnB,OAAgB,EAChB,OAAgB,EAChB,YAAoB,EAAA;AAEpB,QAAA,MAAM,EAAC,MAAM,EAAC,GAAG,MAAM;AACvB,QAAA,MAAM,MAAM,CAAC,wBAAwB,CAAC,aAAa,CAAC;YAClD,eAAe,EAAE,MAAK;gBACpB,OAAOE,yCAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;YAC7D,CAAC;AACD,YAAA,UAAU,EAAE,YAAY;AACzB,SAAA,CAAC;IACJ;AACD;;;;"}
|
|
@@ -36,16 +36,40 @@ function authenticateWebhookFactory(params) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
const session = await ensureValidOfflineSession.ensureValidOfflineSession(params, check.domain);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
let webhookContext;
|
|
40
|
+
if (check.webhookType === shopifyApi.WebhookType.Webhooks) {
|
|
41
|
+
webhookContext = {
|
|
42
|
+
apiVersion: check.apiVersion,
|
|
43
|
+
shop: check.domain,
|
|
44
|
+
topic: check.topic,
|
|
45
|
+
webhookId: check.webhookId,
|
|
46
|
+
payload: JSON.parse(rawBody),
|
|
47
|
+
subTopic: check.subTopic || undefined,
|
|
48
|
+
session: undefined,
|
|
49
|
+
admin: undefined,
|
|
50
|
+
webhookType: check.webhookType,
|
|
51
|
+
name: check.name,
|
|
52
|
+
triggeredAt: check.triggeredAt,
|
|
53
|
+
eventId: check.eventId,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
webhookContext = {
|
|
58
|
+
apiVersion: check.apiVersion,
|
|
59
|
+
shop: check.domain,
|
|
60
|
+
topic: check.topic,
|
|
61
|
+
webhookId: check.webhookId,
|
|
62
|
+
payload: JSON.parse(rawBody),
|
|
63
|
+
session: undefined,
|
|
64
|
+
admin: undefined,
|
|
65
|
+
webhookType: check.webhookType,
|
|
66
|
+
handle: check.handle,
|
|
67
|
+
action: check.action,
|
|
68
|
+
resourceId: check.resourceId,
|
|
69
|
+
triggeredAt: check.triggeredAt,
|
|
70
|
+
eventId: check.eventId,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
49
73
|
if (!session) {
|
|
50
74
|
return webhookContext;
|
|
51
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.js","sources":["../../../../../../src/server/authenticate/webhooks/authenticate.ts"],"sourcesContent":["import {WebhookValidationErrorReason} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\nimport {adminClientFactory} from '../../clients';\nimport {handleClientErrorFactory} from '../admin/helpers';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport type {\n AuthenticateWebhook,\n WebhookContext,\n WebhookContextWithoutSession,\n} from './types';\n\nexport function authenticateWebhookFactory<Topics extends string>(\n params: BasicParams,\n): AuthenticateWebhook<Topics> {\n const {api, logger} = params;\n\n return async function authenticate(\n request: Request,\n ): Promise<WebhookContext<Topics>> {\n if (request.method !== 'POST') {\n logger.debug(\n 'Received a non-POST request for a webhook. Only POST requests are allowed.',\n {url: request.url, method: request.method},\n );\n throw new Response(undefined, {\n status: 405,\n statusText: 'Method not allowed',\n });\n }\n\n const rawBody = await request.text();\n\n const check = await api.webhooks.validate({\n rawBody,\n rawRequest: request,\n });\n\n if (!check.valid) {\n if (check.reason === WebhookValidationErrorReason.InvalidHmac) {\n logger.debug('Webhook HMAC validation failed', check);\n throw new Response(undefined, {\n status: 401,\n statusText: 'Unauthorized',\n });\n } else {\n logger.debug('Webhook validation failed', check);\n throw new Response(undefined, {status: 400, statusText: 'Bad Request'});\n }\n }\n const session = await ensureValidOfflineSession(params, check.domain);\n
|
|
1
|
+
{"version":3,"file":"authenticate.js","sources":["../../../../../../src/server/authenticate/webhooks/authenticate.ts"],"sourcesContent":["import {WebhookValidationErrorReason, WebhookType} from '@shopify/shopify-api';\n\nimport type {BasicParams} from '../../types';\nimport {adminClientFactory} from '../../clients';\nimport {handleClientErrorFactory} from '../admin/helpers';\nimport {ensureValidOfflineSession} from '../../helpers';\n\nimport type {\n AuthenticateWebhook,\n WebhookContext,\n WebhookContextWithoutSession,\n} from './types';\n\nexport function authenticateWebhookFactory<Topics extends string>(\n params: BasicParams,\n): AuthenticateWebhook<Topics> {\n const {api, logger} = params;\n\n return async function authenticate(\n request: Request,\n ): Promise<WebhookContext<Topics>> {\n if (request.method !== 'POST') {\n logger.debug(\n 'Received a non-POST request for a webhook. Only POST requests are allowed.',\n {url: request.url, method: request.method},\n );\n throw new Response(undefined, {\n status: 405,\n statusText: 'Method not allowed',\n });\n }\n\n const rawBody = await request.text();\n\n const check = await api.webhooks.validate({\n rawBody,\n rawRequest: request,\n });\n\n if (!check.valid) {\n if (check.reason === WebhookValidationErrorReason.InvalidHmac) {\n logger.debug('Webhook HMAC validation failed', check);\n throw new Response(undefined, {\n status: 401,\n statusText: 'Unauthorized',\n });\n } else {\n logger.debug('Webhook validation failed', check);\n throw new Response(undefined, {status: 400, statusText: 'Bad Request'});\n }\n }\n const session = await ensureValidOfflineSession(params, check.domain);\n\n let webhookContext: WebhookContextWithoutSession<Topics>;\n\n if (check.webhookType === WebhookType.Webhooks) {\n webhookContext = {\n apiVersion: check.apiVersion,\n shop: check.domain,\n topic: check.topic as Topics,\n webhookId: check.webhookId,\n payload: JSON.parse(rawBody),\n subTopic: check.subTopic || undefined,\n session: undefined,\n admin: undefined,\n webhookType: check.webhookType,\n name: check.name,\n triggeredAt: check.triggeredAt,\n eventId: check.eventId,\n };\n } else {\n webhookContext = {\n apiVersion: check.apiVersion,\n shop: check.domain,\n topic: check.topic as Topics,\n webhookId: check.webhookId,\n payload: JSON.parse(rawBody),\n session: undefined,\n admin: undefined,\n webhookType: check.webhookType,\n handle: check.handle,\n action: check.action,\n resourceId: check.resourceId,\n triggeredAt: check.triggeredAt,\n eventId: check.eventId,\n };\n }\n\n if (!session) {\n return webhookContext;\n }\n\n const admin = adminClientFactory({\n params,\n session,\n handleClientError: handleClientErrorFactory({request}),\n });\n\n return {\n ...webhookContext,\n session,\n admin,\n };\n };\n}\n"],"names":["WebhookValidationErrorReason","ensureValidOfflineSession","WebhookType","adminClientFactory","handleClientErrorFactory"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flags.js","sources":["../../../../../src/server/future/flags.ts"],"sourcesContent":["import type {ConfigParams, Shopify} from '@shopify/shopify-api';\n\nimport {AppConfig} from '../config-types';\n\n// When adding new flags, you should also add them to the `TEST_FUTURE_FLAGS` object in `test-config.ts` to ensure that\n// it doesn't cause regressions.\nexport interface FutureFlags {\n /**\n * When enabled, embedded apps will fetch access tokens via [token exchange](https://shopify.dev/docs/apps/auth/get-access-tokens/token-exchange).\n * This assumes the app has scopes declared for [Shopify managing installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation).\n *\n * Learn more about this [new embedded app auth strategy](https://shopify.dev/docs/api/shopify-app-remix#embedded-auth-strategy).\n *\n * @default false\n */\n unstable_newEmbeddedAuthStrategy?: boolean;\n /**\n * When enabled, the app will start using expiring offline access tokens and automatically refresh them when they are close to expiring.\n *\n * @default false\n */\n expiringOfflineAccessTokens?: boolean;\n}\n\n// When adding new flags, use this format:\n// apiFutureFlag: Future extends FutureFlags ? Future['remixFutureFlag'] : false;\nexport interface ApiFutureFlags<Future extends FutureFlagOptions> {\n expiringOfflineAccessTokens: Future extends FutureFlags\n ? Future['expiringOfflineAccessTokens']\n : false;\n unstable_managedPricingSupport: true;\n}\n\nexport type ApiConfigWithFutureFlags<Future extends FutureFlagOptions> =\n ConfigParams<ApiFutureFlags<Future>>;\n\nexport type FutureFlagOptions = FutureFlags | undefined;\n\nexport type FeatureEnabled<\n Future extends FutureFlagOptions,\n Flag extends keyof FutureFlags,\n> = Future extends FutureFlags\n ? Future[Flag] extends true\n ? true\n : false\n : false;\n\nexport function logDisabledFutureFlags(\n config: AppConfig,\n logger: Shopify['logger'],\n) {\n const logFlag = (flag: string, message: string) =>\n logger.info(`Future flag ${flag} is disabled.\\n\\n ${message}\\n`);\n\n if (!config.future.unstable_newEmbeddedAuthStrategy) {\n logFlag(\n 'unstable_newEmbeddedAuthStrategy',\n 'Enable this to use OAuth token exchange instead of auth code to generate API access tokens.' +\n '\\n Your app must be using Shopify managed install: https://shopify.dev/docs/apps/auth/installation',\n );\n }\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"flags.js","sources":["../../../../../src/server/future/flags.ts"],"sourcesContent":["import type {ConfigParams, Shopify} from '@shopify/shopify-api';\n\nimport {AppConfig} from '../config-types';\n\n// When adding new flags, you should also add them to the `TEST_FUTURE_FLAGS` object in `test-config.ts` to ensure that\n// it doesn't cause regressions.\n/**\n * Set future flags using the `future` configuration field to opt in to upcoming breaking changes.\n *\n * With this feature, you can prepare for major releases ahead of time, as well as try out new features before they are released.\n * @publicDocs\n */\nexport interface FutureFlags {\n /**\n * When enabled, embedded apps will fetch access tokens via [token exchange](https://shopify.dev/docs/apps/auth/get-access-tokens/token-exchange).\n * This assumes the app has scopes declared for [Shopify managing installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation).\n *\n * Learn more about this [new embedded app auth strategy](https://shopify.dev/docs/api/shopify-app-remix#embedded-auth-strategy).\n *\n * @default false\n */\n unstable_newEmbeddedAuthStrategy?: boolean;\n /**\n * When enabled, the app will start using expiring offline access tokens and automatically refresh them when they are close to expiring.\n *\n * @default false\n */\n expiringOfflineAccessTokens?: boolean;\n}\n\n// When adding new flags, use this format:\n// apiFutureFlag: Future extends FutureFlags ? Future['remixFutureFlag'] : false;\nexport interface ApiFutureFlags<Future extends FutureFlagOptions> {\n expiringOfflineAccessTokens: Future extends FutureFlags\n ? Future['expiringOfflineAccessTokens']\n : false;\n unstable_managedPricingSupport: true;\n}\n\nexport type ApiConfigWithFutureFlags<Future extends FutureFlagOptions> =\n ConfigParams<ApiFutureFlags<Future>>;\n\nexport type FutureFlagOptions = FutureFlags | undefined;\n\nexport type FeatureEnabled<\n Future extends FutureFlagOptions,\n Flag extends keyof FutureFlags,\n> = Future extends FutureFlags\n ? Future[Flag] extends true\n ? true\n : false\n : false;\n\nexport function logDisabledFutureFlags(\n config: AppConfig,\n logger: Shopify['logger'],\n) {\n const logFlag = (flag: string, message: string) =>\n logger.info(`Future flag ${flag} is disabled.\\n\\n ${message}\\n`);\n\n if (!config.future.unstable_newEmbeddedAuthStrategy) {\n logFlag(\n 'unstable_newEmbeddedAuthStrategy',\n 'Enable this to use OAuth token exchange instead of auth code to generate API access tokens.' +\n '\\n Your app must be using Shopify managed install: https://shopify.dev/docs/apps/auth/installation',\n );\n }\n}\n"],"names":[],"mappings":";;AAqDM,SAAU,sBAAsB,CACpC,MAAiB,EACjB,MAAyB,EAAA;AAEzB,IAAA,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,OAAe,KAC5C,MAAM,CAAC,IAAI,CAAC,CAAA,YAAA,EAAe,IAAI,sBAAsB,OAAO,CAAA,EAAA,CAAI,CAAC;AAEnE,IAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,gCAAgC,EAAE;QACnD,OAAO,CACL,kCAAkC,EAClC,6FAA6F;AAC3F,YAAA,qGAAqG,CACxG;IACH;AACF;;;;"}
|
|
@@ -28,6 +28,7 @@ var flags = require('./future/flags.js');
|
|
|
28
28
|
*
|
|
29
29
|
* @param appConfig Configuration options for your Shopify app, such as the scopes your app needs.
|
|
30
30
|
* @returns `ShopifyApp` An object constructed using your appConfig. It has methods for interacting with Shopify.
|
|
31
|
+
* @publicDocs
|
|
31
32
|
*
|
|
32
33
|
* @example
|
|
33
34
|
* <caption>The minimum viable configuration</caption>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shopify-app.js","sources":["../../../../src/server/shopify-app.ts"],"sourcesContent":["import '@shopify/shopify-api/adapters/web-api';\nimport {\n ConfigInterface as ApiConfig,\n ShopifyError,\n shopifyApi,\n} from '@shopify/shopify-api';\nimport {SessionStorage} from '@shopify/shopify-app-session-storage';\n\nimport {type AppConfig, type AppConfigArg} from './config-types';\nimport {\n AppDistribution,\n type BasicParams,\n type ShopifyApp,\n type ShopifyAppBase,\n type AdminApp,\n type SingleMerchantApp,\n type AppStoreApp,\n} from './types';\nimport {SHOPIFY_REMIX_LIBRARY_VERSION} from './version';\nimport {registerWebhooksFactory} from './authenticate/webhooks';\nimport {authStrategyFactory} from './authenticate/admin/authenticate';\nimport {authenticateWebhookFactory} from './authenticate/webhooks/authenticate';\nimport {overrideLogger} from './override-logger';\nimport {addDocumentResponseHeadersFactory} from './authenticate/helpers';\nimport {loginFactory} from './authenticate/login/login';\nimport {unauthenticatedAdminContextFactory} from './unauthenticated/admin';\nimport {authenticatePublicFactory} from './authenticate/public';\nimport {unauthenticatedStorefrontContextFactory} from './unauthenticated/storefront';\nimport {AuthCodeFlowStrategy} from './authenticate/admin/strategies/auth-code-flow';\nimport {TokenExchangeStrategy} from './authenticate/admin/strategies/token-exchange';\nimport {MerchantCustomAuth} from './authenticate/admin/strategies/merchant-custom-app';\nimport {IdempotentPromiseHandler} from './authenticate/helpers/idempotent-promise-handler';\nimport {authenticateFlowFactory} from './authenticate/flow/authenticate';\nimport {authenticateFulfillmentServiceFactory} from './authenticate/fulfillment-service/authenticate';\nimport {FutureFlagOptions, logDisabledFutureFlags} from './future/flags';\n\n/**\n * Creates an object your app will use to interact with Shopify.\n *\n * @param appConfig Configuration options for your Shopify app, such as the scopes your app needs.\n * @returns `ShopifyApp` An object constructed using your appConfig. It has methods for interacting with Shopify.\n *\n * @example\n * <caption>The minimum viable configuration</caption>\n * ```ts\n * // /shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n *\n * const shopify = shopifyApp({\n * apiKey: process.env.SHOPIFY_API_KEY!,\n * apiSecretKey: process.env.SHOPIFY_API_SECRET!,\n * scopes: process.env.SCOPES?.split(\",\")!,\n * appUrl: process.env.SHOPIFY_APP_URL!,\n * });\n * export default shopify;\n * ```\n */\nexport function shopifyApp<\n Config extends AppConfigArg<Storage, Future>,\n Storage extends SessionStorage,\n Future extends FutureFlagOptions = Config['future'],\n>(appConfig: Readonly<Config>): ShopifyApp<Config> {\n const api = deriveApi(appConfig);\n const config = deriveConfig<Storage>(appConfig, api.config);\n const logger = overrideLogger(api.logger);\n\n if (appConfig.webhooks) {\n api.webhooks.addHandlers(appConfig.webhooks);\n }\n\n const params: BasicParams = {api, config, logger};\n\n let strategy;\n if (config.distribution === AppDistribution.ShopifyAdmin) {\n strategy = new MerchantCustomAuth(params);\n } else if (\n config.future.unstable_newEmbeddedAuthStrategy &&\n config.isEmbeddedApp\n ) {\n strategy = new TokenExchangeStrategy(params);\n } else {\n strategy = new AuthCodeFlowStrategy(params);\n }\n\n const authStrategy = authStrategyFactory<Config>({\n ...params,\n strategy,\n });\n\n const shopify:\n | AdminApp<Config>\n | AppStoreApp<Config>\n | SingleMerchantApp<Config> = {\n sessionStorage: config.sessionStorage,\n addDocumentResponseHeaders: addDocumentResponseHeadersFactory(params),\n registerWebhooks: registerWebhooksFactory(params),\n authenticate: {\n admin: authStrategy,\n flow: authenticateFlowFactory(params),\n public: authenticatePublicFactory(params),\n fulfillmentService: authenticateFulfillmentServiceFactory(params),\n webhook: authenticateWebhookFactory<string>(params),\n },\n unauthenticated: {\n admin: unauthenticatedAdminContextFactory(params),\n storefront: unauthenticatedStorefrontContextFactory(params),\n },\n };\n\n if (\n isAppStoreApp(shopify, appConfig) ||\n isSingleMerchantApp(shopify, appConfig)\n ) {\n shopify.login = loginFactory(params);\n }\n\n logDisabledFutureFlags(config, logger);\n\n return shopify as ShopifyApp<Config>;\n}\n\nfunction isAppStoreApp<Config extends AppConfigArg>(\n _shopify: ShopifyAppBase<Config>,\n config: Config,\n): _shopify is AppStoreApp<Config> {\n return config.distribution === AppDistribution.AppStore;\n}\n\nfunction isSingleMerchantApp<Config extends AppConfigArg>(\n _shopify: ShopifyAppBase<Config>,\n config: Config,\n): _shopify is SingleMerchantApp<Config> {\n return config.distribution === AppDistribution.SingleMerchant;\n}\n\n// This function is only exported so we can unit test it without having to mock the underlying module.\n// It's not available to consumers of the library because it is not exported in the index module, and never should be.\nexport function deriveApi(appConfig: AppConfigArg): BasicParams['api'] {\n let appUrl: URL;\n try {\n appUrl = new URL(appConfig.appUrl);\n } catch (error) {\n const message =\n appConfig.appUrl === ''\n ? `Detected an empty appUrl configuration, please make sure to set the necessary environment variables.\\n` +\n `If you're deploying your app, you can find more information at https://shopify.dev/docs/apps/launch/deployment/deploy-web-app/deploy-to-hosting-service#step-4-set-up-environment-variables`\n : `Invalid appUrl configuration '${appConfig.appUrl}', please provide a valid URL.`;\n throw new ShopifyError(message);\n }\n\n /* eslint-disable no-process-env */\n if (appUrl.hostname === 'localhost' && !appUrl.port && process.env.PORT) {\n appUrl.port = process.env.PORT;\n }\n /* eslint-enable no-process-env */\n appConfig.appUrl = appUrl.origin;\n\n let userAgentPrefix = `Shopify Remix Library v${SHOPIFY_REMIX_LIBRARY_VERSION}`;\n if (appConfig.userAgentPrefix) {\n userAgentPrefix = `${appConfig.userAgentPrefix} | ${userAgentPrefix}`;\n }\n\n return shopifyApi({\n ...appConfig,\n hostName: appUrl.host,\n hostScheme: appUrl.protocol.replace(':', '') as 'http' | 'https',\n userAgentPrefix,\n isEmbeddedApp: appConfig.isEmbeddedApp ?? true,\n apiVersion: appConfig.apiVersion,\n isCustomStoreApp: appConfig.distribution === AppDistribution.ShopifyAdmin,\n billing: appConfig.billing as ApiConfig['billing'],\n future: {\n unstable_managedPricingSupport: true,\n },\n _logDisabledFutureFlags: false,\n });\n}\n\nfunction deriveConfig<Storage extends SessionStorage>(\n appConfig: AppConfigArg,\n apiConfig: ApiConfig,\n): AppConfig<Storage> {\n if (\n !appConfig.sessionStorage &&\n appConfig.distribution !== AppDistribution.ShopifyAdmin\n ) {\n throw new ShopifyError(\n 'Please provide a valid session storage. Refer to https://github.com/Shopify/shopify-app-js/blob/main/README.md#session-storage-options for options.',\n );\n }\n\n const authPathPrefix = appConfig.authPathPrefix || '/auth';\n appConfig.distribution = appConfig.distribution ?? AppDistribution.AppStore;\n\n return {\n ...appConfig,\n ...apiConfig,\n billing: appConfig.billing as ApiConfig['billing'],\n scopes: apiConfig.scopes,\n idempotentPromiseHandler: new IdempotentPromiseHandler(),\n canUseLoginForm: appConfig.distribution !== AppDistribution.ShopifyAdmin,\n useOnlineTokens: appConfig.useOnlineTokens ?? false,\n hooks: appConfig.hooks ?? {},\n sessionStorage: appConfig.sessionStorage as Storage,\n future: appConfig.future ?? {},\n auth: {\n path: authPathPrefix,\n callbackPath: `${authPathPrefix}/callback`,\n patchSessionTokenPath: `${authPathPrefix}/session-token`,\n exitIframePath: `${authPathPrefix}/exit-iframe`,\n loginPath: `${authPathPrefix}/login`,\n },\n distribution: appConfig.distribution,\n };\n}\n"],"names":["overrideLogger","AppDistribution","MerchantCustomAuth","TokenExchangeStrategy","AuthCodeFlowStrategy","authStrategyFactory","addDocumentResponseHeadersFactory","registerWebhooksFactory","authenticateFlowFactory","authenticatePublicFactory","authenticateFulfillmentServiceFactory","authenticateWebhookFactory","unauthenticatedAdminContextFactory","unauthenticatedStorefrontContextFactory","loginFactory","logDisabledFutureFlags","ShopifyError","SHOPIFY_REMIX_LIBRARY_VERSION","shopifyApi","IdempotentPromiseHandler"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shopify-app.js","sources":["../../../../src/server/shopify-app.ts"],"sourcesContent":["import '@shopify/shopify-api/adapters/web-api';\nimport {\n ConfigInterface as ApiConfig,\n ShopifyError,\n shopifyApi,\n} from '@shopify/shopify-api';\nimport {SessionStorage} from '@shopify/shopify-app-session-storage';\n\nimport {type AppConfig, type AppConfigArg} from './config-types';\nimport {\n AppDistribution,\n type BasicParams,\n type ShopifyApp,\n type ShopifyAppBase,\n type AdminApp,\n type SingleMerchantApp,\n type AppStoreApp,\n} from './types';\nimport {SHOPIFY_REMIX_LIBRARY_VERSION} from './version';\nimport {registerWebhooksFactory} from './authenticate/webhooks';\nimport {authStrategyFactory} from './authenticate/admin/authenticate';\nimport {authenticateWebhookFactory} from './authenticate/webhooks/authenticate';\nimport {overrideLogger} from './override-logger';\nimport {addDocumentResponseHeadersFactory} from './authenticate/helpers';\nimport {loginFactory} from './authenticate/login/login';\nimport {unauthenticatedAdminContextFactory} from './unauthenticated/admin';\nimport {authenticatePublicFactory} from './authenticate/public';\nimport {unauthenticatedStorefrontContextFactory} from './unauthenticated/storefront';\nimport {AuthCodeFlowStrategy} from './authenticate/admin/strategies/auth-code-flow';\nimport {TokenExchangeStrategy} from './authenticate/admin/strategies/token-exchange';\nimport {MerchantCustomAuth} from './authenticate/admin/strategies/merchant-custom-app';\nimport {IdempotentPromiseHandler} from './authenticate/helpers/idempotent-promise-handler';\nimport {authenticateFlowFactory} from './authenticate/flow/authenticate';\nimport {authenticateFulfillmentServiceFactory} from './authenticate/fulfillment-service/authenticate';\nimport {FutureFlagOptions, logDisabledFutureFlags} from './future/flags';\n\n/**\n * Creates an object your app will use to interact with Shopify.\n *\n * @param appConfig Configuration options for your Shopify app, such as the scopes your app needs.\n * @returns `ShopifyApp` An object constructed using your appConfig. It has methods for interacting with Shopify.\n * @publicDocs\n *\n * @example\n * <caption>The minimum viable configuration</caption>\n * ```ts\n * // /shopify.server.ts\n * import { shopifyApp } from \"@shopify/shopify-app-remix/server\";\n *\n * const shopify = shopifyApp({\n * apiKey: process.env.SHOPIFY_API_KEY!,\n * apiSecretKey: process.env.SHOPIFY_API_SECRET!,\n * scopes: process.env.SCOPES?.split(\",\")!,\n * appUrl: process.env.SHOPIFY_APP_URL!,\n * });\n * export default shopify;\n * ```\n */\nexport function shopifyApp<\n Config extends AppConfigArg<Storage, Future>,\n Storage extends SessionStorage,\n Future extends FutureFlagOptions = Config['future'],\n>(appConfig: Readonly<Config>): ShopifyApp<Config> {\n const api = deriveApi(appConfig);\n const config = deriveConfig<Storage>(appConfig, api.config);\n const logger = overrideLogger(api.logger);\n\n if (appConfig.webhooks) {\n api.webhooks.addHandlers(appConfig.webhooks);\n }\n\n const params: BasicParams = {api, config, logger};\n\n let strategy;\n if (config.distribution === AppDistribution.ShopifyAdmin) {\n strategy = new MerchantCustomAuth(params);\n } else if (\n config.future.unstable_newEmbeddedAuthStrategy &&\n config.isEmbeddedApp\n ) {\n strategy = new TokenExchangeStrategy(params);\n } else {\n strategy = new AuthCodeFlowStrategy(params);\n }\n\n const authStrategy = authStrategyFactory<Config>({\n ...params,\n strategy,\n });\n\n const shopify:\n | AdminApp<Config>\n | AppStoreApp<Config>\n | SingleMerchantApp<Config> = {\n sessionStorage: config.sessionStorage,\n addDocumentResponseHeaders: addDocumentResponseHeadersFactory(params),\n registerWebhooks: registerWebhooksFactory(params),\n authenticate: {\n admin: authStrategy,\n flow: authenticateFlowFactory(params),\n public: authenticatePublicFactory(params),\n fulfillmentService: authenticateFulfillmentServiceFactory(params),\n webhook: authenticateWebhookFactory<string>(params),\n },\n unauthenticated: {\n admin: unauthenticatedAdminContextFactory(params),\n storefront: unauthenticatedStorefrontContextFactory(params),\n },\n };\n\n if (\n isAppStoreApp(shopify, appConfig) ||\n isSingleMerchantApp(shopify, appConfig)\n ) {\n shopify.login = loginFactory(params);\n }\n\n logDisabledFutureFlags(config, logger);\n\n return shopify as ShopifyApp<Config>;\n}\n\nfunction isAppStoreApp<Config extends AppConfigArg>(\n _shopify: ShopifyAppBase<Config>,\n config: Config,\n): _shopify is AppStoreApp<Config> {\n return config.distribution === AppDistribution.AppStore;\n}\n\nfunction isSingleMerchantApp<Config extends AppConfigArg>(\n _shopify: ShopifyAppBase<Config>,\n config: Config,\n): _shopify is SingleMerchantApp<Config> {\n return config.distribution === AppDistribution.SingleMerchant;\n}\n\n// This function is only exported so we can unit test it without having to mock the underlying module.\n// It's not available to consumers of the library because it is not exported in the index module, and never should be.\nexport function deriveApi(appConfig: AppConfigArg): BasicParams['api'] {\n let appUrl: URL;\n try {\n appUrl = new URL(appConfig.appUrl);\n } catch (error) {\n const message =\n appConfig.appUrl === ''\n ? `Detected an empty appUrl configuration, please make sure to set the necessary environment variables.\\n` +\n `If you're deploying your app, you can find more information at https://shopify.dev/docs/apps/launch/deployment/deploy-web-app/deploy-to-hosting-service#step-4-set-up-environment-variables`\n : `Invalid appUrl configuration '${appConfig.appUrl}', please provide a valid URL.`;\n throw new ShopifyError(message);\n }\n\n /* eslint-disable no-process-env */\n if (appUrl.hostname === 'localhost' && !appUrl.port && process.env.PORT) {\n appUrl.port = process.env.PORT;\n }\n /* eslint-enable no-process-env */\n appConfig.appUrl = appUrl.origin;\n\n let userAgentPrefix = `Shopify Remix Library v${SHOPIFY_REMIX_LIBRARY_VERSION}`;\n if (appConfig.userAgentPrefix) {\n userAgentPrefix = `${appConfig.userAgentPrefix} | ${userAgentPrefix}`;\n }\n\n return shopifyApi({\n ...appConfig,\n hostName: appUrl.host,\n hostScheme: appUrl.protocol.replace(':', '') as 'http' | 'https',\n userAgentPrefix,\n isEmbeddedApp: appConfig.isEmbeddedApp ?? true,\n apiVersion: appConfig.apiVersion,\n isCustomStoreApp: appConfig.distribution === AppDistribution.ShopifyAdmin,\n billing: appConfig.billing as ApiConfig['billing'],\n future: {\n unstable_managedPricingSupport: true,\n },\n _logDisabledFutureFlags: false,\n });\n}\n\nfunction deriveConfig<Storage extends SessionStorage>(\n appConfig: AppConfigArg,\n apiConfig: ApiConfig,\n): AppConfig<Storage> {\n if (\n !appConfig.sessionStorage &&\n appConfig.distribution !== AppDistribution.ShopifyAdmin\n ) {\n throw new ShopifyError(\n 'Please provide a valid session storage. Refer to https://github.com/Shopify/shopify-app-js/blob/main/README.md#session-storage-options for options.',\n );\n }\n\n const authPathPrefix = appConfig.authPathPrefix || '/auth';\n appConfig.distribution = appConfig.distribution ?? AppDistribution.AppStore;\n\n return {\n ...appConfig,\n ...apiConfig,\n billing: appConfig.billing as ApiConfig['billing'],\n scopes: apiConfig.scopes,\n idempotentPromiseHandler: new IdempotentPromiseHandler(),\n canUseLoginForm: appConfig.distribution !== AppDistribution.ShopifyAdmin,\n useOnlineTokens: appConfig.useOnlineTokens ?? false,\n hooks: appConfig.hooks ?? {},\n sessionStorage: appConfig.sessionStorage as Storage,\n future: appConfig.future ?? {},\n auth: {\n path: authPathPrefix,\n callbackPath: `${authPathPrefix}/callback`,\n patchSessionTokenPath: `${authPathPrefix}/session-token`,\n exitIframePath: `${authPathPrefix}/exit-iframe`,\n loginPath: `${authPathPrefix}/login`,\n },\n distribution: appConfig.distribution,\n };\n}\n"],"names":["overrideLogger","AppDistribution","MerchantCustomAuth","TokenExchangeStrategy","AuthCodeFlowStrategy","authStrategyFactory","addDocumentResponseHeadersFactory","registerWebhooksFactory","authenticateFlowFactory","authenticatePublicFactory","authenticateFulfillmentServiceFactory","authenticateWebhookFactory","unauthenticatedAdminContextFactory","unauthenticatedStorefrontContextFactory","loginFactory","logDisabledFutureFlags","ShopifyError","SHOPIFY_REMIX_LIBRARY_VERSION","shopifyApi","IdempotentPromiseHandler"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sources":["../../../../src/server/version.ts"],"sourcesContent":["export const SHOPIFY_REMIX_LIBRARY_VERSION = '4.
|
|
1
|
+
{"version":3,"file":"version.js","sources":["../../../../src/server/version.ts"],"sourcesContent":["export const SHOPIFY_REMIX_LIBRARY_VERSION = '4.2.1';\n"],"names":[],"mappings":";;AAAO,MAAM,6BAA6B,GAAG;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppProvider.mjs","sources":["../../../../../../src/react/components/AppProvider/AppProvider.tsx"],"sourcesContent":["import {\n AppProvider as PolarisAppProvider,\n AppProviderProps as PolarisAppProviderProps,\n} from '@shopify/polaris';\n// This leads to some TS errors, but it does compile to something that works\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport englishI18n from '@shopify/polaris/locales/en.json' with {type: 'json'};\nimport {useNavigate} from '@remix-run/react';\nimport {useEffect} from 'react';\n\nimport {APP_BRIDGE_URL} from '../../const';\nimport {RemixPolarisLink} from '../RemixPolarisLink';\n\nexport interface AppProviderProps
|
|
1
|
+
{"version":3,"file":"AppProvider.mjs","sources":["../../../../../../src/react/components/AppProvider/AppProvider.tsx"],"sourcesContent":["import {\n AppProvider as PolarisAppProvider,\n AppProviderProps as PolarisAppProviderProps,\n} from '@shopify/polaris';\n// This leads to some TS errors, but it does compile to something that works\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport englishI18n from '@shopify/polaris/locales/en.json' with {type: 'json'};\nimport {useNavigate} from '@remix-run/react';\nimport {useEffect} from 'react';\n\nimport {APP_BRIDGE_URL} from '../../const';\nimport {RemixPolarisLink} from '../RemixPolarisLink';\n\n/**\n * Props for the `AppProvider` component.\n * @publicDocs\n */\nexport interface AppProviderProps extends Omit<\n PolarisAppProviderProps,\n 'linkComponent' | 'i18n'\n> {\n /**\n * The API key for your Shopify app. This is the `Client ID` from the Partner Dashboard.\n *\n * When using the Shopify CLI, this is the `SHOPIFY_API_KEY` environment variable. If you're using the environment\n * variable, then you need to pass it from the loader to the component.\n */\n apiKey: string;\n /**\n * Whether the app is loaded inside the Shopify Admin. Default is `true`.\n *\n * {@link https://shopify.dev/docs/apps/admin/embedded-app-home}\n */\n isEmbeddedApp?: boolean;\n /**\n * The internationalization (i18n) configuration for your Polaris provider.\n *\n * {@link https://polaris.shopify.com/components/utilities/app-provider}\n */\n i18n?: PolarisAppProviderProps['i18n'];\n /**\n * Used internally by Shopify. You don't need to set this.\n * @private\n */\n __APP_BRIDGE_URL?: string;\n}\n\n/**\n * Sets up the Polaris `AppProvider` and injects the App Bridge script.\n *\n * This component extends the [`AppProvider`](https://polaris.shopify.com/components/utilities/app-provider) component\n * from Polaris, and accepts all of its props except for `linkComponent`, which is overridden to use the Remix `Link`\n * component.\n *\n * {@link https://polaris.shopify.com/components/utilities/app-provider}\n * {@link https://shopify.dev/tools/app-bridge}\n *\n * @example\n * <caption>Set up AppProvider.</caption>\n * <description>Wrap your app in the `AppProvider` component and pass in your API key.</description>\n * ```ts\n * // /app/routes/**\\/*.ts\n * import {authenticate} from '~/shopify.server';\n * import {AppProvider} from '@shopify/shopify-app-remix/react';\n *\n * export async function loader({ request }) {\n * await authenticate.admin(request);\n *\n * return json({ apiKey: process.env.SHOPIFY_API_KEY });\n * }\n *\n * export default function App() {\n * const { apiKey } = useLoaderData();\n *\n * return (\n * <AppProvider isEmbeddedApp apiKey={apiKey}>\n * <Outlet />\n * </AppProvider>\n * );\n * }\n * ```\n *\n * @example\n * <caption>Localize Polaris components.</caption>\n * <description>Pass in a different locale for Polaris to translate its components.</description>\n * ```ts\n * // /app/routes/**\\/*.ts\n * import {authenticate} from '~/shopify.server';\n * import {AppProvider} from '@shopify/shopify-app-remix/react';\n *\n * export async function loader({ request }) {\n * await authenticate.admin(request);\n *\n * return json({\n * apiKey: process.env.SHOPIFY_API_KEY,\n * polarisTranslations: require(\"@shopify/polaris/locales/fr.json\"),\n * });\n * }\n *\n * export default function App() {\n * const { apiKey, polarisTranslations } = useLoaderData();\n *\n * return (\n * <AppProvider apiKey={apiKey} i18n={polarisTranslations}>\n * <Outlet />\n * </AppProvider>\n * );\n * }\n * ```\n */\nexport function AppProvider(props: AppProviderProps) {\n const {\n children,\n apiKey,\n i18n,\n isEmbeddedApp = true,\n __APP_BRIDGE_URL = APP_BRIDGE_URL,\n ...polarisProps\n } = props;\n\n const navigate = useNavigate();\n\n useEffect(() => {\n const handleNavigate = (event: Event) => {\n const href = (event.target as HTMLElement)?.getAttribute('href');\n if (href) {\n navigate(href);\n }\n };\n\n addEventListener('shopify:navigate', handleNavigate);\n\n return () => {\n removeEventListener('shopify:navigate', handleNavigate);\n };\n }, [navigate]);\n\n return (\n <>\n {isEmbeddedApp && <script src={__APP_BRIDGE_URL} data-api-key={apiKey} />}\n <PolarisAppProvider\n {...polarisProps}\n linkComponent={RemixPolarisLink}\n i18n={i18n || englishI18n}\n >\n {children}\n </PolarisAppProvider>\n </>\n );\n}\n"],"names":["_jsxs","_Fragment","_jsx","PolarisAppProvider"],"mappings":";;;;;;;;AAgDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DG;AACG,SAAU,WAAW,CAAC,KAAuB,EAAA;IACjD,MAAM,EACJ,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,aAAa,GAAG,IAAI,EACpB,gBAAgB,GAAG,cAAc,EACjC,GAAG,YAAY,EAChB,GAAG,KAAK;AAET,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE;IAE9B,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,cAAc,GAAG,CAAC,KAAY,KAAI;YACtC,MAAM,IAAI,GAAI,KAAK,CAAC,MAAsB,EAAE,YAAY,CAAC,MAAM,CAAC;YAChE,IAAI,IAAI,EAAE;gBACR,QAAQ,CAAC,IAAI,CAAC;YAChB;AACF,QAAA,CAAC;AAED,QAAA,gBAAgB,CAAC,kBAAkB,EAAE,cAAc,CAAC;AAEpD,QAAA,OAAO,MAAK;AACV,YAAA,mBAAmB,CAAC,kBAAkB,EAAE,cAAc,CAAC;AACzD,QAAA,CAAC;AACH,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;AAEd,IAAA,QACEA,IAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAA,CACG,aAAa,IAAIC,GAAA,CAAA,QAAA,EAAA,EAAQ,GAAG,EAAE,gBAAgB,EAAA,cAAA,EAAgB,MAAM,EAAA,CAAI,EACzEA,IAACC,aAAkB,EAAA,EAAA,GACb,YAAY,EAChB,aAAa,EAAE,gBAAgB,EAC/B,IAAI,EAAE,IAAI,IAAI,WAAW,EAAA,QAAA,EAExB,QAAQ,EAAA,CACU,CAAA,EAAA,CACpB;AAEP;;;;"}
|