@shopify/shopify-app-remix 1.3.0 → 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.
Files changed (53) hide show
  1. package/README.md +32 -281
  2. package/build/cjs/server/authenticate/public/factory.js +1 -1
  3. package/build/cjs/server/authenticate/webhooks/authenticate.js +38 -20
  4. package/build/cjs/server/shopify-app.js +4 -4
  5. package/build/cjs/server/version.js +1 -1
  6. package/build/ts/server/__test-helpers/test-config.d.ts +9 -4
  7. package/build/ts/server/__test-helpers/test-config.d.ts.map +1 -1
  8. package/build/ts/server/__test-helpers/test-config.js +2 -2
  9. package/build/ts/server/__test-helpers/test-config.js.map +1 -1
  10. package/build/ts/server/authenticate/admin/billing/types.d.ts +8 -8
  11. package/build/ts/server/authenticate/admin/types.d.ts +12 -12
  12. package/build/ts/server/authenticate/public/appProxy/types.d.ts +2 -2
  13. package/build/ts/server/authenticate/public/checkout/types.d.ts +4 -4
  14. package/build/ts/server/authenticate/public/factory.js +1 -1
  15. package/build/ts/server/authenticate/public/types.d.ts +4 -4
  16. package/build/ts/server/authenticate/webhooks/authenticate.d.ts +3 -2
  17. package/build/ts/server/authenticate/webhooks/authenticate.d.ts.map +1 -1
  18. package/build/ts/server/authenticate/webhooks/authenticate.js +31 -19
  19. package/build/ts/server/authenticate/webhooks/authenticate.js.map +1 -1
  20. package/build/ts/server/authenticate/webhooks/authenticate.webhooks.doc.d.ts.map +1 -1
  21. package/build/ts/server/authenticate/webhooks/authenticate.webhooks.doc.js +9 -2
  22. package/build/ts/server/authenticate/webhooks/authenticate.webhooks.doc.js.map +1 -1
  23. package/build/ts/server/authenticate/webhooks/types.d.ts +70 -9
  24. package/build/ts/server/authenticate/webhooks/types.d.ts.map +1 -1
  25. package/build/ts/server/clients/admin/types.d.ts +7 -7
  26. package/build/ts/server/clients/storefront/types.d.ts +2 -2
  27. package/build/ts/server/config-types.d.ts +13 -4
  28. package/build/ts/server/config-types.d.ts.map +1 -1
  29. package/build/ts/server/future/flags.d.ts +11 -0
  30. package/build/ts/server/future/flags.d.ts.map +1 -0
  31. package/build/ts/server/future/flags.js +3 -0
  32. package/build/ts/server/future/flags.js.map +1 -0
  33. package/build/ts/server/shopify-app.d.ts.map +1 -1
  34. package/build/ts/server/shopify-app.doc.d.ts.map +1 -1
  35. package/build/ts/server/shopify-app.doc.js +6 -0
  36. package/build/ts/server/shopify-app.doc.js.map +1 -1
  37. package/build/ts/server/shopify-app.js +3 -4
  38. package/build/ts/server/shopify-app.js.map +1 -1
  39. package/build/ts/server/types.d.ts +13 -13
  40. package/build/ts/server/types.d.ts.map +1 -1
  41. package/build/ts/server/unauthenticated/admin/types.d.ts +2 -2
  42. package/build/ts/server/unauthenticated/helpers/get-offline-session.d.ts +1 -1
  43. package/build/ts/server/unauthenticated/helpers/get-offline-session.d.ts.map +1 -1
  44. package/build/ts/server/unauthenticated/helpers/get-offline-session.js.map +1 -1
  45. package/build/ts/server/unauthenticated/storefront/factory.d.ts +1 -1
  46. package/build/ts/server/unauthenticated/storefront/factory.d.ts.map +1 -1
  47. package/build/ts/server/unauthenticated/storefront/factory.js.map +1 -1
  48. package/build/ts/server/unauthenticated/storefront/types.d.ts +2 -2
  49. package/build/ts/server/unauthenticated/types.d.ts +4 -4
  50. package/build/ts/server/version.d.ts +1 -1
  51. package/build/ts/server/version.js +1 -1
  52. package/package.json +6 -6
  53. 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 follow these usage guides, you will need to:
15
+ To use this package, you will need to have:
14
16
 
