@porulle/core 0.7.0 → 0.8.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/dist/auth/setup.d.ts.map +1 -1
- package/dist/auth/setup.js +1 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +5 -0
- package/dist/config/types.d.ts +17 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/generated/plugin-manifest.d.ts +3 -0
- package/dist/generated/plugin-manifest.d.ts.map +1 -1
- package/dist/generated/plugin-manifest.js +1 -0
- package/dist/hooks/checkout.d.ts.map +1 -1
- package/dist/hooks/checkout.js +16 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/interfaces/rest/index.d.ts.map +1 -1
- package/dist/interfaces/rest/index.js +12 -0
- package/dist/interfaces/rest/routes/admin/staff.d.ts +12 -0
- package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/admin/staff.js +172 -0
- package/dist/interfaces/rest/routes/analytics.d.ts +5 -0
- package/dist/interfaces/rest/routes/analytics.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/analytics.js +24 -0
- package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/carts.js +39 -2
- package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/catalog.js +17 -1
- package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/checkout.js +17 -0
- package/dist/interfaces/rest/routes/documents.d.ts +10 -0
- package/dist/interfaces/rest/routes/documents.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/documents.js +40 -0
- package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/orders.js +98 -1
- package/dist/interfaces/rest/routes/pricing.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/pricing.js +36 -1
- package/dist/interfaces/rest/routes/settings.d.ts +5 -0
- package/dist/interfaces/rest/routes/settings.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/settings.js +50 -0
- package/dist/interfaces/rest/routes/shipping.d.ts +5 -0
- package/dist/interfaces/rest/routes/shipping.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/shipping.js +68 -0
- package/dist/interfaces/rest/routes/tax.d.ts +5 -0
- package/dist/interfaces/rest/routes/tax.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/tax.js +68 -0
- package/dist/interfaces/rest/schemas/admin-staff.d.ts +899 -0
- package/dist/interfaces/rest/schemas/admin-staff.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/admin-staff.js +98 -0
- package/dist/interfaces/rest/schemas/analytics.d.ts +252 -0
- package/dist/interfaces/rest/schemas/analytics.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/analytics.js +33 -0
- package/dist/interfaces/rest/schemas/carts.d.ts +656 -0
- package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/carts.js +38 -0
- package/dist/interfaces/rest/schemas/catalog.d.ts +1218 -1
- package/dist/interfaces/rest/schemas/catalog.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/catalog.js +48 -0
- package/dist/interfaces/rest/schemas/checkout.d.ts +2 -0
- package/dist/interfaces/rest/schemas/checkout.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/checkout.js +4 -0
- package/dist/interfaces/rest/schemas/customer-portal.d.ts +35 -0
- package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/documents.d.ts +509 -0
- package/dist/interfaces/rest/schemas/documents.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/documents.js +65 -0
- package/dist/interfaces/rest/schemas/orders.d.ts +3110 -43
- package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/orders.js +233 -0
- package/dist/interfaces/rest/schemas/pricing.d.ts +405 -0
- package/dist/interfaces/rest/schemas/pricing.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/pricing.js +70 -0
- package/dist/interfaces/rest/schemas/responses.d.ts +156 -0
- package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/search.d.ts +17 -0
- package/dist/interfaces/rest/schemas/search.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/settings.d.ts +397 -0
- package/dist/interfaces/rest/schemas/settings.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/settings.js +79 -0
- package/dist/interfaces/rest/schemas/shipping.d.ts +1093 -0
- package/dist/interfaces/rest/schemas/shipping.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/shipping.js +146 -0
- package/dist/interfaces/rest/schemas/tax.d.ts +1074 -0
- package/dist/interfaces/rest/schemas/tax.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/tax.js +132 -0
- package/dist/kernel/database/schema.d.ts +4 -0
- package/dist/kernel/database/schema.d.ts.map +1 -1
- package/dist/kernel/database/schema.js +8 -0
- package/dist/kernel/hooks/types.d.ts +1 -1
- package/dist/kernel/hooks/types.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.d.ts +23 -0
- package/dist/kernel/plugin/manifest.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.js +17 -2
- package/dist/modules/analytics/module.d.ts.map +1 -1
- package/dist/modules/analytics/module.js +6 -0
- package/dist/modules/analytics/reports.d.ts +58 -0
- package/dist/modules/analytics/reports.d.ts.map +1 -0
- package/dist/modules/analytics/reports.js +249 -0
- package/dist/modules/analytics/service.d.ts +10 -0
- package/dist/modules/analytics/service.d.ts.map +1 -1
- package/dist/modules/analytics/service.js +14 -0
- package/dist/modules/cart/repository/index.d.ts +7 -0
- package/dist/modules/cart/repository/index.d.ts.map +1 -1
- package/dist/modules/cart/repository/index.js +25 -1
- package/dist/modules/cart/schema.d.ts +17 -0
- package/dist/modules/cart/schema.d.ts.map +1 -1
- package/dist/modules/cart/schema.js +2 -0
- package/dist/modules/cart/schemas.d.ts +1 -0
- package/dist/modules/cart/schemas.d.ts.map +1 -1
- package/dist/modules/cart/schemas.js +1 -0
- package/dist/modules/cart/service.d.ts +32 -0
- package/dist/modules/cart/service.d.ts.map +1 -1
- package/dist/modules/cart/service.js +58 -0
- package/dist/modules/catalog/entity-service.d.ts +21 -0
- package/dist/modules/catalog/entity-service.d.ts.map +1 -1
- package/dist/modules/catalog/entity-service.js +132 -3
- package/dist/modules/catalog/schema.d.ts +34 -0
- package/dist/modules/catalog/schema.d.ts.map +1 -1
- package/dist/modules/catalog/schema.js +5 -0
- package/dist/modules/catalog/schemas.d.ts +3 -0
- package/dist/modules/catalog/schemas.d.ts.map +1 -1
- package/dist/modules/catalog/schemas.js +3 -0
- package/dist/modules/catalog/service.d.ts +36 -0
- package/dist/modules/catalog/service.d.ts.map +1 -1
- package/dist/modules/catalog/service.js +6 -0
- package/dist/modules/documents/module.d.ts +7 -0
- package/dist/modules/documents/module.d.ts.map +1 -0
- package/dist/modules/documents/module.js +12 -0
- package/dist/modules/documents/pdf.d.ts +25 -0
- package/dist/modules/documents/pdf.d.ts.map +1 -0
- package/dist/modules/documents/pdf.js +80 -0
- package/dist/modules/documents/render.d.ts +32 -0
- package/dist/modules/documents/render.d.ts.map +1 -0
- package/dist/modules/documents/render.js +190 -0
- package/dist/modules/documents/repository/index.d.ts +25 -0
- package/dist/modules/documents/repository/index.d.ts.map +1 -0
- package/dist/modules/documents/repository/index.js +47 -0
- package/dist/modules/documents/schema.d.ts +214 -0
- package/dist/modules/documents/schema.d.ts.map +1 -0
- package/dist/modules/documents/schema.js +42 -0
- package/dist/modules/documents/service.d.ts +51 -0
- package/dist/modules/documents/service.d.ts.map +1 -0
- package/dist/modules/documents/service.js +119 -0
- package/dist/modules/fulfillment/service.d.ts +18 -0
- package/dist/modules/fulfillment/service.d.ts.map +1 -1
- package/dist/modules/fulfillment/service.js +85 -1
- package/dist/modules/orders/repository/index.d.ts +18 -1
- package/dist/modules/orders/repository/index.d.ts.map +1 -1
- package/dist/modules/orders/repository/index.js +86 -1
- package/dist/modules/orders/schema.d.ts +374 -0
- package/dist/modules/orders/schema.d.ts.map +1 -1
- package/dist/modules/orders/schema.js +52 -1
- package/dist/modules/orders/service.d.ts +86 -1
- package/dist/modules/orders/service.d.ts.map +1 -1
- package/dist/modules/orders/service.js +447 -20
- package/dist/modules/pricing/repository/index.d.ts +5 -0
- package/dist/modules/pricing/repository/index.d.ts.map +1 -1
- package/dist/modules/pricing/repository/index.js +19 -0
- package/dist/modules/pricing/service.d.ts +18 -0
- package/dist/modules/pricing/service.d.ts.map +1 -1
- package/dist/modules/pricing/service.js +38 -0
- package/dist/modules/settings/module.d.ts +6 -0
- package/dist/modules/settings/module.d.ts.map +1 -0
- package/dist/modules/settings/module.js +11 -0
- package/dist/modules/settings/repository/index.d.ts +16 -0
- package/dist/modules/settings/repository/index.d.ts.map +1 -0
- package/dist/modules/settings/repository/index.js +41 -0
- package/dist/modules/settings/schema.d.ts +121 -0
- package/dist/modules/settings/schema.d.ts.map +1 -0
- package/dist/modules/settings/schema.js +24 -0
- package/dist/modules/settings/service.d.ts +26 -0
- package/dist/modules/settings/service.d.ts.map +1 -0
- package/dist/modules/settings/service.js +51 -0
- package/dist/modules/shipping/calculator.d.ts +5 -0
- package/dist/modules/shipping/calculator.d.ts.map +1 -1
- package/dist/modules/shipping/calculator.js +10 -0
- package/dist/modules/shipping/module.d.ts +5 -1
- package/dist/modules/shipping/module.d.ts.map +1 -1
- package/dist/modules/shipping/module.js +4 -1
- package/dist/modules/shipping/repository/index.d.ts +27 -2
- package/dist/modules/shipping/repository/index.d.ts.map +1 -1
- package/dist/modules/shipping/repository/index.js +105 -1
- package/dist/modules/shipping/schema.d.ts +419 -0
- package/dist/modules/shipping/schema.d.ts.map +1 -0
- package/dist/modules/shipping/schema.js +56 -0
- package/dist/modules/shipping/service.d.ts +54 -0
- package/dist/modules/shipping/service.d.ts.map +1 -1
- package/dist/modules/shipping/service.js +161 -2
- package/dist/modules/tax/adapter.d.ts +13 -0
- package/dist/modules/tax/adapter.d.ts.map +1 -1
- package/dist/modules/tax/module.d.ts +5 -1
- package/dist/modules/tax/module.d.ts.map +1 -1
- package/dist/modules/tax/module.js +4 -1
- package/dist/modules/tax/repository/index.d.ts +38 -2
- package/dist/modules/tax/repository/index.d.ts.map +1 -1
- package/dist/modules/tax/repository/index.js +138 -1
- package/dist/modules/tax/schema.d.ts +355 -0
- package/dist/modules/tax/schema.d.ts.map +1 -0
- package/dist/modules/tax/schema.js +55 -0
- package/dist/modules/tax/service.d.ts +60 -1
- package/dist/modules/tax/service.d.ts.map +1 -1
- package/dist/modules/tax/service.js +227 -2
- package/dist/runtime/kernel-modules.d.ts +15 -2
- package/dist/runtime/kernel-modules.d.ts.map +1 -1
- package/dist/runtime/kernel-modules.js +4 -0
- package/dist/runtime/kernel-types.d.ts +5 -1
- package/dist/runtime/kernel-types.d.ts.map +1 -1
- package/dist/runtime/kernel-types.js +2 -0
- package/dist/runtime/server.js +1 -1
- package/dist/test-utils/create-plugin-test-app.d.ts +3 -0
- package/dist/test-utils/create-plugin-test-app.d.ts.map +1 -1
- package/dist/test-utils/create-plugin-test-app.js +15 -3
- package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
- package/dist/test-utils/rest-api-test-utils.js +6 -0
- package/package.json +3 -3
- package/src/auth/setup.ts +1 -0
- package/src/config/defaults.ts +5 -0
- package/src/config/types.ts +17 -1
- package/src/generated/plugin-capabilities.d.ts +1 -0
- package/src/generated/plugin-manifest.ts +1 -0
- package/src/generated/plugin-repositories.d.ts +1 -0
- package/src/hooks/checkout.ts +25 -3
- package/src/index.ts +1 -0
- package/src/interfaces/rest/index.ts +12 -0
- package/src/interfaces/rest/routes/admin/staff.ts +218 -0
- package/src/interfaces/rest/routes/analytics.ts +33 -0
- package/src/interfaces/rest/routes/carts.ts +52 -2
- package/src/interfaces/rest/routes/catalog.ts +34 -0
- package/src/interfaces/rest/routes/checkout.ts +22 -0
- package/src/interfaces/rest/routes/documents.ts +61 -0
- package/src/interfaces/rest/routes/orders.ts +137 -1
- package/src/interfaces/rest/routes/pricing.ts +44 -1
- package/src/interfaces/rest/routes/settings.ts +61 -0
- package/src/interfaces/rest/routes/shipping.ts +92 -0
- package/src/interfaces/rest/routes/tax.ts +90 -0
- package/src/interfaces/rest/schemas/admin-staff.ts +110 -0
- package/src/interfaces/rest/schemas/analytics.ts +39 -0
- package/src/interfaces/rest/schemas/carts.ts +40 -0
- package/src/interfaces/rest/schemas/catalog.ts +53 -0
- package/src/interfaces/rest/schemas/checkout.ts +4 -0
- package/src/interfaces/rest/schemas/documents.ts +72 -0
- package/src/interfaces/rest/schemas/orders.ts +257 -0
- package/src/interfaces/rest/schemas/pricing.ts +75 -0
- package/src/interfaces/rest/schemas/settings.ts +93 -0
- package/src/interfaces/rest/schemas/shipping.ts +164 -0
- package/src/interfaces/rest/schemas/tax.ts +148 -0
- package/src/kernel/database/schema.ts +12 -0
- package/src/kernel/hooks/types.ts +1 -0
- package/src/kernel/plugin/manifest.ts +38 -2
- package/src/modules/analytics/module.ts +10 -0
- package/src/modules/analytics/reports.ts +311 -0
- package/src/modules/analytics/service.ts +23 -0
- package/src/modules/cart/repository/index.ts +30 -1
- package/src/modules/cart/schema.ts +2 -0
- package/src/modules/cart/schemas.ts +1 -0
- package/src/modules/cart/service.ts +101 -0
- package/src/modules/catalog/entity-service.ts +168 -3
- package/src/modules/catalog/schema.ts +5 -0
- package/src/modules/catalog/schemas.ts +3 -0
- package/src/modules/catalog/service.ts +30 -0
- package/src/modules/documents/module.ts +19 -0
- package/src/modules/documents/pdf.ts +101 -0
- package/src/modules/documents/render.ts +231 -0
- package/src/modules/documents/repository/index.ts +68 -0
- package/src/modules/documents/schema.ts +44 -0
- package/src/modules/documents/service.ts +176 -0
- package/src/modules/fulfillment/service.ts +139 -1
- package/src/modules/orders/repository/index.ts +127 -1
- package/src/modules/orders/schema.ts +54 -1
- package/src/modules/orders/service.ts +654 -22
- package/src/modules/pricing/repository/index.ts +34 -0
- package/src/modules/pricing/service.ts +71 -0
- package/src/modules/settings/module.ts +18 -0
- package/src/modules/settings/repository/index.ts +59 -0
- package/src/modules/settings/schema.ts +25 -0
- package/src/modules/settings/service.ts +82 -0
- package/src/modules/shipping/calculator.ts +27 -0
- package/src/modules/shipping/module.ts +6 -2
- package/src/modules/shipping/repository/index.ts +136 -2
- package/src/modules/shipping/schema.ts +58 -0
- package/src/modules/shipping/service.ts +260 -1
- package/src/modules/tax/adapter.ts +9 -0
- package/src/modules/tax/module.ts +6 -2
- package/src/modules/tax/repository/index.ts +169 -2
- package/src/modules/tax/schema.ts +57 -0
- package/src/modules/tax/service.ts +313 -2
- package/src/runtime/kernel-modules.ts +4 -0
- package/src/runtime/kernel-types.ts +6 -0
- package/src/runtime/server.ts +1 -1
- package/src/test-utils/create-plugin-test-app.ts +17 -4
- package/src/test-utils/rest-api-test-utils.ts +6 -0
|
@@ -1,11 +1,53 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgId } from "../../auth/org.js";
|
|
2
|
+
import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
|
|
2
3
|
import { Err, Ok } from "../../kernel/result.js";
|
|
3
4
|
export class TaxService {
|
|
4
5
|
adapter;
|
|
6
|
+
repository;
|
|
5
7
|
constructor(deps) {
|
|
6
8
|
this.adapter = deps.adapter;
|
|
9
|
+
this.repository = deps.repository;
|
|
7
10
|
}
|
|
8
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Calculates tax. Resolution order:
|
|
13
|
+
* 1. Product tax classes (issue #57) — when the org defines active classes,
|
|
14
|
+
* each line taxes by its class (variant taxClass beats entity taxClass;
|
|
15
|
+
* unclassed lines use the default class or 0), with `orderDiscount`
|
|
16
|
+
* pro-rated across lines first. Returns per-line results in `lines`.
|
|
17
|
+
* 2. Runtime tax rates for the org matching `toAddress` (issue #45) —
|
|
18
|
+
* state-specific matches beat country-level; matches at the winning
|
|
19
|
+
* specificity are summed (e.g. GST + PST).
|
|
20
|
+
* 3. The configured tax adapter.
|
|
21
|
+
* 4. Zero tax.
|
|
22
|
+
*/
|
|
23
|
+
async calculate(params, orgId, ctx) {
|
|
24
|
+
if (this.repository && orgId && params.lineItems.length > 0) {
|
|
25
|
+
const classes = await this.repository.findActiveClasses(orgId, ctx);
|
|
26
|
+
if (classes.length > 0) {
|
|
27
|
+
return Ok(await this.calculateByClasses(params, classes, ctx));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (this.repository && orgId && params.toAddress) {
|
|
31
|
+
const matched = await this.matchRuntimeRates(orgId, params.toAddress, ctx);
|
|
32
|
+
if (matched.length > 0) {
|
|
33
|
+
const taxableAmount = params.lineItems.reduce((sum, lineItem) => sum + lineItem.unitPrice * lineItem.quantity - (lineItem.discount ?? 0), 0);
|
|
34
|
+
let amountToCollect = 0;
|
|
35
|
+
const breakdown = {};
|
|
36
|
+
for (const rate of matched) {
|
|
37
|
+
const base = taxableAmount + (rate.appliesToShipping ? params.shippingAmount : 0);
|
|
38
|
+
const amount = Math.max(0, Math.round((base * rate.rateBps) / 10_000));
|
|
39
|
+
amountToCollect += amount;
|
|
40
|
+
breakdown[rate.name] = { rateBps: rate.rateBps, amount };
|
|
41
|
+
}
|
|
42
|
+
const totalBps = matched.reduce((sum, r) => sum + r.rateBps, 0);
|
|
43
|
+
return Ok({
|
|
44
|
+
amountToCollect,
|
|
45
|
+
taxableAmount,
|
|
46
|
+
rate: totalBps / 10_000,
|
|
47
|
+
breakdown,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
9
51
|
if (!this.adapter) {
|
|
10
52
|
return Ok({
|
|
11
53
|
amountToCollect: 0,
|
|
@@ -15,6 +57,123 @@ export class TaxService {
|
|
|
15
57
|
}
|
|
16
58
|
return this.adapter.calculateTax(params);
|
|
17
59
|
}
|
|
60
|
+
/** Per-line class-based tax with cart-discount pro-ration (issue #57). */
|
|
61
|
+
async calculateByClasses(params, classes, ctx) {
|
|
62
|
+
const byName = new Map(classes.map((c) => [c.name, c]));
|
|
63
|
+
const defaultClass = classes.find((c) => c.isDefault) ?? null;
|
|
64
|
+
const { byEntity, byVariant } = await this.repository.resolveCatalogTaxClasses(params.lineItems.map((li) => ({ entityId: li.entityId, variantId: li.variantId })), ctx);
|
|
65
|
+
// Pro-rate the cart-level discount across lines by value share; the last
|
|
66
|
+
// line absorbs the rounding remainder so the sum stays exact.
|
|
67
|
+
const lineValues = params.lineItems.map((li) => Math.max(0, li.unitPrice * li.quantity - (li.discount ?? 0)));
|
|
68
|
+
const totalValue = lineValues.reduce((sum, v) => sum + v, 0);
|
|
69
|
+
const orderDiscount = Math.min(params.orderDiscount ?? 0, totalValue);
|
|
70
|
+
const prorated = lineValues.map((value) => totalValue > 0 ? Math.round((orderDiscount * value) / totalValue) : 0);
|
|
71
|
+
if (lineValues.length > 0) {
|
|
72
|
+
const drift = orderDiscount - prorated.reduce((sum, v) => sum + v, 0);
|
|
73
|
+
prorated[prorated.length - 1] += drift;
|
|
74
|
+
}
|
|
75
|
+
let amountToCollect = 0;
|
|
76
|
+
let taxableAmount = 0;
|
|
77
|
+
const breakdown = {};
|
|
78
|
+
const lines = [];
|
|
79
|
+
for (const [i, lineItem] of params.lineItems.entries()) {
|
|
80
|
+
const className = (lineItem.variantId ? byVariant.get(lineItem.variantId) : null) ??
|
|
81
|
+
byEntity.get(lineItem.entityId) ??
|
|
82
|
+
defaultClass?.name ??
|
|
83
|
+
null;
|
|
84
|
+
const taxClass = className ? (byName.get(className) ?? defaultClass) : defaultClass;
|
|
85
|
+
const base = Math.max(0, lineValues[i] - prorated[i]);
|
|
86
|
+
const taxAmount = taxClass
|
|
87
|
+
? Math.max(0, Math.round((base * taxClass.rateBps) / 10_000))
|
|
88
|
+
: 0;
|
|
89
|
+
amountToCollect += taxAmount;
|
|
90
|
+
taxableAmount += base;
|
|
91
|
+
lines.push({ id: lineItem.id, taxClass: taxClass?.name ?? null, taxAmount });
|
|
92
|
+
if (taxClass) {
|
|
93
|
+
const entry = breakdown[taxClass.name] ?? {
|
|
94
|
+
rateBps: taxClass.rateBps,
|
|
95
|
+
amount: 0,
|
|
96
|
+
};
|
|
97
|
+
entry.amount += taxAmount;
|
|
98
|
+
breakdown[taxClass.name] = entry;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
amountToCollect,
|
|
103
|
+
taxableAmount,
|
|
104
|
+
rate: taxableAmount > 0 ? amountToCollect / taxableAmount : 0,
|
|
105
|
+
breakdown,
|
|
106
|
+
lines,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// ── Tax class management (issue #57) ─────────────────────────────────────
|
|
110
|
+
async createTaxClass(input, actor, ctx) {
|
|
111
|
+
const repo = this.requireRepository();
|
|
112
|
+
if (!repo.ok)
|
|
113
|
+
return repo;
|
|
114
|
+
if (input.rateBps < 0) {
|
|
115
|
+
return Err(new CommerceValidationError("rateBps must be non-negative."));
|
|
116
|
+
}
|
|
117
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
118
|
+
if (input.isDefault)
|
|
119
|
+
await repo.value.clearDefaultClass(orgId, ctx);
|
|
120
|
+
const created = await repo.value.createClass({
|
|
121
|
+
organizationId: orgId,
|
|
122
|
+
name: input.name,
|
|
123
|
+
rateBps: input.rateBps,
|
|
124
|
+
isDefault: input.isDefault ?? false,
|
|
125
|
+
isActive: input.isActive ?? true,
|
|
126
|
+
}, ctx);
|
|
127
|
+
return Ok(created);
|
|
128
|
+
}
|
|
129
|
+
async listTaxClasses(actor, ctx) {
|
|
130
|
+
const repo = this.requireRepository();
|
|
131
|
+
if (!repo.ok)
|
|
132
|
+
return repo;
|
|
133
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
134
|
+
return Ok(await repo.value.findAllClasses(orgId, ctx));
|
|
135
|
+
}
|
|
136
|
+
async updateTaxClass(id, patch, actor, ctx) {
|
|
137
|
+
const repo = this.requireRepository();
|
|
138
|
+
if (!repo.ok)
|
|
139
|
+
return repo;
|
|
140
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
141
|
+
const existing = await repo.value.findClassById(orgId, id, ctx);
|
|
142
|
+
if (!existing)
|
|
143
|
+
return Err(new CommerceNotFoundError("Tax class not found."));
|
|
144
|
+
if (patch.isDefault)
|
|
145
|
+
await repo.value.clearDefaultClass(orgId, ctx);
|
|
146
|
+
const updated = await repo.value.updateClass(id, {
|
|
147
|
+
...(patch.name !== undefined ? { name: patch.name } : {}),
|
|
148
|
+
...(patch.rateBps !== undefined ? { rateBps: patch.rateBps } : {}),
|
|
149
|
+
...(patch.isDefault !== undefined ? { isDefault: patch.isDefault } : {}),
|
|
150
|
+
...(patch.isActive !== undefined ? { isActive: patch.isActive } : {}),
|
|
151
|
+
}, ctx);
|
|
152
|
+
return Ok(updated);
|
|
153
|
+
}
|
|
154
|
+
async deleteTaxClass(id, actor, ctx) {
|
|
155
|
+
const repo = this.requireRepository();
|
|
156
|
+
if (!repo.ok)
|
|
157
|
+
return repo;
|
|
158
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
159
|
+
const existing = await repo.value.findClassById(orgId, id, ctx);
|
|
160
|
+
if (!existing)
|
|
161
|
+
return Err(new CommerceNotFoundError("Tax class not found."));
|
|
162
|
+
await repo.value.deleteClass(id, ctx);
|
|
163
|
+
return Ok({ deleted: true });
|
|
164
|
+
}
|
|
165
|
+
async matchRuntimeRates(orgId, toAddress, ctx) {
|
|
166
|
+
const rates = await this.repository.findActive(orgId, ctx);
|
|
167
|
+
if (rates.length === 0)
|
|
168
|
+
return [];
|
|
169
|
+
const country = toAddress.country?.toUpperCase();
|
|
170
|
+
const state = toAddress.state?.toUpperCase();
|
|
171
|
+
const countryMatches = rates.filter((r) => r.country === "*" || r.country.toUpperCase() === country);
|
|
172
|
+
const stateMatches = countryMatches.filter((r) => r.state != null && state != null && r.state.toUpperCase() === state);
|
|
173
|
+
if (stateMatches.length > 0)
|
|
174
|
+
return stateMatches;
|
|
175
|
+
return countryMatches.filter((r) => r.state == null);
|
|
176
|
+
}
|
|
18
177
|
async reportTransaction(params) {
|
|
19
178
|
if (!this.adapter)
|
|
20
179
|
return Ok({ transactionId: params.transactionId });
|
|
@@ -31,4 +190,70 @@ export class TaxService {
|
|
|
31
190
|
}
|
|
32
191
|
return Ok(this.adapter);
|
|
33
192
|
}
|
|
193
|
+
// ── Runtime tax-rate management (issue #45) ────────────────────────────
|
|
194
|
+
requireRepository() {
|
|
195
|
+
if (!this.repository) {
|
|
196
|
+
return Err(new CommerceValidationError("Tax rate persistence is not available."));
|
|
197
|
+
}
|
|
198
|
+
return Ok(this.repository);
|
|
199
|
+
}
|
|
200
|
+
async createTaxRate(input, actor, ctx) {
|
|
201
|
+
const repo = this.requireRepository();
|
|
202
|
+
if (!repo.ok)
|
|
203
|
+
return repo;
|
|
204
|
+
if (input.rateBps < 0) {
|
|
205
|
+
return Err(new CommerceValidationError("rateBps must be non-negative."));
|
|
206
|
+
}
|
|
207
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
208
|
+
const rate = await repo.value.create({
|
|
209
|
+
organizationId: orgId,
|
|
210
|
+
name: input.name,
|
|
211
|
+
country: input.country.toUpperCase(),
|
|
212
|
+
state: input.state?.toUpperCase() ?? null,
|
|
213
|
+
rateBps: input.rateBps,
|
|
214
|
+
appliesToShipping: input.appliesToShipping ?? true,
|
|
215
|
+
priority: input.priority ?? 100,
|
|
216
|
+
isActive: input.isActive ?? true,
|
|
217
|
+
}, ctx);
|
|
218
|
+
return Ok(rate);
|
|
219
|
+
}
|
|
220
|
+
async listTaxRates(actor, ctx) {
|
|
221
|
+
const repo = this.requireRepository();
|
|
222
|
+
if (!repo.ok)
|
|
223
|
+
return repo;
|
|
224
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
225
|
+
return Ok(await repo.value.findAll(orgId, ctx));
|
|
226
|
+
}
|
|
227
|
+
async updateTaxRate(id, patch, actor, ctx) {
|
|
228
|
+
const repo = this.requireRepository();
|
|
229
|
+
if (!repo.ok)
|
|
230
|
+
return repo;
|
|
231
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
232
|
+
const existing = await repo.value.findById(orgId, id, ctx);
|
|
233
|
+
if (!existing)
|
|
234
|
+
return Err(new CommerceNotFoundError("Tax rate not found."));
|
|
235
|
+
const updated = await repo.value.update(id, {
|
|
236
|
+
...(patch.name !== undefined ? { name: patch.name } : {}),
|
|
237
|
+
...(patch.country !== undefined ? { country: patch.country.toUpperCase() } : {}),
|
|
238
|
+
...(patch.state !== undefined ? { state: patch.state?.toUpperCase() ?? null } : {}),
|
|
239
|
+
...(patch.rateBps !== undefined ? { rateBps: patch.rateBps } : {}),
|
|
240
|
+
...(patch.appliesToShipping !== undefined
|
|
241
|
+
? { appliesToShipping: patch.appliesToShipping }
|
|
242
|
+
: {}),
|
|
243
|
+
...(patch.priority !== undefined ? { priority: patch.priority } : {}),
|
|
244
|
+
...(patch.isActive !== undefined ? { isActive: patch.isActive } : {}),
|
|
245
|
+
}, ctx);
|
|
246
|
+
return Ok(updated);
|
|
247
|
+
}
|
|
248
|
+
async deleteTaxRate(id, actor, ctx) {
|
|
249
|
+
const repo = this.requireRepository();
|
|
250
|
+
if (!repo.ok)
|
|
251
|
+
return repo;
|
|
252
|
+
const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
|
|
253
|
+
const existing = await repo.value.findById(orgId, id, ctx);
|
|
254
|
+
if (!existing)
|
|
255
|
+
return Err(new CommerceNotFoundError("Tax rate not found."));
|
|
256
|
+
await repo.value.delete(id, ctx);
|
|
257
|
+
return Ok({ deleted: true });
|
|
258
|
+
}
|
|
34
259
|
}
|
|
@@ -179,6 +179,13 @@ export declare const KERNEL_ALL_MODULES: {
|
|
|
179
179
|
dialect: "pg";
|
|
180
180
|
}>;
|
|
181
181
|
}, import("../index.js").AuditService, Record<string, unknown>>;
|
|
182
|
+
readonly settings: AppModule<{
|
|
183
|
+
storeSettings: typeof import("../modules/settings/schema.js").storeSettings;
|
|
184
|
+
}, import("../modules/settings/service.js").SettingsService, Record<string, never>>;
|
|
185
|
+
readonly documents: AppModule<{
|
|
186
|
+
invoiceSequences: typeof import("../modules/documents/schema.js").invoiceSequences;
|
|
187
|
+
orderDocuments: typeof import("../modules/documents/schema.js").orderDocuments;
|
|
188
|
+
}, import("../modules/documents/service.js").DocumentsService, Record<string, never>>;
|
|
182
189
|
readonly webhooks: AppModule<{
|
|
183
190
|
webhookEndpoints: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
184
191
|
name: "webhook_endpoints";
|
|
@@ -1701,10 +1708,16 @@ export declare const KERNEL_ALL_MODULES: {
|
|
|
1701
1708
|
readonly search: AppModule<Record<string, never>, import("../modules/search/service.js").SearchService, {
|
|
1702
1709
|
catalog: import("../modules/catalog/service.js").CatalogServiceImpl;
|
|
1703
1710
|
}>;
|
|
1704
|
-
readonly shipping: AppModule<
|
|
1711
|
+
readonly shipping: AppModule<{
|
|
1712
|
+
shippingZones: typeof import("../modules/shipping/schema.js").shippingZones;
|
|
1713
|
+
shippingRates: typeof import("../modules/shipping/schema.js").shippingRates;
|
|
1714
|
+
}, import("../modules/shipping/service.js").ShippingService, {
|
|
1705
1715
|
catalog: import("../modules/catalog/service.js").CatalogServiceImpl;
|
|
1706
1716
|
}>;
|
|
1707
|
-
readonly tax: AppModule<
|
|
1717
|
+
readonly tax: AppModule<{
|
|
1718
|
+
taxRates: typeof import("../modules/tax/schema.js").taxRates;
|
|
1719
|
+
taxClasses: typeof import("../modules/tax/schema.js").taxClasses;
|
|
1720
|
+
}, import("../modules/tax/service.js").TaxService, Record<string, never>>;
|
|
1708
1721
|
readonly payments: AppModule<Record<string, never>, import("../modules/payments/service.js").PaymentsService, Record<string, never>>;
|
|
1709
1722
|
readonly analytics: AppModule<Record<string, never>, import("../modules/analytics/service.js").AnalyticsService, Record<string, never>>;
|
|
1710
1723
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel-modules.d.ts","sourceRoot":"","sources":["../../src/runtime/kernel-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"kernel-modules.d.ts","sourceRoot":"","sources":["../../src/runtime/kernel-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAsB3D,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoBrB,CAAC;AAEX,2FAA2F;AAC3F,wBAAgB,wBAAwB,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAoBpE;AAED,wBAAgB,8BAA8B,IAAI,SAAS,MAAM,EAAE,CAElE"}
|
|
@@ -4,6 +4,7 @@ import { analyticsModule } from "../modules/analytics/module.js";
|
|
|
4
4
|
import { cartModule } from "../modules/cart/module.js";
|
|
5
5
|
import { catalogModule } from "../modules/catalog/module.js";
|
|
6
6
|
import { customersModule } from "../modules/customers/index.js";
|
|
7
|
+
import { documentsModule } from "../modules/documents/module.js";
|
|
7
8
|
import { fulfillmentModule } from "../modules/fulfillment/module.js";
|
|
8
9
|
import { inventoryModule } from "../modules/inventory/module.js";
|
|
9
10
|
import { mediaModule } from "../modules/media/index.js";
|
|
@@ -13,11 +14,14 @@ import { paymentsModule } from "../modules/payments/module.js";
|
|
|
13
14
|
import { pricingModule } from "../modules/pricing/index.js";
|
|
14
15
|
import { promotionsModule } from "../modules/promotions/module.js";
|
|
15
16
|
import { searchModule } from "../modules/search/module.js";
|
|
17
|
+
import { settingsModule } from "../modules/settings/module.js";
|
|
16
18
|
import { shippingModule } from "../modules/shipping/module.js";
|
|
17
19
|
import { taxModule } from "../modules/tax/module.js";
|
|
18
20
|
import { webhooksModule } from "../modules/webhooks/index.js";
|
|
19
21
|
export const KERNEL_ALL_MODULES = {
|
|
20
22
|
audit: auditModule,
|
|
23
|
+
settings: settingsModule,
|
|
24
|
+
documents: documentsModule,
|
|
21
25
|
webhooks: webhooksModule,
|
|
22
26
|
media: mediaModule,
|
|
23
27
|
organization: organizationModule,
|
|
@@ -16,6 +16,8 @@ import { PromotionService } from "../modules/promotions/service.js";
|
|
|
16
16
|
import { TaxService } from "../modules/tax/service.js";
|
|
17
17
|
import { ShippingService } from "../modules/shipping/service.js";
|
|
18
18
|
import { SearchService } from "../modules/search/service.js";
|
|
19
|
+
import { SettingsService } from "../modules/settings/service.js";
|
|
20
|
+
import { DocumentsService } from "../modules/documents/service.js";
|
|
19
21
|
import type { AuditService } from "../modules/audit/service.js";
|
|
20
22
|
import { OrganizationService } from "../modules/organization/service.js";
|
|
21
23
|
import { createLogger } from "../utils/logger.js";
|
|
@@ -51,6 +53,8 @@ export interface Kernel {
|
|
|
51
53
|
tax: TaxService;
|
|
52
54
|
shipping: ShippingService;
|
|
53
55
|
search: SearchService;
|
|
56
|
+
settings: SettingsService;
|
|
57
|
+
documents: DocumentsService;
|
|
54
58
|
audit: AuditService;
|
|
55
59
|
compensationFailures: CompensationFailuresRepository;
|
|
56
60
|
email: CommerceConfig["email"];
|
|
@@ -59,7 +63,7 @@ export interface Kernel {
|
|
|
59
63
|
pluginPermissions: PluginPermission[];
|
|
60
64
|
logger: ReturnType<typeof createLogger>;
|
|
61
65
|
}
|
|
62
|
-
export declare const KERNEL_REQUIRED_SERVICE_KEYS: ["catalog", "inventory", "media", "cart", "orders", "payments", "fulfillment", "customers", "webhooks", "analytics", "pricing", "promotions", "tax", "shipping", "search", "audit", "compensationFailures"];
|
|
66
|
+
export declare const KERNEL_REQUIRED_SERVICE_KEYS: ["catalog", "inventory", "media", "cart", "orders", "payments", "fulfillment", "customers", "webhooks", "analytics", "pricing", "promotions", "tax", "shipping", "search", "settings", "documents", "audit", "compensationFailures"];
|
|
63
67
|
export declare function assertKernelServicesReady(services: Partial<Kernel["services"]>): asserts services is Kernel["services"];
|
|
64
68
|
export declare function assertSortedBefore(topo: readonly string[], a: string, b: string): void;
|
|
65
69
|
//# sourceMappingURL=kernel-types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel-types.d.ts","sourceRoot":"","sources":["../../src/runtime/kernel-types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"kernel-types.d.ts","sourceRoot":"","sources":["../../src/runtime/kernel-types.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/server.js
CHANGED
|
@@ -281,7 +281,7 @@ export async function createServer(config) {
|
|
|
281
281
|
// body-limit stack apply (all are scoped to /api/*).
|
|
282
282
|
app.route("/api/me", createCustomerPortalRoutes(kernel));
|
|
283
283
|
if (config.routes) {
|
|
284
|
-
config.routes(app, kernel);
|
|
284
|
+
config.routes(app, kernel, auth);
|
|
285
285
|
}
|
|
286
286
|
// OpenAPI spec — disabled in production unless explicitly enabled
|
|
287
287
|
const exposeSpec = config.exposeOpenApiSpec ?? !isProd;
|
|
@@ -21,6 +21,7 @@ import type { PgDatabase, PgQueryResultHKT } from "drizzle-orm/pg-core";
|
|
|
21
21
|
import type { CommerceConfig, CommercePlugin } from "../config/types.js";
|
|
22
22
|
import type { Actor } from "../auth/types.js";
|
|
23
23
|
import type { Kernel } from "../runtime/kernel.js";
|
|
24
|
+
import { type AuthInstance } from "../auth/setup.js";
|
|
24
25
|
/**
|
|
25
26
|
* Hono environment type for the test app. Declares the `actor` context
|
|
26
27
|
* variable so c.set("actor", ...) / c.get("actor") are properly typed
|
|
@@ -38,6 +39,8 @@ export interface PluginTestApp {
|
|
|
38
39
|
kernel: Kernel;
|
|
39
40
|
/** Drizzle database instance for direct queries in test assertions. */
|
|
40
41
|
db: PgDatabase<PgQueryResultHKT, Record<string, unknown>>;
|
|
42
|
+
/** The Better Auth instance passed to plugin routes (mint/verify API keys in tests). */
|
|
43
|
+
auth: AuthInstance;
|
|
41
44
|
}
|
|
42
45
|
/**
|
|
43
46
|
* Creates a fully-wired test application for plugin E2E testing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-plugin-test-app.d.ts","sourceRoot":"","sources":["../../src/test-utils/create-plugin-test-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"create-plugin-test-app.d.ts","sourceRoot":"","sources":["../../src/test-utils/create-plugin-test-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAKnD,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAajE;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE;QACT,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;KACrB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,GAAG,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAC7B,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,EAAE,EAAE,UAAU,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,wFAAwF;IACxF,IAAI,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,eAAe,GAAE,OAAO,CAAC,cAAc,CAAM,GAC5C,OAAO,CAAC,aAAa,CAAC,CAyFxB"}
|
|
@@ -24,6 +24,8 @@ import { buildSchema } from "../kernel/database/migrate.js";
|
|
|
24
24
|
import { unwrapDb } from "../kernel/database/adapter.js";
|
|
25
25
|
import { ensureDefaultOrg } from "../auth/org.js";
|
|
26
26
|
import { mapErrorToStatus } from "../kernel/error-mapper.js";
|
|
27
|
+
import { createAuth } from "../auth/setup.js";
|
|
28
|
+
import { authMiddleware } from "../auth/middleware.js";
|
|
27
29
|
// drizzle-kit/api uses CJS internally; createRequire provides ESM compat.
|
|
28
30
|
const require = createRequire(import.meta.url);
|
|
29
31
|
/**
|
|
@@ -56,7 +58,10 @@ export async function createPluginTestApp(plugin, configOverrides = {}) {
|
|
|
56
58
|
// 5. Create OpenAPIHono --- matching production server.ts
|
|
57
59
|
// Plugin routes register via manifest.ts which calls app.openapi().
|
|
58
60
|
const app = new OpenAPIHono();
|
|
59
|
-
|
|
61
|
+
const auth = createAuth(kernel.database, config);
|
|
62
|
+
// 6. Test actor middleware: parse x-test-actor header -> set on context.
|
|
63
|
+
// Requests without the header fall through to the real auth middleware,
|
|
64
|
+
// so API keys minted by plugins (issue #51) authenticate like production.
|
|
60
65
|
app.use("*", async (c, next) => {
|
|
61
66
|
const header = c.req.header("x-test-actor");
|
|
62
67
|
if (header) {
|
|
@@ -67,9 +72,15 @@ export async function createPluginTestApp(plugin, configOverrides = {}) {
|
|
|
67
72
|
}
|
|
68
73
|
await next();
|
|
69
74
|
});
|
|
70
|
-
|
|
75
|
+
app.use("*", async (c, next) => {
|
|
76
|
+
if (c.get("actor"))
|
|
77
|
+
return next();
|
|
78
|
+
return authMiddleware(auth, config)(c, next);
|
|
79
|
+
});
|
|
80
|
+
// 7. Register plugin routes (deferred via config.routes) — with the auth
|
|
81
|
+
// instance, matching server.ts's config.routes(app, kernel, auth).
|
|
71
82
|
const routes = config.routes;
|
|
72
|
-
routes?.(app, kernel);
|
|
83
|
+
routes?.(app, kernel, auth);
|
|
73
84
|
// 8. Error handler matching production server.ts — maps CommerceError
|
|
74
85
|
// subclasses (CommerceForbiddenError, CommerceNotFoundError, etc.)
|
|
75
86
|
// to their proper HTTP status codes (403, 404, 409, 422, 503).
|
|
@@ -89,5 +100,6 @@ export async function createPluginTestApp(plugin, configOverrides = {}) {
|
|
|
89
100
|
app,
|
|
90
101
|
kernel,
|
|
91
102
|
db: kernel.database.db,
|
|
103
|
+
auth,
|
|
92
104
|
};
|
|
93
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest-api-test-utils.d.ts","sourceRoot":"","sources":["../../src/test-utils/rest-api-test-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,KAAK,SAAS,GAAG;IACf,SAAS,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;KACrB,CAAC;CACH,CAAC;AAiDF;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM,GACtC,OAAO,CAAC;IACT,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC,CAqDD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAEnF;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"rest-api-test-utils.d.ts","sourceRoot":"","sources":["../../src/test-utils/rest-api-test-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,KAAK,SAAS,GAAG;IACf,SAAS,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;KACrB,CAAC;CACH,CAAC;AAiDF;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,GAAE,OAAO,CAAC,cAAc,CAAM,GACtC,OAAO,CAAC;IACT,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC,CAqDD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAEnF;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,KAmCvB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,KAS3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,KASzB,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,WAwBA;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EACvB,OAAO,EAAE;IACP,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,qBAYF"}
|
|
@@ -133,9 +133,15 @@ export const testActor = {
|
|
|
133
133
|
"cart:create",
|
|
134
134
|
"cart:update",
|
|
135
135
|
"cart:read",
|
|
136
|
+
"cart:manage",
|
|
136
137
|
"customers:update:self",
|
|
137
138
|
"webhooks:manage",
|
|
138
139
|
"pricing:manage",
|
|
140
|
+
"shipping:manage",
|
|
141
|
+
"tax:manage",
|
|
142
|
+
"settings:manage",
|
|
143
|
+
"analytics:read",
|
|
144
|
+
"staff:manage",
|
|
139
145
|
"promotions:manage",
|
|
140
146
|
"promotions:read",
|
|
141
147
|
"audit:read",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"eslint": "^9.39.1",
|
|
57
57
|
"typescript": "5.9.2",
|
|
58
58
|
"vitest": "^3.2.4",
|
|
59
|
-
"@porulle/
|
|
60
|
-
"@porulle/
|
|
59
|
+
"@porulle/typescript-config": "0.1.0",
|
|
60
|
+
"@porulle/eslint-config": "0.1.0"
|
|
61
61
|
},
|
|
62
62
|
"publishConfig": {
|
|
63
63
|
"access": "public"
|
package/src/auth/setup.ts
CHANGED
package/src/config/defaults.ts
CHANGED
|
@@ -30,6 +30,11 @@ export const defaultConfig: Partial<CommerceConfig> = {
|
|
|
30
30
|
"orders:update",
|
|
31
31
|
"cart:create",
|
|
32
32
|
"cart:update",
|
|
33
|
+
"cart:manage",
|
|
34
|
+
"shipping:manage",
|
|
35
|
+
"tax:manage",
|
|
36
|
+
"settings:manage",
|
|
37
|
+
"analytics:read",
|
|
33
38
|
"customers:read:self",
|
|
34
39
|
"customers:update:self",
|
|
35
40
|
],
|
package/src/config/types.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { BeforeHook, AfterHook } from "../kernel/hooks/types.js";
|
|
|
4
4
|
import type { PaymentAdapter } from "../modules/payments/adapter.js";
|
|
5
5
|
import type { StorageAdapter } from "../modules/media/adapter.js";
|
|
6
6
|
import type { Kernel } from "../runtime/kernel.js";
|
|
7
|
+
import type { AuthInstance } from "../auth/setup.js";
|
|
7
8
|
import type { DatabaseAdapter } from "../kernel/database/adapter.js";
|
|
8
9
|
import type { TaxAdapter } from "../modules/tax/adapter.js";
|
|
9
10
|
import type { SearchAdapter } from "../modules/search/adapter.js";
|
|
@@ -102,6 +103,16 @@ export interface ApiKeyScopeDefinition {
|
|
|
102
103
|
/** Time window in milliseconds. */
|
|
103
104
|
timeWindow: number;
|
|
104
105
|
};
|
|
106
|
+
/**
|
|
107
|
+
* Expiry bounds for keys minted under this scope, in DAYS (Better Auth
|
|
108
|
+
* semantics; fractions allowed — 1/24 = one hour). Better Auth defaults
|
|
109
|
+
* minExpiresIn to 1 day, which blocks short-lived credentials like
|
|
110
|
+
* per-shift POS keys (issue #51).
|
|
111
|
+
*/
|
|
112
|
+
keyExpiration?: {
|
|
113
|
+
minExpiresIn?: number;
|
|
114
|
+
maxExpiresIn?: number;
|
|
115
|
+
};
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
export interface AuthConfig {
|
|
@@ -374,7 +385,12 @@ export interface CommerceConfig {
|
|
|
374
385
|
hooks?: Record<string, Array<(...args: unknown[]) => unknown>>;
|
|
375
386
|
plugins?: CommercePlugin[];
|
|
376
387
|
middleware?: MiddlewareHandler[];
|
|
377
|
-
|
|
388
|
+
/**
|
|
389
|
+
* Custom route registration. Receives the Better Auth instance as the
|
|
390
|
+
* third argument so integrations can mint/revoke API keys or call
|
|
391
|
+
* `auth.api.*` without module-global holder shims.
|
|
392
|
+
*/
|
|
393
|
+
routes?: (app: Hono<any>, kernel: Kernel, auth?: AuthInstance) => void;
|
|
378
394
|
/** Log level for structured logging. Default: "info". */
|
|
379
395
|
logLevel?: "fatal" | "error" | "warn" | "info" | "debug" | "trace";
|
|
380
396
|
/**
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export interface PluginCapabilityRegistryShape {
|
|
5
5
|
"appointments": Record<string, unknown>;
|
|
6
6
|
"gift-cards": Record<string, unknown>;
|
|
7
|
+
"layaway": Record<string, unknown>;
|
|
7
8
|
"loyalty": Record<string, unknown>;
|
|
8
9
|
"marketplace": Record<string, unknown>;
|
|
9
10
|
"notifications": Record<string, unknown>;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export const resolvedPluginManifest = [
|
|
6
6
|
{ id: "appointments", directory: "plugin-appointments" },
|
|
7
7
|
{ id: "gift-cards", directory: "plugin-gift-cards" },
|
|
8
|
+
{ id: "layaway", directory: "plugin-layaway" },
|
|
8
9
|
{ id: "loyalty", directory: "plugin-loyalty" },
|
|
9
10
|
{ id: "marketplace", directory: "plugin-marketplace" },
|
|
10
11
|
{ id: "notifications", directory: "plugin-notifications" },
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export interface PluginRepositoryRegistryShape {
|
|
5
5
|
"appointments": Record<string, unknown>;
|
|
6
6
|
"gift-cards": Record<string, unknown>;
|
|
7
|
+
"layaway": Record<string, unknown>;
|
|
7
8
|
"loyalty": Record<string, unknown>;
|
|
8
9
|
"marketplace": Record<string, unknown>;
|
|
9
10
|
"notifications": Record<string, unknown>;
|