@shopify/shopify-app-remix 1.2.1 → 2.0.0
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/README.md +35 -284
- package/build/cjs/react/components/AppProvider/AppProvider.js +35 -4
- package/build/cjs/server/authenticate/admin/billing/request.js +4 -2
- package/build/cjs/server/authenticate/public/appProxy/authenticate.js +7 -1
- package/build/cjs/server/authenticate/public/factory.js +1 -1
- package/build/cjs/server/authenticate/webhooks/authenticate.js +38 -20
- package/build/cjs/server/boundary/index.js +6 -6
- package/build/cjs/server/clients/storefront/factory.js +35 -0
- package/build/cjs/server/shopify-app.js +11 -9
- package/build/cjs/server/types.js +1 -1
- package/build/cjs/server/unauthenticated/admin/factory.js +2 -2
- package/build/cjs/server/unauthenticated/helpers/get-offline-session.js +14 -0
- package/build/cjs/server/unauthenticated/storefront/factory.js +25 -0
- package/build/cjs/server/version.js +1 -1
- package/build/ts/react/components/AppProvider/AppProvider.d.ts +48 -8
- package/build/ts/react/components/AppProvider/AppProvider.d.ts.map +1 -1
- package/build/ts/react/components/AppProvider/AppProvider.doc.d.ts +4 -0
- package/build/ts/react/components/AppProvider/AppProvider.doc.d.ts.map +1 -0
- package/build/ts/react/components/AppProvider/AppProvider.doc.js +34 -0
- package/build/ts/react/components/AppProvider/AppProvider.doc.js.map +1 -0
- package/build/ts/react/components/AppProvider/AppProvider.js +35 -3
- package/build/ts/react/components/AppProvider/AppProvider.js.map +1 -1
- package/build/ts/server/__test-helpers/expect-admin-api-client.d.ts +1 -1
- package/build/ts/server/__test-helpers/expect-admin-api-client.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/expect-storefront-api-client.d.ts +8 -0
- package/build/ts/server/__test-helpers/expect-storefront-api-client.d.ts.map +1 -0
- package/build/ts/server/__test-helpers/expect-storefront-api-client.js +57 -0
- package/build/ts/server/__test-helpers/expect-storefront-api-client.js.map +1 -0
- package/build/ts/server/__test-helpers/index.d.ts +1 -0
- package/build/ts/server/__test-helpers/index.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/index.js +1 -0
- package/build/ts/server/__test-helpers/index.js.map +1 -1
- package/build/ts/server/__test-helpers/test-config.d.ts +9 -4
- package/build/ts/server/__test-helpers/test-config.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/test-config.js +2 -2
- package/build/ts/server/__test-helpers/test-config.js.map +1 -1
- package/build/ts/server/authenticate/admin/authenticate.admin.doc.d.ts +4 -0
- package/build/ts/server/authenticate/admin/authenticate.admin.doc.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/authenticate.admin.doc.js +35 -0
- package/build/ts/server/authenticate/admin/authenticate.admin.doc.js.map +1 -0
- package/build/ts/server/authenticate/admin/authenticate.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/admin/billing/authenticate.admin.billing.doc.d.ts +4 -0
- package/build/ts/server/authenticate/admin/billing/authenticate.admin.billing.doc.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/billing/authenticate.admin.billing.doc.js +26 -0
- package/build/ts/server/authenticate/admin/billing/authenticate.admin.billing.doc.js.map +1 -0
- package/build/ts/server/authenticate/admin/billing/request.d.ts +1 -1
- package/build/ts/server/authenticate/admin/billing/request.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/billing/request.js +2 -8
- package/build/ts/server/authenticate/admin/billing/request.js.map +1 -1
- package/build/ts/server/authenticate/admin/billing/types.d.ts +71 -63
- package/build/ts/server/authenticate/admin/billing/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/types.d.ts +76 -40
- package/build/ts/server/authenticate/admin/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/helpers/add-response-headers.d.ts +2 -1
- package/build/ts/server/authenticate/helpers/add-response-headers.d.ts.map +1 -1
- package/build/ts/server/authenticate/helpers/add-response-headers.js.map +1 -1
- package/build/ts/server/authenticate/public/appProxy/authenticate.d.ts.map +1 -1
- package/build/ts/server/authenticate/public/appProxy/authenticate.js +4 -2
- package/build/ts/server/authenticate/public/appProxy/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.d.ts +4 -0
- package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.d.ts.map +1 -0
- package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.js +32 -0
- package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.js.map +1 -0
- package/build/ts/server/authenticate/public/appProxy/types.d.ts +64 -8
- package/build/ts/server/authenticate/public/appProxy/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/public/checkout/authenticate.public.checkout.doc.d.ts +4 -0
- package/build/ts/server/authenticate/public/checkout/authenticate.public.checkout.doc.d.ts.map +1 -0
- package/build/ts/server/authenticate/public/checkout/authenticate.public.checkout.doc.js +21 -0
- package/build/ts/server/authenticate/public/checkout/authenticate.public.checkout.doc.js.map +1 -0
- package/build/ts/server/authenticate/public/checkout/types.d.ts +19 -17
- package/build/ts/server/authenticate/public/checkout/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/public/factory.js +1 -1
- package/build/ts/server/authenticate/public/types.d.ts +23 -21
- package/build/ts/server/authenticate/public/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/webhooks/authenticate.d.ts +3 -2
- package/build/ts/server/authenticate/webhooks/authenticate.d.ts.map +1 -1
- package/build/ts/server/authenticate/webhooks/authenticate.js +31 -19
- package/build/ts/server/authenticate/webhooks/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/webhooks/authenticate.webhooks.doc.d.ts +4 -0
- package/build/ts/server/authenticate/webhooks/authenticate.webhooks.doc.d.ts.map +1 -0
- package/build/ts/server/authenticate/webhooks/authenticate.webhooks.doc.js +27 -0
- package/build/ts/server/authenticate/webhooks/authenticate.webhooks.doc.js.map +1 -0
- package/build/ts/server/authenticate/webhooks/types.d.ts +170 -6
- package/build/ts/server/authenticate/webhooks/types.d.ts.map +1 -1
- package/build/ts/server/boundary/index.d.ts +6 -6
- package/build/ts/server/boundary/index.js +6 -6
- package/build/ts/server/clients/admin/authenticate.admin.api.doc.d.ts +4 -0
- package/build/ts/server/clients/admin/authenticate.admin.api.doc.d.ts.map +1 -0
- package/build/ts/server/clients/admin/authenticate.admin.api.doc.js +32 -0
- package/build/ts/server/clients/admin/authenticate.admin.api.doc.js.map +1 -0
- package/build/ts/server/clients/admin/factory.d.ts +1 -1
- package/build/ts/server/clients/admin/factory.d.ts.map +1 -1
- package/build/ts/server/clients/admin/factory.js.map +1 -1
- package/build/ts/server/clients/admin/graphql.d.ts +3 -15
- package/build/ts/server/clients/admin/graphql.d.ts.map +1 -1
- package/build/ts/server/clients/admin/graphql.js.map +1 -1
- package/build/ts/server/clients/admin/index.d.ts +1 -0
- package/build/ts/server/clients/admin/index.d.ts.map +1 -1
- package/build/ts/server/clients/admin/index.js +1 -0
- package/build/ts/server/clients/admin/index.js.map +1 -1
- package/build/ts/server/clients/admin/rest.d.ts +1 -1
- package/build/ts/server/clients/admin/rest.d.ts.map +1 -1
- package/build/ts/server/clients/admin/types.d.ts +105 -1
- package/build/ts/server/clients/admin/types.d.ts.map +1 -1
- package/build/ts/server/clients/index.d.ts +3 -0
- package/build/ts/server/clients/index.d.ts.map +1 -0
- package/build/ts/server/clients/index.js +6 -0
- package/build/ts/server/clients/index.js.map +1 -0
- package/build/ts/server/clients/storefront/authenticate.storefront.api.doc.d.ts +4 -0
- package/build/ts/server/clients/storefront/authenticate.storefront.api.doc.d.ts.map +1 -0
- package/build/ts/server/clients/storefront/authenticate.storefront.api.doc.js +32 -0
- package/build/ts/server/clients/storefront/authenticate.storefront.api.doc.js.map +1 -0
- package/build/ts/server/clients/storefront/factory.d.ts +8 -0
- package/build/ts/server/clients/storefront/factory.d.ts.map +1 -0
- package/build/ts/server/clients/storefront/factory.js +39 -0
- package/build/ts/server/clients/storefront/factory.js.map +1 -0
- package/build/ts/server/clients/storefront/index.d.ts +3 -0
- package/build/ts/server/clients/storefront/index.d.ts.map +1 -0
- package/build/ts/server/clients/storefront/index.js +6 -0
- package/build/ts/server/clients/storefront/index.js.map +1 -0
- package/build/ts/server/clients/storefront/types.d.ts +29 -0
- package/build/ts/server/clients/storefront/types.d.ts.map +1 -0
- package/build/ts/server/clients/storefront/types.js +3 -0
- package/build/ts/server/clients/storefront/types.js.map +1 -0
- package/build/ts/server/clients/types.d.ts +15 -0
- package/build/ts/server/clients/types.d.ts.map +1 -0
- package/build/ts/server/clients/types.js +3 -0
- package/build/ts/server/clients/types.js.map +1 -0
- package/build/ts/server/config-types.d.ts +39 -121
- package/build/ts/server/config-types.d.ts.map +1 -1
- package/build/ts/server/future/flags.d.ts +11 -0
- package/build/ts/server/future/flags.d.ts.map +1 -0
- package/build/ts/server/future/flags.js +3 -0
- package/build/ts/server/future/flags.js.map +1 -0
- package/build/ts/server/shopify-app.d.ts +3 -3
- package/build/ts/server/shopify-app.d.ts.map +1 -1
- package/build/ts/server/shopify-app.doc.d.ts +4 -0
- package/build/ts/server/shopify-app.doc.d.ts.map +1 -0
- package/build/ts/server/shopify-app.doc.js +42 -0
- package/build/ts/server/shopify-app.doc.js.map +1 -0
- package/build/ts/server/shopify-app.js +9 -8
- package/build/ts/server/shopify-app.js.map +1 -1
- package/build/ts/server/types.d.ts +202 -170
- package/build/ts/server/types.d.ts.map +1 -1
- package/build/ts/server/types.js.map +1 -1
- package/build/ts/server/unauthenticated/admin/factory.d.ts.map +1 -1
- package/build/ts/server/unauthenticated/admin/factory.js +3 -4
- package/build/ts/server/unauthenticated/admin/factory.js.map +1 -1
- package/build/ts/server/unauthenticated/admin/types.d.ts +11 -9
- package/build/ts/server/unauthenticated/admin/types.d.ts.map +1 -1
- package/build/ts/server/unauthenticated/admin/unauthenticated.admin.doc.d.ts +4 -0
- package/build/ts/server/unauthenticated/admin/unauthenticated.admin.doc.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/admin/unauthenticated.admin.doc.js +29 -0
- package/build/ts/server/unauthenticated/admin/unauthenticated.admin.doc.js.map +1 -0
- package/build/ts/server/unauthenticated/helpers/get-offline-session.d.ts +4 -0
- package/build/ts/server/unauthenticated/helpers/get-offline-session.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/helpers/get-offline-session.js +22 -0
- package/build/ts/server/unauthenticated/helpers/get-offline-session.js.map +1 -0
- package/build/ts/server/unauthenticated/helpers/index.d.ts +2 -0
- package/build/ts/server/unauthenticated/helpers/index.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/helpers/index.js +5 -0
- package/build/ts/server/unauthenticated/helpers/index.js.map +1 -0
- package/build/ts/server/unauthenticated/storefront/factory.d.ts +4 -0
- package/build/ts/server/unauthenticated/storefront/factory.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/storefront/factory.js +29 -0
- package/build/ts/server/unauthenticated/storefront/factory.js.map +1 -0
- package/build/ts/server/unauthenticated/storefront/index.d.ts +2 -0
- package/build/ts/server/unauthenticated/storefront/index.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/storefront/index.js +5 -0
- package/build/ts/server/unauthenticated/storefront/index.js.map +1 -0
- package/build/ts/server/unauthenticated/storefront/types.d.ts +34 -0
- package/build/ts/server/unauthenticated/storefront/types.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/storefront/types.js +3 -0
- package/build/ts/server/unauthenticated/storefront/types.js.map +1 -0
- package/build/ts/server/unauthenticated/storefront/unauthenticated.storefront.doc.d.ts +4 -0
- package/build/ts/server/unauthenticated/storefront/unauthenticated.storefront.doc.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/storefront/unauthenticated.storefront.doc.js +29 -0
- package/build/ts/server/unauthenticated/storefront/unauthenticated.storefront.doc.js.map +1 -0
- package/build/ts/server/unauthenticated/types.d.ts +66 -0
- package/build/ts/server/unauthenticated/types.d.ts.map +1 -0
- package/build/ts/server/unauthenticated/types.js +3 -0
- package/build/ts/server/unauthenticated/types.js.map +1 -0
- package/build/ts/server/version.d.ts +1 -1
- package/build/ts/server/version.js +1 -1
- package/package.json +11 -6
- package/build/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
This package makes it easy to use [Remix](https://remix.run/) to build Shopify apps.
|
|
9
9
|
It builds on the `@shopify/shopify-api` package and exposes a `shopifyApp` function. You can use `shopifyApp` to configure your app and then authenticate requests from Shopify.
|
|
10
10
|
|
|
11
|
+
Visit the [`shopify.dev` documentation](https://shopify.dev/docs/api/shopify-app-remix) for more details on the Remix app package.
|
|
12
|
+
|
|
11
13
|
## Requirements
|
|
12
14
|
|
|
13
|
-
To
|
|
15
|
+
To use this package, you will need to have:
|
|
14
16
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
17
|
+
- a Shopify Partner account and development store
|
|
18
|
+
- an app already set up on your partner account
|
|
19
|
+
- a JavaScript package manager such as [yarn](https://yarnpkg.com) installed
|
|
18
20
|
|
|
19
21
|
## Getting started
|
|
20
22
|
|
|
@@ -24,11 +26,11 @@ The easiest way to get started with developing Shopify apps is using the [Shopif
|
|
|
24
26
|
It helps you set up your environment for developing and publishing your apps and extensions.
|
|
25
27
|
|
|
26
28
|
We strongly recommend using the CLI to create and manage your Remix apps and extensions!
|
|
27
|
-
|
|
29
|
+
Refer to the [getting started documentation](https://shopify.dev/docs/apps/getting-started/create) to create your app using the Shopify CLI.
|
|
28
30
|
|
|
29
31
|
### Using a plain Remix app
|
|
30
32
|
|
|
31
|
-
This package works with any Remix app. If you're starting an app from scratch, you can create a brand new Remix app that uses the indie-stack:
|
|
33
|
+
This package works with any Remix app. If you're starting an app from scratch, then you can create a brand new Remix app that uses the indie-stack:
|
|
32
34
|
|
|
33
35
|
```bash
|
|
34
36
|
npx create-remix@latest --template remix-run/indie-stack
|
|
@@ -41,11 +43,18 @@ Now let's install this package:
|
|
|
41
43
|
npm install @shopify/shopify-app-remix
|
|
42
44
|
```
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
Next, you'll need to set up some routes and headers so you can embed your app in the Shopify admin.
|
|
47
|
+
You can find more details on all the steps described here in the [package documentation](https://shopify.dev/docs/api/shopify-app-remix).
|
|
48
|
+
|
|
49
|
+
Create `app/shopify.server.js`. We will use this file to configure our Shopify app by calling the [`shopifyApp` function](https://shopify.dev/docs/api/shopify-app-remix/latest/entrypoints/shopifyapp):
|
|
45
50
|
|
|
46
51
|
```ts
|
|
47
52
|
// app/shopify.server.js
|
|
53
|
+
// Note that you don't need to import the node adapter if you're running on a different runtime.
|
|
48
54
|
import '@shopify/shopify-app-remix/server/adapters/node';
|
|
55
|
+
// Memory storage makes it easy to set an app up, but should never be used in production.
|
|
56
|
+
import {MemorySessionStorage} from '@shopify/shopify-app-session-storage-memory';
|
|
57
|
+
|
|
49
58
|
import {LATEST_API_VERSION, shopifyApp} from '@shopify/shopify-app-remix';
|
|
50
59
|
|
|
51
60
|
const shopify = shopifyApp({
|
|
@@ -54,21 +63,11 @@ const shopify = shopifyApp({
|
|
|
54
63
|
appUrl: process.env.SHOPIFY_APP_URL!,
|
|
55
64
|
scopes: ['read_products'],
|
|
56
65
|
apiVersion: LATEST_API_VERSION,
|
|
66
|
+
sessionStorage: new MemorySessionStorage(),
|
|
57
67
|
});
|
|
58
68
|
export default shopify;
|
|
59
69
|
```
|
|
60
70
|
|
|
61
|
-
A description of these config options:
|
|
62
|
-
|
|
63
|
-
| option | description |
|
|
64
|
-
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
65
|
-
| apiKey | The Client ID for your app. Copy it from your app in the Shopify partners dashboard. This is public. |
|
|
66
|
-
| apiSecretKey | The API Secret for your app. Copy it from your app in the Shopify partners dashboard. This is private. Do not commit this. |
|
|
67
|
-
| appUrl | This is the URL for your app. |
|
|
68
|
-
| scopes | What permissions your app needs. [More information](https://shopify.dev/docs/api/usage/access-scopes). |
|
|
69
|
-
| apiVersion | What versions of the [Admin API's](https://shopify.dev/docs/api/) do you want to use. If you are creating anew app use LATEST_API_VERSION. |
|
|
70
|
-
| restResources | What version of the [Shopify Admin REST API](https://shopify.dev/docs/api/admin-rest) do you want to use. If you are creating anew app use LATEST_API_VERSION. |
|
|
71
|
-
|
|
72
71
|
This will require some environment variables. So let's create an `.env` file:
|
|
73
72
|
|
|
74
73
|
```env
|
|
@@ -77,45 +76,34 @@ SHOPIFY_API_SECRET="[Copy from partners dashboard]"
|
|
|
77
76
|
SHOPIFY_APP_URL="[The tunnel URL you are using to run your app]"
|
|
78
77
|
```
|
|
79
78
|
|
|
80
|
-
`shopifyApp` needs to reserve a [splat route](https://remix.run/docs/en/main/guides/routing#splats)
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
// app/shopify.server.js
|
|
84
|
-
import {shopifyApp} from '@shopify/shopify-app-remix';
|
|
85
|
-
|
|
86
|
-
const shopify = shopifyApp({
|
|
87
|
-
// ...
|
|
88
|
-
authPathPrefix: '/auth',
|
|
89
|
-
});
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Now let's create the [splat route](https://remix.run/docs/en/main/guides/routing#splats) for auth. It should export a loader that uses `shopifyApp` to authenticate:
|
|
79
|
+
`shopifyApp` needs to reserve a [splat route](https://remix.run/docs/en/main/guides/routing#splats) for auth.
|
|
80
|
+
It should export a loader that uses `shopifyApp` to authenticate:
|
|
93
81
|
|
|
94
82
|
```ts
|
|
95
83
|
// app/routes/auth/$.tsx
|
|
96
|
-
import {
|
|
84
|
+
import {LoaderFunctionArgs} from '@remix-run/node';
|
|
97
85
|
|
|
98
86
|
import shopify from '~/shopify.server';
|
|
99
87
|
|
|
100
|
-
export async function loader({request}:
|
|
88
|
+
export async function loader({request}: LoaderFunctionArgs) {
|
|
101
89
|
await shopify.authenticate.admin(request);
|
|
102
90
|
|
|
103
91
|
return null;
|
|
104
92
|
}
|
|
105
93
|
```
|
|
106
94
|
|
|
107
|
-
Next, set up the `AppProvider` component in your app's routes. To do this pass the `process.env.SHOPIFY_API_KEY` to the frontend via the loader.
|
|
95
|
+
Next, set up the [`AppProvider` component](https://shopify.dev/docs/api/shopify-app-remix/latest/entrypoints/appprovider) in your app's routes. To do this pass the `process.env.SHOPIFY_API_KEY` to the frontend via the loader.
|
|
108
96
|
|
|
109
97
|
Here is an example:
|
|
110
98
|
|
|
111
99
|
```ts
|
|
112
100
|
// root.tsx
|
|
113
|
-
import {
|
|
101
|
+
import {LoaderFunctionArgs} from '@remix-run/node';
|
|
114
102
|
import {AppProvider} from '@shopify/shopify-app-remix/react';
|
|
115
103
|
|
|
116
104
|
import shopify from '~/shopify.server';
|
|
117
105
|
|
|
118
|
-
export async function loader({request}:
|
|
106
|
+
export async function loader({request}: LoaderFunctionArgs) {
|
|
119
107
|
await shopify.authenticate.admin(request);
|
|
120
108
|
|
|
121
109
|
return json({
|
|
@@ -142,7 +130,7 @@ export default function App() {
|
|
|
142
130
|
}
|
|
143
131
|
```
|
|
144
132
|
|
|
145
|
-
This component will set up [Polaris](https://polaris.shopify.com/components/utilities/app-provider) and [App Bridge](https://shopify.dev/tools/app-bridge). If your app
|
|
133
|
+
This component will set up [Polaris](https://polaris.shopify.com/components/utilities/app-provider) and [App Bridge](https://shopify.dev/tools/app-bridge). If your app isn't embedded, set the `isEmbeddedApp` prop to `false`.
|
|
146
134
|
|
|
147
135
|
Now that your app is ready to respond to requests, it will also need to add the required `Content-Security-Policy` header directives, as per [our documentation](https://shopify.dev/docs/apps/store/security/iframe-protection).
|
|
148
136
|
To do that, this package provides the `shopify.addDocumentResponseHeaders` method.
|
|
@@ -166,263 +154,26 @@ export default function handleRequest(
|
|
|
166
154
|
}
|
|
167
155
|
```
|
|
168
156
|
|
|
169
|
-
|
|
157
|
+
### Running your app
|
|
170
158
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
Since Node.js doesn't fully implement that API, apps will need to import an extra adapter to set it up before using this package's exports.
|
|
174
|
-
|
|
175
|
-
In the [Getting Started](#getting-started) section above, you'll notice that the example runs
|
|
176
|
-
|
|
177
|
-
```ts
|
|
178
|
-
import '@shopify/shopify-app-remix/server/adapters/node';
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
before calling `shopifyApp`.
|
|
182
|
-
If you're running on a runtime other than Node, you can simply omit that line.
|
|
183
|
-
|
|
184
|
-
## Loading your app in admin
|
|
185
|
-
|
|
186
|
-
To load your app within the Shopify Admin, you need to:
|
|
159
|
+
To run your app and load it within the Shopify Admin, you need to:
|
|
187
160
|
|
|
188
161
|
1. Update your app's URL in your Partners Dashboard app setup page to `http://localhost:8080`
|
|
189
162
|
1. Update your app's callback URL to `http://localhost:8080/api/auth/callback` in that same page
|
|
190
163
|
1. Go to **Test your app** in Partners Dashboard and select your development store
|
|
191
164
|
|
|
192
|
-
##
|
|
193
|
-
|
|
194
|
-
`shopifyApp` provides methods for authenticating admin requests.
|
|
195
|
-
To authenticate admin requests you can call `shopify.authenticate.admin(request)` in a loader or an action:
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
// app/routes/**/*.tsx
|
|
199
|
-
export const loader = async ({request}: LoaderArgs) => {
|
|
200
|
-
await shopify.authenticate.admin(request);
|
|
201
|
-
|
|
202
|
-
return null;
|
|
203
|
-
};
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
If there is a session for this user, this loader will return null.
|
|
207
|
-
If there is no session for the user, the loader will throw the appropriate redirect Response.
|
|
208
|
-
|
|
209
|
-
> **Note**: If you are authenticating more than one route, we recommend using [Remix layout routes](https://remix.run/docs/en/1.18.1/file-conventions/routes-files#layout-routes) to automatically authenticate them.
|
|
210
|
-
|
|
211
|
-
## Authenticating cross-origin admin requests
|
|
212
|
-
|
|
213
|
-
If your Remix server is authenticating an admin extension, a request from the extension to Remix will be cross-origin. Here `shopify.authenticate.admin` provides a cors function to add the required cross-origin headers:
|
|
214
|
-
|
|
215
|
-
```ts
|
|
216
|
-
export const loader = async ({request}: LoaderArgs) => {
|
|
217
|
-
const {cors} = await shopify.authenticate.admin(request);
|
|
218
|
-
|
|
219
|
-
return cors(json({my: 'data'}));
|
|
220
|
-
};
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
### Headers
|
|
224
|
-
|
|
225
|
-
It's important to note that the authentication functions in this package rely on throwing `Response` objects, which must be handled in your Remix routes using them.
|
|
165
|
+
## Next steps
|
|
226
166
|
|
|
227
|
-
|
|
228
|
-
We provide some abstractions for the error and headers boundaries to make it easier for apps to set those up.
|
|
167
|
+
Once your app is up and running, you can start using this package to interact with Shopify APIs, webhooks and more.
|
|
229
168
|
|
|
230
|
-
|
|
231
|
-
// app/routes/**/*.tsx
|
|
232
|
-
import {boundary} from '@shopify/shopify-app-remix';
|
|
233
|
-
|
|
234
|
-
export function ErrorBoundary() {
|
|
235
|
-
return boundary.error(useRouteError());
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export const headers = (headersArgs) => {
|
|
239
|
-
return boundary.headers(headersArgs);
|
|
240
|
-
};
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
> **Note**: You can also add this to a layout if you want to authenticate more than one route.
|
|
244
|
-
|
|
245
|
-
### Using the Shopify admin GraphQL API
|
|
169
|
+
Here are some guides to help you set up your app:
|
|
246
170
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
E.g:
|
|
250
|
-
|
|
251
|
-
```ts
|
|
252
|
-
// routes/**/*.tsx
|
|
253
|
-
import shopify from '../shopify.server';
|
|
254
|
-
import {ActionArgs, json} from '@remix-run/node';
|
|
255
|
-
|
|
256
|
-
export async function action({request}: ActionArgs) {
|
|
257
|
-
const {admin} = await shopify.authenticate.admin(request);
|
|
258
|
-
|
|
259
|
-
const response = await admin.graphql(
|
|
260
|
-
`#graphql
|
|
261
|
-
mutation populateProduct($input: ProductInput!) {
|
|
262
|
-
productCreate(input: $input) {
|
|
263
|
-
product {
|
|
264
|
-
id
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}`,
|
|
268
|
-
{
|
|
269
|
-
variables: {
|
|
270
|
-
input: {
|
|
271
|
-
title: 'New product',
|
|
272
|
-
variants: [{price: 100}],
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
);
|
|
277
|
-
const parsedResponse = await response.json();
|
|
278
|
-
|
|
279
|
-
return json({data: parsedResponse.data});
|
|
280
|
-
}
|
|
281
|
-
```
|
|
171
|
+
- [Interacting with Shopify Admin](https://shopify.dev/docs/api/shopify-app-remix/latest/guide-admin)
|
|
172
|
+
- [Subscribing to webhooks](https://shopify.dev/docs/api/shopify-app-remix/latest/guide-webhooks)
|
|
282
173
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
`shopify.authenticate.admin` can returns methods for interacting with [Shopify Admin REST API](https://shopify.dev/docs/api/admin-rest). To access the [Shopify Admin REST API](https://shopify.dev/docs/api/admin-rest) first configure `shopifyApp` with the REST resources you would like to use:
|
|
286
|
-
|
|
287
|
-
```ts
|
|
288
|
-
// app/routes/**/*.tsx
|
|
289
|
-
import {restResources} from '@shopify/shopify-api/rest/admin/2023-04';
|
|
290
|
-
|
|
291
|
-
const shopify = shopifyApp({
|
|
292
|
-
restResources,
|
|
293
|
-
// ...etc
|
|
294
|
-
});
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
Next pass a request to `shopify.authenticate.admin` in a loader or an action. This will either redirect the merchant to install your app or it will give you access to API functions. E.g:
|
|
298
|
-
|
|
299
|
-
```ts
|
|
300
|
-
// app/routes/**/*.tsx
|
|
301
|
-
export const loader = async ({request}: LoaderArgs) => {
|
|
302
|
-
const {admin, session} = await shopify.authenticate.admin(request);
|
|
303
|
-
const data = await admin.rest.resources.Product.count({session});
|
|
304
|
-
|
|
305
|
-
return json(data);
|
|
306
|
-
};
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
## Authenticating webhook requests
|
|
310
|
-
|
|
311
|
-
Your app must respond to [mandatory webhook topics](https://shopify.dev/docs/apps/webhooks/configuration/mandatory-webhooks). In addition, your app can register [optional webhook topics](https://shopify.dev/docs/api/admin-rest/2023-04/resources/webhook#event-topics).
|
|
312
|
-
|
|
313
|
-
To setup webhooks first we need to configure `shopifyApp` with 2 pieces:
|
|
314
|
-
|
|
315
|
-
1. The webhooks you want to subscribe to. In this example we subscribe to the `APP_UNINSTALLED` topic.
|
|
316
|
-
2. The code to register the `APP_UNINSTALLED` topic after a merchant installs you app. Here `shopifyApp` provides an `afterAuth` hook.
|
|
317
|
-
|
|
318
|
-
```ts
|
|
319
|
-
// shopify.server.js
|
|
320
|
-
import {shopifyApp, DeliveryMethod} from '@shopify/shopify-app-remix';
|
|
321
|
-
|
|
322
|
-
const shopify = shopifyApp({
|
|
323
|
-
apiKey: '1707326264fde5037c658n120626ce3f',
|
|
324
|
-
// ...etc
|
|
325
|
-
webhooks: {
|
|
326
|
-
APP_UNINSTALLED: {
|
|
327
|
-
deliveryMethod: DeliveryMethod.Http,
|
|
328
|
-
callbackUrl: '/webhooks',
|
|
329
|
-
},
|
|
330
|
-
},
|
|
331
|
-
hooks: {
|
|
332
|
-
afterAuth: async ({session}) => {
|
|
333
|
-
shopify.registerWebhooks({session});
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
Next you must add a route for each `callbackUrl` you pass. It should use the `shopify.authenticate.webhook` function to authenticate the request. For example:
|
|
340
|
-
|
|
341
|
-
To do this, your app must authenticate the request.
|
|
342
|
-
|
|
343
|
-
```ts
|
|
344
|
-
// routes/webhooks.tsx
|
|
345
|
-
import {ActionArgs} from '@remix-run/node';
|
|
346
|
-
|
|
347
|
-
import shopify from '../shopify.server';
|
|
348
|
-
import db from '../db.server';
|
|
349
|
-
|
|
350
|
-
export const action = async ({request}) => {
|
|
351
|
-
const {topic, shop, session} = await authenticate.webhook(request);
|
|
352
|
-
|
|
353
|
-
switch (topic) {
|
|
354
|
-
case 'APP_UNINSTALLED':
|
|
355
|
-
if (session) {
|
|
356
|
-
await db.session.deleteMany({where: {shop}});
|
|
357
|
-
}
|
|
358
|
-
break;
|
|
359
|
-
case 'CUSTOMERS_DATA_REQUEST':
|
|
360
|
-
case 'CUSTOMERS_REDACT':
|
|
361
|
-
case 'SHOP_REDACT':
|
|
362
|
-
default:
|
|
363
|
-
throw new Response('Unhandled webhook topic', {status: 404});
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
throw new Response();
|
|
367
|
-
};
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
## Authenticating public requests
|
|
371
|
-
|
|
372
|
-
Your Remix app may need to authenticate requests coming from a public context. An example of this would be a checkout extension. Here is how:
|
|
373
|
-
|
|
374
|
-
```ts
|
|
375
|
-
// e.g: routes/api.public.notes.tsx
|
|
376
|
-
import shopify from '../shopify.server';
|
|
377
|
-
import {LoaderArgs, json} from '@remix-run/node';
|
|
378
|
-
import {getNotes} from '~/models/notes';
|
|
379
|
-
|
|
380
|
-
export const loader = async ({request}: LoaderArgs) => {
|
|
381
|
-
const {sessionToken, cors} = await shopify.authenticate.public(request);
|
|
382
|
-
|
|
383
|
-
// E.g: Get notes using the shops admin domain
|
|
384
|
-
return cors(json(await getNotes(sessionToken.iss)));
|
|
385
|
-
};
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
This can be useful if your app exposes checkout or theme extensions and those extensions need to access data from your app.
|
|
389
|
-
|
|
390
|
-
**Note:** These requests will be cross-origin. So you must use the cross-origin helper returned from `shopify.authenticate.public`.
|
|
391
|
-
|
|
392
|
-
## Session Storage
|
|
393
|
-
|
|
394
|
-
When calling `shopifyApp`, you must pass in a `sesionStorage` to store sessions.
|
|
395
|
-
You can change this by passing a different Session Adaptor to `shopifyApp`.
|
|
396
|
-
To make this easy Shopify offers [some production ready session adaptors](https://github.com/Shopify/shopify-app-js/tree/main/packages).
|
|
397
|
-
|
|
398
|
-
In this example we'll swap the default session adaptor for [Prisma](https://www.prisma.io/).
|
|
399
|
-
|
|
400
|
-
Let's pass the [Prisma app session storage](https://github.com/Shopify/shopify-app-js/blob/main/packages/shopify-app-session-storage-prisma/README.md) adaptor to `shopifyApp`:
|
|
401
|
-
|
|
402
|
-
```ts
|
|
403
|
-
// app/shopify.server.js
|
|
404
|
-
import {shopifyApp} from '@shopify/shopify-app-remix';
|
|
405
|
-
import {PrismaSessionStorage} from '@shopify/shopify-app-session-storage-prisma';
|
|
406
|
-
import {PrismaClient} from '@prisma/client';
|
|
407
|
-
|
|
408
|
-
const prisma = new PrismaClient();
|
|
409
|
-
const storage = new PrismaSessionStorage(prisma);
|
|
410
|
-
|
|
411
|
-
const shopify = shopifyApp({
|
|
412
|
-
sessionStorage: storage,
|
|
413
|
-
// ...
|
|
414
|
-
});
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
Note that this requires a `schema.prisma` file as defined in the README for [Prisma app session storage](https://github.com/Shopify/shopify-app-js/tree/main/packages/shopify-app-session-storage-prisma).
|
|
418
|
-
Remember to [set up your migrations](https://www.prisma.io/docs/concepts/components/prisma-migrate/get-started) after creating the schema file!
|
|
174
|
+
You can also authenticate requests from surfaces other than the admin.
|
|
175
|
+
To see all supported methods, see [the `shopify.authenticate` object documentation](https://shopify.dev/docs/api/shopify-app-remix/latest/authenticate).
|
|
419
176
|
|
|
420
177
|
## Gotchas / Troubleshooting
|
|
421
178
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
In Remix apps, you can navigate to a different page either by adding an `<a>` tag, or using the `<Link>` component from `@remix-run/react`.
|
|
425
|
-
|
|
426
|
-
In Shopify Remix apps you should avoid using `<a>`.
|
|
427
|
-
Use `<Link> `from `@remix-run/react` instead.
|
|
428
|
-
This ensures that your user remains authenticated.
|
|
179
|
+
If you're experiencing unexpected behaviors when using this package, check our [app template's documentation](https://github.com/Shopify/shopify-app-template-remix#gotchas--troubleshooting) for the solution to common issues.
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
require('react');
|
|
6
5
|
var polaris = require('@shopify/polaris');
|
|
7
6
|
var englishI18n = require('@shopify/polaris/locales/en.json');
|
|
8
7
|
var _const = require('../../const.js');
|
|
@@ -14,13 +13,18 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
14
13
|
var englishI18n__default = /*#__PURE__*/_interopDefaultLegacy(englishI18n);
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
|
-
* Sets up the Polaris AppProvider and injects the App Bridge script.
|
|
16
|
+
* Sets up the Polaris `AppProvider` and injects the App Bridge script.
|
|
17
|
+
*
|
|
18
|
+
* This component extends the [`AppProvider`](https://polaris.shopify.com/components/utilities/app-provider) component
|
|
19
|
+
* from Polaris, and accepts all of its props except for `linkComponent`, which is overridden to use the Remix `Link`
|
|
20
|
+
* component.
|
|
18
21
|
*
|
|
19
22
|
* {@link https://polaris.shopify.com/components/utilities/app-provider}
|
|
20
23
|
* {@link https://shopify.dev/tools/app-bridge}
|
|
21
24
|
*
|
|
22
25
|
* @example
|
|
23
|
-
*
|
|
26
|
+
* <caption>Set up AppProvider.</caption>
|
|
27
|
+
* <description>Wrap your app in the `AppProvider` component and pass in your API key.</description>
|
|
24
28
|
* ```ts
|
|
25
29
|
* import {authenticate} from '~/shopify.server';
|
|
26
30
|
* import {AppProvider} from '@shopify/shopify-app-remix/react';
|
|
@@ -35,7 +39,34 @@ var englishI18n__default = /*#__PURE__*/_interopDefaultLegacy(englishI18n);
|
|
|
35
39
|
* const { apiKey } = useLoaderData();
|
|
36
40
|
*
|
|
37
41
|
* return (
|
|
38
|
-
* <AppProvider apiKey={apiKey}>
|
|
42
|
+
* <AppProvider isEmbeddedApp apiKey={apiKey}>
|
|
43
|
+
* <Outlet />
|
|
44
|
+
* </AppProvider>
|
|
45
|
+
* );
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* <caption>Localize Polaris components.</caption>
|
|
51
|
+
* <description>Pass in a different locale for Polaris to translate its components.</description>
|
|
52
|
+
* ```ts
|
|
53
|
+
* import {authenticate} from '~/shopify.server';
|
|
54
|
+
* import {AppProvider} from '@shopify/shopify-app-remix/react';
|
|
55
|
+
*
|
|
56
|
+
* export async function loader({ request }) {
|
|
57
|
+
* await authenticate.admin(request);
|
|
58
|
+
*
|
|
59
|
+
* return json({
|
|
60
|
+
* apiKey: process.env.SHOPIFY_API_KEY,
|
|
61
|
+
* polarisTranslations: require("@shopify/polaris/locales/fr.json"),
|
|
62
|
+
* });
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* export default function App() {
|
|
66
|
+
* const { apiKey, polarisTranslations } = useLoaderData();
|
|
67
|
+
*
|
|
68
|
+
* return (
|
|
69
|
+
* <AppProvider apiKey={apiKey} i18n={polarisTranslations}>
|
|
39
70
|
* <Outlet />
|
|
40
71
|
* </AppProvider>
|
|
41
72
|
* );
|
|
@@ -11,7 +11,8 @@ function requestBillingFactory(params, request, session) {
|
|
|
11
11
|
return async function requestBilling({
|
|
12
12
|
plan,
|
|
13
13
|
isTest,
|
|
14
|
-
returnUrl
|
|
14
|
+
returnUrl,
|
|
15
|
+
...overrides
|
|
15
16
|
}) {
|
|
16
17
|
const {
|
|
17
18
|
api,
|
|
@@ -30,7 +31,8 @@ function requestBillingFactory(params, request, session) {
|
|
|
30
31
|
session,
|
|
31
32
|
isTest,
|
|
32
33
|
returnUrl,
|
|
33
|
-
returnObject: true
|
|
34
|
+
returnObject: true,
|
|
35
|
+
...overrides
|
|
34
36
|
});
|
|
35
37
|
} catch (error) {
|
|
36
38
|
if (error instanceof shopifyApi.HttpResponseError && error.response.code === 401) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var factory = require('../../../clients/admin/factory.js');
|
|
6
|
+
var factory$1 = require('../../../clients/storefront/factory.js');
|
|
6
7
|
|
|
7
8
|
function authenticateAppProxyFactory(params) {
|
|
8
9
|
const {
|
|
@@ -42,7 +43,8 @@ function authenticateAppProxyFactory(params) {
|
|
|
42
43
|
const context = {
|
|
43
44
|
liquid,
|
|
44
45
|
session: undefined,
|
|
45
|
-
admin: undefined
|
|
46
|
+
admin: undefined,
|
|
47
|
+
storefront: undefined
|
|
46
48
|
};
|
|
47
49
|
return context;
|
|
48
50
|
}
|
|
@@ -52,6 +54,10 @@ function authenticateAppProxyFactory(params) {
|
|
|
52
54
|
admin: factory.adminClientFactory({
|
|
53
55
|
params,
|
|
54
56
|
session
|
|
57
|
+
}),
|
|
58
|
+
storefront: factory$1.storefrontClientFactory({
|
|
59
|
+
params,
|
|
60
|
+
session
|
|
55
61
|
})
|
|
56
62
|
};
|
|
57
63
|
return context;
|
|
@@ -11,7 +11,7 @@ function authenticatePublicFactory(params) {
|
|
|
11
11
|
} = params;
|
|
12
12
|
const authenticateCheckout = authenticate$1.authenticateCheckoutFactory(params);
|
|
13
13
|
const authenticatePublic = (request, options) => {
|
|
14
|
-
logger.deprecated('
|
|
14
|
+
logger.deprecated('3.0.0', 'authenticate.public() will be deprecated in v3. Use authenticate.public.checkout() instead.');
|
|
15
15
|
return authenticateCheckout(request, options);
|
|
16
16
|
};
|
|
17
17
|
authenticatePublic.checkout = authenticateCheckout;
|
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
var factory = require('../../clients/admin/factory.js');
|
|
6
|
+
require('@shopify/shopify-api/runtime');
|
|
7
|
+
var handleClientError = require('../admin/helpers/handle-client-error.js');
|
|
8
|
+
require('@remix-run/server-runtime');
|
|
9
|
+
|
|
10
|
+
function authenticateWebhookFactory(params) {
|
|
11
|
+
const {
|
|
12
|
+
api,
|
|
13
|
+
config,
|
|
14
|
+
logger
|
|
15
|
+
} = params;
|
|
10
16
|
return async function authenticate(request) {
|
|
11
17
|
if (request.method !== 'POST') {
|
|
12
18
|
logger.debug('Received a non-POST request for a webhook. Only POST requests are allowed.', {
|
|
@@ -44,24 +50,36 @@ function authenticateWebhookFactory({
|
|
|
44
50
|
if (!session) {
|
|
45
51
|
return webhookContext;
|
|
46
52
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
let admin;
|
|
54
|
+
if (config.future.v3_webhookAdminContext) {
|
|
55
|
+
admin = factory.adminClientFactory({
|
|
56
|
+
params,
|
|
57
|
+
session,
|
|
58
|
+
handleClientError: handleClientError.handleClientErrorFactory({
|
|
59
|
+
request
|
|
60
|
+
})
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
const restClient = new api.clients.Rest({
|
|
64
|
+
session,
|
|
65
|
+
apiVersion: check.apiVersion
|
|
66
|
+
});
|
|
67
|
+
const graphqlClient = new api.clients.Graphql({
|
|
68
|
+
session,
|
|
69
|
+
apiVersion: check.apiVersion
|
|
70
|
+
});
|
|
71
|
+
Object.entries(api.rest).forEach(([name, resource]) => {
|
|
72
|
+
Reflect.set(restClient, name, resource);
|
|
73
|
+
});
|
|
74
|
+
admin = {
|
|
75
|
+
rest: restClient,
|
|
76
|
+
graphql: graphqlClient
|
|
77
|
+
};
|
|
78
|
+
}
|
|
58
79
|
return {
|
|
59
80
|
...webhookContext,
|
|
60
81
|
session,
|
|
61
|
-
admin:
|
|
62
|
-
rest: restClient,
|
|
63
|
-
graphql: graphqlClient
|
|
64
|
-
}
|
|
82
|
+
admin: admin
|
|
65
83
|
};
|
|
66
84
|
};
|
|
67
85
|
}
|
|
@@ -13,10 +13,10 @@ const boundary = {
|
|
|
13
13
|
* A function that handles errors or thrown responses.
|
|
14
14
|
*
|
|
15
15
|
* @example
|
|
16
|
-
* Catching errors in a route
|
|
16
|
+
* <caption>Catching errors in a route</caption>
|
|
17
17
|
* ```ts
|
|
18
|
-
* // app/routes/admin/widgets.ts
|
|
19
|
-
* import { boundary } from "@shopify/shopify-app-remix";
|
|
18
|
+
* // /app/routes/admin/widgets.ts
|
|
19
|
+
* import { boundary } from "@shopify/shopify-app-remix/server";
|
|
20
20
|
*
|
|
21
21
|
* export function ErrorBoundary() {
|
|
22
22
|
* return boundary.error(useRouteError());
|
|
@@ -28,10 +28,10 @@ const boundary = {
|
|
|
28
28
|
* A function that sets the appropriate document repsonse headers.
|
|
29
29
|
*
|
|
30
30
|
* @example
|
|
31
|
-
* Catching errors in a route
|
|
31
|
+
* <caption>Catching errors in a route</caption>
|
|
32
32
|
* ```ts
|
|
33
|
-
* // app/routes/admin/widgets.ts
|
|
34
|
-
* import { boundary } from "@shopify/shopify-app-remix";
|
|
33
|
+
* // /app/routes/admin/widgets.ts
|
|
34
|
+
* import { boundary } from "@shopify/shopify-app-remix/server";
|
|
35
35
|
*
|
|
36
36
|
* export const headers = (headersArgs) => {
|
|
37
37
|
* return boundary.headers(headersArgs);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var runtime = require('@shopify/shopify-api/runtime');
|
|
6
|
+
|
|
7
|
+
function storefrontClientFactory({
|
|
8
|
+
params,
|
|
9
|
+
session
|
|
10
|
+
}) {
|
|
11
|
+
const {
|
|
12
|
+
api
|
|
13
|
+
} = params;
|
|
14
|
+
return {
|
|
15
|
+
graphql: async (query, options = {}) => {
|
|
16
|
+
const client = new api.clients.Storefront({
|
|
17
|
+
session,
|
|
18
|
+
apiVersion: options.apiVersion
|
|
19
|
+
});
|
|
20
|
+
const apiResponse = await client.query({
|
|
21
|
+
data: {
|
|
22
|
+
query,
|
|
23
|
+
variables: options === null || options === void 0 ? void 0 : options.variables
|
|
24
|
+
},
|
|
25
|
+
tries: options.tries,
|
|
26
|
+
extraHeaders: options.headers
|
|
27
|
+
});
|
|
28
|
+
return new Response(JSON.stringify(apiResponse.body), {
|
|
29
|
+
headers: runtime.flatHeaders(apiResponse.headers)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
exports.storefrontClientFactory = storefrontClientFactory;
|