shopify-nuxt 0.0.2 → 0.0.3

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 (63) hide show
  1. package/README.md +293 -23
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +23 -5
  4. package/dist/runtime/components/polaris/ShButton.d.vue.ts +1 -1
  5. package/dist/runtime/components/polaris/ShButton.vue.d.ts +1 -1
  6. package/dist/runtime/components/polaris/ShCheckbox.d.vue.ts +2 -2
  7. package/dist/runtime/components/polaris/ShCheckbox.vue.d.ts +2 -2
  8. package/dist/runtime/components/polaris/ShChoiceList.d.vue.ts +2 -2
  9. package/dist/runtime/components/polaris/ShChoiceList.vue.d.ts +2 -2
  10. package/dist/runtime/components/polaris/ShColorField.d.vue.ts +2 -2
  11. package/dist/runtime/components/polaris/ShColorField.vue.d.ts +2 -2
  12. package/dist/runtime/components/polaris/ShColorPicker.d.vue.ts +2 -2
  13. package/dist/runtime/components/polaris/ShColorPicker.vue.d.ts +2 -2
  14. package/dist/runtime/components/polaris/ShDateField.d.vue.ts +2 -2
  15. package/dist/runtime/components/polaris/ShDateField.vue.d.ts +2 -2
  16. package/dist/runtime/components/polaris/ShDatePicker.d.vue.ts +2 -2
  17. package/dist/runtime/components/polaris/ShDatePicker.vue.d.ts +2 -2
  18. package/dist/runtime/components/polaris/ShDropZone.d.vue.ts +2 -2
  19. package/dist/runtime/components/polaris/ShDropZone.vue.d.ts +2 -2
  20. package/dist/runtime/components/polaris/ShEmailField.d.vue.ts +2 -2
  21. package/dist/runtime/components/polaris/ShEmailField.vue.d.ts +2 -2
  22. package/dist/runtime/components/polaris/ShMoneyField.d.vue.ts +2 -2
  23. package/dist/runtime/components/polaris/ShMoneyField.vue.d.ts +2 -2
  24. package/dist/runtime/components/polaris/ShNumberField.d.vue.ts +2 -2
  25. package/dist/runtime/components/polaris/ShNumberField.vue.d.ts +2 -2
  26. package/dist/runtime/components/polaris/ShPasswordField.d.vue.ts +2 -2
  27. package/dist/runtime/components/polaris/ShPasswordField.vue.d.ts +2 -2
  28. package/dist/runtime/components/polaris/ShSearchField.d.vue.ts +2 -2
  29. package/dist/runtime/components/polaris/ShSearchField.vue.d.ts +2 -2
  30. package/dist/runtime/components/polaris/ShSelect.d.vue.ts +2 -2
  31. package/dist/runtime/components/polaris/ShSelect.vue.d.ts +2 -2
  32. package/dist/runtime/components/polaris/ShSwitch.d.vue.ts +2 -2
  33. package/dist/runtime/components/polaris/ShSwitch.vue.d.ts +2 -2
  34. package/dist/runtime/components/polaris/ShTextArea.d.vue.ts +2 -2
  35. package/dist/runtime/components/polaris/ShTextArea.vue.d.ts +2 -2
  36. package/dist/runtime/components/polaris/ShTextField.d.vue.ts +2 -2
  37. package/dist/runtime/components/polaris/ShTextField.vue.d.ts +2 -2
  38. package/dist/runtime/components/polaris/ShUrlField.d.vue.ts +2 -2
  39. package/dist/runtime/components/polaris/ShUrlField.vue.d.ts +2 -2
  40. package/dist/runtime/composables/useAppBridge.d.ts +4 -1
  41. package/dist/runtime/composables/useAppBridge.js +24 -13
  42. package/dist/runtime/middleware/shopify-auth.js +10 -4
  43. package/dist/runtime/pages/auth-login.d.vue.ts +3 -0
  44. package/dist/runtime/pages/auth-login.vue +90 -0
  45. package/dist/runtime/pages/auth-login.vue.d.ts +3 -0
  46. package/dist/runtime/server/index.d.ts +2 -0
  47. package/dist/runtime/server/index.js +4 -0
  48. package/dist/runtime/server/plugins/shopify-defaults.d.ts +8 -0
  49. package/dist/runtime/server/plugins/shopify-defaults.js +12 -0
  50. package/dist/runtime/server/routes/auth-callback.d.ts +1 -1
  51. package/dist/runtime/server/routes/auth-exit-iframe.d.ts +1 -1
  52. package/dist/runtime/server/routes/auth-session-token.d.ts +1 -1
  53. package/dist/runtime/server/routes/auth.d.ts +1 -1
  54. package/dist/runtime/server/services/shopify.js +3 -3
  55. package/dist/runtime/server/utils/clients.d.ts +24 -5
  56. package/dist/runtime/server/utils/clients.js +21 -2
  57. package/dist/runtime/server/utils/helpers.js +13 -11
  58. package/dist/runtime/server/utils/unauthenticated-storefront.d.ts +1 -5
  59. package/dist/runtime/server/utils/unauthenticated-storefront.js +2 -8
  60. package/dist/runtime/types.d.ts +33 -2
  61. package/package.json +9 -5
  62. package/dist/runtime/plugins/polaris.d.ts +0 -1
  63. package/dist/runtime/plugins/polaris.js +0 -0
