@nextblock-cms/ecom 0.21.3 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -43
- package/lib/invoice-server.cjs +2 -2
- package/lib/invoice-server.es.js +22 -22
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
# @nextblock-cms/ecom
|
|
2
|
-
|
|
3
|
-
The premium commerce module of [NextBlock](https://github.com/nextblock-cms/nextblock), the
|
|
4
|
-
open-core CMS for Next.js and Supabase: products and variants, cart and checkout, orders,
|
|
5
|
-
coupons, currencies, shipping zones, tax rates and invoices. Physical products are paid through
|
|
6
|
-
Stripe and digital products through Freemius.
|
|
7
|
-
|
|
8
|
-
NextBlock projects install it under the alias `@nextblock-cms/ecommerce`, and every import uses
|
|
9
|
-
that name. Projects created with `npm create nextblock@latest` already have it:
|
|
10
|
-
|
|
11
|
-
```json
|
|
12
|
-
"@nextblock-cms/ecommerce": "npm:@nextblock-cms/ecom@latest"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
It needs Next.js 16 and React 19 (peer dependencies), plus the NextBlock database schema that
|
|
16
|
-
`@nextblock-cms/db` ships.
|
|
17
|
-
|
|
18
|
-
## Licensing
|
|
19
|
-
|
|
20
|
-
The source is public under AGPL-3.0-or-later, and the features are license-gated. A NextBlock
|
|
21
|
-
project turns on its checkout API and commerce CMS screens only after an ecommerce license is
|
|
22
|
-
active: start a trial or buy one in the CMS under **Settings → Packages**. The app checks it
|
|
23
|
-
with `verifyPackageOnline('ecommerce')` from `@nextblock-cms/db/server`.
|
|
24
|
-
|
|
25
|
-
## Entry points
|
|
26
|
-
|
|
27
|
-
| Import | Use it from | What it holds |
|
|
28
|
-
| :-- | :-- | :-- |
|
|
29
|
-
| `@nextblock-cms/ecommerce` | client or server | Storefront and account components (`Cart`, `CartDrawer`, `Checkout`, `ProductGrid`, `ProductCard`, `FeaturedProduct`, `AddToCartButton`, `CurrencySwitcher`, …), the cart store, `CurrencyProvider`, and the CMS `ProductForm` |
|
|
30
|
-
| `@nextblock-cms/ecommerce/server` | server only | Stripe checkout, webhooks and order sync, payment configuration, inventory, invoices, tax details and coupons |
|
|
31
|
-
| `@nextblock-cms/ecommerce/<module>` | depends on the module | One compiled module, for example `@nextblock-cms/ecommerce/cart-store`, `/components/Cart` or `/server-actions/product-actions` |
|
|
32
|
-
|
|
33
|
-
The package keeps each module's `'use client'` or `'use server'` directive, so the consuming
|
|
34
|
-
Next.js build splits client and server code correctly.
|
|
35
|
-
|
|
36
|
-
## Documentation
|
|
37
|
-
|
|
38
|
-
- [Ecommerce capabilities](https://github.com/nextblock-cms/nextblock/blob/master/docs/02-ECOMMERCE-CAPABILITIES.md)
|
|
39
|
-
- [Project overview](https://github.com/nextblock-cms/nextblock/blob/master/docs/01-PROJECT-OVERVIEW.md)
|
|
40
|
-
|
|
41
|
-
## License
|
|
42
|
-
|
|
43
|
-
AGPL-3.0-or-later.
|
|
1
|
+
# @nextblock-cms/ecom
|
|
2
|
+
|
|
3
|
+
The premium commerce module of [NextBlock](https://github.com/nextblock-cms/nextblock), the
|
|
4
|
+
open-core CMS for Next.js and Supabase: products and variants, cart and checkout, orders,
|
|
5
|
+
coupons, currencies, shipping zones, tax rates and invoices. Physical products are paid through
|
|
6
|
+
Stripe and digital products through Freemius.
|
|
7
|
+
|
|
8
|
+
NextBlock projects install it under the alias `@nextblock-cms/ecommerce`, and every import uses
|
|
9
|
+
that name. Projects created with `npm create nextblock@latest` already have it:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
"@nextblock-cms/ecommerce": "npm:@nextblock-cms/ecom@latest"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
It needs Next.js 16 and React 19 (peer dependencies), plus the NextBlock database schema that
|
|
16
|
+
`@nextblock-cms/db` ships.
|
|
17
|
+
|
|
18
|
+
## Licensing
|
|
19
|
+
|
|
20
|
+
The source is public under AGPL-3.0-or-later, and the features are license-gated. A NextBlock
|
|
21
|
+
project turns on its checkout API and commerce CMS screens only after an ecommerce license is
|
|
22
|
+
active: start a trial or buy one in the CMS under **Settings → Packages**. The app checks it
|
|
23
|
+
with `verifyPackageOnline('ecommerce')` from `@nextblock-cms/db/server`.
|
|
24
|
+
|
|
25
|
+
## Entry points
|
|
26
|
+
|
|
27
|
+
| Import | Use it from | What it holds |
|
|
28
|
+
| :-- | :-- | :-- |
|
|
29
|
+
| `@nextblock-cms/ecommerce` | client or server | Storefront and account components (`Cart`, `CartDrawer`, `Checkout`, `ProductGrid`, `ProductCard`, `FeaturedProduct`, `AddToCartButton`, `CurrencySwitcher`, …), the cart store, `CurrencyProvider`, and the CMS `ProductForm` |
|
|
30
|
+
| `@nextblock-cms/ecommerce/server` | server only | Stripe checkout, webhooks and order sync, payment configuration, inventory, invoices, tax details and coupons |
|
|
31
|
+
| `@nextblock-cms/ecommerce/<module>` | depends on the module | One compiled module, for example `@nextblock-cms/ecommerce/cart-store`, `/components/Cart` or `/server-actions/product-actions` |
|
|
32
|
+
|
|
33
|
+
The package keeps each module's `'use client'` or `'use server'` directive, so the consuming
|
|
34
|
+
Next.js build splits client and server code correctly.
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
|
|
38
|
+
- [Ecommerce capabilities](https://github.com/nextblock-cms/nextblock/blob/master/docs/02-ECOMMERCE-CAPABILITIES.md)
|
|
39
|
+
- [Project overview](https://github.com/nextblock-cms/nextblock/blob/master/docs/01-PROJECT-OVERVIEW.md)
|
|
40
|
+
|
|
41
|
+
## License
|
|
42
|
+
|
|
43
|
+
AGPL-3.0-or-later.
|
package/lib/invoice-server.cjs
CHANGED
|
@@ -7,7 +7,7 @@ const e=require("./customer.cjs"),t=require("./invoice.cjs"),n=require("./order-
|
|
|
7
7
|
width,
|
|
8
8
|
height
|
|
9
9
|
)
|
|
10
|
-
`;async function l(e){let{data:t}=await e.from(`site_settings`).select(`value`).eq(`key`,s).maybeSingle(),n=t?.value,r=typeof n==`string`&&n.length>0?n:null;if(r){let{data:t}=await e.from(`logos`).select(c).eq(`id`,r).maybeSingle();if(t)return t}let{data:i}=await e.from(`logos`).select(c).order(`created_at`,{ascending:!1}).limit(1).maybeSingle();return i??null}async function u(e){let n=a(e),[r,i]=await Promise.all([n.from(`site_settings`).select(`value`).eq(`key`,t.INVOICE_SETTINGS_KEY).maybeSingle(),l(n)]);return{settings:t.normalizeInvoiceSettings(r.data?.value??t.DEFAULT_INVOICE_SETTINGS),logo:o(i)}}async function d(e){let{data:t,error:n}=await a(e.client).rpc(`assign_order_invoice_metadata`,{p_order_id:e.orderId,p_paid_at:e.paidAt??null}).single();if(n)throw Error(n.message);return{invoiceNumber:t?.invoice_number??null,paidAt:t?.paid_at??null}}async function f(t,
|
|
10
|
+
`;async function l(e){let{data:t}=await e.from(`site_settings`).select(`value`).eq(`key`,s).maybeSingle(),n=t?.value,r=typeof n==`string`&&n.length>0?n:null;if(r){let{data:t}=await e.from(`logos`).select(c).eq(`id`,r).maybeSingle();if(t)return t}let{data:i}=await e.from(`logos`).select(c).order(`created_at`,{ascending:!1}).limit(1).maybeSingle();return i??null}async function u(e){let n=a(e),[r,i]=await Promise.all([n.from(`site_settings`).select(`value`).eq(`key`,t.INVOICE_SETTINGS_KEY).maybeSingle(),l(n)]);return{settings:t.normalizeInvoiceSettings(r.data?.value??t.DEFAULT_INVOICE_SETTINGS),logo:o(i)}}async function d(e){let{data:t,error:n}=await a(e.client).rpc(`assign_order_invoice_metadata`,{p_order_id:e.orderId,p_paid_at:e.paidAt??null}).single();if(n)throw Error(n.message);return{invoiceNumber:t?.invoice_number??null,paidAt:t?.paid_at??null}}async function f(t,i){let{data:o,error:s}=await a(i).from(`orders`).select(`
|
|
11
11
|
id,
|
|
12
12
|
invoice_number,
|
|
13
13
|
paid_at,
|
|
@@ -30,4 +30,4 @@ const e=require("./customer.cjs"),t=require("./invoice.cjs"),n=require("./order-
|
|
|
30
30
|
quantity,
|
|
31
31
|
price_at_purchase
|
|
32
32
|
)
|
|
33
|
-
`).eq(`id`,t).single();if(s||!o)throw Error(s?.message||`Order not found`);let c=(o.order_items||[]).map(e=>e.product_id).filter(Boolean),l=(o.order_items||[]).map(e=>e.variant_id).filter(Boolean),
|
|
33
|
+
`).eq(`id`,t).single();if(s||!o)throw Error(s?.message||`Order not found`);let c=(o.order_items||[]).map(e=>e.product_id).filter(Boolean),l=(o.order_items||[]).map(e=>e.variant_id).filter(Boolean),u=(0,r.getServiceRoleSupabaseClient)(),[d,f]=await Promise.all([c.length?u.from(`products`).select(`id, title, sku`).in(`id`,c):Promise.resolve({data:[],error:null}),l.length?u.from(`product_variants`).select(`id, sku`).in(`id`,l):Promise.resolve({data:[],error:null})]),p=new Map((d.data||[]).map(e=>[e.id,e])),m=new Map((f.data||[]).map(e=>[e.id,e])),h=(o.order_items||[]).map(e=>{let t=e.product_id?p.get(e.product_id):null,n=e.variant_id?m.get(e.variant_id):null,r=t?.title||`Product`,i=n?.sku?`SKU: ${n.sku}`:t?.sku?`SKU: ${t.sku}`:null;return{id:e.id,product_id:e.product_id??null,variant_id:e.variant_id??null,title:r,description:i,quantity:e.quantity,unit_amount:e.price_at_purchase,total_amount:e.price_at_purchase*e.quantity,sku:n?.sku??t?.sku??null}});return{id:o.id,invoice_number:o.invoice_number??null,paid_at:o.paid_at??null,created_at:o.created_at??null,currency:o.currency||`usd`,status:o.status,provider:o.provider??null,subtotal:typeof o.subtotal==`number`?o.subtotal:h.reduce((e,t)=>e+t.total_amount,0),shipping_total:typeof o.shipping_total==`number`?o.shipping_total:0,discount_total:typeof o.discount_total==`number`?o.discount_total:0,coupon_code:o.coupon_code??null,tax_total:typeof o.tax_total==`number`?o.tax_total:0,total:o.total,customer_details:e.normalizeOrderCustomerDetails(o.customer_details??{}),tax_details:n.normalizeOrderTaxDetails(o.tax_details),items:h}}async function p(e,t){let n=a(t),[r,i]=await Promise.all([f(e,n),u(n)]);return{order:r,settings:i.settings,logo:i.logo}}exports.assignInvoiceMetadata=d,exports.getInvoiceBrandingData=u,exports.getInvoiceOrder=f,exports.getInvoicePresentationData=p;
|
package/lib/invoice-server.es.js
CHANGED
|
@@ -49,16 +49,16 @@ async function p(e) {
|
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
async function m(t, n) {
|
|
52
|
-
let
|
|
53
|
-
if (o || !
|
|
54
|
-
let c = (
|
|
52
|
+
let { data: r, error: o } = await s(n).from("orders").select("\n id,\n invoice_number,\n paid_at,\n created_at,\n currency,\n status,\n provider,\n subtotal,\n shipping_total,\n discount_total,\n coupon_code,\n tax_total,\n total,\n customer_details,\n tax_details,\n order_items (\n id,\n product_id,\n variant_id,\n quantity,\n price_at_purchase\n )\n ").eq("id", t).single();
|
|
53
|
+
if (o || !r) throw Error(o?.message || "Order not found");
|
|
54
|
+
let c = (r.order_items || []).map((e) => e.product_id).filter(Boolean), l = (r.order_items || []).map((e) => e.variant_id).filter(Boolean), u = a(), [d, f] = await Promise.all([c.length ? u.from("products").select("id, title, sku").in("id", c) : Promise.resolve({
|
|
55
55
|
data: [],
|
|
56
56
|
error: null
|
|
57
|
-
}), l.length ?
|
|
57
|
+
}), l.length ? u.from("product_variants").select("id, sku").in("id", l) : Promise.resolve({
|
|
58
58
|
data: [],
|
|
59
59
|
error: null
|
|
60
|
-
})]),
|
|
61
|
-
let t = e.product_id ?
|
|
60
|
+
})]), p = new Map((d.data || []).map((e) => [e.id, e])), m = new Map((f.data || []).map((e) => [e.id, e])), h = (r.order_items || []).map((e) => {
|
|
61
|
+
let t = e.product_id ? p.get(e.product_id) : null, n = e.variant_id ? m.get(e.variant_id) : null, r = t?.title || "Product", i = n?.sku ? `SKU: ${n.sku}` : t?.sku ? `SKU: ${t.sku}` : null;
|
|
62
62
|
return {
|
|
63
63
|
id: e.id,
|
|
64
64
|
product_id: e.product_id ?? null,
|
|
@@ -72,22 +72,22 @@ async function m(t, n) {
|
|
|
72
72
|
};
|
|
73
73
|
});
|
|
74
74
|
return {
|
|
75
|
-
id:
|
|
76
|
-
invoice_number:
|
|
77
|
-
paid_at:
|
|
78
|
-
created_at:
|
|
79
|
-
currency:
|
|
80
|
-
status:
|
|
81
|
-
provider:
|
|
82
|
-
subtotal: typeof
|
|
83
|
-
shipping_total: typeof
|
|
84
|
-
discount_total: typeof
|
|
85
|
-
coupon_code:
|
|
86
|
-
tax_total: typeof
|
|
87
|
-
total:
|
|
88
|
-
customer_details: e(
|
|
89
|
-
tax_details: i(
|
|
90
|
-
items:
|
|
75
|
+
id: r.id,
|
|
76
|
+
invoice_number: r.invoice_number ?? null,
|
|
77
|
+
paid_at: r.paid_at ?? null,
|
|
78
|
+
created_at: r.created_at ?? null,
|
|
79
|
+
currency: r.currency || "usd",
|
|
80
|
+
status: r.status,
|
|
81
|
+
provider: r.provider ?? null,
|
|
82
|
+
subtotal: typeof r.subtotal == "number" ? r.subtotal : h.reduce((e, t) => e + t.total_amount, 0),
|
|
83
|
+
shipping_total: typeof r.shipping_total == "number" ? r.shipping_total : 0,
|
|
84
|
+
discount_total: typeof r.discount_total == "number" ? r.discount_total : 0,
|
|
85
|
+
coupon_code: r.coupon_code ?? null,
|
|
86
|
+
tax_total: typeof r.tax_total == "number" ? r.tax_total : 0,
|
|
87
|
+
total: r.total,
|
|
88
|
+
customer_details: e(r.customer_details ?? {}),
|
|
89
|
+
tax_details: i(r.tax_details),
|
|
90
|
+
items: h
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
async function h(e, t) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextblock-cms/ecom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@nextblock-cms/db": "^0.
|
|
16
|
-
"@nextblock-cms/ui": "^0.
|
|
17
|
-
"@nextblock-cms/utils": "^0.
|
|
15
|
+
"@nextblock-cms/db": "^0.22.0",
|
|
16
|
+
"@nextblock-cms/ui": "^0.22.0",
|
|
17
|
+
"@nextblock-cms/utils": "^0.22.0",
|
|
18
18
|
"@freemius/checkout": "^1.5.1",
|
|
19
19
|
"@freemius/sdk": "^0.5.0",
|
|
20
20
|
"@hookform/resolvers": "^5.9.1",
|