@porulle/core 0.7.0 → 0.9.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/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +26 -7
- package/dist/auth/setup.d.ts.map +1 -1
- package/dist/auth/setup.js +8 -5
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +7 -0
- package/dist/config/types.d.ts +26 -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-completion.d.ts.map +1 -1
- package/dist/hooks/checkout-completion.js +2 -2
- package/dist/hooks/checkout.d.ts.map +1 -1
- package/dist/hooks/checkout.js +17 -2
- 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 +206 -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 +9 -0
- package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/checkout.js +97 -21
- 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/inventory.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/inventory.js +13 -0
- package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/orders.js +111 -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 +234 -1
- 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 +190 -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/database/scoped-db.d.ts +2 -1
- package/dist/kernel/database/scoped-db.d.ts.map +1 -1
- package/dist/kernel/database/scoped-db.js +62 -1
- 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 +26 -0
- package/dist/kernel/plugin/manifest.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.js +17 -2
- package/dist/modules/analytics/drizzle-adapter.d.ts.map +1 -1
- package/dist/modules/analytics/drizzle-adapter.js +16 -3
- 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 +61 -2
- 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 +166 -5
- 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/customers/service.d.ts.map +1 -1
- package/dist/modules/customers/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 +391 -0
- package/dist/modules/orders/schema.d.ts.map +1 -1
- package/dist/modules/orders/schema.js +56 -1
- package/dist/modules/orders/service.d.ts +102 -3
- package/dist/modules/orders/service.d.ts.map +1 -1
- package/dist/modules/orders/service.js +653 -29
- package/dist/modules/orders/stale-order-cleanup.d.ts.map +1 -1
- package/dist/modules/orders/stale-order-cleanup.js +13 -1
- 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 +43 -5
- 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/create-test-config.d.ts.map +1 -1
- package/dist/test-utils/create-test-config.js +2 -0
- package/dist/test-utils/order-test-helpers.d.ts +12 -0
- package/dist/test-utils/order-test-helpers.d.ts.map +1 -0
- package/dist/test-utils/order-test-helpers.js +18 -0
- package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
- package/dist/test-utils/rest-api-test-utils.js +7 -0
- package/dist/test-utils/test-actors.js +1 -1
- package/dist/testing.d.ts +1 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -0
- package/package.json +3 -3
- package/src/auth/middleware.ts +26 -7
- package/src/auth/setup.ts +11 -4
- package/src/config/defaults.ts +7 -0
- package/src/config/types.ts +26 -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-completion.ts +22 -16
- package/src/hooks/checkout.ts +36 -11
- package/src/index.ts +1 -0
- package/src/interfaces/rest/index.ts +12 -0
- package/src/interfaces/rest/routes/admin/staff.ts +260 -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 +114 -27
- package/src/interfaces/rest/routes/documents.ts +61 -0
- package/src/interfaces/rest/routes/inventory.ts +14 -0
- package/src/interfaces/rest/routes/orders.ts +148 -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 +258 -1
- 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/database/scoped-db.ts +70 -1
- package/src/kernel/hooks/types.ts +1 -0
- package/src/kernel/plugin/manifest.ts +41 -2
- package/src/modules/analytics/drizzle-adapter.ts +19 -3
- 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 +104 -2
- package/src/modules/catalog/entity-service.ts +196 -4
- 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/customers/service.ts +6 -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 +58 -1
- package/src/modules/orders/service.ts +1041 -65
- package/src/modules/orders/stale-order-cleanup.ts +18 -4
- package/src/modules/pricing/repository/index.ts +34 -0
- package/src/modules/pricing/service.ts +76 -6
- 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/create-test-config.ts +2 -0
- package/src/test-utils/order-test-helpers.ts +26 -0
- package/src/test-utils/rest-api-test-utils.ts +7 -0
- package/src/test-utils/test-actors.ts +1 -1
- package/src/testing.ts +1 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { z, createRoute } from "@hono/zod-openapi";
|
|
2
|
+
import { errorResponses } from "./shared.js";
|
|
3
|
+
|
|
4
|
+
export const CreateTaxRateBodySchema = z.object({
|
|
5
|
+
name: z.string().min(1).openapi({ example: "NY sales tax" }),
|
|
6
|
+
country: z.string().min(1).openapi({ example: "US", description: "ISO 3166-1 alpha-2; \"*\" matches any country" }),
|
|
7
|
+
state: z.string().min(1).optional().openapi({ example: "NY" }),
|
|
8
|
+
rateBps: z.number().int().nonnegative().openapi({ example: 500, description: "Basis points: 500 = 5%" }),
|
|
9
|
+
appliesToShipping: z.boolean().optional(),
|
|
10
|
+
priority: z.number().int().optional(),
|
|
11
|
+
isActive: z.boolean().optional(),
|
|
12
|
+
}).openapi("CreateTaxRateRequest");
|
|
13
|
+
|
|
14
|
+
export const UpdateTaxRateBodySchema = z.object({
|
|
15
|
+
name: z.string().min(1).optional(),
|
|
16
|
+
country: z.string().min(1).optional(),
|
|
17
|
+
state: z.string().min(1).nullable().optional(),
|
|
18
|
+
rateBps: z.number().int().nonnegative().optional(),
|
|
19
|
+
appliesToShipping: z.boolean().optional(),
|
|
20
|
+
priority: z.number().int().optional(),
|
|
21
|
+
isActive: z.boolean().optional(),
|
|
22
|
+
}).openapi("UpdateTaxRateRequest");
|
|
23
|
+
|
|
24
|
+
const IdParam = z.object({
|
|
25
|
+
id: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const DataResponse = z.object({ data: z.any() }).openapi("TaxConfigResponse");
|
|
29
|
+
|
|
30
|
+
export const createTaxRateRoute = createRoute({
|
|
31
|
+
method: "post",
|
|
32
|
+
path: "/rates",
|
|
33
|
+
tags: ["Tax"],
|
|
34
|
+
summary: "Create a tax rate",
|
|
35
|
+
request: {
|
|
36
|
+
body: { content: { "application/json": { schema: CreateTaxRateBodySchema } }, required: true },
|
|
37
|
+
},
|
|
38
|
+
responses: {
|
|
39
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Tax rate created." },
|
|
40
|
+
...errorResponses,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const listTaxRatesRoute = createRoute({
|
|
45
|
+
method: "get",
|
|
46
|
+
path: "/rates",
|
|
47
|
+
tags: ["Tax"],
|
|
48
|
+
summary: "List tax rates",
|
|
49
|
+
responses: {
|
|
50
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Tax rates" },
|
|
51
|
+
...errorResponses,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const updateTaxRateRoute = createRoute({
|
|
56
|
+
method: "patch",
|
|
57
|
+
path: "/rates/{id}",
|
|
58
|
+
tags: ["Tax"],
|
|
59
|
+
summary: "Update a tax rate",
|
|
60
|
+
request: {
|
|
61
|
+
params: IdParam,
|
|
62
|
+
body: { content: { "application/json": { schema: UpdateTaxRateBodySchema } }, required: true },
|
|
63
|
+
},
|
|
64
|
+
responses: {
|
|
65
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Tax rate updated." },
|
|
66
|
+
...errorResponses,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export const deleteTaxRateRoute = createRoute({
|
|
71
|
+
method: "delete",
|
|
72
|
+
path: "/rates/{id}",
|
|
73
|
+
tags: ["Tax"],
|
|
74
|
+
summary: "Delete a tax rate",
|
|
75
|
+
request: { params: IdParam },
|
|
76
|
+
responses: {
|
|
77
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Tax rate deleted." },
|
|
78
|
+
...errorResponses,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// ── Product tax classes (issue #57) ─────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
export const CreateTaxClassBodySchema = z.object({
|
|
85
|
+
name: z.string().min(1).regex(/^[a-z][a-z0-9_-]*$/, "lowercase slug (e.g. standard, zero)"),
|
|
86
|
+
rateBps: z.number().int().nonnegative().openapi({ example: 1800, description: "Basis points: 1800 = 18%" }),
|
|
87
|
+
isDefault: z.boolean().optional().openapi({ description: "Lines with no taxClass use the default class." }),
|
|
88
|
+
isActive: z.boolean().optional(),
|
|
89
|
+
}).openapi("CreateTaxClassRequest");
|
|
90
|
+
|
|
91
|
+
export const UpdateTaxClassBodySchema = z.object({
|
|
92
|
+
name: z.string().min(1).regex(/^[a-z][a-z0-9_-]*$/).optional(),
|
|
93
|
+
rateBps: z.number().int().nonnegative().optional(),
|
|
94
|
+
isDefault: z.boolean().optional(),
|
|
95
|
+
isActive: z.boolean().optional(),
|
|
96
|
+
}).openapi("UpdateTaxClassRequest");
|
|
97
|
+
|
|
98
|
+
const ClassIdParam = z.object({ id: z.uuid() });
|
|
99
|
+
|
|
100
|
+
export const createTaxClassRoute = createRoute({
|
|
101
|
+
method: "post",
|
|
102
|
+
path: "/classes",
|
|
103
|
+
tags: ["Tax"],
|
|
104
|
+
summary: "Create a product tax class",
|
|
105
|
+
request: { body: { content: { "application/json": { schema: CreateTaxClassBodySchema } }, required: true } },
|
|
106
|
+
responses: {
|
|
107
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Tax class created." },
|
|
108
|
+
...errorResponses,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
export const listTaxClassesRoute = createRoute({
|
|
113
|
+
method: "get",
|
|
114
|
+
path: "/classes",
|
|
115
|
+
tags: ["Tax"],
|
|
116
|
+
summary: "List product tax classes",
|
|
117
|
+
responses: {
|
|
118
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Tax classes." },
|
|
119
|
+
...errorResponses,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
export const updateTaxClassRoute = createRoute({
|
|
124
|
+
method: "patch",
|
|
125
|
+
path: "/classes/{id}",
|
|
126
|
+
tags: ["Tax"],
|
|
127
|
+
summary: "Update a product tax class",
|
|
128
|
+
request: {
|
|
129
|
+
params: ClassIdParam,
|
|
130
|
+
body: { content: { "application/json": { schema: UpdateTaxClassBodySchema } }, required: true },
|
|
131
|
+
},
|
|
132
|
+
responses: {
|
|
133
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Tax class updated." },
|
|
134
|
+
...errorResponses,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export const deleteTaxClassRoute = createRoute({
|
|
139
|
+
method: "delete",
|
|
140
|
+
path: "/classes/{id}",
|
|
141
|
+
tags: ["Tax"],
|
|
142
|
+
summary: "Delete a product tax class",
|
|
143
|
+
request: { params: ClassIdParam },
|
|
144
|
+
responses: {
|
|
145
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Tax class deleted." },
|
|
146
|
+
...errorResponses,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
@@ -43,6 +43,18 @@ export * from "../../modules/webhooks/schema.js";
|
|
|
43
43
|
// Fulfillment module
|
|
44
44
|
export * from "../../modules/fulfillment/schema.js";
|
|
45
45
|
|
|
46
|
+
// Shipping module (runtime zones & rates)
|
|
47
|
+
export * from "../../modules/shipping/schema.js";
|
|
48
|
+
|
|
49
|
+
// Tax module (runtime tax rates)
|
|
50
|
+
export * from "../../modules/tax/schema.js";
|
|
51
|
+
|
|
52
|
+
// Settings module (org-scoped runtime settings)
|
|
53
|
+
export * from "../../modules/settings/schema.js";
|
|
54
|
+
|
|
55
|
+
// Documents module (fiscal sequences + issued documents)
|
|
56
|
+
export * from "../../modules/documents/schema.js";
|
|
57
|
+
|
|
46
58
|
// Jobs (kernel)
|
|
47
59
|
export * from "../jobs/schema.js";
|
|
48
60
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Wraps a Drizzle PgDatabase instance so that INSERT operations on
|
|
5
5
|
* org-scoped tables automatically include the actor's organizationId,
|
|
6
|
-
* and SELECT
|
|
6
|
+
* and SELECT / UPDATE / DELETE against org-scoped tables constrain rows to
|
|
7
|
+
* that organization — including when the caller supplies no WHERE clause.
|
|
7
8
|
*
|
|
8
9
|
* Plugin route handlers receive this scoped db via PluginContext.database.db
|
|
9
10
|
* (organization resolved per operation from AsyncLocalStorage when used from
|
|
@@ -30,6 +31,33 @@ function tableHasOrganizationId(table: unknown): boolean {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Pre-apply the org predicate to a WHERE-able builder (UPDATE/DELETE) and wrap
|
|
36
|
+
* its `.where()` so a caller-supplied condition is AND-ed with the org filter
|
|
37
|
+
* rather than replacing it. Pre-applying `orgEq` immediately means a builder
|
|
38
|
+
* executed with NO caller `.where()` (e.g. `update(t).set(...)`) is still
|
|
39
|
+
* constrained to the org — it can never touch another tenant's rows.
|
|
40
|
+
*/
|
|
41
|
+
function scopeWhereBuilder(
|
|
42
|
+
builder: { where: (c: SQL | undefined) => unknown },
|
|
43
|
+
orgEq: SQL,
|
|
44
|
+
): unknown {
|
|
45
|
+
const scoped = builder.where(orgEq);
|
|
46
|
+
return new Proxy(scoped as Record<string, unknown>, {
|
|
47
|
+
get(st, sp, sr) {
|
|
48
|
+
const sv = Reflect.get(st, sp, sr);
|
|
49
|
+
if (sp === "where" && typeof sv === "function") {
|
|
50
|
+
return (condition?: unknown, ...wRest: unknown[]) => {
|
|
51
|
+
const c = condition as SQL | undefined;
|
|
52
|
+
const merged = c ? and(orgEq, c) : orgEq;
|
|
53
|
+
return (sv as (...a: unknown[]) => unknown).call(st, merged, ...wRest);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return typeof sv === "function" ? sv.bind(st) : sv;
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
33
61
|
export function createScopedDb<TDb>(rawDb: TDb, orgSource: ScopedOrganizationId): TDb {
|
|
34
62
|
if (!rawDb || typeof rawDb !== "object") return rawDb;
|
|
35
63
|
|
|
@@ -106,6 +134,47 @@ export function createScopedDb<TDb>(rawDb: TDb, orgSource: ScopedOrganizationId)
|
|
|
106
134
|
};
|
|
107
135
|
}
|
|
108
136
|
|
|
137
|
+
if (prop === "update" && typeof value === "function") {
|
|
138
|
+
return (table: PgTable) => {
|
|
139
|
+
const builder = value.call(target, table);
|
|
140
|
+
if (!tableHasOrganizationId(table)) return builder;
|
|
141
|
+
const orgCol = getTableColumns(table).organizationId;
|
|
142
|
+
if (!orgCol) return builder;
|
|
143
|
+
const orgEq = eq(orgCol, resolveOrganizationId(orgSource));
|
|
144
|
+
// The org filter lives after `.set()`, so wrap `.set()` and scope the
|
|
145
|
+
// resulting WHERE-able builder.
|
|
146
|
+
return new Proxy(builder as Record<string, unknown>, {
|
|
147
|
+
get(t, p, r) {
|
|
148
|
+
const v = Reflect.get(t, p, r);
|
|
149
|
+
if (p === "set" && typeof v === "function") {
|
|
150
|
+
return (data: unknown) => {
|
|
151
|
+
const setBuilder = (v as (...a: unknown[]) => unknown).call(t, data);
|
|
152
|
+
return scopeWhereBuilder(
|
|
153
|
+
setBuilder as { where: (c: SQL | undefined) => unknown },
|
|
154
|
+
orgEq,
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return typeof v === "function" ? v.bind(t) : v;
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (prop === "delete" && typeof value === "function") {
|
|
165
|
+
return (table: PgTable) => {
|
|
166
|
+
const builder = value.call(target, table);
|
|
167
|
+
if (!tableHasOrganizationId(table)) return builder;
|
|
168
|
+
const orgCol = getTableColumns(table).organizationId;
|
|
169
|
+
if (!orgCol) return builder;
|
|
170
|
+
const orgEq = eq(orgCol, resolveOrganizationId(orgSource));
|
|
171
|
+
return scopeWhereBuilder(
|
|
172
|
+
builder as { where: (c: SQL | undefined) => unknown },
|
|
173
|
+
orgEq,
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
109
178
|
return typeof value === "function" ? value.bind(target) : value;
|
|
110
179
|
},
|
|
111
180
|
}) as TDb;
|
|
@@ -59,6 +59,14 @@ export interface PluginContext {
|
|
|
59
59
|
transaction<T>(fn: (tx: PluginDb) => Promise<T>): Promise<T>;
|
|
60
60
|
};
|
|
61
61
|
logger: PluginLogger;
|
|
62
|
+
/**
|
|
63
|
+
* The Better Auth instance (issue #51) — lets plugins mint/revoke
|
|
64
|
+
* credentials (e.g. per-shift API keys from a POS PIN login). Present when
|
|
65
|
+
* routes are mounted by createServer; may be absent in bare-kernel setups,
|
|
66
|
+
* so plugins must degrade gracefully. Typed loosely to avoid coupling every
|
|
67
|
+
* plugin to Better Auth's generics — cast to the narrow surface you use.
|
|
68
|
+
*/
|
|
69
|
+
auth?: unknown;
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
const UNSCOPED_WARN_COOLDOWN_MS = 60_000;
|
|
@@ -139,6 +147,21 @@ export interface CommercePluginManifest {
|
|
|
139
147
|
hooks?: () => PluginHookRegistration[];
|
|
140
148
|
routes?: (ctx: PluginContext) => PluginRouteRegistration[];
|
|
141
149
|
analyticsModels?: () => unknown[];
|
|
150
|
+
/**
|
|
151
|
+
* Named API-key scopes this plugin mints credentials under (issue #51),
|
|
152
|
+
* merged into `config.auth.apiKeyScopes`. User-defined scopes with the
|
|
153
|
+
* same name win.
|
|
154
|
+
*/
|
|
155
|
+
apiKeyScopes?: () => Record<string, {
|
|
156
|
+
prefix?: string;
|
|
157
|
+
description?: string;
|
|
158
|
+
permissions?: Record<string, string[]>;
|
|
159
|
+
/** Expiry bounds in DAYS (fractions allowed — 1/24 = one hour). */
|
|
160
|
+
keyExpiration?: { minExpiresIn?: number; maxExpiresIn?: number };
|
|
161
|
+
/** Better Auth ownership model for keys minted under this scope. */
|
|
162
|
+
references?: "user" | "organization";
|
|
163
|
+
enableMetadata?: boolean;
|
|
164
|
+
}>;
|
|
142
165
|
}
|
|
143
166
|
|
|
144
167
|
// ─── Plugin Dependency Tracking ──────────────────────────────────────
|
|
@@ -193,6 +216,21 @@ export function defineCommercePlugin(
|
|
|
193
216
|
};
|
|
194
217
|
}
|
|
195
218
|
|
|
219
|
+
// 0. API-key scopes — merge into auth.apiKeyScopes (user config wins)
|
|
220
|
+
if (manifest.apiKeyScopes) {
|
|
221
|
+
const scopes = manifest.apiKeyScopes();
|
|
222
|
+
result = {
|
|
223
|
+
...result,
|
|
224
|
+
auth: {
|
|
225
|
+
...(result.auth ?? {}),
|
|
226
|
+
apiKeyScopes: {
|
|
227
|
+
...scopes,
|
|
228
|
+
...(result.auth?.apiKeyScopes ?? {}),
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
} as CommerceConfig;
|
|
232
|
+
}
|
|
233
|
+
|
|
196
234
|
// 1. Schema — push into customSchemas for kernel to register
|
|
197
235
|
if (manifest.schema) {
|
|
198
236
|
const schemas = manifest.schema();
|
|
@@ -220,8 +258,8 @@ export function defineCommercePlugin(
|
|
|
220
258
|
const pluginRoutes = manifest.routes;
|
|
221
259
|
result = {
|
|
222
260
|
...result,
|
|
223
|
-
routes: (app: Hono, kernel: Kernel) => {
|
|
224
|
-
existingRoutes?.(app, kernel);
|
|
261
|
+
routes: (app: Hono, kernel: Kernel, auth?: unknown) => {
|
|
262
|
+
existingRoutes?.(app, kernel, auth as never);
|
|
225
263
|
const k = kernel as {
|
|
226
264
|
config: CommerceConfig;
|
|
227
265
|
services: Record<string, unknown>;
|
|
@@ -240,6 +278,7 @@ export function defineCommercePlugin(
|
|
|
240
278
|
k.logger,
|
|
241
279
|
),
|
|
242
280
|
logger: k.logger,
|
|
281
|
+
...(auth !== undefined ? { auth } : {}),
|
|
243
282
|
});
|
|
244
283
|
for (const route of regs) {
|
|
245
284
|
// ── Error boundary: wrap handler with plugin context ──
|
|
@@ -216,6 +216,17 @@ export class DrizzleAnalyticsAdapter implements AnalyticsAdapter {
|
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
// Validate that requested time dimensions exist in the cube
|
|
220
|
+
for (const td of params.timeDimensions ?? []) {
|
|
221
|
+
const shortName = td.dimension.split(".")[1];
|
|
222
|
+
if (shortName && !cube.dimensions[shortName]) {
|
|
223
|
+
const available = Object.keys(cube.dimensions).map((d) => `${cubeName}.${d}`).join(", ");
|
|
224
|
+
return Err(new CommerceValidationError(
|
|
225
|
+
`Unknown time dimension: "${td.dimension}". Available dimensions for ${cubeName}: ${available}`,
|
|
226
|
+
));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
219
230
|
try {
|
|
220
231
|
const rows = await this.executeQuery(cube, params, scope);
|
|
221
232
|
return Ok({
|
|
@@ -330,14 +341,17 @@ export class DrizzleAnalyticsAdapter implements AnalyticsAdapter {
|
|
|
330
341
|
const shortName = dim.split(".")[1]!;
|
|
331
342
|
const dimDef = cube.dimensions[shortName];
|
|
332
343
|
if (!dimDef) continue;
|
|
333
|
-
|
|
344
|
+
const alias = `${cube.name}.${shortName}`;
|
|
345
|
+
selectParts.push(sql.raw(`${dimDef.sql} AS "${alias}"`));
|
|
334
346
|
groupByParts.push(sql.raw(dimDef.sql));
|
|
335
347
|
}
|
|
336
348
|
|
|
337
349
|
// Time dimensions → SELECT + GROUP BY + WHERE (dateRange)
|
|
338
350
|
for (const td of params.timeDimensions ?? []) {
|
|
351
|
+
const shortName = td.dimension.split(".")[1]!;
|
|
339
352
|
const selectExpr = compileTimeDimensionSelect(cube, td);
|
|
340
|
-
|
|
353
|
+
const alias = `${cube.name}.${shortName}`;
|
|
354
|
+
selectParts.push(sql`${selectExpr} AS ${sql.raw(`"${alias}"`)}`);
|
|
341
355
|
groupByParts.push(selectExpr);
|
|
342
356
|
|
|
343
357
|
// Date range filter
|
|
@@ -357,7 +371,9 @@ export class DrizzleAnalyticsAdapter implements AnalyticsAdapter {
|
|
|
357
371
|
|
|
358
372
|
// Measures → SELECT
|
|
359
373
|
for (const measure of params.measures) {
|
|
360
|
-
|
|
374
|
+
const shortName = measure.split(".")[1]!;
|
|
375
|
+
const alias = `${cube.name}.${shortName}`;
|
|
376
|
+
selectParts.push(sql`${compileMeasure(cube, measure)} AS ${sql.raw(`"${alias}"`)}`);
|
|
361
377
|
}
|
|
362
378
|
|
|
363
379
|
// If no select parts (shouldn't happen with validation), bail
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { CommerceConfig } from "../../config/types.js";
|
|
2
2
|
import type { DrizzleDatabase } from "../../kernel/database/drizzle-db.js";
|
|
3
3
|
import { defineModule } from "../../kernel/module/index.js";
|
|
4
|
+
import type { SettingsService } from "../settings/service.js";
|
|
4
5
|
import { DrizzleAnalyticsAdapter } from "./drizzle-adapter.js";
|
|
5
6
|
import { BUILTIN_ANALYTICS_MODELS } from "./models.js";
|
|
7
|
+
import { RetailReportsEngine } from "./reports.js";
|
|
6
8
|
import { AnalyticsService } from "./service.js";
|
|
7
9
|
|
|
8
10
|
export const analyticsModule = defineModule<
|
|
@@ -17,9 +19,17 @@ export const analyticsModule = defineModule<
|
|
|
17
19
|
for (const model of BUILTIN_ANALYTICS_MODELS) {
|
|
18
20
|
adapter.registerModel(model);
|
|
19
21
|
}
|
|
22
|
+
// Settings is resolved lazily from the shared service container — the
|
|
23
|
+
// settings module may instantiate after analytics.
|
|
24
|
+
const services = deps.services as Record<string, unknown>;
|
|
25
|
+
const reports = new RetailReportsEngine(
|
|
26
|
+
deps.db.db as DrizzleDatabase,
|
|
27
|
+
(orgId, group) => (services.settings as SettingsService).read(orgId, group),
|
|
28
|
+
);
|
|
20
29
|
return new AnalyticsService({
|
|
21
30
|
adapter,
|
|
22
31
|
config: deps.config as CommerceConfig,
|
|
32
|
+
reports,
|
|
23
33
|
});
|
|
24
34
|
},
|
|
25
35
|
});
|