@commercejs/nuxt 0.2.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 (123) hide show
  1. package/README.md +99 -0
  2. package/dist/module.cjs +5 -0
  3. package/dist/module.d.mts +23 -0
  4. package/dist/module.d.ts +23 -0
  5. package/dist/module.json +12 -0
  6. package/dist/module.mjs +101 -0
  7. package/dist/runtime/composables/index.d.ts +0 -0
  8. package/dist/runtime/composables/index.js +15 -0
  9. package/dist/runtime/composables/useAdapter.d.ts +0 -0
  10. package/dist/runtime/composables/useAdapter.js +11 -0
  11. package/dist/runtime/composables/useBrands.d.ts +0 -0
  12. package/dist/runtime/composables/useBrands.js +32 -0
  13. package/dist/runtime/composables/useCart.d.ts +0 -0
  14. package/dist/runtime/composables/useCart.js +144 -0
  15. package/dist/runtime/composables/useCategories.d.ts +0 -0
  16. package/dist/runtime/composables/useCategories.js +9 -0
  17. package/dist/runtime/composables/useCheckout.d.ts +0 -0
  18. package/dist/runtime/composables/useCheckout.js +142 -0
  19. package/dist/runtime/composables/useCountries.d.ts +0 -0
  20. package/dist/runtime/composables/useCountries.js +32 -0
  21. package/dist/runtime/composables/useCustomer.d.ts +0 -0
  22. package/dist/runtime/composables/useCustomer.js +179 -0
  23. package/dist/runtime/composables/useLocations.d.ts +0 -0
  24. package/dist/runtime/composables/useLocations.js +32 -0
  25. package/dist/runtime/composables/useProduct.d.ts +0 -0
  26. package/dist/runtime/composables/useProduct.js +16 -0
  27. package/dist/runtime/composables/useProducts.d.ts +0 -0
  28. package/dist/runtime/composables/useProducts.js +26 -0
  29. package/dist/runtime/composables/usePromotions.d.ts +0 -0
  30. package/dist/runtime/composables/usePromotions.js +48 -0
  31. package/dist/runtime/composables/useReturns.d.ts +0 -0
  32. package/dist/runtime/composables/useReturns.js +89 -0
  33. package/dist/runtime/composables/useReviews.d.ts +0 -0
  34. package/dist/runtime/composables/useReviews.js +77 -0
  35. package/dist/runtime/composables/useStoreInfo.d.ts +0 -0
  36. package/dist/runtime/composables/useStoreInfo.js +15 -0
  37. package/dist/runtime/composables/useWishlist.d.ts +0 -0
  38. package/dist/runtime/composables/useWishlist.js +82 -0
  39. package/dist/runtime/plugin.d.ts +0 -0
  40. package/dist/runtime/plugin.js +24 -0
  41. package/dist/runtime/server/api/auth.forgot-password.post.d.ts +0 -0
  42. package/dist/runtime/server/api/auth.forgot-password.post.js +8 -0
  43. package/dist/runtime/server/api/auth.login.post.d.ts +0 -0
  44. package/dist/runtime/server/api/auth.login.post.js +7 -0
  45. package/dist/runtime/server/api/auth.logout.post.d.ts +0 -0
  46. package/dist/runtime/server/api/auth.logout.post.js +7 -0
  47. package/dist/runtime/server/api/auth.register.post.d.ts +0 -0
  48. package/dist/runtime/server/api/auth.register.post.js +7 -0
  49. package/dist/runtime/server/api/auth.reset-password.post.d.ts +0 -0
  50. package/dist/runtime/server/api/auth.reset-password.post.js +8 -0
  51. package/dist/runtime/server/api/brands.get.d.ts +0 -0
  52. package/dist/runtime/server/api/brands.get.js +6 -0
  53. package/dist/runtime/server/api/cart.[id].get.d.ts +0 -0
  54. package/dist/runtime/server/api/cart.[id].get.js +7 -0
  55. package/dist/runtime/server/api/cart.[id].items.[itemId].delete.d.ts +0 -0
  56. package/dist/runtime/server/api/cart.[id].items.[itemId].delete.js +8 -0
  57. package/dist/runtime/server/api/cart.[id].items.[itemId].put.d.ts +0 -0
  58. package/dist/runtime/server/api/cart.[id].items.[itemId].put.js +9 -0
  59. package/dist/runtime/server/api/cart.[id].items.post.d.ts +0 -0
  60. package/dist/runtime/server/api/cart.[id].items.post.js +8 -0
  61. package/dist/runtime/server/api/cart.post.d.ts +0 -0
  62. package/dist/runtime/server/api/cart.post.js +6 -0
  63. package/dist/runtime/server/api/categories.get.d.ts +0 -0
  64. package/dist/runtime/server/api/categories.get.js +10 -0
  65. package/dist/runtime/server/api/checkout.payment-methods.[cartId].get.d.ts +0 -0
  66. package/dist/runtime/server/api/checkout.payment-methods.[cartId].get.js +7 -0
  67. package/dist/runtime/server/api/checkout.place-order.post.d.ts +0 -0
  68. package/dist/runtime/server/api/checkout.place-order.post.js +7 -0
  69. package/dist/runtime/server/api/checkout.shipping-methods.[cartId].get.d.ts +0 -0
  70. package/dist/runtime/server/api/checkout.shipping-methods.[cartId].get.js +7 -0
  71. package/dist/runtime/server/api/countries.get.d.ts +0 -0
  72. package/dist/runtime/server/api/countries.get.js +6 -0
  73. package/dist/runtime/server/api/customer.addresses.[addressId].delete.d.ts +0 -0
  74. package/dist/runtime/server/api/customer.addresses.[addressId].delete.js +8 -0
  75. package/dist/runtime/server/api/customer.addresses.[addressId].put.d.ts +0 -0
  76. package/dist/runtime/server/api/customer.addresses.[addressId].put.js +8 -0
  77. package/dist/runtime/server/api/customer.addresses.get.d.ts +0 -0
  78. package/dist/runtime/server/api/customer.addresses.get.js +6 -0
  79. package/dist/runtime/server/api/customer.addresses.post.d.ts +0 -0
  80. package/dist/runtime/server/api/customer.addresses.post.js +7 -0
  81. package/dist/runtime/server/api/customer.get.d.ts +0 -0
  82. package/dist/runtime/server/api/customer.get.js +6 -0
  83. package/dist/runtime/server/api/customer.orders.get.d.ts +0 -0
  84. package/dist/runtime/server/api/customer.orders.get.js +10 -0
  85. package/dist/runtime/server/api/locations.get.d.ts +0 -0
  86. package/dist/runtime/server/api/locations.get.js +6 -0
  87. package/dist/runtime/server/api/products.[id].get.d.ts +0 -0
  88. package/dist/runtime/server/api/products.[id].get.js +7 -0
  89. package/dist/runtime/server/api/products.get.d.ts +0 -0
  90. package/dist/runtime/server/api/products.get.js +13 -0
  91. package/dist/runtime/server/api/promotions.get.d.ts +0 -0
  92. package/dist/runtime/server/api/promotions.get.js +6 -0
  93. package/dist/runtime/server/api/promotions.validate.post.d.ts +0 -0
  94. package/dist/runtime/server/api/promotions.validate.post.js +7 -0
  95. package/dist/runtime/server/api/returns.[returnId].cancel.post.d.ts +0 -0
  96. package/dist/runtime/server/api/returns.[returnId].cancel.post.js +7 -0
  97. package/dist/runtime/server/api/returns.[returnId].get.d.ts +0 -0
  98. package/dist/runtime/server/api/returns.[returnId].get.js +7 -0
  99. package/dist/runtime/server/api/returns.get.d.ts +0 -0
  100. package/dist/runtime/server/api/returns.get.js +10 -0
  101. package/dist/runtime/server/api/returns.post.d.ts +0 -0
  102. package/dist/runtime/server/api/returns.post.js +7 -0
  103. package/dist/runtime/server/api/reviews.[productId].get.d.ts +0 -0
  104. package/dist/runtime/server/api/reviews.[productId].get.js +11 -0
  105. package/dist/runtime/server/api/reviews.[productId].summary.get.d.ts +0 -0
  106. package/dist/runtime/server/api/reviews.[productId].summary.get.js +7 -0
  107. package/dist/runtime/server/api/reviews.post.d.ts +0 -0
  108. package/dist/runtime/server/api/reviews.post.js +7 -0
  109. package/dist/runtime/server/api/store.get.d.ts +0 -0
  110. package/dist/runtime/server/api/store.get.js +6 -0
  111. package/dist/runtime/server/api/wishlist.get.d.ts +0 -0
  112. package/dist/runtime/server/api/wishlist.get.js +6 -0
  113. package/dist/runtime/server/api/wishlist.items.[itemId].delete.d.ts +0 -0
  114. package/dist/runtime/server/api/wishlist.items.[itemId].delete.js +7 -0
  115. package/dist/runtime/server/api/wishlist.items.post.d.ts +0 -0
  116. package/dist/runtime/server/api/wishlist.items.post.js +7 -0
  117. package/dist/runtime/server/plugins/commerce-adapter.d.ts +0 -0
  118. package/dist/runtime/server/plugins/commerce-adapter.js +25 -0
  119. package/dist/runtime/server/utils/adapter.d.ts +0 -0
  120. package/dist/runtime/server/utils/adapter.js +11 -0
  121. package/dist/types.d.mts +7 -0
  122. package/dist/types.d.ts +7 -0
  123. package/package.json +43 -0
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # @commercejs/nuxt
2
+
3
+ CommerceJS Nuxt module — composables, plugin, and auto-generated REST API.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@commercejs/nuxt?color=CB3837)](https://www.npmjs.com/package/@commercejs/nuxt)
6
+ [![Nuxt](https://img.shields.io/badge/Nuxt-00DC82?logo=nuxt.js&logoColor=white)](https://nuxt.com/)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ## Overview
11
+
12
+ `@commercejs/nuxt` is a Nuxt module that integrates CommerceJS into your Nuxt application. It provides auto-imported composables, injects the adapter into your app context, and optionally generates a full REST API from your adapter — zero boilerplate.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install @commercejs/nuxt @commercejs/types @commercejs/adapter-salla
18
+ ```
19
+
20
+ ## Setup
21
+
22
+ Add the module to your `nuxt.config.ts`:
23
+
24
+ ```typescript
25
+ export default defineNuxtConfig({
26
+ modules: ['@commercejs/nuxt'],
27
+
28
+ commerce: {
29
+ adapter: 'salla', // adapter package to use
30
+ apiBase: '/api/_commerce', // REST API base path (default)
31
+ apiRoutes: true, // auto-generate REST routes (default)
32
+ },
33
+ })
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Composables
39
+
40
+ The module auto-imports composables for your Vue components:
41
+
42
+ ```vue
43
+ <script setup>
44
+ const { data: products } = await useCommerce().getProducts({ limit: 12 })
45
+ const { data: cart } = await useCommerce().getCart(cartId)
46
+ </script>
47
+ ```
48
+
49
+ ### Plugin
50
+
51
+ The adapter is available on `$commerce` in your Nuxt app:
52
+
53
+ ```typescript
54
+ const { $commerce } = useNuxtApp()
55
+ const store = await $commerce.getStore()
56
+ ```
57
+
58
+ ### Auto-Generated REST API
59
+
60
+ When `apiRoutes` is enabled, the module registers 40+ REST endpoints:
61
+
62
+ | Endpoint | Method | Description |
63
+ |----------|--------|-------------|
64
+ | `/api/_commerce/products` | GET | List products |
65
+ | `/api/_commerce/products/:id` | GET | Get product by ID |
66
+ | `/api/_commerce/categories` | GET | List categories |
67
+ | `/api/_commerce/cart` | POST | Create cart |
68
+ | `/api/_commerce/cart/:id` | GET | Get cart |
69
+ | `/api/_commerce/cart/:id/items` | POST | Add to cart |
70
+ | `/api/_commerce/checkout/place-order` | POST | Place order |
71
+ | `/api/_commerce/auth/login` | POST | Login |
72
+ | `/api/_commerce/customer` | GET | Get customer profile |
73
+ | `/api/_commerce/customer/orders` | GET | List orders |
74
+ | `/api/_commerce/wishlist` | GET | Get wishlist |
75
+ | `/api/_commerce/reviews/:productId` | GET | Get product reviews |
76
+ | ... | ... | 30+ more routes |
77
+
78
+ ## Configuration
79
+
80
+ ```typescript
81
+ interface CommerceModuleOptions {
82
+ /** Adapter name: 'salla', 'shopify', 'medusa', etc. */
83
+ adapter?: string
84
+
85
+ /** REST API base path (default: '/api/_commerce') */
86
+ apiBase?: string
87
+
88
+ /** Auto-generate REST API routes (default: true) */
89
+ apiRoutes?: boolean
90
+ }
91
+ ```
92
+
93
+ ## Documentation
94
+
95
+ Full docs at [commerce.js.org](https://commerce.js.org)
96
+
97
+ ## License
98
+
99
+ [MIT](../../LICENSE)
@@ -0,0 +1,5 @@
1
+ module.exports = function(...args) {
2
+ return import('./module.mjs').then(m => m.default.call(this, ...args))
3
+ }
4
+ const _meta = module.exports.meta = require('./module.json')
5
+ module.exports.getMeta = () => Promise.resolve(_meta)
@@ -0,0 +1,23 @@
1
+ import { NuxtModule } from '@nuxt/schema';
2
+
3
+ interface CommerceModuleOptions {
4
+ /**
5
+ * The adapter to use (e.g., 'salla', 'zid', 'shopify', 'medusa').
6
+ * The adapter package must be installed separately.
7
+ */
8
+ adapter?: string;
9
+ /**
10
+ * Base path for auto-generated REST API routes.
11
+ * @default '/api/_commerce'
12
+ */
13
+ apiBase?: string;
14
+ /**
15
+ * Whether to register auto-generated REST API routes.
16
+ * @default true
17
+ */
18
+ apiRoutes?: boolean;
19
+ }
20
+ declare const commerceModule: NuxtModule<CommerceModuleOptions>;
21
+
22
+ export { commerceModule as default };
23
+ export type { CommerceModuleOptions };
@@ -0,0 +1,23 @@
1
+ import { NuxtModule } from '@nuxt/schema';
2
+
3
+ interface CommerceModuleOptions {
4
+ /**
5
+ * The adapter to use (e.g., 'salla', 'zid', 'shopify', 'medusa').
6
+ * The adapter package must be installed separately.
7
+ */
8
+ adapter?: string;
9
+ /**
10
+ * Base path for auto-generated REST API routes.
11
+ * @default '/api/_commerce'
12
+ */
13
+ apiBase?: string;
14
+ /**
15
+ * Whether to register auto-generated REST API routes.
16
+ * @default true
17
+ */
18
+ apiRoutes?: boolean;
19
+ }
20
+ declare const commerceModule: NuxtModule<CommerceModuleOptions>;
21
+
22
+ export { commerceModule as default };
23
+ export type { CommerceModuleOptions };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@commercejs/nuxt",
3
+ "configKey": "commerce",
4
+ "compatibility": {
5
+ "nuxt": ">=3.0.0"
6
+ },
7
+ "version": "0.2.0",
8
+ "builder": {
9
+ "@nuxt/module-builder": "0.8.4",
10
+ "unbuild": "unknown"
11
+ }
12
+ }
@@ -0,0 +1,101 @@
1
+ import { defineNuxtModule, createResolver, addTypeTemplate, addPlugin, addServerPlugin, addImportsDir, addServerHandler } from '@nuxt/kit';
2
+ import { consola } from 'consola';
3
+
4
+ const logger = consola.withTag("@commercejs/nuxt");
5
+ const commerceModule = defineNuxtModule({
6
+ meta: {
7
+ name: "@commercejs/nuxt",
8
+ configKey: "commerce",
9
+ compatibility: {
10
+ nuxt: ">=3.0.0"
11
+ }
12
+ },
13
+ defaults: {
14
+ apiBase: "/api/_commerce",
15
+ apiRoutes: true
16
+ },
17
+ setup(options, nuxt) {
18
+ const { resolve } = createResolver(import.meta.url);
19
+ logger.info("Initializing CommerceJS module...");
20
+ nuxt.options.runtimeConfig.public.commerce = {
21
+ adapter: options.adapter || "",
22
+ apiBase: options.apiBase || "/api/_commerce"
23
+ };
24
+ addTypeTemplate({
25
+ filename: "types/commercejs.d.ts",
26
+ getContents: () => `
27
+ import type { CommerceAdapter } from '@commercejs/types'
28
+
29
+ declare module '#app' {
30
+ interface NuxtApp {
31
+ $commerce: CommerceAdapter
32
+ }
33
+ }
34
+
35
+ declare module 'vue' {
36
+ interface ComponentCustomProperties {
37
+ $commerce: CommerceAdapter
38
+ }
39
+ }
40
+
41
+ export {}
42
+ `
43
+ });
44
+ addPlugin(resolve("./runtime/plugin"));
45
+ addServerPlugin(resolve("./runtime/server/plugins/commerce-adapter"));
46
+ addImportsDir(resolve("./runtime/composables"));
47
+ if (options.apiRoutes) {
48
+ const apiBase = options.apiBase || "/api/_commerce";
49
+ let routeCount = 0;
50
+ const route = (path, handler, method) => {
51
+ addServerHandler({
52
+ route: `${apiBase}${path}`,
53
+ handler: resolve(`./runtime/server/api/${handler}`),
54
+ ...method ? { method } : {}
55
+ });
56
+ routeCount++;
57
+ };
58
+ route("/store", "store.get");
59
+ route("/products", "products.get");
60
+ route("/products/:id", "products.[id].get");
61
+ route("/categories", "categories.get");
62
+ route("/brands", "brands.get");
63
+ route("/cart", "cart.post", "post");
64
+ route("/cart/:id", "cart.[id].get");
65
+ route("/cart/:id/items", "cart.[id].items.post", "post");
66
+ route("/cart/:id/items/:itemId", "cart.[id].items.[itemId].put", "put");
67
+ route("/cart/:id/items/:itemId", "cart.[id].items.[itemId].delete", "delete");
68
+ route("/checkout/shipping-methods/:cartId", "checkout.shipping-methods.[cartId].get");
69
+ route("/checkout/payment-methods/:cartId", "checkout.payment-methods.[cartId].get");
70
+ route("/checkout/place-order", "checkout.place-order.post", "post");
71
+ route("/auth/login", "auth.login.post", "post");
72
+ route("/auth/register", "auth.register.post", "post");
73
+ route("/auth/logout", "auth.logout.post", "post");
74
+ route("/auth/forgot-password", "auth.forgot-password.post", "post");
75
+ route("/auth/reset-password", "auth.reset-password.post", "post");
76
+ route("/customer", "customer.get");
77
+ route("/customer/orders", "customer.orders.get");
78
+ route("/customer/addresses", "customer.addresses.get");
79
+ route("/customer/addresses", "customer.addresses.post", "post");
80
+ route("/customer/addresses/:addressId", "customer.addresses.[addressId].put", "put");
81
+ route("/customer/addresses/:addressId", "customer.addresses.[addressId].delete", "delete");
82
+ route("/reviews/:productId", "reviews.[productId].get");
83
+ route("/reviews/:productId/summary", "reviews.[productId].summary.get");
84
+ route("/reviews", "reviews.post", "post");
85
+ route("/wishlist", "wishlist.get");
86
+ route("/wishlist/items", "wishlist.items.post", "post");
87
+ route("/wishlist/items/:itemId", "wishlist.items.[itemId].delete", "delete");
88
+ route("/promotions", "promotions.get");
89
+ route("/promotions/validate", "promotions.validate.post", "post");
90
+ route("/returns", "returns.get");
91
+ route("/returns", "returns.post", "post");
92
+ route("/returns/:returnId", "returns.[returnId].get");
93
+ route("/returns/:returnId/cancel", "returns.[returnId].cancel.post", "post");
94
+ route("/countries", "countries.get");
95
+ route("/locations", "locations.get");
96
+ logger.info(`Registered ${routeCount} REST API routes under ${apiBase}`);
97
+ }
98
+ }
99
+ });
100
+
101
+ export { commerceModule as default };
File without changes
@@ -0,0 +1,15 @@
1
+ export { useAdapter } from "./useAdapter.js";
2
+ export { useProduct } from "./useProduct.js";
3
+ export { useProducts } from "./useProducts.js";
4
+ export { useCategories } from "./useCategories.js";
5
+ export { useCart } from "./useCart.js";
6
+ export { useCustomer } from "./useCustomer.js";
7
+ export { useCheckout } from "./useCheckout.js";
8
+ export { useWishlist } from "./useWishlist.js";
9
+ export { useReviews } from "./useReviews.js";
10
+ export { useStoreInfo } from "./useStoreInfo.js";
11
+ export { usePromotions } from "./usePromotions.js";
12
+ export { useReturns } from "./useReturns.js";
13
+ export { useBrands } from "./useBrands.js";
14
+ export { useCountries } from "./useCountries.js";
15
+ export { useLocations } from "./useLocations.js";
File without changes
@@ -0,0 +1,11 @@
1
+ import { useNuxtApp } from "#imports";
2
+ export function useAdapter() {
3
+ const nuxtApp = useNuxtApp();
4
+ const adapter = nuxtApp.$commerce;
5
+ if (!adapter && import.meta.server) {
6
+ throw new Error(
7
+ "[@commercejs/nuxt] No commerce adapter available. Make sure you have installed and configured an adapter package (e.g., @commercejs/adapter-salla, @commercejs/adapter-zid)."
8
+ );
9
+ }
10
+ return adapter || null;
11
+ }
File without changes
@@ -0,0 +1,32 @@
1
+ import { useState, readonly } from "#imports";
2
+ import { CommerceError, isCommerceError } from "@commercejs/types";
3
+ import { useAdapter } from "./useAdapter.js";
4
+ export function useBrands() {
5
+ const adapter = useAdapter();
6
+ const brands = useState("commerce:brands", () => []);
7
+ const loading = useState("commerce:brands:loading", () => false);
8
+ const error = useState("commerce:brands:error", () => null);
9
+ async function refresh() {
10
+ loading.value = true;
11
+ error.value = null;
12
+ try {
13
+ brands.value = await adapter.getBrands();
14
+ } catch (err) {
15
+ const e = isCommerceError(err) ? err : new CommerceError(
16
+ err instanceof Error ? err.message : String(err),
17
+ "UNKNOWN",
18
+ void 0,
19
+ err
20
+ );
21
+ error.value = e;
22
+ } finally {
23
+ loading.value = false;
24
+ }
25
+ }
26
+ return {
27
+ brands: readonly(brands),
28
+ loading: readonly(loading),
29
+ error: readonly(error),
30
+ refresh
31
+ };
32
+ }
File without changes
@@ -0,0 +1,144 @@
1
+ import { useState, useCookie, computed, readonly, useRuntimeConfig } from "#imports";
2
+ import { CommerceError, isCommerceError } from "@commercejs/types";
3
+ import { createEventHook } from "@vueuse/core";
4
+ export function useCart() {
5
+ const config = useRuntimeConfig();
6
+ const apiBase = config.public.commerce?.apiBase || "/api/_commerce";
7
+ const cartId = useCookie("commerce_cart_id", { maxAge: 60 * 60 * 24 * 30 });
8
+ const cart = useState("commerce_cart", () => null);
9
+ const loading = useState("commerce_cart_loading", () => false);
10
+ const error = useState("commerce_cart_error", () => null);
11
+ const itemAddedHook = createEventHook();
12
+ const itemUpdatedHook = createEventHook();
13
+ const itemRemovedHook = createEventHook();
14
+ const errorHook = createEventHook();
15
+ function handleError(err) {
16
+ const e = isCommerceError(err) ? err : new CommerceError(
17
+ err instanceof Error ? err.message : String(err),
18
+ "UNKNOWN",
19
+ void 0,
20
+ err
21
+ );
22
+ error.value = e;
23
+ errorHook.trigger(e);
24
+ return e;
25
+ }
26
+ async function createCart() {
27
+ loading.value = true;
28
+ error.value = null;
29
+ try {
30
+ const newCart = await $fetch(`${apiBase}/cart`, { method: "POST" });
31
+ cart.value = newCart;
32
+ cartId.value = newCart.id;
33
+ return newCart;
34
+ } catch (err) {
35
+ throw handleError(err);
36
+ } finally {
37
+ loading.value = false;
38
+ }
39
+ }
40
+ async function refresh() {
41
+ if (!cartId.value) return;
42
+ loading.value = true;
43
+ error.value = null;
44
+ try {
45
+ cart.value = await $fetch(`${apiBase}/cart/${cartId.value}`);
46
+ } catch (err) {
47
+ handleError(err);
48
+ } finally {
49
+ loading.value = false;
50
+ }
51
+ }
52
+ async function addItem(item) {
53
+ if (!cartId.value) {
54
+ throw new Error("[@commercejs/nuxt] No cart ID. Ensure the cart is initialized.");
55
+ }
56
+ loading.value = true;
57
+ error.value = null;
58
+ try {
59
+ cart.value = await $fetch(`${apiBase}/cart/${cartId.value}/items`, {
60
+ method: "POST",
61
+ body: item
62
+ });
63
+ itemAddedHook.trigger(cart.value);
64
+ } catch (err) {
65
+ throw handleError(err);
66
+ } finally {
67
+ loading.value = false;
68
+ }
69
+ }
70
+ async function updateItem(itemId, quantity) {
71
+ if (!cartId.value) return;
72
+ loading.value = true;
73
+ error.value = null;
74
+ try {
75
+ cart.value = await $fetch(`${apiBase}/cart/${cartId.value}/items/${itemId}`, {
76
+ method: "PUT",
77
+ body: { quantity }
78
+ });
79
+ itemUpdatedHook.trigger(cart.value);
80
+ } catch (err) {
81
+ throw handleError(err);
82
+ } finally {
83
+ loading.value = false;
84
+ }
85
+ }
86
+ async function removeItem(itemId) {
87
+ if (!cartId.value) return;
88
+ loading.value = true;
89
+ error.value = null;
90
+ try {
91
+ cart.value = await $fetch(`${apiBase}/cart/${cartId.value}/items/${itemId}`, {
92
+ method: "DELETE"
93
+ });
94
+ itemRemovedHook.trigger(cart.value);
95
+ } catch (err) {
96
+ throw handleError(err);
97
+ } finally {
98
+ loading.value = false;
99
+ }
100
+ }
101
+ async function applyCoupon(code) {
102
+ if (!cartId.value) return;
103
+ loading.value = true;
104
+ error.value = null;
105
+ try {
106
+ cart.value = await $fetch(`${apiBase}/promotions/validate`, {
107
+ method: "POST",
108
+ body: { cartId: cartId.value, code }
109
+ });
110
+ } catch (err) {
111
+ throw handleError(err);
112
+ } finally {
113
+ loading.value = false;
114
+ }
115
+ }
116
+ async function removeCoupon() {
117
+ await refresh();
118
+ }
119
+ return {
120
+ /** Reactive cart state (readonly to enforce mutations through methods) */
121
+ cart: readonly(cart),
122
+ /** Cart ID stored in cookie */
123
+ cartId,
124
+ /** Whether a cart operation is in progress */
125
+ loading: readonly(loading),
126
+ /** Last error from a cart operation */
127
+ error: readonly(error),
128
+ /** Number of items in the cart */
129
+ itemCount: computed(() => cart.value?.itemCount ?? 0),
130
+ // Event hooks — subscribe: onItemAdded((cart) => { ... })
131
+ onItemAdded: itemAddedHook.on,
132
+ onItemUpdated: itemUpdatedHook.on,
133
+ onItemRemoved: itemRemovedHook.on,
134
+ onError: errorHook.on,
135
+ // Methods
136
+ createCart,
137
+ refresh,
138
+ addItem,
139
+ updateItem,
140
+ removeItem,
141
+ applyCoupon,
142
+ removeCoupon
143
+ };
144
+ }
File without changes
@@ -0,0 +1,9 @@
1
+ import { useFetch, useRuntimeConfig } from "#imports";
2
+ export function useCategories() {
3
+ const config = useRuntimeConfig();
4
+ const apiBase = config.public.commerce?.apiBase || "/api/_commerce";
5
+ return useFetch(
6
+ `${apiBase}/categories`,
7
+ { key: "categories" }
8
+ );
9
+ }
File without changes
@@ -0,0 +1,142 @@
1
+ import { useState, readonly } from "#imports";
2
+ import { CommerceError, isCommerceError } from "@commercejs/types";
3
+ import { createEventHook } from "@vueuse/core";
4
+ import { useAdapter } from "./useAdapter.js";
5
+ import { useCart } from "./useCart.js";
6
+ export function useCheckout() {
7
+ const adapter = useAdapter();
8
+ const { cart, cartId } = useCart();
9
+ const shippingMethods = useState("commerce_shipping_methods", () => []);
10
+ const paymentMethods = useState("commerce_payment_methods", () => []);
11
+ const loading = useState("commerce_checkout_loading", () => false);
12
+ const error = useState("commerce_checkout_error", () => null);
13
+ const orderPlacedHook = createEventHook();
14
+ const errorHook = createEventHook();
15
+ function handleError(err) {
16
+ const e = isCommerceError(err) ? err : new CommerceError(
17
+ err instanceof Error ? err.message : String(err),
18
+ "UNKNOWN",
19
+ void 0,
20
+ err
21
+ );
22
+ error.value = e;
23
+ errorHook.trigger(e);
24
+ return e;
25
+ }
26
+ function requireCartId() {
27
+ if (!cartId.value) {
28
+ throw new Error("[@commercejs/nuxt] No cart ID found. Add items to cart first.");
29
+ }
30
+ return cartId.value;
31
+ }
32
+ async function loadShippingMethods() {
33
+ const id = requireCartId();
34
+ loading.value = true;
35
+ error.value = null;
36
+ try {
37
+ shippingMethods.value = await adapter.getShippingMethods(id);
38
+ } catch (err) {
39
+ throw handleError(err);
40
+ } finally {
41
+ loading.value = false;
42
+ }
43
+ }
44
+ async function loadPaymentMethods() {
45
+ const id = requireCartId();
46
+ loading.value = true;
47
+ error.value = null;
48
+ try {
49
+ paymentMethods.value = await adapter.getPaymentMethods(id);
50
+ } catch (err) {
51
+ throw handleError(err);
52
+ } finally {
53
+ loading.value = false;
54
+ }
55
+ }
56
+ async function setShippingAddress(address) {
57
+ const id = requireCartId();
58
+ loading.value = true;
59
+ error.value = null;
60
+ try {
61
+ const updatedCart = await adapter.setShippingAddress(id, address);
62
+ useState("commerce_cart").value = updatedCart;
63
+ } catch (err) {
64
+ throw handleError(err);
65
+ } finally {
66
+ loading.value = false;
67
+ }
68
+ }
69
+ async function setBillingAddress(address) {
70
+ const id = requireCartId();
71
+ loading.value = true;
72
+ error.value = null;
73
+ try {
74
+ const updatedCart = await adapter.setBillingAddress(id, address);
75
+ useState("commerce_cart").value = updatedCart;
76
+ } catch (err) {
77
+ throw handleError(err);
78
+ } finally {
79
+ loading.value = false;
80
+ }
81
+ }
82
+ async function setShippingMethod(methodId) {
83
+ const id = requireCartId();
84
+ loading.value = true;
85
+ error.value = null;
86
+ try {
87
+ const updatedCart = await adapter.setShippingMethod(id, methodId);
88
+ useState("commerce_cart").value = updatedCart;
89
+ } catch (err) {
90
+ throw handleError(err);
91
+ } finally {
92
+ loading.value = false;
93
+ }
94
+ }
95
+ async function setPaymentMethod(methodId) {
96
+ const id = requireCartId();
97
+ loading.value = true;
98
+ error.value = null;
99
+ try {
100
+ const updatedCart = await adapter.setPaymentMethod(id, methodId);
101
+ useState("commerce_cart").value = updatedCart;
102
+ } catch (err) {
103
+ throw handleError(err);
104
+ } finally {
105
+ loading.value = false;
106
+ }
107
+ }
108
+ async function placeOrder() {
109
+ const id = requireCartId();
110
+ loading.value = true;
111
+ error.value = null;
112
+ try {
113
+ const order = await adapter.placeOrder(id);
114
+ useState("commerce_cart").value = null;
115
+ cartId.value = "";
116
+ orderPlacedHook.trigger(order);
117
+ return order;
118
+ } catch (err) {
119
+ throw handleError(err);
120
+ } finally {
121
+ loading.value = false;
122
+ }
123
+ }
124
+ return {
125
+ cart,
126
+ shippingMethods: readonly(shippingMethods),
127
+ paymentMethods: readonly(paymentMethods),
128
+ loading: readonly(loading),
129
+ error: readonly(error),
130
+ // Event hooks
131
+ onOrderPlaced: orderPlacedHook.on,
132
+ onError: errorHook.on,
133
+ // Methods
134
+ loadShippingMethods,
135
+ loadPaymentMethods,
136
+ setShippingAddress,
137
+ setBillingAddress,
138
+ setShippingMethod,
139
+ setPaymentMethod,
140
+ placeOrder
141
+ };
142
+ }
File without changes
@@ -0,0 +1,32 @@
1
+ import { useState, readonly } from "#imports";
2
+ import { CommerceError, isCommerceError } from "@commercejs/types";
3
+ import { useAdapter } from "./useAdapter.js";
4
+ export function useCountries() {
5
+ const adapter = useAdapter();
6
+ const countries = useState("commerce:countries", () => []);
7
+ const loading = useState("commerce:countries:loading", () => false);
8
+ const error = useState("commerce:countries:error", () => null);
9
+ async function refresh() {
10
+ loading.value = true;
11
+ error.value = null;
12
+ try {
13
+ countries.value = await adapter.getCountries();
14
+ } catch (err) {
15
+ const e = isCommerceError(err) ? err : new CommerceError(
16
+ err instanceof Error ? err.message : String(err),
17
+ "UNKNOWN",
18
+ void 0,
19
+ err
20
+ );
21
+ error.value = e;
22
+ } finally {
23
+ loading.value = false;
24
+ }
25
+ }
26
+ return {
27
+ countries: readonly(countries),
28
+ loading: readonly(loading),
29
+ error: readonly(error),
30
+ refresh
31
+ };
32
+ }
File without changes