@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopify/shopify-app-remix",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"description": "Shopify Remix - to simplify the building of Shopify Apps with Remix",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.10.0"
|
|
@@ -66,25 +66,25 @@
|
|
|
66
66
|
"Storefront API"
|
|
67
67
|
],
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@babel/preset-env": "^7.
|
|
70
|
-
"@remix-run/node": "^2.17.
|
|
71
|
-
"@remix-run/react": "^2.17.
|
|
72
|
-
"@remix-run/testing": "^2.17.
|
|
73
|
-
"@shopify/generate-docs": "^
|
|
69
|
+
"@babel/preset-env": "^7.29.7",
|
|
70
|
+
"@remix-run/node": "^2.17.5",
|
|
71
|
+
"@remix-run/react": "^2.17.5",
|
|
72
|
+
"@remix-run/testing": "^2.17.5",
|
|
73
|
+
"@shopify/generate-docs": "^1.2.0",
|
|
74
74
|
"@shopify/polaris": "^12.18.0",
|
|
75
75
|
"@shopify/react-testing": "^6.0.0",
|
|
76
|
-
"@shopify/shopify-app-session-storage-memory": "^
|
|
77
|
-
"@types/react": "^19.2.
|
|
76
|
+
"@shopify/shopify-app-session-storage-memory": "^6.0.1",
|
|
77
|
+
"@types/react": "^19.2.16",
|
|
78
78
|
"jest-fetch-mock": "^3.0.3"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"@remix-run/server-runtime": "^2.17.
|
|
82
|
-
"@shopify/admin-api-client": "^1.1.
|
|
83
|
-
"@shopify/shopify-api": "^
|
|
84
|
-
"@shopify/shopify-app-session-storage": "^
|
|
85
|
-
"@shopify/storefront-api-client": "^1.0.
|
|
81
|
+
"@remix-run/server-runtime": "^2.17.5",
|
|
82
|
+
"@shopify/admin-api-client": "^1.1.2",
|
|
83
|
+
"@shopify/shopify-api": "^13.1.0",
|
|
84
|
+
"@shopify/shopify-app-session-storage": "^5.0.1",
|
|
85
|
+
"@shopify/storefront-api-client": "^1.0.10",
|
|
86
86
|
"compare-versions": "^6.1.1",
|
|
87
|
-
"isbot": "^5.1.
|
|
87
|
+
"isbot": "^5.1.40"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
90
|
"@remix-run/node": "*",
|
|
@@ -102,6 +102,10 @@
|
|
|
102
102
|
},
|
|
103
103
|
"files": [
|
|
104
104
|
"dist/*",
|
|
105
|
+
"src",
|
|
106
|
+
"!src/**/__tests__",
|
|
107
|
+
"!src/**/*.test.ts",
|
|
108
|
+
"!src/**/*.test.tsx",
|
|
105
109
|
"!build/**/__tests__",
|
|
106
110
|
"!tsconfig.tsbuildinfo",
|
|
107
111
|
"!node_modules"
|
|
@@ -109,7 +113,7 @@
|
|
|
109
113
|
"scripts": {
|
|
110
114
|
"build-docs": "sh docs/build-docs.sh",
|
|
111
115
|
"validate-docs": "sh ./docs/build-docs.sh isTest && pnpm compare-docs",
|
|
112
|
-
"lint": "eslint .
|
|
116
|
+
"lint": "eslint .",
|
|
113
117
|
"build": "pnpm rollup && pnpm tsc -p ./tsconfig.build.json",
|
|
114
118
|
"tsc": "tsc",
|
|
115
119
|
"test": "jest",
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AppProvider as PolarisAppProvider,
|
|
3
|
+
AppProviderProps as PolarisAppProviderProps,
|
|
4
|
+
} from '@shopify/polaris';
|
|
5
|
+
// This leads to some TS errors, but it does compile to something that works
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
import englishI18n from '@shopify/polaris/locales/en.json' with {type: 'json'};
|
|
9
|
+
import {useNavigate} from '@remix-run/react';
|
|
10
|
+
import {useEffect} from 'react';
|
|
11
|
+
|
|
12
|
+
import {APP_BRIDGE_URL} from '../../const';
|
|
13
|
+
import {RemixPolarisLink} from '../RemixPolarisLink';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Props for the `AppProvider` component.
|
|
17
|
+
* @publicDocs
|
|
18
|
+
*/
|
|
19
|
+
export interface AppProviderProps extends Omit<
|
|
20
|
+
PolarisAppProviderProps,
|
|
21
|
+
'linkComponent' | 'i18n'
|
|
22
|
+
> {
|
|
23
|
+
/**
|
|
24
|
+
* The API key for your Shopify app. This is the `Client ID` from the Partner Dashboard.
|
|
25
|
+
*
|
|
26
|
+
* When using the Shopify CLI, this is the `SHOPIFY_API_KEY` environment variable. If you're using the environment
|
|
27
|
+
* variable, then you need to pass it from the loader to the component.
|
|
28
|
+
*/
|
|
29
|
+
apiKey: string;
|
|
30
|
+
/**
|
|
31
|
+
* Whether the app is loaded inside the Shopify Admin. Default is `true`.
|
|
32
|
+
*
|
|
33
|
+
* {@link https://shopify.dev/docs/apps/admin/embedded-app-home}
|
|
34
|
+
*/
|
|
35
|
+
isEmbeddedApp?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The internationalization (i18n) configuration for your Polaris provider.
|
|
38
|
+
*
|
|
39
|
+
* {@link https://polaris.shopify.com/components/utilities/app-provider}
|
|
40
|
+
*/
|
|
41
|
+
i18n?: PolarisAppProviderProps['i18n'];
|
|
42
|
+
/**
|
|
43
|
+
* Used internally by Shopify. You don't need to set this.
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
46
|
+
__APP_BRIDGE_URL?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Sets up the Polaris `AppProvider` and injects the App Bridge script.
|
|
51
|
+
*
|
|
52
|
+
* This component extends the [`AppProvider`](https://polaris.shopify.com/components/utilities/app-provider) component
|
|
53
|
+
* from Polaris, and accepts all of its props except for `linkComponent`, which is overridden to use the Remix `Link`
|
|
54
|
+
* component.
|
|
55
|
+
*
|
|
56
|
+
* {@link https://polaris.shopify.com/components/utilities/app-provider}
|
|
57
|
+
* {@link https://shopify.dev/tools/app-bridge}
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* <caption>Set up AppProvider.</caption>
|
|
61
|
+
* <description>Wrap your app in the `AppProvider` component and pass in your API key.</description>
|
|
62
|
+
* ```ts
|
|
63
|
+
* // /app/routes/**\/*.ts
|
|
64
|
+
* import {authenticate} from '~/shopify.server';
|
|
65
|
+
* import {AppProvider} from '@shopify/shopify-app-remix/react';
|
|
66
|
+
*
|
|
67
|
+
* export async function loader({ request }) {
|
|
68
|
+
* await authenticate.admin(request);
|
|
69
|
+
*
|
|
70
|
+
* return json({ apiKey: process.env.SHOPIFY_API_KEY });
|
|
71
|
+
* }
|
|
72
|
+
*
|
|
73
|
+
* export default function App() {
|
|
74
|
+
* const { apiKey } = useLoaderData();
|
|
75
|
+
*
|
|
76
|
+
* return (
|
|
77
|
+
* <AppProvider isEmbeddedApp apiKey={apiKey}>
|
|
78
|
+
* <Outlet />
|
|
79
|
+
* </AppProvider>
|
|
80
|
+
* );
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* <caption>Localize Polaris components.</caption>
|
|
86
|
+
* <description>Pass in a different locale for Polaris to translate its components.</description>
|
|
87
|
+
* ```ts
|
|
88
|
+
* // /app/routes/**\/*.ts
|
|
89
|
+
* import {authenticate} from '~/shopify.server';
|
|
90
|
+
* import {AppProvider} from '@shopify/shopify-app-remix/react';
|
|
91
|
+
*
|
|
92
|
+
* export async function loader({ request }) {
|
|
93
|
+
* await authenticate.admin(request);
|
|
94
|
+
*
|
|
95
|
+
* return json({
|
|
96
|
+
* apiKey: process.env.SHOPIFY_API_KEY,
|
|
97
|
+
* polarisTranslations: require("@shopify/polaris/locales/fr.json"),
|
|
98
|
+
* });
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* export default function App() {
|
|
102
|
+
* const { apiKey, polarisTranslations } = useLoaderData();
|
|
103
|
+
*
|
|
104
|
+
* return (
|
|
105
|
+
* <AppProvider apiKey={apiKey} i18n={polarisTranslations}>
|
|
106
|
+
* <Outlet />
|
|
107
|
+
* </AppProvider>
|
|
108
|
+
* );
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function AppProvider(props: AppProviderProps) {
|
|
113
|
+
const {
|
|
114
|
+
children,
|
|
115
|
+
apiKey,
|
|
116
|
+
i18n,
|
|
117
|
+
isEmbeddedApp = true,
|
|
118
|
+
__APP_BRIDGE_URL = APP_BRIDGE_URL,
|
|
119
|
+
...polarisProps
|
|
120
|
+
} = props;
|
|
121
|
+
|
|
122
|
+
const navigate = useNavigate();
|
|
123
|
+
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
const handleNavigate = (event: Event) => {
|
|
126
|
+
const href = (event.target as HTMLElement)?.getAttribute('href');
|
|
127
|
+
if (href) {
|
|
128
|
+
navigate(href);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
addEventListener('shopify:navigate', handleNavigate);
|
|
133
|
+
|
|
134
|
+
return () => {
|
|
135
|
+
removeEventListener('shopify:navigate', handleNavigate);
|
|
136
|
+
};
|
|
137
|
+
}, [navigate]);
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<>
|
|
141
|
+
{isEmbeddedApp && <script src={__APP_BRIDGE_URL} data-api-key={apiKey} />}
|
|
142
|
+
<PolarisAppProvider
|
|
143
|
+
{...polarisProps}
|
|
144
|
+
linkComponent={RemixPolarisLink}
|
|
145
|
+
i18n={i18n || englishI18n}
|
|
146
|
+
>
|
|
147
|
+
{children}
|
|
148
|
+
</PolarisAppProvider>
|
|
149
|
+
</>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './AppProvider';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {forwardRef, useContext} from 'react';
|
|
2
|
+
import {Form, type FormProps} from '@remix-run/react';
|
|
3
|
+
|
|
4
|
+
import {AppProxyProviderContext} from '../AppProxyProvider';
|
|
5
|
+
|
|
6
|
+
export interface AppProxyFormProps extends FormProps {
|
|
7
|
+
action: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Sets up a Remix `<Form>` component that works when rendered on an app proxy page.
|
|
12
|
+
*
|
|
13
|
+
* Supports any properties accepted by the `<Form>` component.
|
|
14
|
+
*
|
|
15
|
+
* Because Remix doesn't support URL rewriting, any route using this component should <b>match the pathname of the proxy
|
|
16
|
+
* URL exactly</b>, and <b>end in a trailing slash</b> (e.g., `https://<shop>/apps/proxy/`), or set the Remix Form prop
|
|
17
|
+
* `navigate` to `false`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <caption>Render a form element in a proxied route.</caption>
|
|
21
|
+
* <description>Use an `AppProxyForm` within an `AppProxy` to create a form.</description>
|
|
22
|
+
* ```ts
|
|
23
|
+
* // /app/routes/apps/appProxy.ts
|
|
24
|
+
* import {
|
|
25
|
+
* AppProxyProvider,
|
|
26
|
+
* AppProxyForm,
|
|
27
|
+
* } from "@shopify/shopify-app-remix/react";
|
|
28
|
+
* import { authenticate } from "~/shopify.server";
|
|
29
|
+
*
|
|
30
|
+
* export async function loader({ request }) {
|
|
31
|
+
* await authenticate.public.appProxy(request);
|
|
32
|
+
*
|
|
33
|
+
* return json({ appUrl: process.env.SHOPIFY_APP_URL });
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* export async function action({ request }) {
|
|
37
|
+
* await authenticate.public.appProxy(request);
|
|
38
|
+
*
|
|
39
|
+
* const formData = await request.formData();
|
|
40
|
+
* const field = formData.get("field")?.toString();
|
|
41
|
+
*
|
|
42
|
+
* // Perform actions
|
|
43
|
+
* if (field) {
|
|
44
|
+
* console.log("Field:", field);
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* // Return JSON to the client
|
|
48
|
+
* return json({ message: "Success!" });
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* export default function App() {
|
|
52
|
+
* const { appUrl } = useLoaderData();
|
|
53
|
+
*
|
|
54
|
+
* return (
|
|
55
|
+
* <AppProxyProvider appUrl={appUrl}>
|
|
56
|
+
* <AppProxyForm action="/apps/appProxy" method="post">
|
|
57
|
+
* <input type="text" name="field" />
|
|
58
|
+
*
|
|
59
|
+
* <input type="submit" name="Submit" />
|
|
60
|
+
* </AppProxyForm>
|
|
61
|
+
* </AppProxyProvider>
|
|
62
|
+
* );
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
* @publicDocs
|
|
66
|
+
*/
|
|
67
|
+
export const AppProxyForm = forwardRef<HTMLFormElement, AppProxyFormProps>(
|
|
68
|
+
function AppProxyForm(props, ref) {
|
|
69
|
+
const context = useContext(AppProxyProviderContext);
|
|
70
|
+
|
|
71
|
+
if (!context) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
'AppProxyForm must be used within an AppProxyProvider component',
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const {children, action, ...otherProps} = props;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Form action={context.formatUrl(action, false)} {...otherProps} ref={ref}>
|
|
81
|
+
{children}
|
|
82
|
+
</Form>
|
|
83
|
+
);
|
|
84
|
+
},
|
|
85
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {AppProxyForm, type AppProxyFormProps} from './AppProxyForm';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {forwardRef, useContext} from 'react';
|
|
2
|
+
|
|
3
|
+
import {AppProxyProviderContext} from '../AppProxyProvider';
|
|
4
|
+
|
|
5
|
+
export interface AppProxyLinkProps extends React.DetailedHTMLProps<
|
|
6
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
7
|
+
HTMLAnchorElement
|
|
8
|
+
> {
|
|
9
|
+
href: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Sets up an `<a />` HTML element that works when rendered behind an app proxy.
|
|
14
|
+
*
|
|
15
|
+
* Supports any properties accepted by the `<a />` HTML element.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* <caption>Link to a different route.</caption>
|
|
19
|
+
* <description>Use an `AppProxyLink` within an `AppProxyProvider` to link to a different proxied route.</description>
|
|
20
|
+
* ```ts
|
|
21
|
+
* // /app/routes/**\/*.ts
|
|
22
|
+
* import {authenticate} from '~/shopify.server';
|
|
23
|
+
* import {AppProxyProvider, AppProxyLink} from '@shopify/shopify-app-remix/react';
|
|
24
|
+
*
|
|
25
|
+
* export async function loader({ request }) {
|
|
26
|
+
* await authenticate.public.appProxy(request);
|
|
27
|
+
*
|
|
28
|
+
* return json({ appUrl: process.env.SHOPIFY_APP_URL });
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* export default function App() {
|
|
32
|
+
* const { appUrl } = useLoaderData();
|
|
33
|
+
*
|
|
34
|
+
* return (
|
|
35
|
+
* <AppProxyProvider appUrl={appUrl}>
|
|
36
|
+
* <AppProxyLink href="/other-proxy-route">Link to another route</AppProxyLink>
|
|
37
|
+
* </AppProxyProvider>
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
* @publicDocs
|
|
42
|
+
*/
|
|
43
|
+
export const AppProxyLink = forwardRef<HTMLAnchorElement, AppProxyLinkProps>(
|
|
44
|
+
function AppProxyLink(props, ref) {
|
|
45
|
+
const context = useContext(AppProxyProviderContext);
|
|
46
|
+
|
|
47
|
+
if (!context) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'AppProxyLink must be used within an AppProxyProvider component',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const {children, href, ...otherProps} = props;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<a href={context.formatUrl(href)} {...otherProps} ref={ref}>
|
|
57
|
+
{children}
|
|
58
|
+
</a>
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {AppProxyLink, type AppProxyLinkProps} from './AppProxyLink';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {createContext, useEffect, useState} from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for the `AppProxyProvider` component.
|
|
5
|
+
* @publicDocs
|
|
6
|
+
*/
|
|
7
|
+
export interface AppProxyProviderProps {
|
|
8
|
+
/**
|
|
9
|
+
* The URL where the app is hosted. You can set this from the `SHOPIFY_APP_URL` environment variable.
|
|
10
|
+
*/
|
|
11
|
+
appUrl: string;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The children to render.
|
|
15
|
+
*/
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type FormatUrlFunction = (
|
|
20
|
+
url: string | undefined,
|
|
21
|
+
addOrigin?: boolean,
|
|
22
|
+
) => string | undefined;
|
|
23
|
+
|
|
24
|
+
interface AppProxyProviderContextProps {
|
|
25
|
+
appUrl: string;
|
|
26
|
+
formatUrl: FormatUrlFunction;
|
|
27
|
+
requestUrl?: URL;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const AppProxyProviderContext =
|
|
31
|
+
createContext<AppProxyProviderContextProps | null>(null);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Sets up a page to render behind a Shopify app proxy, enabling JavaScript and CSS to be loaded from the app.
|
|
35
|
+
*
|
|
36
|
+
* Also provides components that enable using other components such as links and forms within proxies.
|
|
37
|
+
*
|
|
38
|
+
* > Caution:
|
|
39
|
+
* Because Remix doesn't support URL rewriting, any route using this component should <b>match the pathname of the proxy
|
|
40
|
+
* URL exactly</b>, and <b>end in a trailing slash</b> (e.g., `https://<shop>/apps/proxy/`).
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* <caption>Wrap a route with an AppProxyProvider component.</caption>
|
|
44
|
+
* <description>Wrap your route component in the `AppProxyProvider` component and pass in your app URL.</description>
|
|
45
|
+
* ```ts
|
|
46
|
+
* // /app/routes/**\/*.ts
|
|
47
|
+
* import {authenticate} from '~/shopify.server';
|
|
48
|
+
* import {AppProxyProvider} from '@shopify/shopify-app-remix/react';
|
|
49
|
+
*
|
|
50
|
+
* export async function loader({ request }) {
|
|
51
|
+
* await authenticate.public.appProxy(request);
|
|
52
|
+
*
|
|
53
|
+
* return json({ appUrl: process.env.SHOPIFY_APP_URL });
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* export default function App() {
|
|
57
|
+
* const { appUrl } = useLoaderData();
|
|
58
|
+
*
|
|
59
|
+
* return (
|
|
60
|
+
* <AppProxyProvider appUrl={appUrl}>
|
|
61
|
+
* Page content
|
|
62
|
+
* </AppProxyProvider>
|
|
63
|
+
* );
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export function AppProxyProvider(props: AppProxyProviderProps) {
|
|
68
|
+
const {children, appUrl} = props;
|
|
69
|
+
const [requestUrl, setRequestUrl] = useState<URL | undefined>();
|
|
70
|
+
|
|
71
|
+
useEffect(
|
|
72
|
+
() => setRequestUrl(new URL(window.location.href)),
|
|
73
|
+
[setRequestUrl],
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<AppProxyProviderContext.Provider
|
|
78
|
+
value={{appUrl, requestUrl, formatUrl: formatProxyUrl(requestUrl)}}
|
|
79
|
+
>
|
|
80
|
+
<base href={appUrl} />
|
|
81
|
+
|
|
82
|
+
{children}
|
|
83
|
+
</AppProxyProviderContext.Provider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function formatProxyUrl(requestUrl: URL | undefined): FormatUrlFunction {
|
|
88
|
+
return (url: string | undefined, addOrigin = true) => {
|
|
89
|
+
if (!url) {
|
|
90
|
+
return url;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let finalUrl = url;
|
|
94
|
+
|
|
95
|
+
if (addOrigin && requestUrl && finalUrl.startsWith('/')) {
|
|
96
|
+
finalUrl = new URL(`${requestUrl.origin}${url}`).href;
|
|
97
|
+
}
|
|
98
|
+
if (!finalUrl.endsWith('/')) {
|
|
99
|
+
finalUrl = `${finalUrl}/`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return finalUrl;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {Link} from '@remix-run/react';
|
|
3
|
+
// Polaris' LinkProps doesn't match this type, so we need to import it directly
|
|
4
|
+
import type {
|
|
5
|
+
LinkLikeComponent,
|
|
6
|
+
LinkLikeComponentProps,
|
|
7
|
+
} from '@shopify/polaris/build/ts/src/utilities/link';
|
|
8
|
+
|
|
9
|
+
export const RemixPolarisLink = React.forwardRef<
|
|
10
|
+
HTMLAnchorElement,
|
|
11
|
+
LinkLikeComponentProps
|
|
12
|
+
>((props, ref) => (
|
|
13
|
+
<Link {...props} to={props.url ?? props.to} ref={ref} />
|
|
14
|
+
)) as LinkLikeComponent;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {ApiVersion} from '@shopify/shopify-api';
|
|
2
|
+
import {TEST_SHOP} from '@shopify/shopify-api/test-helpers';
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
API_KEY,
|
|
6
|
+
API_SECRET_KEY,
|
|
7
|
+
APP_URL,
|
|
8
|
+
TEST_SHOP_NAME,
|
|
9
|
+
TEST_SHOP,
|
|
10
|
+
SHOPIFY_HOST,
|
|
11
|
+
BASE64_HOST,
|
|
12
|
+
USER_ID,
|
|
13
|
+
} from '@shopify/shopify-api/test-helpers';
|
|
14
|
+
export const GRAPHQL_URL = `https://${TEST_SHOP}/admin/api/${ApiVersion.July25}/graphql.json`;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {ApiVersion, Session} from '@shopify/shopify-api';
|
|
2
|
+
|
|
3
|
+
import type {AdminApiContext} from '../clients';
|
|
4
|
+
|
|
5
|
+
import {TEST_SHOP} from './const';
|
|
6
|
+
import {mockExternalRequest} from './request-mock';
|
|
7
|
+
|
|
8
|
+
export function expectAdminApiClient(
|
|
9
|
+
factory: () => Promise<{
|
|
10
|
+
admin: AdminApiContext;
|
|
11
|
+
expectedSession: Session;
|
|
12
|
+
actualSession: Session;
|
|
13
|
+
}>,
|
|
14
|
+
) {
|
|
15
|
+
describe('Graphql client', () => {
|
|
16
|
+
it('can perform requests', async () => {
|
|
17
|
+
// GIVEN
|
|
18
|
+
const {admin, actualSession} = await factory();
|
|
19
|
+
await mockExternalRequest({
|
|
20
|
+
request: new Request(
|
|
21
|
+
`https://${TEST_SHOP}/admin/api/${ApiVersion.July25}/graphql.json`,
|
|
22
|
+
{
|
|
23
|
+
method: 'POST',
|
|
24
|
+
headers: {'X-Shopify-Access-Token': actualSession.accessToken!},
|
|
25
|
+
},
|
|
26
|
+
),
|
|
27
|
+
response: new Response(
|
|
28
|
+
JSON.stringify({data: {shop: {name: 'Test shop'}}}),
|
|
29
|
+
),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// WHEN
|
|
33
|
+
const response = await admin.graphql('{ shop { name } }');
|
|
34
|
+
|
|
35
|
+
// THEN
|
|
36
|
+
expect(response.status).toEqual(200);
|
|
37
|
+
expect(await response.json()).toEqual({
|
|
38
|
+
data: {shop: {name: 'Test shop'}},
|
|
39
|
+
headers: {'Content-Type': ['application/json']},
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns a session object as part of the context', async () => {
|
|
44
|
+
// GIVEN
|
|
45
|
+
const {expectedSession, actualSession} = await factory();
|
|
46
|
+
|
|
47
|
+
// THEN
|
|
48
|
+
expect(expectedSession).toEqual(actualSession);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {TEST_SHOP} from './const';
|
|
2
|
+
import {testConfig} from './test-config';
|
|
3
|
+
|
|
4
|
+
export function expectBeginAuthRedirect(
|
|
5
|
+
config: ReturnType<typeof testConfig>,
|
|
6
|
+
response: Response,
|
|
7
|
+
) {
|
|
8
|
+
expect(response.status).toEqual(302);
|
|
9
|
+
|
|
10
|
+
const {hostname, pathname, searchParams} = new URL(
|
|
11
|
+
response.headers.get('location')!,
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
expect(hostname).toBe(TEST_SHOP);
|
|
15
|
+
expect(pathname).toBe('/admin/oauth/authorize');
|
|
16
|
+
expect(searchParams.get('client_id')).toBe(config.apiKey);
|
|
17
|
+
expect(searchParams.get('scope')).toBe(config.scopes!.toString());
|
|
18
|
+
expect(searchParams.get('redirect_uri')).toBe(
|
|
19
|
+
`${config.appUrl}/auth/callback`,
|
|
20
|
+
);
|
|
21
|
+
expect(searchParams.get('state')).toStrictEqual(expect.any(String));
|
|
22
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {APP_BRIDGE_URL} from '../authenticate/const';
|
|
2
|
+
|
|
3
|
+
import {TEST_SHOP} from './const';
|
|
4
|
+
|
|
5
|
+
export function expectDocumentRequestHeaders(
|
|
6
|
+
response: Response,
|
|
7
|
+
isEmbeddedApp = true,
|
|
8
|
+
) {
|
|
9
|
+
const headers = response.headers;
|
|
10
|
+
|
|
11
|
+
if (isEmbeddedApp) {
|
|
12
|
+
expect(headers.get('Content-Security-Policy')).toEqual(
|
|
13
|
+
`frame-ancestors https://${encodeURIComponent(
|
|
14
|
+
TEST_SHOP,
|
|
15
|
+
)} https://admin.shopify.com https://*.spin.dev https://admin.myshopify.io https://admin.shop.dev;`,
|
|
16
|
+
);
|
|
17
|
+
expect(headers.get('Link')).toEqual(
|
|
18
|
+
`<${APP_BRIDGE_URL}>; rel="preload"; as="script";`,
|
|
19
|
+
);
|
|
20
|
+
} else {
|
|
21
|
+
expect(headers.get('Content-Security-Policy')).toEqual(
|
|
22
|
+
`frame-ancestors 'none';`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {APP_URL, BASE64_HOST, TEST_SHOP} from './const';
|
|
2
|
+
|
|
3
|
+
interface ExpectExitIframeRedirectOptions {
|
|
4
|
+
shop?: string;
|
|
5
|
+
host?: string | null;
|
|
6
|
+
destination?: string;
|
|
7
|
+
addHostToExitIframePath?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function expectExitIframeRedirect(
|
|
11
|
+
response: Response,
|
|
12
|
+
{
|
|
13
|
+
shop = TEST_SHOP,
|
|
14
|
+
host = BASE64_HOST,
|
|
15
|
+
destination = `/auth?shop=${shop}`,
|
|
16
|
+
addHostToExitIframePath = true,
|
|
17
|
+
}: ExpectExitIframeRedirectOptions = {},
|
|
18
|
+
) {
|
|
19
|
+
expect(response.status).toBe(302);
|
|
20
|
+
|
|
21
|
+
const {pathname, searchParams} = new URL(
|
|
22
|
+
response.headers.get('location')!,
|
|
23
|
+
APP_URL,
|
|
24
|
+
);
|
|
25
|
+
expect(pathname).toBe('/auth/exit-iframe');
|
|
26
|
+
|
|
27
|
+
expect(searchParams.get('shop')).toBe(shop);
|
|
28
|
+
|
|
29
|
+
let expectedDestination = destination;
|
|
30
|
+
if (host) {
|
|
31
|
+
expect(searchParams.get('host')).toBe(host);
|
|
32
|
+
if (addHostToExitIframePath) {
|
|
33
|
+
expectedDestination = destination.concat(`&host=${host}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
expect(searchParams.get('exitIframe')).toBe(expectedDestination);
|
|
37
|
+
}
|