@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,61 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import type { Kernel } from "../../../runtime/kernel.js";
|
|
3
|
+
import {
|
|
4
|
+
KNOWN_GROUP_SCHEMAS,
|
|
5
|
+
getAllSettingsRoute,
|
|
6
|
+
getSettingsGroupRoute,
|
|
7
|
+
patchSettingsGroupRoute,
|
|
8
|
+
} from "../schemas/settings.js";
|
|
9
|
+
import { type AppEnv, mapErrorToResponse, mapErrorToStatus, requirePerm } from "../utils.js";
|
|
10
|
+
|
|
11
|
+
export function settingsRoutes(kernel: Kernel) {
|
|
12
|
+
const router = new OpenAPIHono<AppEnv>();
|
|
13
|
+
|
|
14
|
+
router.use("/", requirePerm("settings:manage"));
|
|
15
|
+
router.use("/:group", requirePerm("settings:manage"));
|
|
16
|
+
|
|
17
|
+
// @ts-expect-error -- openapi handler union return type
|
|
18
|
+
router.openapi(getAllSettingsRoute, async (c) => {
|
|
19
|
+
const result = await kernel.services.settings.getAll(c.get("actor"));
|
|
20
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
21
|
+
return c.json({ data: result.value });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// @ts-expect-error -- openapi handler union return type
|
|
25
|
+
router.openapi(getSettingsGroupRoute, async (c) => {
|
|
26
|
+
const result = await kernel.services.settings.getGroup(c.req.param("group"), c.get("actor"));
|
|
27
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
28
|
+
return c.json({ data: result.value });
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// @ts-expect-error -- openapi handler union return type
|
|
32
|
+
router.openapi(patchSettingsGroupRoute, async (c) => {
|
|
33
|
+
const group = c.req.param("group");
|
|
34
|
+
const body = c.req.valid("json");
|
|
35
|
+
|
|
36
|
+
// Known groups get typed validation; unknown groups accept any object.
|
|
37
|
+
const groupSchema = KNOWN_GROUP_SCHEMAS[group];
|
|
38
|
+
if (groupSchema) {
|
|
39
|
+
const parsed = groupSchema.safeParse(body);
|
|
40
|
+
if (!parsed.success) {
|
|
41
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
42
|
+
return c.json({
|
|
43
|
+
error: {
|
|
44
|
+
code: "VALIDATION_FAILED",
|
|
45
|
+
message: isProd
|
|
46
|
+
? "Invalid input."
|
|
47
|
+
: parsed.error.issues
|
|
48
|
+
.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
49
|
+
.join("; "),
|
|
50
|
+
},
|
|
51
|
+
}, 422);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result = await kernel.services.settings.updateGroup(group, body, c.get("actor"));
|
|
56
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
57
|
+
return c.json({ data: result.value });
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return router;
|
|
61
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import type { Kernel } from "../../../runtime/kernel.js";
|
|
3
|
+
import {
|
|
4
|
+
createShippingZoneRoute,
|
|
5
|
+
listShippingZonesRoute,
|
|
6
|
+
updateShippingZoneRoute,
|
|
7
|
+
deleteShippingZoneRoute,
|
|
8
|
+
createShippingRateRoute,
|
|
9
|
+
listShippingRatesRoute,
|
|
10
|
+
updateShippingRateRoute,
|
|
11
|
+
deleteShippingRateRoute,
|
|
12
|
+
} from "../schemas/shipping.js";
|
|
13
|
+
import { type AppEnv, mapErrorToResponse, mapErrorToStatus, requirePerm } from "../utils.js";
|
|
14
|
+
|
|
15
|
+
export function shippingRoutes(kernel: Kernel) {
|
|
16
|
+
const router = new OpenAPIHono<AppEnv>();
|
|
17
|
+
|
|
18
|
+
router.use("/zones", requirePerm("shipping:manage"));
|
|
19
|
+
router.use("/zones/:id", requirePerm("shipping:manage"));
|
|
20
|
+
router.use("/rates", requirePerm("shipping:manage"));
|
|
21
|
+
router.use("/rates/:id", requirePerm("shipping:manage"));
|
|
22
|
+
|
|
23
|
+
// @ts-expect-error -- openapi handler union return type
|
|
24
|
+
router.openapi(createShippingZoneRoute, async (c) => {
|
|
25
|
+
const result = await kernel.services.shipping.createZone(c.req.valid("json"), c.get("actor"));
|
|
26
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
27
|
+
return c.json({ data: result.value }, 201);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// @ts-expect-error -- openapi handler union return type
|
|
31
|
+
router.openapi(listShippingZonesRoute, async (c) => {
|
|
32
|
+
const result = await kernel.services.shipping.listZones(c.get("actor"));
|
|
33
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
34
|
+
return c.json({ data: result.value });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// @ts-expect-error -- openapi handler union return type
|
|
38
|
+
router.openapi(updateShippingZoneRoute, async (c) => {
|
|
39
|
+
const result = await kernel.services.shipping.updateZone(
|
|
40
|
+
c.req.param("id"),
|
|
41
|
+
c.req.valid("json"),
|
|
42
|
+
c.get("actor"),
|
|
43
|
+
);
|
|
44
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
45
|
+
return c.json({ data: result.value });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// @ts-expect-error -- openapi handler union return type
|
|
49
|
+
router.openapi(deleteShippingZoneRoute, async (c) => {
|
|
50
|
+
const result = await kernel.services.shipping.deleteZone(c.req.param("id"), c.get("actor"));
|
|
51
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
52
|
+
return c.json({ data: result.value });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// @ts-expect-error -- openapi handler union return type
|
|
56
|
+
router.openapi(createShippingRateRoute, async (c) => {
|
|
57
|
+
const result = await kernel.services.shipping.createRate(c.req.valid("json"), c.get("actor"));
|
|
58
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
59
|
+
return c.json({ data: result.value }, 201);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// @ts-expect-error -- openapi handler union return type
|
|
63
|
+
router.openapi(listShippingRatesRoute, async (c) => {
|
|
64
|
+
const zoneId = c.req.query("zoneId");
|
|
65
|
+
const result = await kernel.services.shipping.listRates(
|
|
66
|
+
zoneId !== undefined ? { zoneId } : undefined,
|
|
67
|
+
c.get("actor"),
|
|
68
|
+
);
|
|
69
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
70
|
+
return c.json({ data: result.value });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// @ts-expect-error -- openapi handler union return type
|
|
74
|
+
router.openapi(updateShippingRateRoute, async (c) => {
|
|
75
|
+
const result = await kernel.services.shipping.updateRate(
|
|
76
|
+
c.req.param("id"),
|
|
77
|
+
c.req.valid("json"),
|
|
78
|
+
c.get("actor"),
|
|
79
|
+
);
|
|
80
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
81
|
+
return c.json({ data: result.value });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// @ts-expect-error -- openapi handler union return type
|
|
85
|
+
router.openapi(deleteShippingRateRoute, async (c) => {
|
|
86
|
+
const result = await kernel.services.shipping.deleteRate(c.req.param("id"), c.get("actor"));
|
|
87
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
88
|
+
return c.json({ data: result.value });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return router;
|
|
92
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import type { Kernel } from "../../../runtime/kernel.js";
|
|
3
|
+
import {
|
|
4
|
+
createTaxRateRoute,
|
|
5
|
+
listTaxRatesRoute,
|
|
6
|
+
updateTaxRateRoute,
|
|
7
|
+
deleteTaxRateRoute,
|
|
8
|
+
createTaxClassRoute,
|
|
9
|
+
listTaxClassesRoute,
|
|
10
|
+
updateTaxClassRoute,
|
|
11
|
+
deleteTaxClassRoute,
|
|
12
|
+
} from "../schemas/tax.js";
|
|
13
|
+
import { type AppEnv, mapErrorToResponse, mapErrorToStatus, requirePerm } from "../utils.js";
|
|
14
|
+
|
|
15
|
+
export function taxRoutes(kernel: Kernel) {
|
|
16
|
+
const router = new OpenAPIHono<AppEnv>();
|
|
17
|
+
|
|
18
|
+
router.use("/rates", requirePerm("tax:manage"));
|
|
19
|
+
router.use("/rates/:id", requirePerm("tax:manage"));
|
|
20
|
+
router.use("/classes", requirePerm("tax:manage"));
|
|
21
|
+
router.use("/classes/:id", requirePerm("tax:manage"));
|
|
22
|
+
|
|
23
|
+
// @ts-expect-error -- openapi handler union return type
|
|
24
|
+
router.openapi(createTaxRateRoute, async (c) => {
|
|
25
|
+
const result = await kernel.services.tax.createTaxRate(c.req.valid("json"), c.get("actor"));
|
|
26
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
27
|
+
return c.json({ data: result.value }, 201);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// @ts-expect-error -- openapi handler union return type
|
|
31
|
+
router.openapi(listTaxRatesRoute, async (c) => {
|
|
32
|
+
const result = await kernel.services.tax.listTaxRates(c.get("actor"));
|
|
33
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
34
|
+
return c.json({ data: result.value });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// @ts-expect-error -- openapi handler union return type
|
|
38
|
+
router.openapi(updateTaxRateRoute, async (c) => {
|
|
39
|
+
const result = await kernel.services.tax.updateTaxRate(
|
|
40
|
+
c.req.param("id"),
|
|
41
|
+
c.req.valid("json"),
|
|
42
|
+
c.get("actor"),
|
|
43
|
+
);
|
|
44
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
45
|
+
return c.json({ data: result.value });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// @ts-expect-error -- openapi handler union return type
|
|
49
|
+
router.openapi(deleteTaxRateRoute, async (c) => {
|
|
50
|
+
const result = await kernel.services.tax.deleteTaxRate(c.req.param("id"), c.get("actor"));
|
|
51
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
52
|
+
return c.json({ data: result.value });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ── Product tax classes (issue #57) ───────────────────────────────
|
|
56
|
+
|
|
57
|
+
// @ts-expect-error -- openapi handler union return type
|
|
58
|
+
router.openapi(createTaxClassRoute, async (c) => {
|
|
59
|
+
const result = await kernel.services.tax.createTaxClass(c.req.valid("json"), c.get("actor"));
|
|
60
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
61
|
+
return c.json({ data: result.value }, 201);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// @ts-expect-error -- openapi handler union return type
|
|
65
|
+
router.openapi(listTaxClassesRoute, async (c) => {
|
|
66
|
+
const result = await kernel.services.tax.listTaxClasses(c.get("actor"));
|
|
67
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
68
|
+
return c.json({ data: result.value });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// @ts-expect-error -- openapi handler union return type
|
|
72
|
+
router.openapi(updateTaxClassRoute, async (c) => {
|
|
73
|
+
const result = await kernel.services.tax.updateTaxClass(
|
|
74
|
+
c.req.param("id"),
|
|
75
|
+
c.req.valid("json"),
|
|
76
|
+
c.get("actor"),
|
|
77
|
+
);
|
|
78
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
79
|
+
return c.json({ data: result.value });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// @ts-expect-error -- openapi handler union return type
|
|
83
|
+
router.openapi(deleteTaxClassRoute, async (c) => {
|
|
84
|
+
const result = await kernel.services.tax.deleteTaxClass(c.req.param("id"), c.get("actor"));
|
|
85
|
+
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
86
|
+
return c.json({ data: result.value });
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return router;
|
|
90
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { z, createRoute } from "@hono/zod-openapi";
|
|
2
|
+
import { errorResponses } from "./shared.js";
|
|
3
|
+
|
|
4
|
+
export const CreateStaffBodySchema = z.object({
|
|
5
|
+
userId: z.string().min(1).openapi({ example: "user_abc123", description: "Better Auth user id of an existing user" }),
|
|
6
|
+
role: z.string().min(1).openapi({ example: "manager" }),
|
|
7
|
+
}).openapi("CreateStaffRequest");
|
|
8
|
+
|
|
9
|
+
export const InviteStaffBodySchema = z.object({
|
|
10
|
+
email: z.email().openapi({ example: "newhire@example.com" }),
|
|
11
|
+
role: z.string().min(1).openapi({ example: "manager" }),
|
|
12
|
+
}).openapi("InviteStaffRequest");
|
|
13
|
+
|
|
14
|
+
export const UpdateStaffRoleBodySchema = z.object({
|
|
15
|
+
role: z.string().min(1).openapi({ example: "admin" }),
|
|
16
|
+
}).openapi("UpdateStaffRoleRequest");
|
|
17
|
+
|
|
18
|
+
const MemberIdParam = z.object({
|
|
19
|
+
id: z.string().min(1).openapi({ example: "mem_abc123" }),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const DataResponse = z.object({ data: z.any() }).openapi("AdminStaffResponse");
|
|
23
|
+
|
|
24
|
+
export const listStaffRoute = createRoute({
|
|
25
|
+
method: "get",
|
|
26
|
+
path: "/staff",
|
|
27
|
+
tags: ["Admin"],
|
|
28
|
+
summary: "List staff members with their roles",
|
|
29
|
+
responses: {
|
|
30
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Staff members" },
|
|
31
|
+
...errorResponses,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const createStaffRoute = createRoute({
|
|
36
|
+
method: "post",
|
|
37
|
+
path: "/staff",
|
|
38
|
+
tags: ["Admin"],
|
|
39
|
+
summary: "Add an existing user as a staff member with a role",
|
|
40
|
+
request: {
|
|
41
|
+
body: { content: { "application/json": { schema: CreateStaffBodySchema } }, required: true },
|
|
42
|
+
},
|
|
43
|
+
responses: {
|
|
44
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Staff member created." },
|
|
45
|
+
...errorResponses,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export const inviteStaffRoute = createRoute({
|
|
50
|
+
method: "post",
|
|
51
|
+
path: "/staff/invitations",
|
|
52
|
+
tags: ["Admin"],
|
|
53
|
+
summary: "Invite a teammate by email with a role",
|
|
54
|
+
request: {
|
|
55
|
+
body: { content: { "application/json": { schema: InviteStaffBodySchema } }, required: true },
|
|
56
|
+
},
|
|
57
|
+
responses: {
|
|
58
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Invitation created." },
|
|
59
|
+
...errorResponses,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const listStaffInvitationsRoute = createRoute({
|
|
64
|
+
method: "get",
|
|
65
|
+
path: "/staff/invitations",
|
|
66
|
+
tags: ["Admin"],
|
|
67
|
+
summary: "List pending staff invitations",
|
|
68
|
+
responses: {
|
|
69
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Invitations" },
|
|
70
|
+
...errorResponses,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const listStaffRolesRoute = createRoute({
|
|
75
|
+
method: "get",
|
|
76
|
+
path: "/staff/roles",
|
|
77
|
+
tags: ["Admin"],
|
|
78
|
+
summary: "Role → permission mapping staff roles resolve to",
|
|
79
|
+
responses: {
|
|
80
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Roles" },
|
|
81
|
+
...errorResponses,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export const updateStaffRoleRoute = createRoute({
|
|
86
|
+
method: "patch",
|
|
87
|
+
path: "/staff/{id}",
|
|
88
|
+
tags: ["Admin"],
|
|
89
|
+
summary: "Change a staff member's role",
|
|
90
|
+
request: {
|
|
91
|
+
params: MemberIdParam,
|
|
92
|
+
body: { content: { "application/json": { schema: UpdateStaffRoleBodySchema } }, required: true },
|
|
93
|
+
},
|
|
94
|
+
responses: {
|
|
95
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Role updated." },
|
|
96
|
+
...errorResponses,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
export const revokeStaffRoute = createRoute({
|
|
101
|
+
method: "delete",
|
|
102
|
+
path: "/staff/{id}",
|
|
103
|
+
tags: ["Admin"],
|
|
104
|
+
summary: "Revoke a staff member's membership",
|
|
105
|
+
request: { params: MemberIdParam },
|
|
106
|
+
responses: {
|
|
107
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Membership revoked." },
|
|
108
|
+
...errorResponses,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z, createRoute } from "@hono/zod-openapi";
|
|
2
|
+
import { errorResponses } from "./shared.js";
|
|
3
|
+
|
|
4
|
+
const DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
5
|
+
|
|
6
|
+
const ReportParamsSchema = z.object({
|
|
7
|
+
name: z.string().regex(/^[a-z][a-z0-9-]*$/).openapi({ example: "daily-journal" }),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const ReportQuerySchema = z.object({
|
|
11
|
+
date: z.string().regex(DATE).optional().openapi({ description: "Local calendar date (single-day reports)." }),
|
|
12
|
+
from: z.string().regex(DATE).optional().openapi({ description: "Local range start, inclusive." }),
|
|
13
|
+
to: z.string().regex(DATE).optional().openapi({ description: "Local range end, inclusive." }),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const DataResponse = z.object({ data: z.any() }).openapi("AnalyticsReportResponse");
|
|
17
|
+
|
|
18
|
+
export const listReportsRoute = createRoute({
|
|
19
|
+
method: "get",
|
|
20
|
+
path: "/reports",
|
|
21
|
+
tags: ["Analytics"],
|
|
22
|
+
summary: "List the canned retail reports",
|
|
23
|
+
responses: {
|
|
24
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Available reports." },
|
|
25
|
+
...errorResponses,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const getReportRoute = createRoute({
|
|
30
|
+
method: "get",
|
|
31
|
+
path: "/reports/{name}",
|
|
32
|
+
tags: ["Analytics"],
|
|
33
|
+
summary: "Run a canned retail report (calendar math in the store's timezone)",
|
|
34
|
+
request: { params: ReportParamsSchema, query: ReportQuerySchema },
|
|
35
|
+
responses: {
|
|
36
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Report result." },
|
|
37
|
+
...errorResponses,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
@@ -26,6 +26,46 @@ const CartItemParams = z.object({
|
|
|
26
26
|
|
|
27
27
|
// ─── Route Definitions ──────────────────────────────────────────────────────
|
|
28
28
|
|
|
29
|
+
export const listCartsRoute = createRoute({
|
|
30
|
+
method: "get",
|
|
31
|
+
path: "/",
|
|
32
|
+
tags: ["Carts"],
|
|
33
|
+
summary: "List carts (admin) — abandoned-checkout recovery filters",
|
|
34
|
+
description: "Lists carts with status/olderThan/hasCustomer filters and pagination. Includes shopper identity (cart email + linked customer email). Requires cart:manage.",
|
|
35
|
+
request: {
|
|
36
|
+
query: z.object({
|
|
37
|
+
status: z.enum(["active", "checking_out", "merged", "checked_out", "abandoned"]).optional(),
|
|
38
|
+
olderThan: z.string().optional().openapi({ example: "2026-06-30T00:00:00Z", description: "Only carts not updated since this ISO timestamp" }),
|
|
39
|
+
hasCustomer: z.string().optional().openapi({ example: "true" }),
|
|
40
|
+
page: z.string().optional(),
|
|
41
|
+
limit: z.string().optional(),
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
responses: {
|
|
45
|
+
200: {
|
|
46
|
+
content: { "application/json": { schema: CartResponse } },
|
|
47
|
+
description: "Carts",
|
|
48
|
+
},
|
|
49
|
+
...errorResponses,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const recoverCartRoute = createRoute({
|
|
54
|
+
method: "post",
|
|
55
|
+
path: "/{id}/recover",
|
|
56
|
+
tags: ["Carts"],
|
|
57
|
+
summary: "Recover an abandoned cart (admin)",
|
|
58
|
+
description: "Reactivates the cart, extends its expiry, and returns a resume secret suitable for a recovery email's resume/checkout link. Fires the cart.afterRecover hook. Requires cart:manage.",
|
|
59
|
+
request: { params: CartIdParam },
|
|
60
|
+
responses: {
|
|
61
|
+
200: {
|
|
62
|
+
content: { "application/json": { schema: CartResponse } },
|
|
63
|
+
description: "Recovery payload (cartId, secret, expiresAt, shopper identity).",
|
|
64
|
+
},
|
|
65
|
+
...errorResponses,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
29
69
|
export const getCartRoute = createRoute({
|
|
30
70
|
method: "get",
|
|
31
71
|
path: "/{id}",
|
|
@@ -477,3 +477,56 @@ export const generateVariantsRoute = createRoute({
|
|
|
477
477
|
...errorResponses,
|
|
478
478
|
},
|
|
479
479
|
});
|
|
480
|
+
|
|
481
|
+
// ── One-call variant creation (issue #50) ───────────────────────────────────
|
|
482
|
+
|
|
483
|
+
export const QuickVariantBodySchema = z.object({
|
|
484
|
+
options: z.record(z.string().min(1), z.string().min(1)).openapi({
|
|
485
|
+
example: { color: "Red", size: "M" },
|
|
486
|
+
description: "Axis name → value. Option types/values are upserted inline.",
|
|
487
|
+
}),
|
|
488
|
+
sku: z.string().min(1).optional(),
|
|
489
|
+
barcode: z.string().min(1).optional(),
|
|
490
|
+
}).openapi("QuickVariantRequest");
|
|
491
|
+
|
|
492
|
+
export const BulkVariantsBodySchema = z.object({
|
|
493
|
+
axes: z.array(z.object({
|
|
494
|
+
name: z.string().min(1),
|
|
495
|
+
values: z.array(z.string().min(1)).min(1),
|
|
496
|
+
})).openapi({
|
|
497
|
+
example: [{ name: "color", values: ["Red", "Blue"] }, { name: "size", values: ["S", "M"] }],
|
|
498
|
+
description: "Matrix axes; an empty array creates one option-less variant.",
|
|
499
|
+
}),
|
|
500
|
+
skuPrefix: z.string().min(1).optional(),
|
|
501
|
+
}).openapi("BulkVariantsRequest");
|
|
502
|
+
|
|
503
|
+
export const quickVariantRoute = createRoute({
|
|
504
|
+
method: "post",
|
|
505
|
+
path: "/entities/{id}/variants/quick",
|
|
506
|
+
tags: ["Catalog"],
|
|
507
|
+
summary: "Create one sellable variant in a single call (upserts axes, seeds inventory)",
|
|
508
|
+
request: {
|
|
509
|
+
params: EntityIdParam,
|
|
510
|
+
body: { content: { "application/json": { schema: QuickVariantBodySchema } }, required: true },
|
|
511
|
+
},
|
|
512
|
+
responses: {
|
|
513
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Variant created and inventory seeded." },
|
|
514
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "The combination already existed; the existing variant is returned." },
|
|
515
|
+
...errorResponses,
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
export const bulkVariantsRoute = createRoute({
|
|
520
|
+
method: "post",
|
|
521
|
+
path: "/entities/{id}/variants/bulk",
|
|
522
|
+
tags: ["Catalog"],
|
|
523
|
+
summary: "Create a variant matrix in a single call (upserts axes, seeds inventory, skips existing)",
|
|
524
|
+
request: {
|
|
525
|
+
params: EntityIdParam,
|
|
526
|
+
body: { content: { "application/json": { schema: BulkVariantsBodySchema } }, required: true },
|
|
527
|
+
},
|
|
528
|
+
responses: {
|
|
529
|
+
201: { content: { "application/json": { schema: DataResponse } }, description: "Variants created (existing combinations skipped)." },
|
|
530
|
+
...errorResponses,
|
|
531
|
+
},
|
|
532
|
+
});
|
|
@@ -6,6 +6,10 @@ import { ErrorSchema, errorResponses } from "./shared.js";
|
|
|
6
6
|
export const CheckoutBodySchema = z.object({
|
|
7
7
|
cartId: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
8
8
|
paymentMethodId: z.string().openapi({ example: "pm_card_visa" }),
|
|
9
|
+
idempotencyKey: z.string().min(8).max(255).optional().openapi({
|
|
10
|
+
example: "checkout-8f14e45f-1738312200",
|
|
11
|
+
description: "Client-supplied retry key. A re-submitted checkout with the same key returns the already-created order without re-authorizing payment (safe offline-queue replay).",
|
|
12
|
+
}),
|
|
9
13
|
customerId: z.string().optional().openapi({ example: "customer-uuid-or-user-id" }),
|
|
10
14
|
customerGroupIds: z.array(z.string()).optional(),
|
|
11
15
|
currency: z.string().length(3).optional().openapi({ example: "USD" }),
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z, createRoute } from "@hono/zod-openapi";
|
|
2
|
+
import { errorResponses } from "./shared.js";
|
|
3
|
+
|
|
4
|
+
const IdParam = z.object({
|
|
5
|
+
id: z.uuid().openapi({ example: "550e8400-e29b-41d4-a716-446655440000" }),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const EmailInvoiceBodySchema = z.object({
|
|
9
|
+
to: z.email().openapi({ example: "customer@example.com" }),
|
|
10
|
+
}).openapi("EmailInvoiceRequest");
|
|
11
|
+
|
|
12
|
+
const DataResponse = z.object({ data: z.any() }).openapi("DocumentActionResponse");
|
|
13
|
+
|
|
14
|
+
export const invoicePdfRoute = createRoute({
|
|
15
|
+
method: "get",
|
|
16
|
+
path: "/{id}/invoice.pdf",
|
|
17
|
+
tags: ["Documents"],
|
|
18
|
+
summary: "Render the order's invoice as PDF (issues a fiscal invoice number on first render)",
|
|
19
|
+
request: { params: IdParam },
|
|
20
|
+
responses: {
|
|
21
|
+
200: {
|
|
22
|
+
content: { "application/pdf": { schema: z.any().openapi({ type: "string", format: "binary" }) } },
|
|
23
|
+
description: "The rendered PDF invoice.",
|
|
24
|
+
},
|
|
25
|
+
...errorResponses,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const invoiceHtmlRoute = createRoute({
|
|
30
|
+
method: "get",
|
|
31
|
+
path: "/{id}/invoice.html",
|
|
32
|
+
tags: ["Documents"],
|
|
33
|
+
summary: "Render the order's invoice as HTML",
|
|
34
|
+
request: { params: IdParam },
|
|
35
|
+
responses: {
|
|
36
|
+
200: {
|
|
37
|
+
content: { "text/html": { schema: z.string() } },
|
|
38
|
+
description: "The rendered HTML invoice.",
|
|
39
|
+
},
|
|
40
|
+
...errorResponses,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const receiptHtmlRoute = createRoute({
|
|
45
|
+
method: "get",
|
|
46
|
+
path: "/{id}/receipt.html",
|
|
47
|
+
tags: ["Documents"],
|
|
48
|
+
summary: "Render the order's receipt as HTML",
|
|
49
|
+
request: { params: IdParam },
|
|
50
|
+
responses: {
|
|
51
|
+
200: {
|
|
52
|
+
content: { "text/html": { schema: z.string() } },
|
|
53
|
+
description: "The rendered HTML receipt.",
|
|
54
|
+
},
|
|
55
|
+
...errorResponses,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const emailInvoiceRoute = createRoute({
|
|
60
|
+
method: "post",
|
|
61
|
+
path: "/{id}/invoice/email",
|
|
62
|
+
tags: ["Documents"],
|
|
63
|
+
summary: "Email the order's invoice via the configured email adapter",
|
|
64
|
+
request: {
|
|
65
|
+
params: IdParam,
|
|
66
|
+
body: { content: { "application/json": { schema: EmailInvoiceBodySchema } }, required: true },
|
|
67
|
+
},
|
|
68
|
+
responses: {
|
|
69
|
+
200: { content: { "application/json": { schema: DataResponse } }, description: "Invoice emailed." },
|
|
70
|
+
...errorResponses,
|
|
71
|
+
},
|
|
72
|
+
});
|