15
- - have a Shopify Partner account and development store
16
- - have an app already set up on your partner account
17
- - have a JavaScript package manager such as [yarn](https://yarnpkg.com) installed
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
 
@@ -41,11 +43,18 @@ Now let's install this package:
41
43
  npm install @shopify/shopify-app-remix
42
44
  ```
43
45
 
44
- Create `app/shopify.server.js`. We will use this file to configure our Shopify app:
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). The default is `apps/routes/auth/$.tsx`, but you can configure this route using the `authPathPrefix option`:
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 {LoaderArgs} from '@remix-run/node';
84
+ import {LoaderFunctionArgs} from '@remix-run/node';
97
85
 
98
86
  import shopify from '~/shopify.server';
99
87
 
100
- export async function loader({request}: LoaderArgs) {
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 {LoaderArgs} from '@remix-run/node';
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}: LoaderArgs) {
106
+ export async function loader({request}: LoaderFunctionArgs) {
119
107
  await shopify.authenticate.admin(request);
120
108
 
121
109
  return json({
@@ -166,263 +154,26 @@ export default function handleRequest(
166
154
  }
167
155
  ```
168
156
 
169
- ## Setting up for your runtime
157
+ ### Running your app
170
158
 
171
- By default, this package will work with the runtimes supported by [Remix adapters](https://remix.run/docs/en/1.17.1/other-api/adapter#official-adapters) because it relies on the same [Web Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
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, then 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
- ## Authenticating admin requests
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 is 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
- To do that, you can set up a [Remix `ErrorBoundary`](https://remix.run/docs/en/main/guides/errors).
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
- ```ts
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
- To access the [Shopify Admin GraphQL API](https://shopify.dev/docs/api/admin-graphql) pass a request from a loader or an action to `shopify.authenticate.admin`.
248
- This will either redirect the merchant to install your app or it will give you access to API functions.
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
- ### Using the Shopify admin REST API
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 are 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
- ### Navigating to other pages breaks
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.
@@ -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('2.0.0', 'authenticate.public() will be deprecated in v2. Use authenticate.public.checkout() instead.');
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
- function authenticateWebhookFactory({
6
- api,
7
- config,
8
- logger
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
- const restClient = new api.clients.Rest({
48
- session,
49
- apiVersion: check.apiVersion
50
- });
51
- const graphqlClient = new api.clients.Graphql({
52
- session,
53
- apiVersion: check.apiVersion
54
- });
55
- Object.entries(api.rest).forEach(([name, resource]) => {
56
- Reflect.set(restClient, name, resource);
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
  }
@@ -94,7 +94,7 @@ function deriveApi(appConfig) {
94
94
  if (appConfig.userAgentPrefix) {
95
95
  userAgentPrefix = `${appConfig.userAgentPrefix} | ${userAgentPrefix}`;
96
96
  }
97
- const cleanApiConfig = {
97
+ return shopifyApi.shopifyApi({
98
98
  ...appConfig,
99
99
  hostName: appUrl.host,
100
100
  hostScheme: appUrl.protocol.replace(':', ''),
@@ -102,11 +102,10 @@ function deriveApi(appConfig) {
102
102
  isEmbeddedApp: (_appConfig$isEmbedded = appConfig.isEmbeddedApp) !== null && _appConfig$isEmbedded !== void 0 ? _appConfig$isEmbedded : true,
103
103
  apiVersion: (_appConfig$apiVersion = appConfig.apiVersion) !== null && _appConfig$apiVersion !== void 0 ? _appConfig$apiVersion : shopifyApi.LATEST_API_VERSION,
104
104
  isCustomStoreApp: appConfig.distribution === types.AppDistribution.ShopifyAdmin
105
- };
106
- return shopifyApi.shopifyApi(cleanApiConfig);
105
+ });
107
106
  }
108
107
  function deriveConfig(appConfig, apiConfig) {
109
- var _appConfig$distributi, _appConfig$useOnlineT, _appConfig$hooks;
108
+ var _appConfig$distributi, _appConfig$useOnlineT, _appConfig$hooks, _appConfig$future;
110
109
  if (!appConfig.sessionStorage) {
111
110
  throw new shopifyApi.ShopifyError('Please provide a valid session storage. Refer to https://github.com/Shopify/shopify-app-js/blob/main/README.md#session-storage-options for options.');
112
111
  }
@@ -119,6 +118,7 @@ function deriveConfig(appConfig, apiConfig) {
119
118
  useOnlineTokens: (_appConfig$useOnlineT = appConfig.useOnlineTokens) !== null && _appConfig$useOnlineT !== void 0 ? _appConfig$useOnlineT : false,
120
119
  hooks: (_appConfig$hooks = appConfig.hooks) !== null && _appConfig$hooks !== void 0 ? _appConfig$hooks : {},
121
120
  sessionStorage: appConfig.sessionStorage,
121
+ future: (_appConfig$future = appConfig.future) !== null && _appConfig$future !== void 0 ? _appConfig$future : {},
122
122
  auth: {
123
123
  path: authPathPrefix,
124
124
  callbackPath: `${authPathPrefix}/callback`,
@@ -2,6 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const SHOPIFY_REMIX_LIBRARY_VERSION = '1.3.0';
5
+ const SHOPIFY_REMIX_LIBRARY_VERSION = '2.0.0';
6
6
 
7
7
  exports.SHOPIFY_REMIX_LIBRARY_VERSION = SHOPIFY_REMIX_LIBRARY_VERSION;
@@ -1,6 +1,11 @@
1
- import { SessionStorage } from '@shopify/shopify-app-session-storage';
2
- import { AppConfigArg } from '../config-types';
3
- export declare function testConfig(overrides?: Partial<AppConfigArg>): AppConfigArg & {
4
- sessionStorage: SessionStorage;
1
+ import type { AppConfigArg } from '../config-types';
2
+ import type { FutureFlags } from '../future/flags';
3
+ type DefaultedFutureFlag<Overrides extends Partial<AppConfigArg>, Flag extends keyof FutureFlags> = Overrides['future'] extends FutureFlags ? Overrides['future'][Flag] : true;
4
+ type TestConfig<Overrides extends Partial<AppConfigArg>> = Omit<AppConfigArg, 'billing'> & Overrides & {
5
+ future: {
6
+ v3_webhookAdminContext: DefaultedFutureFlag<Overrides, 'v3_webhookAdminContext'>;
7
+ };
5
8
  };
9
+ export declare function testConfig<Overrides extends Partial<AppConfigArg>>(overrides?: Overrides): TestConfig<Overrides>;
10
+ export {};
6
11
  //# sourceMappingURL=test-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-config.d.ts","sourceRoot":"","sources":["../../../../src/server/__test-helpers/test-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,sCAAsC,CAAC;AAIpE,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAI7C,wBAAgB,UAAU,CACxB,SAAS,GAAE,OAAO,CAAC,YAAY,CAAM,GACpC,YAAY,GAAG;IAAC,cAAc,EAAE,cAAc,CAAA;CAAC,CAejD"}
1
+ {"version":3,"file":"test-config.d.ts","sourceRoot":"","sources":["../../../../src/server/__test-helpers/test-config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAIjD,KAAK,mBAAmB,CACtB,SAAS,SAAS,OAAO,CAAC,YAAY,CAAC,EACvC,IAAI,SAAS,MAAM,WAAW,IAC5B,SAAS,CAAC,QAAQ,CAAC,SAAS,WAAW,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE/E,KAAK,UAAU,CAAC,SAAS,SAAS,OAAO,CAAC,YAAY,CAAC,IAErD,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAC3B,SAAS,GAAG;IAEV,MAAM,EAAE;QACN,sBAAsB,EAAE,mBAAmB,CACzC,SAAS,EACT,wBAAwB,CACzB,CAAC;KACH,CAAC;CACH,CAAC;AAEN,wBAAgB,UAAU,CAAC,SAAS,SAAS,OAAO,CAAC,YAAY,CAAC,EAChE,SAAS,GAAE,SAA2B,GACrC,UAAU,CAAC,SAAS,CAAC,CAmBvB"}
@@ -7,10 +7,10 @@ var shopify_app_session_storage_memory_1 = require("@shopify/shopify-app-session
7
7
  var const_1 = require("./const");
8
8
  function testConfig(overrides) {
9
9
  if (overrides === void 0) { overrides = {}; }
10
- return tslib_1.__assign({ apiKey: const_1.API_KEY, apiSecretKey: const_1.API_SECRET_KEY, scopes: ['testScope'], apiVersion: shopify_api_1.LATEST_API_VERSION, appUrl: const_1.APP_URL, logger: {
10
+ return tslib_1.__assign(tslib_1.__assign({ apiKey: const_1.API_KEY, apiSecretKey: const_1.API_SECRET_KEY, scopes: ['testScope'], apiVersion: shopify_api_1.LATEST_API_VERSION, appUrl: const_1.APP_URL, logger: {
11
11
  log: jest.fn(),
12
12
  level: shopify_api_1.LogSeverity.Debug,
13
- }, isEmbeddedApp: true, sessionStorage: new shopify_app_session_storage_memory_1.MemorySessionStorage() }, overrides);
13
+ }, isEmbeddedApp: true, sessionStorage: new shopify_app_session_storage_memory_1.MemorySessionStorage() }, overrides), { future: tslib_1.__assign({ v3_webhookAdminContext: true }, overrides.future) });
14
14
  }
15
15
  exports.testConfig = testConfig;
16
16
  //# sourceMappingURL=test-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-config.js","sourceRoot":"","sources":["../../../../src/server/__test-helpers/test-config.ts"],"names":[],"mappings":";;;;AACA,oDAAqE;AACrE,kGAAiF;AAIjF,iCAAyD;AAEzD,SAAgB,UAAU,CACxB,SAAqC;IAArC,0BAAA,EAAA,cAAqC;IAErC,0BACE,MAAM,EAAE,eAAO,EACf,YAAY,EAAE,sBAAc,EAC5B,MAAM,EAAE,CAAC,WAAW,CAAC,EACrB,UAAU,EAAE,gCAAkB,EAC9B,MAAM,EAAE,eAAO,EACf,MAAM,EAAE;YACN,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE;YACd,KAAK,EAAE,yBAAW,CAAC,KAAK;SACzB,EACD,aAAa,EAAE,IAAI,EACnB,cAAc,EAAE,IAAI,yDAAoB,EAAE,IACvC,SAAS,EACZ;AACJ,CAAC;AAjBD,gCAiBC"}
1
+ {"version":3,"file":"test-config.js","sourceRoot":"","sources":["../../../../src/server/__test-helpers/test-config.ts"],"names":[],"mappings":";;;;AAAA,oDAAqE;AACrE,kGAAiF;AAKjF,iCAAyD;AAoBzD,SAAgB,UAAU,CACxB,SAAsC;IAAtC,0BAAA,EAAA,YAAuB,EAAe;IAEtC,2CACE,MAAM,EAAE,eAAO,EACf,YAAY,EAAE,sBAAc,EAC5B,MAAM,EAAE,CAAC,WAAW,CAAC,EACrB,UAAU,EAAE,gCAAkB,EAC9B,MAAM,EAAE,eAAO,EACf,MAAM,EAAE;YACN,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE;YACd,KAAK,EAAE,yBAAW,CAAC,KAAK;SACzB,EACD,aAAa,EAAE,IAAI,EACnB,cAAc,EAAE,IAAI,yDAAoB,EAAE,IACvC,SAAS,KACZ,MAAM,qBACJ,sBAAsB,EAAE,IAAI,IACxB,SAAS,CAAC,MAA8B,KAE9C;AACJ,CAAC;AArBD,gCAqBC"}
@@ -40,10 +40,10 @@ export interface BillingContext<Config extends AppConfigArg> {
40
40
  * <description>Call `billing.request` in the `onFailure` callback to immediately request payment.</description>
41
41
  * ```ts
42
42
  * // /app/routes/**\/*.ts
43
- * import { LoaderArgs } from "@remix-run/node";
43
+ * import { LoaderFunctionArgs } from "@remix-run/node";
44
44
  * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
45
45
  *
46
- * export const loader = async ({ request }: LoaderArgs) => {
46
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
47
47
  * const { billing } = await authenticate.admin(request);
48
48
  * await billing.require({
49
49
  * plans: [MONTHLY_PLAN],
@@ -85,10 +85,10 @@ export interface BillingContext<Config extends AppConfigArg> {
85
85
  * <description>Redirect to a different page in the `onFailure` callback, where the merchant can select a billing plan.</description>
86
86
  * ```ts
87
87
  * // /app/routes/**\/*.ts
88
- * import { LoaderArgs, redirect } from "@remix-run/node";
88
+ * import { LoaderFunctionArgs, redirect } from "@remix-run/node";
89
89
  * import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from "../shopify.server";
90
90
  *
91
- * export const loader = async ({ request }: LoaderArgs) => {
91
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
92
92
  * const { billing } = await authenticate.admin(request);
93
93
  * const billingCheck = await billing.require({
94
94
  * plans: [MONTHLY_PLAN, ANNUAL_PLAN],
@@ -139,10 +139,10 @@ export interface BillingContext<Config extends AppConfigArg> {
139
139
  * <description>Change where the merchant is returned to after approving the purchase using the `returnUrl` option.</description>
140
140
  * ```ts
141
141
  * // /app/routes/**\/*.ts
142
- * import { LoaderArgs } from "@remix-run/node";
142
+ * import { LoaderFunctionArgs } from "@remix-run/node";
143
143
  * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
144
144
  *
145
- * export const loader = async ({ request }: LoaderArgs) => {
145
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
146
146
  * const { billing } = await authenticate.admin(request);
147
147
  * await billing.require({
148
148
  * plans: [MONTHLY_PLAN],
@@ -193,10 +193,10 @@ export interface BillingContext<Config extends AppConfigArg> {
193
193
  * <description>Use the `billing.cancel` function to cancel an active subscription with the id returned from `billing.require`.</description>
194
194
  * ```ts
195
195
  * // /app/routes/cancel-subscription.ts
196
- * import { LoaderArgs } from "@remix-run/node";
196
+ * import { LoaderFunctionArgs } from "@remix-run/node";
197
197
  * import { authenticate, MONTHLY_PLAN } from "../shopify.server";
198
198
  *
199
- * export const loader = async ({ request }: LoaderArgs) => {
199
+ * export const loader = async ({ request }: LoaderFunctionArgs) => {
200
200
  * const { billing } = await authenticate.admin(request);
201
201
  * const billingCheck = await billing.require({
202
202
  * plans: [MONTHLY_PLAN],