shopify-nuxt 0.0.10 → 0.0.12

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 (27) hide show
  1. package/README.md +178 -21
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/admin-api-client.d.ts +1 -0
  4. package/dist/runtime/admin-api-client.js +1 -0
  5. package/dist/runtime/components/polaris/ShUiModal.d.vue.ts +36 -0
  6. package/dist/runtime/components/polaris/ShUiModal.vue +39 -0
  7. package/dist/runtime/components/polaris/ShUiModal.vue.d.ts +36 -0
  8. package/dist/runtime/components/polaris/ShUiNavMenu.d.vue.ts +13 -0
  9. package/dist/runtime/components/polaris/ShUiNavMenu.vue +9 -0
  10. package/dist/runtime/components/polaris/ShUiNavMenu.vue.d.ts +13 -0
  11. package/dist/runtime/components/polaris/ShUiSaveBar.d.vue.ts +31 -0
  12. package/dist/runtime/components/polaris/ShUiSaveBar.vue +36 -0
  13. package/dist/runtime/components/polaris/ShUiSaveBar.vue.d.ts +31 -0
  14. package/dist/runtime/components/polaris/ShUiTitleBar.d.vue.ts +16 -0
  15. package/dist/runtime/components/polaris/ShUiTitleBar.vue +14 -0
  16. package/dist/runtime/components/polaris/ShUiTitleBar.vue.d.ts +16 -0
  17. package/dist/runtime/composables/useShopifyFetch.d.ts +6 -9
  18. package/dist/runtime/composables/useShopifyFetch.js +40 -43
  19. package/dist/runtime/shopify-api.d.ts +1 -0
  20. package/dist/runtime/shopify-api.js +1 -0
  21. package/dist/runtime/shopify-app-session-storage-memory.d.ts +1 -0
  22. package/dist/runtime/shopify-app-session-storage-memory.js +1 -0
  23. package/dist/runtime/shopify-app-session-storage.d.ts +1 -0
  24. package/dist/runtime/shopify-app-session-storage.js +1 -0
  25. package/dist/runtime/storefront-api-client.d.ts +1 -0
  26. package/dist/runtime/storefront-api-client.js +1 -0
  27. package/package.json +37 -2