package/README.md CHANGED
@@ -47,22 +47,34 @@ export default defineNuxtConfig({
47
47
  shopify: {
48
48
  apiKey: 'ApiKeyFromPartnersDashboard',
49
49
  apiSecretKey: 'ApiSecretKeyFromPartnersDashboard',
50
- scopes: ['read_products', 'write_products'],
51
50
  appUrl: 'https://your-app-url.com'
52
51
  }
53
52
  })
54
53
  ```
55
54
 
56
- For session storage and post-auth hooks, create a Nitro server plugin:
55
+ All values can also be set via environment variables:
56
+
57
+ | Option | Env Variable |
58
+ | -------------- | ----------------------------- |
59
+ | `apiKey` | `NUXT_SHOPIFY_API_KEY` |
60
+ | `apiSecretKey` | `NUXT_SHOPIFY_API_SECRET_KEY` |
61
+ | `appUrl` | `NUXT_SHOPIFY_APP_URL` |
62
+
63
+ ### Session storage
64
+
65
+ By default, the module provides an in-memory session storage (`MemorySessionStorage`) that works out of the box — no configuration needed. For production use, you should use a persistent session storage adapter.
66
+
67
+ To override the default session storage or configure lifecycle hooks, create a Nitro server plugin:
57
68
 
58
69
  ```ts
59
70
  // server/plugins/shopify.ts
60
71
  import { configureShopify } from '#shopify/server'
61
- import { MemorySessionStorage } from '@shopify/shopify-app-session-storage-memory'
72
+ import { PrismaSessionStorage } from '@shopify/shopify-app-session-storage-prisma'
73
+ import { prisma } from '~/server/utils/prisma'
62
74
 