package/README.md CHANGED
@@ -6,7 +6,9 @@
6
6
 
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE.md)
8
8
  [![npm version](https://badge.fury.io/js/shopify-nuxt.svg)](https://badge.fury.io/js/shopify-nuxt)
9
+ [![NPM Downloads](https://img.shields.io/npm/dm/shopify-nuxt)](https://npmtrends.com/shopify-nuxt)
9
10
  [![Nuxt](https://img.shields.io/badge/Nuxt-020420?logo=nuxt)](https://nuxt.com)
11
+ [![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/shopify-nuxt.svg)](https://img.shields.io/bundlephobia/minzip/shopify-nuxt.svg)
10
12
 
11
13
  This package makes it easy to use [Nuxt](https://nuxt.com/) to build Shopify apps.
12
14
 
@@ -281,21 +283,36 @@ const shop = shopify.config.shop
281
283
 
282
284
  ### Authenticated fetch
283
285
 
284
- Use `useShopifyFetch()` for client-side API calls that automatically include the session token:
286
+ Use `useShopifyFetch()` for API calls that automatically include the Shopify session token. It works on both client and server — on the client it fetches a session token via App Bridge, on the server it forwards the incoming `Authorization` header.
285
287
 
286
288
  ```vue
287
289
  <script setup>
288
- const shopifyFetch = useShopifyFetch()
290
+ const { data: shop } = await useAsyncData(
291
+ 'shop',
292
+ () => useShopifyFetch('/api/shop'),
293
+ { server: false }
294
+ )
295
+ </script>
296
+ ```
289
297
 
290
- const { data: products } = await useAsyncData(
291
- 'products',
292
- () => shopifyFetch('/api/products'),
298
+ With generic types for full type safety:
299
+
300
+ ```vue
301
+ <script setup lang="ts">
302
+ interface ShopData {
303
+ shop: { name: string; currencyCode: string }
304
+ }
305
+
306
+ const { data } = await useAsyncData(
307
+ 'shop',
308
+ () => useShopifyFetch<ShopData>('/api/shop'),
293
309
  { server: false }
294
310
  )
311
+ // data.value.data.shop.name is fully typed
295
312
  </script>
296
313
  ```
297
314
 
298
- > **Important**: Always use `server: false` with `useShopifyFetch()` — session tokens are only available on the client side within the Shopify admin iframe.
315
+ > **Important**: Always use `server: false` with `useShopifyFetch()` in `useAsyncData` — session tokens are only available on the client side within the Shopify admin iframe.
299
316
 
300
317
  ## Using Polaris components
301
318
 
@@ -391,6 +408,10 @@ Content: `ShText`, `ShHeading`, `ShParagraph`, `ShIcon`, `ShImage`, `ShThumbnail
391
408
 
392
409
  Other: `ShModal`, `ShQueryContainer`
393
410
 
411
+ App Bridge UI: `ShUiModal`, `ShUiTitleBar`, `ShUiSaveBar`, `ShUiNavMenu`
412
+
413
+ Loading: `ShLoadingIndicator`
414
+
394
415
  ### Using `ShModal`
395
416
 
396
417
  `ShModal` wraps the [Polaris `<s-modal>`](https://shopify.dev/docs/api/app-home/web-components/overlays/modal) component — it renders **inside** your app's iframe. Open and close it using `commandFor` / `command` attributes:
@@ -417,7 +438,142 @@ Other: `ShModal`, `ShQueryContainer`
417
438
  </template>
418
439
  ```
419
440
 
420
- > **Note**: `ShModal` is **not** the same as the [App Bridge `<ui-modal>`](https://shopify.dev/docs/api/app-bridge-library/apis/modal) which renders outside the iframe and is controlled via `shopify.modal.show(id)`. If you need the App Bridge modal, use `<ui-modal>` directly.
441
+ > **Note**: `ShModal` is **not** the same as the [App Bridge `<ui-modal>`](https://shopify.dev/docs/api/app-bridge-library/apis/modal) which renders outside the iframe and is controlled via `shopify.modal.show(id)`. If you need the App Bridge modal, use `<ShUiModal>` (see below).
442
+
443
+ ### App Bridge UI components
444
+
445
+ In addition to the Polaris `Sh*` components (which wrap `s-*` web components rendered **inside** your app's iframe), this module also provides Vue wrappers for [App Bridge UI web components](https://shopify.dev/docs/api/app-bridge-library/web-components) (`ui-*`). These render **outside** the app iframe in the Shopify Admin shell.
446
+
447
+ #### Polaris (`Sh*`) vs App Bridge (`ShUi*`) — what's the difference?
448
+
449
+ | | Polaris (`Sh*`) | App Bridge (`ShUi*`) |
450
+ | ------------------ | ----------------------------------------- | --------------------------------------------------------------------------------- |
451
+ | **HTML elements** | `<s-button>`, `<s-modal>`, etc. | `<ui-modal>`, `<ui-title-bar>`, etc. |
452
+ | **Renders in** | Your app's iframe | Shopify Admin (outside the iframe) |
453
+ | **Use for** | In-app UI: forms, tables, buttons, layout | Admin-level chrome: page title, modals overlaying the admin, save bar, navigation |
454
+ | **Controlled via** | Props, slots, `command`/`commandFor` | Props, template refs, `shopify.modal.show(id)` |
455
+
456
+ #### `<ShUiModal>`
457
+
458
+ Wraps [`<ui-modal>`](https://shopify.dev/docs/api/app-bridge-library/web-components/ui-modal) — renders a full-screen overlay **outside** the iframe, managed by Shopify Admin.
459
+
460
+ ```vue
461
+ <script setup>
462
+ const modalRef = ref()
463
+ </script>
464
+
465
+ <template>
466
+ <ShButton @click="modalRef.show()">Open Modal</ShButton>
467
+
468
+ <ShUiModal ref="modalRef" id="my-modal" variant="large" @hide="onClose">
469
+ <p>This content renders outside the iframe.</p>
470
+
471
+ <template #title-bar>
472
+ <ShUiTitleBar title="Edit Product">
473
+ <button variant="primary" onclick="handleSave()">Save</button>
474
+ <button onclick="document.getElementById('my-modal').hide()">
475
+ Cancel
476
+ </button>
477
+ </ShUiTitleBar>
478
+ </template>
479
+ </ShUiModal>
480
+ </template>
481
+ ```
482
+
483
+ | Prop | Type | Default | Description |
484
+ | --------- | --------------------------------------- | -------- | ------------------------------------------------------ |
485
+ | `id` | `string` | — | Unique identifier (used with `shopify.modal.show(id)`) |
486
+ | `variant` | `'small' \| 'base' \| 'large' \| 'max'` | `'base'` | Modal size |
487
+ | `src` | `string` | — | URL to load in an iframe inside the modal |
488
+
489
+ | Event | Description |
490
+ | ------ | ----------------------------- |
491
+ | `show` | Emitted when the modal opens |
492
+ | `hide` | Emitted when the modal closes |
493
+
494
+ Exposed methods via template ref: `show()`, `hide()`, `toggle()`
495
+
496
+ #### `<ShUiTitleBar>`
497
+
498
+ Wraps [`<ui-title-bar>`](https://shopify.dev/docs/api/app-bridge-library/web-components/ui-title-bar) — sets the page title and action buttons in the Shopify Admin title bar.
499
+
500
+ ```vue
501
+ <template>
502
+ <ShUiTitleBar title="Products">
503
+ <button variant="primary" onclick="createProduct()">Create product</button>
504
+ <button onclick="exportProducts()">Export</button>
505
+ </ShUiTitleBar>
506
+ </template>
507
+ ```
508
+
509
+ | Prop | Type | Description |
510
+ | ------- | -------- | ------------------------------------------ |
511
+ | `title` | `string` | The title displayed in the Admin title bar |
512
+
513
+ Child elements: `<button>` (with optional `variant="primary"` and `tone="critical"`), `<a>` (with optional `variant="breadcrumb"`), and `<section>` groups.
514
+
515
+ #### `<ShUiSaveBar>`
516
+
517
+ Wraps [`<ui-save-bar>`](https://shopify.dev/docs/api/app-bridge-library/web-components/ui-save-bar) — shows a contextual save bar at the top of the Admin when there are unsaved changes.
518
+
519
+ ```vue
520
+ <script setup>
521
+ const saveBarRef = ref()
522
+
523
+ function onFormChange() {
524
+ saveBarRef.value.show()
525
+ }
526
+ </script>
527
+
528
+ <template>
529
+ <ShUiSaveBar ref="saveBarRef" id="my-save-bar" discard-confirmation>
530
+ <button variant="primary" onclick="handleSave()">Save</button>
531
+ <button onclick="handleDiscard()">Discard</button>
532
+ </ShUiSaveBar>
533
+ </template>
534
+ ```
535
+
536
+ | Prop | Type | Description |
537
+ | --------------------- | --------- | ------------------------------------- |
538
+ | `id` | `string` | Unique identifier |
539
+ | `discardConfirmation` | `boolean` | Show a confirmation dialog on discard |
540
+
541
+ | Event | Description |
542
+ | ------ | -------------------------------------- |
543
+ | `show` | Emitted when the save bar appears |
544
+ | `hide` | Emitted when the save bar is dismissed |
545
+
546
+ Exposed methods via template ref: `show()`, `hide()`, `toggle()`
547
+
548
+ #### `<ShUiNavMenu>`
549
+
550
+ Wraps [`<ui-nav-menu>`](https://shopify.dev/docs/api/app-bridge-library/web-components/ui-nav-menu) — configures the app's navigation menu in the Shopify Admin sidebar.
551
+
552
+ ```vue
553
+ <template>
554
+ <ShUiNavMenu>
555
+ <a href="/" rel="home">Home</a>
556
+ <a href="/products">Products</a>
557
+ <a href="/settings">Settings</a>
558
+ </ShUiNavMenu>
559
+ </template>
560
+ ```
561
+
562
+ > **Tip**: For most apps, use the `navLinks` config option with `<ShopifyAppProvider>` instead of `<ShUiNavMenu>` directly. Use `<ShUiNavMenu>` only when you need dynamic or conditional navigation.
563
+
564
+ ### Loading indicator
565
+
566
+ `<ShLoadingIndicator>` hooks into Nuxt's `useLoadingIndicator()` and calls `shopify.loading()` to show/hide the Shopify Admin's native top loading bar during page navigations:
567
+
568
+ ```vue
569
+ <!-- app.vue -->
570
+ <template>
571
+ <ShLoadingIndicator />
572
+ <NuxtPage />
573
+ </template>
574
+ ```
575
+
576
+ This replaces `<NuxtLoadingIndicator>` with the native Shopify loading bar for a more integrated experience.
421
577
 
422
578
  ## OAuth routes
423
579
 
@@ -442,20 +598,21 @@ To load your app within the Shopify Admin, you need to:
442
598
 
443
599
  ## Features
444
600
 
445
- | Feature | Description |
446
- | ------------------- | ------------------------------------------------------------------------------- |
447
- | **Authentication** | OAuth flow, session tokens, token exchange — all handled automatically |
448
- | **App Bridge** | CDN-based App Bridge with full TypeScript types via `@shopify/app-bridge-types` |
449
- | **Polaris** | Vue wrapper components (`Sh*`) for all Polaris web components with typed props |
450
- | **Typed GraphQL** | Admin and Storefront API clients typed via `@shopify/admin-api-client` |
451
- | **Webhooks** | HMAC validation, payload parsing, and webhook registration |
452
- | **Admin API** | GraphQL and REST clients with automatic session management |
453
- | **Storefront API** | Typed GraphQL client for Storefront API via `@shopify/storefront-api-client` |
454
- | **Billing** | Billing context for subscription and usage-based charges |
455
- | **Session storage** | Built-in `MemorySessionStorage` default, pluggable via `configureShopify()` |
456
- | **Auto-imports** | Server utilities, client composables, and components are auto-imported |
457
- | **Bot detection** | Admin auth automatically detects bots and returns 410 to avoid unnecessary auth |
458
- | **CORS** | Built-in CORS helpers for public/checkout extension endpoints |
601
+ | Feature | Description |
602
+ | ------------------- | ---------------------------------------------------------------------------------------------- |
603
+ | **Authentication** | OAuth flow, session tokens, token exchange — all handled automatically |
604
+ | **App Bridge** | CDN-based App Bridge with full TypeScript types via `@shopify/app-bridge-types` |
605
+ | **Polaris** | Vue wrapper components (`Sh*`) for all Polaris web components with typed props |
606
+ | **App Bridge UI** | Vue wrappers (`ShUi*`) for App Bridge `ui-*` components (modal, title bar, save bar, nav menu) |
607
+ | **Typed GraphQL** | Admin and Storefront API clients typed via `@shopify/admin-api-client` |
608
+ | **Webhooks** | HMAC validation, payload parsing, and webhook registration |
609
+ | **Admin API** | GraphQL and REST clients with automatic session management |
610
+ | **Storefront API** | Typed GraphQL client for Storefront API via `@shopify/storefront-api-client` |
611
+ | **Billing** | Billing context for subscription and usage-based charges |
612
+ | **Session storage** | Built-in `MemorySessionStorage` default, pluggable via `configureShopify()` |
613
+ | **Auto-imports** | Server utilities, client composables, and components are auto-imported |
614
+ | **Bot detection** | Admin auth automatically detects bots and returns 410 to avoid unnecessary auth |
615
+ | **CORS** | Built-in CORS helpers for public/checkout extension endpoints |
459
616
 
460
617
  ## Server utilities
461
618
 
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shopify-nuxt",
3
3
  "configKey": "shopify",
4
- "version": "0.0.10",
4
+ "version": "0.0.12",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -0,0 +1 @@
1
+ export * from '@shopify/admin-api-client';
@@ -0,0 +1 @@
1
+ export * from "@shopify/admin-api-client";
@@ -0,0 +1,36 @@
1
+ type __VLS_Props = {
2
+ id?: string;
3
+ variant?: 'small' | 'base' | 'large' | 'max';
4
+ src?: string;
5
+ };
6
+ declare function show(): any;
7
+ declare function hide(): any;
8
+ declare function toggle(): any;
9
+ declare var __VLS_12: {}, __VLS_14: {}, __VLS_16: {};
10
+ type __VLS_Slots = {} & {
11
+ default?: (props: typeof __VLS_12) => any;
12
+ } & {
13
+ 'title-bar'?: (props: typeof __VLS_14) => any;
14
+ } & {
15
+ 'save-bar'?: (props: typeof __VLS_16) => any;
16
+ };
17
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
18
+ show: typeof show;
19
+ hide: typeof hide;
20
+ toggle: typeof toggle;
21
+ el: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
22
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
23
+ show: (event: Event) => void;
24
+ hide: (event: Event) => void;
25
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
26
+ onShow?: ((event: Event) => any) | undefined;
27
+ onHide?: ((event: Event) => any) | undefined;
28
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
29
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
32
+ type __VLS_WithSlots<T, S> = T & {
33
+ new (): {
34
+ $slots: S;
35
+ };
36
+ };
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <ui-modal
3
+ ref="modalRef"
4
+ v-bind="polarisAttrs"
5
+ @show="emit('show', $event)"
6
+ @hide="emit('hide', $event)"
7
+ >
8
+ <slot />
9
+ <slot name="title-bar" />
10
+ <slot name="save-bar" />
11
+ </ui-modal>
12
+ </template>
13
+
14
+ <script setup>
15
+ import { ref } from "vue";
16
+ import { usePolarisAttrs } from "./utils";
17
+ defineOptions({ name: "ShUiModal", inheritAttrs: false });
18
+ const props = defineProps({
19
+ id: { type: String, required: false },
20
+ variant: { type: String, required: false },
21
+ src: { type: String, required: false }
22
+ });
23
+ const emit = defineEmits(["show", "hide"]);
24
+ const polarisAttrs = usePolarisAttrs(props);
25
+ const modalRef = ref(null);
26
+ function getEl() {
27
+ return modalRef.value;
28
+ }
29
+ function show() {
30
+ return getEl()?.show?.();
31
+ }
32
+ function hide() {
33
+ return getEl()?.hide?.();
34
+ }
35
+ function toggle() {
36
+ return getEl()?.toggle?.();
37
+ }
38
+ defineExpose({ show, hide, toggle, el: modalRef });
39
+ </script>
@@ -0,0 +1,36 @@
1
+ type __VLS_Props = {
2
+ id?: string;
3
+ variant?: 'small' | 'base' | 'large' | 'max';
4
+ src?: string;
5
+ };
6
+ declare function show(): any;
7
+ declare function hide(): any;
8
+ declare function toggle(): any;
9
+ declare var __VLS_12: {}, __VLS_14: {}, __VLS_16: {};
10
+ type __VLS_Slots = {} & {
11
+ default?: (props: typeof __VLS_12) => any;
12
+ } & {
13
+ 'title-bar'?: (props: typeof __VLS_14) => any;
14
+ } & {
15
+ 'save-bar'?: (props: typeof __VLS_16) => any;
16
+ };
17
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
18
+ show: typeof show;
19
+ hide: typeof hide;
20
+ toggle: typeof toggle;
21
+ el: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
22
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
23
+ show: (event: Event) => void;
24
+ hide: (event: Event) => void;
25
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
26
+ onShow?: ((event: Event) => any) | undefined;
27
+ onHide?: ((event: Event) => any) | undefined;
28
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
29
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
32
+ type __VLS_WithSlots<T, S> = T & {
33
+ new (): {
34
+ $slots: S;
35
+ };
36
+ };
@@ -0,0 +1,13 @@
1
+ declare var __VLS_8: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_8) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ type __VLS_WithSlots<T, S> = T & {
10
+ new (): {
11
+ $slots: S;
12
+ };
13
+ };
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <ui-nav-menu v-bind="$attrs">
3
+ <slot />
4
+ </ui-nav-menu>
5
+ </template>
6
+
7
+ <script setup>
8
+ defineOptions({ name: "ShUiNavMenu", inheritAttrs: false });
9
+ </script>
@@ -0,0 +1,13 @@
1
+ declare var __VLS_8: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_8) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ type __VLS_WithSlots<T, S> = T & {
10
+ new (): {
11
+ $slots: S;
12
+ };
13
+ };
@@ -0,0 +1,31 @@
1
+ type __VLS_Props = {
2
+ id?: string;
3
+ discardConfirmation?: boolean;
4
+ };
5
+ declare function show(): any;
6
+ declare function hide(): any;
7
+ declare function toggle(): any;
8
+ declare var __VLS_12: {};
9
+ type __VLS_Slots = {} & {
10
+ default?: (props: typeof __VLS_12) => any;
11
+ };
12
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
13
+ show: typeof show;
14
+ hide: typeof hide;
15
+ toggle: typeof toggle;
16
+ el: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
17
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
18
+ show: (event: Event) => void;
19
+ hide: (event: Event) => void;
20
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
21
+ onShow?: ((event: Event) => any) | undefined;
22
+ onHide?: ((event: Event) => any) | undefined;
23
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
27
+ type __VLS_WithSlots<T, S> = T & {
28
+ new (): {
29
+ $slots: S;
30
+ };
31
+ };
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <ui-save-bar
3
+ ref="saveBarRef"
4
+ v-bind="polarisAttrs"
5
+ @show="emit('show', $event)"
6
+ @hide="emit('hide', $event)"
7
+ >
8
+ <slot />
9
+ </ui-save-bar>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { ref } from "vue";
14
+ import { usePolarisAttrs } from "./utils";
15
+ defineOptions({ name: "ShUiSaveBar", inheritAttrs: false });
16
+ const props = defineProps({
17
+ id: { type: String, required: false },
18
+ discardConfirmation: { type: Boolean, required: false }
19
+ });
20
+ const emit = defineEmits(["show", "hide"]);
21
+ const polarisAttrs = usePolarisAttrs(props);
22
+ const saveBarRef = ref(null);
23
+ function getEl() {
24
+ return saveBarRef.value;
25
+ }
26
+ function show() {
27
+ return getEl()?.show?.();
28
+ }
29
+ function hide() {
30
+ return getEl()?.hide?.();
31
+ }
32
+ function toggle() {
33
+ return getEl()?.toggle?.();
34
+ }
35
+ defineExpose({ show, hide, toggle, el: saveBarRef });
36
+ </script>
@@ -0,0 +1,31 @@
1
+ type __VLS_Props = {
2
+ id?: string;
3
+ discardConfirmation?: boolean;
4
+ };
5
+ declare function show(): any;
6
+ declare function hide(): any;
7
+ declare function toggle(): any;
8
+ declare var __VLS_12: {};
9
+ type __VLS_Slots = {} & {
10
+ default?: (props: typeof __VLS_12) => any;
11
+ };
12
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
13
+ show: typeof show;
14
+ hide: typeof hide;
15
+ toggle: typeof toggle;
16
+ el: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
17
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
18
+ show: (event: Event) => void;
19
+ hide: (event: Event) => void;
20
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
21
+ onShow?: ((event: Event) => any) | undefined;
22
+ onHide?: ((event: Event) => any) | undefined;
23
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
25
+ declare const _default: typeof __VLS_export;
26
+ export default _default;
27
+ type __VLS_WithSlots<T, S> = T & {
28
+ new (): {
29
+ $slots: S;
30
+ };
31
+ };
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ title?: string;
3
+ };
4
+ declare var __VLS_8: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_8) => any;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <ui-title-bar v-bind="polarisAttrs">
3
+ <slot />
4
+ </ui-title-bar>
5
+ </template>
6
+
7
+ <script setup>
8
+ import { usePolarisAttrs } from "./utils";
9
+ defineOptions({ name: "ShUiTitleBar", inheritAttrs: false });
10
+ const props = defineProps({
11
+ title: { type: String, required: false }
12
+ });
13
+ const polarisAttrs = usePolarisAttrs(props);
14
+ </script>
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ title?: string;
3
+ };
4
+ declare var __VLS_8: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_8) => any;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -1,13 +1,10 @@
1
1
  import type { NitroFetchRequest, TypedInternalResponse, AvailableRouterMethod } from 'nitropack/types';
2
2
  import type { RouterMethod } from 'h3';
3
3
  type ShopifyFetchData<T, R extends NitroFetchRequest, M extends RouterMethod> = [T] extends [undefined] ? TypedInternalResponse<R, unknown, M> : T;
4
- interface ShopifyFetchFunction {
5
- <T = undefined, R extends NitroFetchRequest = NitroFetchRequest, M extends AvailableRouterMethod<R> = 'get' extends AvailableRouterMethod<R> ? 'get' : AvailableRouterMethod<R>>(url: R, options?: Omit<RequestInit, 'method'> & {
6
- method?: Uppercase<M> | M;
7
- }): Promise<{
8
- data: ShopifyFetchData<T, R, Extract<Lowercase<M>, RouterMethod>>;
9
- response: Response;
10
- }>;
11
- }
12
- export declare function useShopifyFetch(): ShopifyFetchFunction;
4
+ export declare function useShopifyFetch<T = undefined, R extends NitroFetchRequest = NitroFetchRequest, M extends AvailableRouterMethod<R> = 'get' extends AvailableRouterMethod<R> ? 'get' : AvailableRouterMethod<R>>(url: R, options?: Omit<RequestInit, 'method'> & {
5
+ method?: Uppercase<M> | M;
6
+ }): Promise<{
7
+ data: ShopifyFetchData<T, R, Extract<Lowercase<M>, RouterMethod>>;
8
+ response: Response;
9
+ }>;
13
10
  export {};
@@ -1,52 +1,49 @@
1
1
  import { useNuxtApp, useRequestEvent } from "#app";
2
- export function useShopifyFetch() {
2
+ export async function useShopifyFetch(url, options) {
3
+ const opts = options ?? {};
3
4
  if (import.meta.server) {
4
5
  const event = useRequestEvent();
5
- return (async (url, options = {}) => {
6
- const headers = {};
7
- const authHeader = event?.headers.get("authorization");
8
- if (authHeader) {
9
- headers["Authorization"] = authHeader;
10
- }
11
- if (options.headers) {
12
- const incoming = new Headers(options.headers);
13
- incoming.forEach((value, key) => {
14
- headers[key] = value;
15
- });
16
- }
17
- const { method, ...rest } = options;
18
- const response = await globalThis.$fetch.raw(url, {
19
- ...rest,
20
- method,
21
- headers
6
+ const headers2 = {};
7
+ const authHeader = event?.headers.get("authorization");
8
+ if (authHeader) {
9
+ headers2["Authorization"] = authHeader;
10
+ }
11
+ if (opts.headers) {
12
+ const incoming = new Headers(opts.headers);
13
+ incoming.forEach((value, key) => {
14
+ headers2[key] = value;
22
15
  });
23
- return { data: response._data, response };
16
+ }
17
+ const { method, ...rest } = opts;
18
+ const fetchResponse2 = await globalThis.$fetch.raw(url, {
19
+ ...rest,
20
+ method,
21
+ headers: headers2
24
22
  });
23
+ return { data: fetchResponse2._data, response: fetchResponse2 };
25
24
  }
26
25
  const nuxtApp = useNuxtApp();
27
- return (async (url, options = {}) => {
28
- const shopify = nuxtApp.$shopify;
29
- if (!shopify) {
30
- throw new Error(
31
- "Shopify App Bridge is not available. Make sure the app is loaded within the Shopify Admin."
32
- );
33
- }
34
- const token = await shopify.idToken();
35
- const headers = new Headers(options.headers || {});
36
- headers.set("Authorization", `Bearer ${token}`);
37
- const response = await fetch(url, {
38
- ...options,
39
- headers
40
- });
41
- if (!response.ok) {
42
- throw new Error(
43
- `Shopify fetch failed: ${response.status} ${response.statusText}`
44
- );
45
- }
46
- const contentType = response.headers.get("content-type");
47
- if (contentType?.includes("application/json")) {
48
- return { data: await response.json(), response };
49
- }
50
- return { data: await response.text(), response };
26
+ const shopify = nuxtApp.$shopify;
27
+ if (!shopify) {
28
+ throw new Error(
29
+ "Shopify App Bridge is not available. Make sure the app is loaded within the Shopify Admin."
30
+ );
31
+ }
32
+ const token = await shopify.idToken();
33
+ const headers = new Headers(opts.headers || {});
34
+ headers.set("Authorization", `Bearer ${token}`);
35
+ const fetchResponse = await fetch(url, {
36
+ ...opts,
37
+ headers
51
38
  });
39
+ if (!fetchResponse.ok) {
40
+ throw new Error(
41
+ `Shopify fetch failed: ${fetchResponse.status} ${fetchResponse.statusText}`
42
+ );
43
+ }
44
+ const contentType = fetchResponse.headers.get("content-type");
45
+ if (contentType?.includes("application/json")) {
46
+ return { data: await fetchResponse.json(), response: fetchResponse };
47
+ }
48
+ return { data: await fetchResponse.text(), response: fetchResponse };
52
49
  }
@@ -0,0 +1 @@
1
+ export * from '@shopify/shopify-api';
@@ -0,0 +1 @@
1
+ export * from "@shopify/shopify-api";
@@ -0,0 +1 @@
1
+ export * from '@shopify/shopify-app-session-storage-memory';
@@ -0,0 +1 @@
1
+ export * from "@shopify/shopify-app-session-storage-memory";
@@ -0,0 +1 @@
1
+ export * from '@shopify/shopify-app-session-storage';
@@ -0,0 +1 @@
1
+ export * from "@shopify/shopify-app-session-storage";
@@ -0,0 +1 @@
1
+ export * from '@shopify/storefront-api-client';
@@ -0,0 +1 @@
1
+ export * from "@shopify/storefront-api-client";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopify-nuxt",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Shopify app integration for Nuxt - authentication, webhooks, billing, and App Bridge",
5
5
  "repository": "kiriminaja/shopify-nuxt",
6
6
  "license": "MIT",
@@ -15,6 +15,26 @@
15
15
  "./test-helpers": {
16
16
  "types": "./dist/runtime/server/test-helpers/index.d.ts",
17
17
  "import": "./dist/runtime/server/test-helpers/index.js"
18
+ },
19
+ "./shopify-api": {
20
+ "types": "./dist/runtime/shopify-api.d.ts",
21
+ "import": "./dist/runtime/shopify-api.js"
22
+ },
23
+ "./shopify-app-session-storage": {
24
+ "types": "./dist/runtime/shopify-app-session-storage.d.ts",
25
+ "import": "./dist/runtime/shopify-app-session-storage.js"
26
+ },
27
+ "./shopify-app-session-storage-memory": {
28
+ "types": "./dist/runtime/shopify-app-session-storage-memory.d.ts",
29
+ "import": "./dist/runtime/shopify-app-session-storage-memory.js"
30
+ },
31
+ "./admin-api-client": {
32
+ "types": "./dist/runtime/admin-api-client.d.ts",
33
+ "import": "./dist/runtime/admin-api-client.js"
34
+ },
35
+ "./storefront-api-client": {
36
+ "types": "./dist/runtime/storefront-api-client.d.ts",
37
+ "import": "./dist/runtime/storefront-api-client.js"
18
38
  }
19
39
  },
20
40
  "main": "./dist/module.mjs",
@@ -23,6 +43,21 @@
23
43
  "*": {
24
44
  ".": [
25
45
  "./dist/types.d.mts"
46
+ ],
47
+ "shopify-api": [
48
+ "./dist/runtime/shopify-api.d.ts"
49
+ ],
50
+ "shopify-app-session-storage": [
51
+ "./dist/runtime/shopify-app-session-storage.d.ts"
52
+ ],
53
+ "shopify-app-session-storage-memory": [
54
+ "./dist/runtime/shopify-app-session-storage-memory.d.ts"
55
+ ],
56
+ "admin-api-client": [
57
+ "./dist/runtime/admin-api-client.d.ts"
58
+ ],
59
+ "storefront-api-client": [
60
+ "./dist/runtime/storefront-api-client.d.ts"
26
61
  ]
27
62
  }
28
63
  },
@@ -53,7 +88,7 @@
53
88
  "@shopify/shopify-app-session-storage": "^5.0.0",
54
89
  "@shopify/shopify-app-session-storage-memory": "^6.0.0",
55
90
  "@shopify/storefront-api-client": "^1.0.10",
56
- "h3": "^1.15.0",
91
+ "h3": "^2.0.0",
57
92
  "isbot": "^5.1.36"
58
93
  },
59
94
  "devDependencies": {