63
75
  export default defineNitroPlugin(() => {
64
76
  configureShopify({
65
- sessionStorage: new MemorySessionStorage(),
77
+ sessionStorage: new PrismaSessionStorage(prisma),
66
78
  hooks: {
67
79
  afterAuth: async ({ session, admin }) => {
68
80
  // Register webhooks, seed data, etc.
@@ -72,14 +84,30 @@ export default defineNitroPlugin(() => {
72
84
  })
73
85
  ```
74
86
 
75
- ### Authenticating admin requests
87
+ Any config passed to `configureShopify()` is merged with the defaults — you only need to specify what you want to override.
88
+
89
+ ### Module options
90
+
91
+ | Option | Type | Default | Description |
92
+ | ----------------- | ----------------- | ---------------- | ----------------------------------------------------------------------- |
93
+ | `apiKey` | `string` | — | Your Shopify API key from the Partners dashboard |
94
+ | `apiSecretKey` | `string` | — | Your Shopify API secret key |
95
+ | `scopes` | `string[]` | `[]` | OAuth scopes (optional — Shopify reads from `shopify.app.toml`) |
96
+ | `appUrl` | `string` | — | Your app's public URL (tunnel URL in development) |
97
+ | `apiVersion` | `ApiVersion` | Latest stable | The Shopify API version to use |
98
+ | `authPathPrefix` | `string` | `/_shopify/auth` | URL prefix for OAuth endpoints |
99
+ | `distribution` | `AppDistribution` | `app_store` | App distribution type (`app_store`, `single_merchant`, `shopify_admin`) |
100
+ | `useOnlineTokens` | `boolean` | `false` | Use online (per-user) tokens in addition to offline (per-shop) tokens |
101
+ | `authPage` | `string \| false` | built-in page | Custom auth page component path, or `false` to disable |
102
+
103
+ ## Authenticating admin requests
76
104
 
77
- Use `useShopifyAdmin()` in your server API routes to authenticate requests from the Shopify admin:
105
+ Use `useShopifyAdmin()` in your server API routes to authenticate requests from the Shopify admin. The returned `admin` object provides **typed GraphQL** and REST clients powered by `@shopify/admin-api-client`:
78
106
 
79
107
  ```ts
80
108
  // server/api/products.ts
81
109
  export default defineEventHandler(async (event) => {
82
- const { admin } = await useShopifyAdmin(event)
110
+ const { admin, session } = await useShopifyAdmin(event)
83
111
 
84
112
  const response = await admin.graphql(`{
85
113
  products(first: 5) {
@@ -92,13 +120,57 @@ export default defineEventHandler(async (event) => {
92
120
  }
93
121
  }`)
94
122
 
95
- return response
123
+ return await response.json()
124
+ })
125
+ ```
126
+
127
+ #### GraphQL with variables
128
+
129
+ ```ts
130
+ const response = await admin.graphql(
131
+ `#graphql
132
+ mutation populateProduct($input: ProductInput!) {
133
+ productCreate(input: $input) {
134
+ product {
135
+ id
136
+ title
137
+ }
138
+ }
139
+ }`,
140
+ {
141
+ variables: {
142
+ input: { title: 'New Product' }
143
+ }
144
+ }
145
+ )
146
+
147
+ const { data } = await response.json()
148
+ ```
149
+
150
+ #### REST API
151
+
152
+ ```ts
153
+ const products = await admin.rest.get({ path: 'products' })
154
+ await admin.rest.post({
155
+ path: 'products',
156
+ data: { product: { title: 'New Product' } }
96
157
  })
97
158
  ```
98
159
 
99
- ### Handling webhooks
160
+ #### Full `AdminContext` return type
161
+
162
+ | Property | Type | Description |
163
+ | -------------- | -------------------------- | -------------------------------------------------- |
164
+ | `session` | `Session` | The authenticated Shopify session |
165
+ | `admin` | `AdminApiContext` | GraphQL and REST API clients |
166
+ | `sessionToken` | `JwtPayload \| undefined` | Decoded session token (embedded apps only) |
167
+ | `billing` | `BillingContext` | Helpers for `require()`, `check()`, `request()` |
168
+ | `cors` | `(response) => Response` | Add CORS headers to a response |
169
+ | `redirect` | `(url, init?) => Response` | Redirect helper that works inside embedded iframes |
170
+
171
+ ## Handling webhooks
100
172
 
101
- Use `useShopifyWebhook()` to validate and process incoming webhooks:
173
+ Use `useShopifyWebhook()` to validate and process incoming webhooks. HMAC verification is handled automatically:
102
174
 
103
175
  ```ts
104
176
  // server/api/webhooks.ts
@@ -118,7 +190,81 @@ export default defineEventHandler(async (event) => {
118
190
  })
119
191
  ```
120
192
 
121
- ### Using App Bridge on the client
193
+ #### Registering webhooks programmatically
194
+
195
+ ```ts
196
+ // server/plugins/shopify.ts
197
+ import { configureShopify, registerShopifyWebhooks } from '#shopify/server'
198
+
199
+ export default defineNitroPlugin(() => {
200
+ configureShopify({
201
+ hooks: {
202
+ afterAuth: async ({ session }) => {
203
+ await registerShopifyWebhooks(session)
204
+ }
205
+ }
206
+ })
207
+ })
208
+ ```
209
+
210
+ > **Tip**: For most apps, registering webhooks via `shopify.app.toml` is sufficient. Use `registerShopifyWebhooks()` only when you need dynamic, per-shop webhook registration.
211
+
212
+ ## Authenticating other request types
213
+
214
+ ### Shopify Flow
215
+
216
+ ```ts
217
+ // server/api/flow.ts
218
+ export default defineEventHandler(async (event) => {
219
+ const { session, admin, payload } = await useShopifyFlow(event)
220
+ // Handle Flow trigger/action
221
+ })
222
+ ```
223
+
224
+ ### Public requests (checkout extensions, etc.)
225
+
226
+ ```ts
227
+ // server/api/public/widget.ts
228
+ export default defineEventHandler(async (event) => {
229
+ const { sessionToken, cors } = await useShopifyPublic(event)
230
+ // sessionToken contains the decoded JWT payload
231
+ // Use cors() to wrap your response with CORS headers
232
+ })
233
+ ```
234
+
235
+ ### Unauthenticated access (background jobs)
236
+
237
+ For accessing the Shopify API without an incoming request (cron jobs, background tasks):
238
+
239
+ ```ts
240
+ // server/api/cron/sync.ts
241
+ export default defineEventHandler(async () => {
242
+ const { admin } = await useShopifyUnauthenticatedAdmin(
243
+ 'my-shop.myshopify.com'
244
+ )
245
+
246
+ const response = await admin.graphql(`{
247
+ products(first: 10) { edges { node { id title } } }
248
+ }`)
249
+
250
+ return await response.json()
251
+ })
252
+ ```
253
+
254
+ ```ts
255
+ // Storefront API access
256
+ const { storefront } = await useShopifyUnauthenticatedStorefront(
257
+ 'my-shop.myshopify.com'
258
+ )
259
+
260
+ const response = await storefront.graphql(`{
261
+ products(first: 10) { edges { node { id title } } }
262
+ }`)
263
+ ```
264
+
265
+ Both the admin and storefront GraphQL clients are typed via `@shopify/admin-api-client` and `@shopify/storefront-api-client` respectively.
266
+
267
+ ## Using App Bridge on the client
122
268
 
123
269
  The module automatically injects the Shopify App Bridge CDN script and provides typed access via composables:
124
270
 
@@ -127,15 +273,32 @@ The module automatically injects the Shopify App Bridge CDN script and provides
127
273
  // Access the App Bridge instance (typed as ShopifyGlobal)
128
274
  const shopify = useAppBridge()
129
275
 
130
- // Or use the authenticated fetch wrapper
276
+ // Get the current shop
277
+ const shop = shopify.config.shop
278
+ </script>
279
+ ```
280
+
281
+ ### Authenticated fetch
282
+
283
+ Use `useShopifyFetch()` for client-side API calls that automatically include the session token:
284
+
285
+ ```vue
286
+ <script setup>
131
287
  const shopifyFetch = useShopifyFetch()
132
- const { data } = await shopifyFetch('/api/products')
288
+
289
+ const { data: products } = await useAsyncData(
290
+ 'products',
291
+ () => shopifyFetch('/api/products'),
292
+ { server: false }
293
+ )
133
294
  </script>
134
295
  ```
135
296
 
136
- ### Using Polaris components
297
+ > **Important**: Always use `server: false` with `useShopifyFetch()` — session tokens are only available on the client side within the Shopify admin iframe.
137
298
 
138
- This module provides Vue wrapper components for [Shopify Polaris web components](https://shopify.dev/docs/api/app-home/web-components). Use the `Sh`-prefixed wrappers instead of the raw `s-*` web components — they provide typed props with autocomplete and work seamlessly with Vue's reactivity system.
299
+ ## Using Polaris components
300
+
301
+ This module provides Vue wrapper components for [Shopify Polaris web components](https://shopify.dev/docs/api/app-home/web-components). Use the `Sh`-prefixed wrappers instead of the raw `s-*` web components — they provide typed props with autocomplete, v-model support for form components, and work seamlessly with Vue's reactivity system.
139
302
 
140
303
  ```vue
141
304
  <template>
@@ -150,17 +313,57 @@ This module provides Vue wrapper components for [Shopify Polaris web components]
150
313
  </ShBanner>
151
314
 
152
315
  <ShTextField
316
+ v-model="title"
153
317
  label="Product title"
154
- :value="title"
155
318
  placeholder="Enter product title"
156
319
  />
320
+
321
+ <ShSelect
322
+ v-model="status"
323
+ label="Status"
324
+ :options="[
325
+ { label: 'Active', value: 'active' },
326
+ { label: 'Draft', value: 'draft' }
327
+ ]"
328
+ />
157
329
  </ShPage>
158
330
  </template>
159
331
  ```
160
332
 
161
333
  All `Sh*` components are auto-imported — no manual imports needed. Each component maps directly to its Polaris web component counterpart (e.g., `<ShButton>` → `<s-button>`, `<ShTextField>` → `<s-text-field>`).
162
334
 
163
- ### Loading your app in Shopify Admin
335
+ ### Available components
336
+
337
+ Layout & structure: `ShPage`, `ShBox`, `ShStack`, `ShGrid`, `ShGridItem`, `ShSection`, `ShDivider`
338
+
339
+ Actions: `ShButton`, `ShButtonGroup`, `ShClickable`, `ShLink`
340
+
341
+ Forms: `ShTextField`, `ShNumberField`, `ShEmailField`, `ShPasswordField`, `ShUrlField`, `ShMoneyField`, `ShColorField`, `ShDateField`, `ShTextArea`, `ShSelect`, `ShCheckbox`, `ShSwitch`, `ShChoiceList`, `ShChoice`, `ShSearchField`, `ShDropZone`, `ShColorPicker`, `ShDatePicker`
342
+
343
+ Feedback: `ShBanner`, `ShBadge`, `ShSpinner`, `ShTooltip`
344
+
345
+ Navigation: `ShAppNav`, `ShMenu`, `ShOption`, `ShOptionGroup`, `ShPopover`
346
+
347
+ Data: `ShTable`, `ShTableHeader`, `ShTableHeaderRow`, `ShTableBody`, `ShTableRow`, `ShTableCell`
348
+
349
+ Content: `ShText`, `ShHeading`, `ShParagraph`, `ShIcon`, `ShImage`, `ShThumbnail`, `ShAvatar`, `ShChip`, `ShClickableChip`, `ShListItem`, `ShOrderedList`, `ShUnorderedList`
350
+
351
+ Other: `ShModal`, `ShQueryContainer`
352
+
353
+ ## OAuth routes
354
+
355
+ The module automatically registers these routes:
356
+
357
+ | Route | Purpose |
358
+ | ---------------------------------- | -------------------------------------- |
359
+ | `GET /_shopify/auth` | Start the OAuth flow |
360
+ | `GET /_shopify/auth/callback` | Handle the OAuth callback from Shopify |
361
+ | `GET /_shopify/auth/exit-iframe` | App Bridge iframe escape page |
362
+ | `GET /_shopify/auth/session-token` | Session token bounce page |
363
+
364
+ The prefix `/_shopify/auth` is configurable via the `authPathPrefix` option.
365
+
366
+ ## Loading your app in Shopify Admin
164
367
 
165
368
  To load your app within the Shopify Admin, you need to:
166
369
 
@@ -175,11 +378,15 @@ To load your app within the Shopify Admin, you need to:
175
378
  | **Authentication** | OAuth flow, session tokens, token exchange — all handled automatically |
176
379
  | **App Bridge** | CDN-based App Bridge with full TypeScript types via `@shopify/app-bridge-types` |
177
380
  | **Polaris** | Vue wrapper components (`Sh*`) for all Polaris web components with typed props |
381
+ | **Typed GraphQL** | Admin and Storefront API clients typed via `@shopify/admin-api-client` |
178
382
  | **Webhooks** | HMAC validation, payload parsing, and webhook registration |
179
383
  | **Admin API** | GraphQL and REST clients with automatic session management |
384
+ | **Storefront API** | Typed GraphQL client for Storefront API via `@shopify/storefront-api-client` |
180
385
  | **Billing** | Billing context for subscription and usage-based charges |
181
- | **Session storage** | Pluggable session storage via `@shopify/shopify-app-session-storage` |
182
- | **Auto-imports** | Server utilities and client composables are auto-imported |
386
+ | **Session storage** | Built-in `MemorySessionStorage` default, pluggable via `configureShopify()` |
387
+ | **Auto-imports** | Server utilities, client composables, and components are auto-imported |
388
+ | **Bot detection** | Admin auth automatically detects bots and returns 410 to avoid unnecessary auth |
389
+ | **CORS** | Built-in CORS helpers for public/checkout extension endpoints |
183
390
 
184
391
  ## Server utilities
185
392
 
@@ -198,14 +405,39 @@ These are auto-imported in your `server/` directory:
198
405
  | `useShopifyUnauthenticatedStorefront(shop)` | Offline session storefront API access |
199
406
  | `registerShopifyWebhooks(session)` | Register webhooks for a shop |
200
407
 
408
+ ### `#shopify/server` exports
409
+
410
+ For use in Nitro plugins and advanced server-side configuration:
411
+
412
+ ```ts
413
+ import {
414
+ configureShopify,
415
+ getShopifyApi,
416
+ getResolvedConfig,
417
+ getSessionStorage,
418
+ registerShopifyWebhooks,
419
+ createAdminApiContext,
420
+ createStorefrontApiContext
421
+ } from '#shopify/server'
422
+
423
+ // Types
424
+ import type {
425
+ AdminApiContext,
426
+ StorefrontApiContext,
427
+ GraphQLClient,
428
+ GraphQLQueryOptions,
429
+ GraphQLResponse
430
+ } from '#shopify/server'
431
+ ```
432
+
201
433
  ## Client composables
202
434
 
203
435
  These are auto-imported in your Vue components:
204
436
 
205
- | Composable | Purpose |
206
- | ------------------- | ------------------------------------------------- |
207
- | `useAppBridge()` | Returns typed `ShopifyGlobal` from App Bridge CDN |
208
- | `useShopifyFetch()` | Fetch wrapper with automatic session token auth |
437
+ | Composable | Purpose |
438
+ | ------------------- | -------------------------------------------------------------------- |
439
+ | `useAppBridge()` | Returns typed `ShopifyGlobal` from App Bridge CDN |
440
+ | `useShopifyFetch()` | Fetch wrapper with automatic session token in `Authorization` header |
209
441
 
210
442
  ## Testing your app
211
443
 
@@ -219,8 +451,38 @@ const config = testConfig()
219
451
 
220
452
  // testSession() returns a mock Shopify session
221
453
  const session = testSession()
454
+
455
+ // Both accept overrides
456
+ const customConfig = testConfig({ apiKey: 'custom-key' })
457
+ const customSession = testSession({ shop: 'custom-shop.myshopify.com' })
458
+ ```
459
+
460
+ ## TypeScript
461
+
462
+ The module augments Nuxt's `RuntimeConfig` types so you get full autocomplete and type safety when accessing config:
463
+
464
+ ```ts
465
+ // Server — all Shopify config fields are typed
466
+ const config = useRuntimeConfig()
467
+ config.shopify.apiKey // string
468
+ config.shopify.apiSecretKey // string
469
+ config.shopify.scopes // string[]
470
+ config.shopify.appUrl // string
471
+
472
+ // Client — only public fields
473
+ const publicConfig = useRuntimeConfig().public
474
+ publicConfig.shopify.apiKey // string
475
+ publicConfig.shopify.authPagePath // string
476
+ publicConfig.shopify.authPathPrefix // string
222
477
  ```
223
478
 
479
+ The types are declared via module augmentation in `nuxt/schema`:
480
+
481
+ | Interface | Key | Fields |
482
+ | --------------------- | --------- | --------------------------------------------------------------------------------------------------------------- |
483
+ | `RuntimeConfig` | `shopify` | `apiKey`, `apiSecretKey`, `scopes`, `appUrl`, `apiVersion`, `authPathPrefix`, `distribution`, `useOnlineTokens` |
484
+ | `PublicRuntimeConfig` | `shopify` | `apiKey`, `authPagePath`, `authPathPrefix` |
485
+
224
486
  ## Resources
225
487
 
226
488
  Getting started:
@@ -237,6 +499,14 @@ Shopify:
237
499
  - [App extensions](https://shopify.dev/docs/apps/app-extensions/list)
238
500
  - [Shopify Functions](https://shopify.dev/docs/api/functions)
239
501
 
502
+ Session storage adapters:
503
+
504
+ - [`@shopify/shopify-app-session-storage-prisma`](https://www.npmjs.com/package/@shopify/shopify-app-session-storage-prisma)
505
+ - [`@shopify/shopify-app-session-storage-drizzle`](https://www.npmjs.com/package/@shopify/shopify-app-session-storage-drizzle)
506
+ - [`@shopify/shopify-app-session-storage-redis`](https://www.npmjs.com/package/@shopify/shopify-app-session-storage-redis)
507
+ - [`@shopify/shopify-app-session-storage-mongodb`](https://www.npmjs.com/package/@shopify/shopify-app-session-storage-mongodb)
508
+ - [`@shopify/shopify-app-session-storage-memory`](https://www.npmjs.com/package/@shopify/shopify-app-session-storage-memory) (default, not for production)
509
+
240
510
  ## Contributing
241
511
 
242
512
  <details>
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shopify-nuxt",
3
3
  "configKey": "shopify",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineNuxtModule, createResolver, addServerImportsDir, addImportsDir, addComponentsDir, addTypeTemplate, addPlugin, addServerHandler, addRouteMiddleware } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, addServerImportsDir, addImportsDir, addComponentsDir, addTypeTemplate, addPlugin, addServerHandler, addRouteMiddleware, extendPages } from '@nuxt/kit';
2
2
  import { ApiVersion } from '@shopify/shopify-api';
3
3
 
4
4
  const module$1 = defineNuxtModule({
@@ -9,7 +9,6 @@ const module$1 = defineNuxtModule({
9
9
  defaults: {
10
10
  apiKey: "",
11
11
  apiSecretKey: "",
12
- scopes: [],
13
12
  appUrl: "",
14
13
  apiVersion: ApiVersion.January26,
15
14
  authPathPrefix: "/_shopify/auth",
@@ -21,7 +20,7 @@ const module$1 = defineNuxtModule({
21
20
  nuxt.options.runtimeConfig.shopify = {
22
21
  apiKey: options.apiKey,
23
22
  apiSecretKey: options.apiSecretKey,
24
- scopes: options.scopes,
23
+ scopes: options.scopes || [],
25
24
  appUrl: options.appUrl,
26
25
  apiVersion: options.apiVersion || ApiVersion.January26,
27
26
  authPathPrefix: options.authPathPrefix || "/_shopify/auth",
@@ -29,7 +28,9 @@ const module$1 = defineNuxtModule({
29
28
  useOnlineTokens: options.useOnlineTokens || false
30
29
  };
31
30
  nuxt.options.runtimeConfig.public.shopify = {
32
- apiKey: options.apiKey
31
+ apiKey: options.apiKey,
32
+ authPagePath: options.authPage !== false ? "/auth" : "",
33
+ authPathPrefix: options.authPathPrefix || "/_shopify/auth"
33
34
  };
34
35
  nuxt.options.alias["#shopify/server"] = resolver.resolve("./runtime/server");
35
36
  addServerImportsDir(resolver.resolve("./runtime/server/utils"));
@@ -115,13 +116,30 @@ export {}
115
116
  path: resolver.resolve("./runtime/middleware/shopify-auth"),
116
117
  global: false
117
118
  });
119
+ if (options.authPage !== false) {
120
+ extendPages((pages) => {
121
+ pages.push({
122
+ name: "shopify-auth-login",
123
+ path: "/auth",
124
+ file: options.authPage || resolver.resolve("./runtime/pages/auth-login.vue")
125
+ });
126
+ });
127
+ }
128
+ nuxt.hook("nitro:config", (nitroConfig) => {
129
+ nitroConfig.plugins = nitroConfig.plugins || [];
130
+ nitroConfig.plugins.push(
131
+ resolver.resolve("./runtime/server/plugins/shopify-defaults")
132
+ );
133
+ });
118
134
  nuxt.options.build.transpile.push(resolver.resolve("./runtime"));
119
135
  nuxt.hook("nitro:config", (nitroConfig) => {
120
136
  nitroConfig.externals = nitroConfig.externals || {};
121
137
  nitroConfig.externals.inline = nitroConfig.externals.inline || [];
122
138
  nitroConfig.externals.inline.push(
123
139
  "@shopify/shopify-api",
124
- "@shopify/shopify-api/adapters/node"
140
+ "@shopify/shopify-api/adapters/node",
141
+ "@shopify/shopify-app-session-storage-memory",
142
+ "isbot"
125
143
  );
126
144
  });
127
145
  nuxt.hook("prepare:types", ({ references }) => {
@@ -22,8 +22,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
22
22
  blur: (event: FocusEvent) => void;
23
23
  focus: (event: FocusEvent) => void;
24
24
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
25
- onBlur?: ((event: FocusEvent) => any) | undefined;
26
25
  onClick?: ((event: MouseEvent) => any) | undefined;
26
+ onBlur?: ((event: FocusEvent) => any) | undefined;
27
27
  onFocus?: ((event: FocusEvent) => any) | undefined;
28
28
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
29
29
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -22,8 +22,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
22
22
  blur: (event: FocusEvent) => void;
23
23
  focus: (event: FocusEvent) => void;
24
24
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
25
- onBlur?: ((event: FocusEvent) => any) | undefined;
26
25
  onClick?: ((event: MouseEvent) => any) | undefined;
26
+ onBlur?: ((event: FocusEvent) => any) | undefined;
27
27
  onFocus?: ((event: FocusEvent) => any) | undefined;
28
28
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
29
29
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -18,11 +18,11 @@ type __VLS_Slots = {} & {
18
18
  };
19
19
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
20
  "update:modelValue": (v: boolean) => void;
21
- change: (event: Event) => void;
22
21
  input: (event: Event) => void;
22
+ change: (event: Event) => void;
23
23
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
24
- onChange?: ((event: Event) => any) | undefined;
25
24
  onInput?: ((event: Event) => any) | undefined;
25
+ onChange?: ((event: Event) => any) | undefined;
26
26
  "onUpdate:modelValue"?: ((v: boolean) => any) | undefined;
27
27
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
28
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -18,11 +18,11 @@ type __VLS_Slots = {} & {
18
18
  };
19
19
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
20
  "update:modelValue": (v: boolean) => void;
21
- change: (event: Event) => void;
22
21
  input: (event: Event) => void;
22
+ change: (event: Event) => void;
23
23
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
24
- onChange?: ((event: Event) => any) | undefined;
25
24
  onInput?: ((event: Event) => any) | undefined;
25
+ onChange?: ((event: Event) => any) | undefined;
26
26
  "onUpdate:modelValue"?: ((v: boolean) => any) | undefined;
27
27
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
28
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -14,11 +14,11 @@ type __VLS_Slots = {} & {
14
14
  };
15
15
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
16
  "update:modelValue": (v: string[]) => void;
17
- change: (event: Event) => void;
18
17
  input: (event: Event) => void;
18
+ change: (event: Event) => void;
19
19
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
20
- onChange?: ((event: Event) => any) | undefined;
21
20
  onInput?: ((event: Event) => any) | undefined;
21
+ onChange?: ((event: Event) => any) | undefined;
22
22
  "onUpdate:modelValue"?: ((v: string[]) => any) | undefined;
23
23
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
24
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -14,11 +14,11 @@ type __VLS_Slots = {} & {
14
14
  };
15
15
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
16
  "update:modelValue": (v: string[]) => void;
17
- change: (event: Event) => void;
18
17
  input: (event: Event) => void;
18
+ change: (event: Event) => void;
19
19
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
20
- onChange?: ((event: Event) => any) | undefined;
21
20
  onInput?: ((event: Event) => any) | undefined;
21
+ onChange?: ((event: Event) => any) | undefined;
22
22
  "onUpdate:modelValue"?: ((v: string[]) => any) | undefined;
23
23
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
24
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -21,14 +21,14 @@ type __VLS_Slots = {} & {
21
21
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
22
22
  "update:modelValue": (v: string) => void;
23
23
  blur: (event: InputEvent) => void;
24
- change: (event: InputEvent) => void;
25
24
  focus: (event: InputEvent) => void;
26
25
  input: (event: InputEvent) => void;
26
+ change: (event: InputEvent) => void;
27
27
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
28
28
  onBlur?: ((event: InputEvent) => any) | undefined;
29
- onChange?: ((event: InputEvent) => any) | undefined;
30
29
  onFocus?: ((event: InputEvent) => any) | undefined;
31
30
  onInput?: ((event: InputEvent) => any) | undefined;
31
+ onChange?: ((event: InputEvent) => any) | undefined;
32
32
  "onUpdate:modelValue"?: ((v: string) => any) | undefined;
33
33
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
34
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -21,14 +21,14 @@ type __VLS_Slots = {} & {
21
21
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
22
22
  "update:modelValue": (v: string) => void;
23
23
  blur: (event: InputEvent) => void;
24
- change: (event: InputEvent) => void;
25
24
  focus: (event: InputEvent) => void;
26
25
  input: (event: InputEvent) => void;
26
+ change: (event: InputEvent) => void;
27
27
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
28
28
  onBlur?: ((event: InputEvent) => any) | undefined;
29
- onChange?: ((event: InputEvent) => any) | undefined;
30
29
  onFocus?: ((event: InputEvent) => any) | undefined;
31
30
  onInput?: ((event: InputEvent) => any) | undefined;
31
+ onChange?: ((event: InputEvent) => any) | undefined;
32
32
  "onUpdate:modelValue"?: ((v: string) => any) | undefined;
33
33
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
34
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -10,11 +10,11 @@ type __VLS_Slots = {} & {
10
10
  };
11
11
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
12
12
  "update:modelValue": (v: string) => void;
13
- change: (event: Event) => void;
14
13
  input: (event: Event) => void;
14
+ change: (event: Event) => void;
15
15
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
- onChange?: ((event: Event) => any) | undefined;
17
16
  onInput?: ((event: Event) => any) | undefined;
17
+ onChange?: ((event: Event) => any) | undefined;
18
18
  "onUpdate:modelValue"?: ((v: string) => any) | undefined;
19
19
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
20
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -10,11 +10,11 @@ type __VLS_Slots = {} & {
10
10
  };
11
11
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
12
12
  "update:modelValue": (v: string) => void;
13
- change: (event: Event) => void;
14
13
  input: (event: Event) => void;
14
+ change: (event: Event) => void;
15
15
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
- onChange?: ((event: Event) => any) | undefined;
17
16
  onInput?: ((event: Event) => any) | undefined;
17
+ onChange?: ((event: Event) => any) | undefined;
18
18
  "onUpdate:modelValue"?: ((v: string) => any) | undefined;
19
19
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
20
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;