@porulle/core 0.10.8 → 0.13.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/auth-schema-guard.d.ts +2444 -0
- package/dist/auth/auth-schema-guard.d.ts.map +1 -0
- package/dist/auth/auth-schema-guard.js +113 -0
- package/dist/auth/auth-schema.d.ts +228 -0
- package/dist/auth/auth-schema.d.ts.map +1 -1
- package/dist/auth/auth-schema.js +24 -2
- package/dist/auth/middleware.d.ts +1 -0
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +13 -5
- package/dist/auth/org.d.ts +8 -2
- package/dist/auth/org.d.ts.map +1 -1
- package/dist/auth/org.js +12 -4
- package/dist/auth/organization-guard.d.ts +5 -0
- package/dist/auth/organization-guard.d.ts.map +1 -0
- package/dist/auth/organization-guard.js +124 -0
- package/dist/auth/permissions.d.ts +10 -0
- package/dist/auth/permissions.d.ts.map +1 -1
- package/dist/auth/permissions.js +31 -7
- package/dist/auth/role-authority.d.ts +44 -0
- package/dist/auth/role-authority.d.ts.map +1 -0
- package/dist/auth/role-authority.js +85 -0
- package/dist/auth/setup.d.ts.map +1 -1
- package/dist/auth/setup.js +17 -0
- package/dist/auth/strict-org-resolution.d.ts.map +1 -1
- package/dist/auth/strict-org-resolution.js +9 -1
- package/dist/auth/types.d.ts +1 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +2 -0
- package/dist/config/types.d.ts +33 -4
- package/dist/config/types.d.ts.map +1 -1
- package/dist/hooks/checkout.d.ts.map +1 -1
- package/dist/hooks/checkout.js +10 -9
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/interfaces/rest/audit-middleware.d.ts.map +1 -1
- package/dist/interfaces/rest/audit-middleware.js +2 -0
- package/dist/interfaces/rest/customer-portal.d.ts.map +1 -1
- package/dist/interfaces/rest/customer-portal.js +9 -8
- package/dist/interfaces/rest/index.d.ts.map +1 -1
- package/dist/interfaces/rest/index.js +4 -0
- package/dist/interfaces/rest/route-coverage.d.ts +14 -0
- package/dist/interfaces/rest/route-coverage.d.ts.map +1 -0
- package/dist/interfaces/rest/route-coverage.js +81 -0
- package/dist/interfaces/rest/router.d.ts +7 -2
- package/dist/interfaces/rest/router.d.ts.map +1 -1
- package/dist/interfaces/rest/router.js +8 -4
- package/dist/interfaces/rest/routes/admin/compensation-failures.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/admin/compensation-failures.js +7 -5
- package/dist/interfaces/rest/routes/admin/custom-field-proposals.d.ts +5 -0
- package/dist/interfaces/rest/routes/admin/custom-field-proposals.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/admin/custom-field-proposals.js +22 -0
- package/dist/interfaces/rest/routes/admin/entity-field-definitions.d.ts +5 -0
- package/dist/interfaces/rest/routes/admin/entity-field-definitions.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/admin/entity-field-definitions.js +39 -0
- package/dist/interfaces/rest/routes/admin/permissions.d.ts +1 -1
- package/dist/interfaces/rest/routes/admin/permissions.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/admin/permissions.js +2 -0
- package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/admin/staff.js +126 -66
- package/dist/interfaces/rest/routes/admin-jobs.js +3 -3
- package/dist/interfaces/rest/routes/audit.js +3 -3
- package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/carts.js +13 -10
- package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/catalog.js +47 -4
- package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/checkout.js +30 -35
- package/dist/interfaces/rest/routes/documents.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/documents.js +10 -5
- package/dist/interfaces/rest/routes/inventory.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/inventory.js +2 -0
- package/dist/interfaces/rest/routes/media.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/media.js +7 -3
- package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/orders.js +26 -8
- package/dist/interfaces/rest/routes/pricing.js +2 -2
- package/dist/interfaces/rest/routes/promotions.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/promotions.js +13 -10
- package/dist/interfaces/rest/routes/search.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/search.js +14 -1
- package/dist/interfaces/rest/schemas/admin-custom-field-proposals.d.ts +134 -0
- package/dist/interfaces/rest/schemas/admin-custom-field-proposals.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/admin-custom-field-proposals.js +26 -0
- package/dist/interfaces/rest/schemas/admin-entity-field-definitions.d.ts +592 -0
- package/dist/interfaces/rest/schemas/admin-entity-field-definitions.d.ts.map +1 -0
- package/dist/interfaces/rest/schemas/admin-entity-field-definitions.js +109 -0
- package/dist/interfaces/rest/schemas/carts.d.ts +7 -0
- package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/catalog.d.ts +1364 -401
- package/dist/interfaces/rest/schemas/catalog.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/catalog.js +86 -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/orders.d.ts +204 -0
- package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/pricing.d.ts +1 -0
- package/dist/interfaces/rest/schemas/pricing.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/responses.d.ts +71 -0
- package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/search.d.ts +1 -0
- package/dist/interfaces/rest/schemas/search.d.ts.map +1 -1
- package/dist/interfaces/rest/schemas/search.js +1 -0
- package/dist/interfaces/rest/utils.d.ts +15 -0
- package/dist/interfaces/rest/utils.d.ts.map +1 -1
- package/dist/interfaces/rest/utils.js +45 -2
- package/dist/kernel/compensation/executor.js +2 -2
- package/dist/kernel/database/tx-context.d.ts +8 -0
- package/dist/kernel/database/tx-context.d.ts.map +1 -1
- package/dist/kernel/database/tx-context.js +13 -0
- package/dist/kernel/hooks/create-context.d.ts +2 -0
- package/dist/kernel/hooks/create-context.d.ts.map +1 -1
- package/dist/kernel/hooks/create-context.js +1 -0
- package/dist/kernel/hooks/types.d.ts +2 -0
- package/dist/kernel/hooks/types.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.d.ts.map +1 -1
- package/dist/kernel/plugin/manifest.js +9 -5
- package/dist/modules/analytics/service.js +2 -2
- package/dist/modules/audit/service.js +3 -3
- package/dist/modules/cart/repository/index.d.ts +13 -7
- package/dist/modules/cart/repository/index.d.ts.map +1 -1
- package/dist/modules/cart/repository/index.js +16 -10
- 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 +4 -0
- package/dist/modules/cart/service.d.ts +22 -9
- package/dist/modules/cart/service.d.ts.map +1 -1
- package/dist/modules/cart/service.js +57 -33
- package/dist/modules/catalog/brand-service.js +7 -7
- package/dist/modules/catalog/category-service.js +7 -7
- package/dist/modules/catalog/entity-service.d.ts +19 -10
- package/dist/modules/catalog/entity-service.d.ts.map +1 -1
- package/dist/modules/catalog/entity-service.js +180 -51
- package/dist/modules/catalog/module.d.ts +6 -1
- package/dist/modules/catalog/module.d.ts.map +1 -1
- package/dist/modules/catalog/module.js +6 -1
- package/dist/modules/catalog/ownership.d.ts +5 -0
- package/dist/modules/catalog/ownership.d.ts.map +1 -0
- package/dist/modules/catalog/ownership.js +11 -0
- package/dist/modules/catalog/read-policy.d.ts +9 -0
- package/dist/modules/catalog/read-policy.d.ts.map +1 -0
- package/dist/modules/catalog/read-policy.js +8 -0
- package/dist/modules/catalog/repository/index.d.ts +55 -3
- package/dist/modules/catalog/repository/index.d.ts.map +1 -1
- package/dist/modules/catalog/repository/index.js +335 -6
- package/dist/modules/catalog/revision.d.ts +4 -0
- package/dist/modules/catalog/revision.d.ts.map +1 -0
- package/dist/modules/catalog/revision.js +33 -0
- package/dist/modules/catalog/schema.d.ts +979 -110
- package/dist/modules/catalog/schema.d.ts.map +1 -1
- package/dist/modules/catalog/schema.js +112 -2
- package/dist/modules/catalog/schemas.d.ts +2 -0
- package/dist/modules/catalog/schemas.d.ts.map +1 -1
- package/dist/modules/catalog/schemas.js +2 -0
- package/dist/modules/catalog/service.d.ts +80 -15
- package/dist/modules/catalog/service.d.ts.map +1 -1
- package/dist/modules/catalog/service.js +522 -14
- package/dist/modules/channels/adapter.d.ts +85 -0
- package/dist/modules/channels/adapter.d.ts.map +1 -1
- package/dist/modules/channels/adapter.js +9 -1
- package/dist/modules/customers/module.d.ts.map +1 -1
- package/dist/modules/customers/module.js +1 -0
- package/dist/modules/customers/service.d.ts +2 -0
- package/dist/modules/customers/service.d.ts.map +1 -1
- package/dist/modules/customers/service.js +21 -20
- package/dist/modules/documents/module.d.ts.map +1 -1
- package/dist/modules/documents/module.js +1 -0
- package/dist/modules/documents/service.d.ts +18 -4
- package/dist/modules/documents/service.d.ts.map +1 -1
- package/dist/modules/documents/service.js +54 -16
- package/dist/modules/fulfillment/module.d.ts.map +1 -1
- package/dist/modules/fulfillment/module.js +1 -0
- package/dist/modules/fulfillment/service.d.ts +2 -0
- package/dist/modules/fulfillment/service.d.ts.map +1 -1
- package/dist/modules/fulfillment/service.js +15 -6
- package/dist/modules/inventory/service.d.ts.map +1 -1
- package/dist/modules/inventory/service.js +15 -14
- package/dist/modules/media/module.d.ts +68 -0
- package/dist/modules/media/module.d.ts.map +1 -1
- package/dist/modules/media/module.js +2 -0
- package/dist/modules/media/schema.d.ts +70 -0
- package/dist/modules/media/schema.d.ts.map +1 -1
- package/dist/modules/media/schema.js +20 -2
- package/dist/modules/media/service.d.ts +8 -1
- package/dist/modules/media/service.d.ts.map +1 -1
- package/dist/modules/media/service.js +71 -23
- package/dist/modules/orders/guest-access.d.ts +27 -0
- package/dist/modules/orders/guest-access.d.ts.map +1 -0
- package/dist/modules/orders/guest-access.js +46 -0
- package/dist/modules/orders/module.d.ts.map +1 -1
- package/dist/modules/orders/module.js +1 -0
- package/dist/modules/orders/quote.d.ts.map +1 -1
- package/dist/modules/orders/quote.js +1 -0
- package/dist/modules/orders/repository/index.d.ts +1 -1
- package/dist/modules/orders/repository/index.d.ts.map +1 -1
- package/dist/modules/orders/repository/index.js +2 -2
- package/dist/modules/orders/schema.d.ts +17 -0
- package/dist/modules/orders/schema.d.ts.map +1 -1
- package/dist/modules/orders/schema.js +5 -3
- package/dist/modules/orders/service.d.ts +16 -7
- package/dist/modules/orders/service.d.ts.map +1 -1
- package/dist/modules/orders/service.js +184 -55
- package/dist/modules/pricing/module.d.ts.map +1 -1
- package/dist/modules/pricing/module.js +1 -0
- package/dist/modules/pricing/schema.d.ts +17 -0
- package/dist/modules/pricing/schema.d.ts.map +1 -1
- package/dist/modules/pricing/schema.js +1 -0
- package/dist/modules/pricing/schemas.d.ts +1 -0
- package/dist/modules/pricing/schemas.d.ts.map +1 -1
- package/dist/modules/pricing/schemas.js +1 -0
- package/dist/modules/pricing/service.d.ts +2 -0
- package/dist/modules/pricing/service.d.ts.map +1 -1
- package/dist/modules/pricing/service.js +18 -12
- package/dist/modules/promotions/module.d.ts.map +1 -1
- package/dist/modules/promotions/module.js +1 -0
- package/dist/modules/promotions/service.d.ts +3 -0
- package/dist/modules/promotions/service.d.ts.map +1 -1
- package/dist/modules/promotions/service.js +19 -11
- package/dist/modules/search/adapter.d.ts +8 -0
- package/dist/modules/search/adapter.d.ts.map +1 -1
- package/dist/modules/search/module.d.ts.map +1 -1
- package/dist/modules/search/module.js +3 -0
- package/dist/modules/search/service.d.ts +5 -0
- package/dist/modules/search/service.d.ts.map +1 -1
- package/dist/modules/search/service.js +131 -11
- package/dist/modules/settings/module.d.ts.map +1 -1
- package/dist/modules/settings/module.js +1 -0
- package/dist/modules/settings/service.d.ts +3 -0
- package/dist/modules/settings/service.d.ts.map +1 -1
- package/dist/modules/settings/service.js +6 -4
- package/dist/modules/shipping/service.js +9 -9
- package/dist/modules/tax/module.d.ts.map +1 -1
- package/dist/modules/tax/module.js +1 -0
- package/dist/modules/tax/service.d.ts +3 -0
- package/dist/modules/tax/service.d.ts.map +1 -1
- package/dist/modules/tax/service.js +11 -9
- package/dist/modules/webhooks/hook.js +2 -2
- package/dist/modules/webhooks/module.d.ts.map +1 -1
- package/dist/modules/webhooks/module.js +1 -0
- package/dist/modules/webhooks/service.d.ts +2 -0
- package/dist/modules/webhooks/service.d.ts.map +1 -1
- package/dist/modules/webhooks/service.js +4 -4
- package/dist/runtime/kernel-modules.d.ts +73 -0
- package/dist/runtime/kernel-modules.d.ts.map +1 -1
- package/dist/runtime/server.d.ts.map +1 -1
- package/dist/runtime/server.js +10 -2
- package/dist/test-utils/create-pglite-adapter.d.ts.map +1 -1
- package/dist/test-utils/create-pglite-adapter.js +35 -13
- package/dist/test-utils/create-test-config.d.ts.map +1 -1
- package/dist/test-utils/create-test-config.js +4 -0
- package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
- package/dist/test-utils/rest-api-test-utils.js +2 -0
- package/dist/test-utils/test-actors.js +2 -2
- package/dist/utils/id.d.ts +2 -0
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +11 -0
- package/package.json +6 -5
- package/src/auth/auth-schema-guard.ts +143 -0
- package/src/auth/auth-schema.ts +50 -19
- package/src/auth/middleware.ts +17 -5
- package/src/auth/org.ts +15 -3
- package/src/auth/organization-guard.ts +158 -0
- package/src/auth/permissions.ts +31 -8
- package/src/auth/role-authority.ts +107 -0
- package/src/auth/setup.ts +17 -0
- package/src/auth/strict-org-resolution.ts +7 -1
- package/src/auth/types.ts +1 -1
- package/src/config/defaults.ts +2 -0
- package/src/config/types.ts +32 -4
- package/src/hooks/checkout.ts +19 -12
- package/src/index.ts +30 -6
- package/src/interfaces/rest/audit-middleware.ts +2 -0
- package/src/interfaces/rest/customer-portal.ts +31 -24
- package/src/interfaces/rest/index.ts +4 -0
- package/src/interfaces/rest/route-coverage.ts +103 -0
- package/src/interfaces/rest/router.ts +16 -10
- package/src/interfaces/rest/routes/admin/compensation-failures.ts +8 -5
- package/src/interfaces/rest/routes/admin/custom-field-proposals.ts +37 -0
- package/src/interfaces/rest/routes/admin/entity-field-definitions.ts +89 -0
- package/src/interfaces/rest/routes/admin/permissions.ts +3 -1
- package/src/interfaces/rest/routes/admin/staff.ts +161 -72
- package/src/interfaces/rest/routes/admin-jobs.ts +3 -3
- package/src/interfaces/rest/routes/audit.ts +3 -3
- package/src/interfaces/rest/routes/carts.ts +17 -7
- package/src/interfaces/rest/routes/catalog.ts +96 -0
- package/src/interfaces/rest/routes/checkout.ts +41 -38
- package/src/interfaces/rest/routes/documents.ts +15 -1
- package/src/interfaces/rest/routes/inventory.ts +2 -0
- package/src/interfaces/rest/routes/media.ts +8 -3
- package/src/interfaces/rest/routes/orders.ts +27 -8
- package/src/interfaces/rest/routes/pricing.ts +2 -2
- package/src/interfaces/rest/routes/promotions.ts +12 -9
- package/src/interfaces/rest/routes/search.ts +19 -1
- package/src/interfaces/rest/schemas/admin-custom-field-proposals.ts +29 -0
- package/src/interfaces/rest/schemas/admin-entity-field-definitions.ts +120 -0
- package/src/interfaces/rest/schemas/catalog.ts +92 -0
- package/src/interfaces/rest/schemas/search.ts +2 -0
- package/src/interfaces/rest/utils.ts +61 -2
- package/src/kernel/compensation/executor.ts +2 -2
- package/src/kernel/database/tx-context.ts +25 -0
- package/src/kernel/hooks/create-context.ts +3 -0
- package/src/kernel/hooks/types.ts +2 -0
- package/src/kernel/plugin/manifest.ts +9 -5
- package/src/modules/analytics/service.ts +2 -2
- package/src/modules/audit/service.ts +3 -3
- package/src/modules/cart/repository/index.ts +22 -8
- package/src/modules/cart/schema.ts +4 -0
- package/src/modules/cart/service.ts +62 -27
- package/src/modules/catalog/brand-service.ts +7 -7
- package/src/modules/catalog/category-service.ts +7 -7
- package/src/modules/catalog/entity-service.ts +188 -53
- package/src/modules/catalog/module.ts +15 -0
- package/src/modules/catalog/ownership.ts +17 -0
- package/src/modules/catalog/read-policy.ts +16 -0
- package/src/modules/catalog/repository/index.ts +566 -4
- package/src/modules/catalog/revision.ts +35 -0
- package/src/modules/catalog/schema.ts +169 -1
- package/src/modules/catalog/schemas.ts +2 -0
- package/src/modules/catalog/service.ts +766 -26
- package/src/modules/channels/adapter.ts +107 -1
- package/src/modules/customers/module.ts +2 -0
- package/src/modules/customers/service.ts +23 -22
- package/src/modules/documents/module.ts +2 -0
- package/src/modules/documents/service.ts +74 -11
- package/src/modules/fulfillment/module.ts +2 -0
- package/src/modules/fulfillment/service.ts +17 -6
- package/src/modules/inventory/service.ts +15 -24
- package/src/modules/media/module.ts +2 -0
- package/src/modules/media/schema.ts +23 -2
- package/src/modules/media/service.ts +89 -28
- package/src/modules/orders/guest-access.ts +55 -0
- package/src/modules/orders/module.ts +1 -0
- package/src/modules/orders/quote.ts +1 -0
- package/src/modules/orders/repository/index.ts +2 -0
- package/src/modules/orders/schema.ts +5 -3
- package/src/modules/orders/service.ts +302 -52
- package/src/modules/pricing/module.ts +2 -0
- package/src/modules/pricing/schema.ts +1 -0
- package/src/modules/pricing/schemas.ts +1 -0
- package/src/modules/pricing/service.ts +21 -18
- package/src/modules/promotions/module.ts +2 -0
- package/src/modules/promotions/service.ts +25 -16
- package/src/modules/search/adapter.ts +8 -0
- package/src/modules/search/module.ts +3 -0
- package/src/modules/search/service.ts +142 -12
- package/src/modules/settings/module.ts +2 -0
- package/src/modules/settings/service.ts +8 -4
- package/src/modules/shipping/service.ts +9 -9
- package/src/modules/tax/module.ts +1 -0
- package/src/modules/tax/service.ts +13 -9
- package/src/modules/webhooks/hook.ts +2 -2
- package/src/modules/webhooks/module.ts +2 -0
- package/src/modules/webhooks/service.ts +6 -4
- package/src/runtime/server.ts +16 -2
- package/src/test-utils/create-pglite-adapter.ts +34 -12
- package/src/test-utils/create-test-config.ts +10 -6
- package/src/test-utils/rest-api-test-utils.ts +2 -0
- package/src/test-utils/test-actors.ts +2 -2
- package/src/utils/id.ts +20 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { RouterRoute } from "hono/types";
|
|
2
|
+
import { isRoutePermissionGuard } from "./utils.js";
|
|
3
|
+
|
|
4
|
+
export type PublicRoute = {
|
|
5
|
+
method: string;
|
|
6
|
+
path: string;
|
|
7
|
+
justification: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const PUBLIC_ROUTES: readonly PublicRoute[] = [
|
|
11
|
+
{ method: "GET", path: "/api/health", justification: "Load balancers need an unauthenticated liveness probe." },
|
|
12
|
+
{ method: "GET", path: "/api/reference", justification: "The development API explorer is intentionally public when enabled." },
|
|
13
|
+
{ method: "GET", path: "/api/doc", justification: "The generated OpenAPI document is public when documentation exposure is enabled." },
|
|
14
|
+
{ method: "GET", path: "/api/doc-ext", justification: "The enriched OpenAPI document is public when documentation exposure is enabled." },
|
|
15
|
+
{ method: "POST", path: "/api/carts", justification: "Anonymous storefront shoppers create secret-backed guest carts." },
|
|
16
|
+
{ method: "GET", path: "/api/carts/:id", justification: "Guest cart reads require the cart secret; customer carts require ownership in the service." },
|
|
17
|
+
{ method: "POST", path: "/api/carts/:id/items", justification: "Anonymous storefront shoppers add items to a secret-backed guest cart." },
|
|
18
|
+
{ method: "PATCH", path: "/api/carts/:id/items/:itemId", justification: "Anonymous storefront shoppers change quantities in a secret-backed guest cart." },
|
|
19
|
+
{ method: "DELETE", path: "/api/carts/:id/items/:itemId", justification: "Anonymous storefront shoppers remove items from a secret-backed guest cart." },
|
|
20
|
+
{ method: "POST", path: "/api/checkout", justification: "Anonymous storefront checkout is authorized by the customer actor and cart/payment pipeline." },
|
|
21
|
+
{ method: "GET", path: "/api/media/:id", justification: "Public media assets redirect to their configured public storage URL; signed URLs still require an actor in the handler." },
|
|
22
|
+
{ method: "POST", path: "/api/promotions/validate", justification: "Storefront shoppers validate a promotion code before checkout; the route is rate-limited." },
|
|
23
|
+
{ method: "POST", path: "/api/payments/webhook", justification: "The payment provider authenticates this endpoint with its signed webhook payload." },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
type RouteTableApp = {
|
|
27
|
+
routes: readonly RouterRoute[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type ComposedRouteHandler = {
|
|
31
|
+
__COMPOSED_HANDLER?: unknown;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function hasPermissionGuard(handler: unknown, method?: string, seen = new Set<unknown>()): boolean {
|
|
35
|
+
if (typeof handler !== "function" || seen.has(handler)) return false;
|
|
36
|
+
seen.add(handler);
|
|
37
|
+
if (isRoutePermissionGuard(handler, method)) return true;
|
|
38
|
+
const composed = (handler as unknown as ComposedRouteHandler).__COMPOSED_HANDLER;
|
|
39
|
+
return hasPermissionGuard(composed, method, seen);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function splitPath(path: string): string[] {
|
|
43
|
+
return path.split("/").filter(Boolean);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function pathPatternCovers(pattern: string, target: string): boolean {
|
|
47
|
+
const patternParts = splitPath(pattern);
|
|
48
|
+
const targetParts = splitPath(target);
|
|
49
|
+
const wildcardIndex = patternParts.indexOf("*");
|
|
50
|
+
if (wildcardIndex >= 0) {
|
|
51
|
+
if (wildcardIndex !== patternParts.length - 1 || targetParts.length < wildcardIndex) return false;
|
|
52
|
+
} else if (patternParts.length !== targetParts.length) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return patternParts.every((part, index) => {
|
|
57
|
+
if (part === "*") return true;
|
|
58
|
+
const targetPart = targetParts[index];
|
|
59
|
+
return part.startsWith(":") || part === targetPart;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function publicRouteCovers(route: RouterRoute): boolean {
|
|
64
|
+
return PUBLIC_ROUTES.some((publicRoute) =>
|
|
65
|
+
publicRoute.method === route.method && pathPatternCovers(publicRoute.path, route.path),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function routeKey(route: RouterRoute): string {
|
|
70
|
+
return `${route.method} ${route.path}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function findUncoveredRoutes(app: RouteTableApp): string[] {
|
|
74
|
+
const routes = app.routes;
|
|
75
|
+
const guardedRoutes = routes
|
|
76
|
+
.map((route, index) => ({ route, index }))
|
|
77
|
+
.filter(({ route }) => route.method === "ALL" && hasPermissionGuard(route.handler));
|
|
78
|
+
const endpoints = new Map<string, { route: RouterRoute; index: number }>();
|
|
79
|
+
|
|
80
|
+
for (const [index, route] of routes.entries()) {
|
|
81
|
+
if (route.method === "ALL") continue;
|
|
82
|
+
const key = routeKey(route);
|
|
83
|
+
if (!endpoints.has(key)) endpoints.set(key, { route, index });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return [...endpoints.values()]
|
|
87
|
+
.filter(({ route, index }) => {
|
|
88
|
+
if (publicRouteCovers(route)) return false;
|
|
89
|
+
const directlyGuarded = hasPermissionGuard(route.handler, route.method);
|
|
90
|
+
const coveredByMiddleware = guardedRoutes.some(({ route: guard, index: guardIndex }) =>
|
|
91
|
+
guardIndex <= index && pathPatternCovers(guard.path, route.path) && hasPermissionGuard(guard.handler, route.method),
|
|
92
|
+
);
|
|
93
|
+
return !directlyGuarded && !coveredByMiddleware;
|
|
94
|
+
})
|
|
95
|
+
.map(({ route }) => routeKey(route));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function assertRouteCoverage(app: RouteTableApp): void {
|
|
99
|
+
const uncovered = findUncoveredRoutes(app);
|
|
100
|
+
if (uncovered.length > 0) {
|
|
101
|
+
throw new Error(`Unclassified routes: ${uncovered.join(", ")}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -28,10 +28,11 @@
|
|
|
28
28
|
|
|
29
29
|
import { createRoute, z } from "@hono/zod-openapi";
|
|
30
30
|
import { ErrorSchema } from "./schemas/shared.js";
|
|
31
|
-
import { mapErrorToResponse, mapErrorToStatus } from "./utils.js";
|
|
31
|
+
import { mapErrorToResponse, mapErrorToStatus, markRoutePermissionGuard } from "./utils.js";
|
|
32
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
32
33
|
import type { PluginRouteRegistration } from "../../kernel/plugin/manifest.js";
|
|
33
34
|
import { createScopedDb } from "../../kernel/database/scoped-db.js";
|
|
34
|
-
import {
|
|
35
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
35
36
|
|
|
36
37
|
// ─── Shared OpenAPI Error Responses ──────────────────────────────────────────
|
|
37
38
|
|
|
@@ -61,8 +62,8 @@ export interface RouteHandlerContext {
|
|
|
61
62
|
/** Path parameters, auto-extracted from {id} segments. */
|
|
62
63
|
params: Record<string, string>;
|
|
63
64
|
/** Authenticated actor. Guaranteed non-null if .auth() or .permission() was called. */
|
|
64
|
-
actor: { userId: string; role: string; permissions: string[]; vendorId?: string | null; [key: string]: unknown } | null;
|
|
65
|
-
/** Resolved organization ID. Derived from actor.organizationId
|
|
65
|
+
actor: { userId: string | null; role: string; permissions: string[]; vendorId?: string | null; [key: string]: unknown } | null;
|
|
66
|
+
/** Resolved organization ID. Derived from actor.organizationId or the deployment config. */
|
|
66
67
|
orgId: string;
|
|
67
68
|
/** Kernel services (orders, cart, inventory, etc.) */
|
|
68
69
|
services: Record<string, unknown>;
|
|
@@ -91,7 +92,7 @@ class RouteChain {
|
|
|
91
92
|
private fullPath: string,
|
|
92
93
|
private tag: string,
|
|
93
94
|
private routesList: PluginRouteRegistration[],
|
|
94
|
-
private pluginCtx?: { services: Record<string, unknown>; db: unknown },
|
|
95
|
+
private pluginCtx?: { config?: CommerceConfig; services: Record<string, unknown>; db: unknown },
|
|
95
96
|
) {
|
|
96
97
|
const paramNames = extractPathParams(fullPath);
|
|
97
98
|
if (paramNames.length > 0) {
|
|
@@ -214,6 +215,7 @@ class RouteChain {
|
|
|
214
215
|
|
|
215
216
|
// Use plugin context if provided (plugin routes), fallback to kernel on Hono context (core routes)
|
|
216
217
|
const kernel = pluginCtx ?? (ctx.get("kernel") as {
|
|
218
|
+
config?: CommerceConfig;
|
|
217
219
|
services?: Record<string, unknown>;
|
|
218
220
|
db?: unknown;
|
|
219
221
|
} | undefined);
|
|
@@ -222,7 +224,7 @@ class RouteChain {
|
|
|
222
224
|
// Plugin route handlers receive a db that auto-filters queries
|
|
223
225
|
// and auto-stamps inserts with the actor's organizationId.
|
|
224
226
|
const rawDb = kernel?.db;
|
|
225
|
-
const orgId =
|
|
227
|
+
const orgId = resolveOrgIdForCommerce(actor, kernel?.config);
|
|
226
228
|
const scopedDb = rawDb ? createScopedDb(rawDb as Record<string, unknown>, orgId) : rawDb;
|
|
227
229
|
|
|
228
230
|
const handlerCtx: RouteHandlerContext = {
|
|
@@ -262,7 +264,10 @@ class RouteChain {
|
|
|
262
264
|
}
|
|
263
265
|
};
|
|
264
266
|
|
|
265
|
-
|
|
267
|
+
const registeredHandler = requireAuth || requiredPermission
|
|
268
|
+
? markRoutePermissionGuard(honoHandler)
|
|
269
|
+
: honoHandler;
|
|
270
|
+
this.routesList.push({ openapi: routeConfig, handler: registeredHandler as (...args: unknown[]) => unknown });
|
|
266
271
|
}
|
|
267
272
|
}
|
|
268
273
|
|
|
@@ -271,12 +276,12 @@ class RouteChain {
|
|
|
271
276
|
class RouterImpl {
|
|
272
277
|
private _routes: PluginRouteRegistration[] = [];
|
|
273
278
|
private _prefix: string;
|
|
274
|
-
private _pluginCtx: { services: Record<string, unknown>; db: unknown } | undefined;
|
|
279
|
+
private _pluginCtx: { config?: CommerceConfig; services: Record<string, unknown>; db: unknown } | undefined;
|
|
275
280
|
|
|
276
281
|
constructor(
|
|
277
282
|
private tag: string,
|
|
278
283
|
prefix: string,
|
|
279
|
-
pluginCtx?: { services?: Record<string, unknown>; database?: { db: unknown } },
|
|
284
|
+
pluginCtx?: { config?: CommerceConfig; services?: Record<string, unknown>; database?: { db: unknown } },
|
|
280
285
|
) {
|
|
281
286
|
// Normalize: ensure /api prefix, strip trailing slash
|
|
282
287
|
let p = prefix.startsWith("/api") ? prefix : `/api${prefix}`;
|
|
@@ -286,6 +291,7 @@ class RouterImpl {
|
|
|
286
291
|
// If plugin context is provided, wire services + db for handler access
|
|
287
292
|
if (pluginCtx) {
|
|
288
293
|
this._pluginCtx = {
|
|
294
|
+
...(pluginCtx.config !== undefined ? { config: pluginCtx.config } : {}),
|
|
289
295
|
services: pluginCtx.services ?? {},
|
|
290
296
|
db: pluginCtx.database?.db,
|
|
291
297
|
};
|
|
@@ -330,6 +336,6 @@ class RouterImpl {
|
|
|
330
336
|
* }
|
|
331
337
|
* ```
|
|
332
338
|
*/
|
|
333
|
-
export function router(tag: string, prefix: string, ctx?: { services?: Record<string, unknown>; database?: { db: unknown } }): RouterImpl {
|
|
339
|
+
export function router(tag: string, prefix: string, ctx?: { config?: CommerceConfig; services?: Record<string, unknown>; database?: { db: unknown } }): RouterImpl {
|
|
334
340
|
return new RouterImpl(tag, prefix, ctx);
|
|
335
341
|
}
|
|
@@ -2,14 +2,14 @@ import { OpenAPIHono } from "@hono/zod-openapi";
|
|
|
2
2
|
import type { Kernel } from "../../../../runtime/kernel.js";
|
|
3
3
|
import type { Actor } from "../../../../auth/types.js";
|
|
4
4
|
import { assertPermission } from "../../../../auth/permissions.js";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveOrgIdForCommerce } from "../../../../auth/org.js";
|
|
6
6
|
import { CommerceValidationError } from "../../../../kernel/errors.js";
|
|
7
7
|
import type { CompensationFailure } from "../../../../kernel/compensation/schema.js";
|
|
8
8
|
import {
|
|
9
9
|
listCompensationFailuresRoute,
|
|
10
10
|
resolveCompensationFailureRoute,
|
|
11
11
|
} from "../../schemas/compensation-failures.js";
|
|
12
|
-
import { type AppEnv, mapErrorToResponse, mapErrorToStatus } from "../../utils.js";
|
|
12
|
+
import { type AppEnv, mapErrorToResponse, mapErrorToStatus, requirePerm } from "../../utils.js";
|
|
13
13
|
|
|
14
14
|
function toIso(d: Date | null | undefined): string | null {
|
|
15
15
|
if (d == null) return null;
|
|
@@ -67,11 +67,14 @@ function parseResolvedFilter(
|
|
|
67
67
|
export function compensationFailureAdminRoutes(kernel: Kernel) {
|
|
68
68
|
const router = new OpenAPIHono<AppEnv>();
|
|
69
69
|
|
|
70
|
+
router.use("/compensation-failures", requirePerm("compensation:admin"));
|
|
71
|
+
router.use("/compensation-failures/*", requirePerm("compensation:admin"));
|
|
72
|
+
|
|
70
73
|
// @ts-expect-error -- openapi handler union return type
|
|
71
74
|
router.openapi(listCompensationFailuresRoute, async (c) => {
|
|
72
75
|
const actor = c.get("actor");
|
|
73
76
|
assertPermission(actor, "compensation:admin");
|
|
74
|
-
const orgId =
|
|
77
|
+
const orgId = resolveOrgIdForCommerce(actor, kernel.config);
|
|
75
78
|
const resolvedParsed = parseResolvedFilter(c.req.query("resolved"));
|
|
76
79
|
if (!resolvedParsed.ok) {
|
|
77
80
|
return c.json(
|
|
@@ -116,7 +119,7 @@ export function compensationFailureAdminRoutes(kernel: Kernel) {
|
|
|
116
119
|
router.openapi(resolveCompensationFailureRoute, async (c) => {
|
|
117
120
|
const actor = c.get("actor");
|
|
118
121
|
assertPermission(actor, "compensation:admin");
|
|
119
|
-
const orgId =
|
|
122
|
+
const orgId = resolveOrgIdForCommerce(actor, kernel.config);
|
|
120
123
|
const id = c.req.param("id");
|
|
121
124
|
const body = c.req.valid("json");
|
|
122
125
|
|
|
@@ -147,7 +150,7 @@ export function compensationFailureAdminRoutes(kernel: Kernel) {
|
|
|
147
150
|
const resolved = await kernel.services.compensationFailures.markResolved({
|
|
148
151
|
id,
|
|
149
152
|
organizationId: orgId,
|
|
150
|
-
resolvedBy: (actor as Actor).userId,
|
|
153
|
+
resolvedBy: (actor as Actor).userId ?? "system",
|
|
151
154
|
...(body.notes !== undefined ? { notes: body.notes } : {}),
|
|
152
155
|
});
|
|
153
156
|
if (!resolved.ok) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import type { Kernel } from "../../../../runtime/kernel.js";
|
|
3
|
+
import { resolveOrgIdForCommerce } from "../../../../auth/org.js";
|
|
4
|
+
import {
|
|
5
|
+
listCustomFieldProposalsRoute,
|
|
6
|
+
} from "../../schemas/admin-custom-field-proposals.js";
|
|
7
|
+
import {
|
|
8
|
+
type AppEnv,
|
|
9
|
+
parsePagination,
|
|
10
|
+
requirePerm,
|
|
11
|
+
} from "../../utils.js";
|
|
12
|
+
|
|
13
|
+
export function adminCustomFieldProposalRoutes(kernel: Kernel) {
|
|
14
|
+
const router = new OpenAPIHono<AppEnv>();
|
|
15
|
+
|
|
16
|
+
router.use("/custom-field-proposals", requirePerm("catalog:update"));
|
|
17
|
+
|
|
18
|
+
router.openapi(listCustomFieldProposalsRoute, async (c) => {
|
|
19
|
+
const pagination = parsePagination(c.req.query());
|
|
20
|
+
const entityType = c.req.query("entityType");
|
|
21
|
+
const result = await kernel.services.catalog.repository.listProposedCustomFields(
|
|
22
|
+
resolveOrgIdForCommerce(c.get("actor"), kernel.config),
|
|
23
|
+
pagination,
|
|
24
|
+
entityType !== undefined ? { entityType } : undefined,
|
|
25
|
+
);
|
|
26
|
+
return c.json({
|
|
27
|
+
data: {
|
|
28
|
+
items: result.items,
|
|
29
|
+
total: result.total,
|
|
30
|
+
page: pagination.page,
|
|
31
|
+
limit: pagination.limit,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return router;
|
|
37
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import type { Kernel } from "../../../../runtime/kernel.js";
|
|
3
|
+
import type {
|
|
4
|
+
CreateEntityFieldDefinitionInput,
|
|
5
|
+
UpdateEntityFieldDefinitionInput,
|
|
6
|
+
} from "../../../../modules/catalog/service.js";
|
|
7
|
+
import {
|
|
8
|
+
archiveEntityFieldDefinitionRoute,
|
|
9
|
+
createEntityFieldDefinitionRoute,
|
|
10
|
+
listEntityFieldDefinitionsRoute,
|
|
11
|
+
updateEntityFieldDefinitionRoute,
|
|
12
|
+
} from "../../schemas/admin-entity-field-definitions.js";
|
|
13
|
+
import {
|
|
14
|
+
type AppEnv,
|
|
15
|
+
mapErrorToResponse,
|
|
16
|
+
mapErrorToStatus,
|
|
17
|
+
requirePerm,
|
|
18
|
+
} from "../../utils.js";
|
|
19
|
+
|
|
20
|
+
export function adminEntityFieldDefinitionRoutes(kernel: Kernel) {
|
|
21
|
+
const router = new OpenAPIHono<AppEnv>();
|
|
22
|
+
|
|
23
|
+
router.use("/entity-field-definitions", requirePerm("catalog:update"));
|
|
24
|
+
router.use("/entity-field-definitions/:id", requirePerm("catalog:update"));
|
|
25
|
+
router.use(
|
|
26
|
+
"/entity-field-definitions/:id/archive",
|
|
27
|
+
requirePerm("catalog:update"),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
// @ts-expect-error -- openapi handler union return type
|
|
31
|
+
router.openapi(createEntityFieldDefinitionRoute, async (c) => {
|
|
32
|
+
const result = await kernel.services.catalog.createEntityFieldDefinition(
|
|
33
|
+
c.req.valid("json") as CreateEntityFieldDefinitionInput,
|
|
34
|
+
c.get("actor"),
|
|
35
|
+
);
|
|
36
|
+
if (!result.ok)
|
|
37
|
+
return c.json(
|
|
38
|
+
mapErrorToResponse(result.error),
|
|
39
|
+
mapErrorToStatus(result.error),
|
|
40
|
+
);
|
|
41
|
+
return c.json({ data: result.value }, 201);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// @ts-expect-error -- openapi handler union return type
|
|
45
|
+
router.openapi(listEntityFieldDefinitionsRoute, async (c) => {
|
|
46
|
+
const entityType = c.req.query("entityType");
|
|
47
|
+
const result = await kernel.services.catalog.listEntityFieldDefinitions(
|
|
48
|
+
c.get("actor"),
|
|
49
|
+
entityType,
|
|
50
|
+
);
|
|
51
|
+
if (!result.ok)
|
|
52
|
+
return c.json(
|
|
53
|
+
mapErrorToResponse(result.error),
|
|
54
|
+
mapErrorToStatus(result.error),
|
|
55
|
+
);
|
|
56
|
+
return c.json({ data: result.value });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// @ts-expect-error -- openapi handler union return type
|
|
60
|
+
router.openapi(updateEntityFieldDefinitionRoute, async (c) => {
|
|
61
|
+
const result = await kernel.services.catalog.updateEntityFieldDefinition(
|
|
62
|
+
c.req.param("id"),
|
|
63
|
+
c.req.valid("json") as UpdateEntityFieldDefinitionInput,
|
|
64
|
+
c.get("actor"),
|
|
65
|
+
);
|
|
66
|
+
if (!result.ok)
|
|
67
|
+
return c.json(
|
|
68
|
+
mapErrorToResponse(result.error),
|
|
69
|
+
mapErrorToStatus(result.error),
|
|
70
|
+
);
|
|
71
|
+
return c.json({ data: result.value });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// @ts-expect-error -- openapi handler union return type
|
|
75
|
+
router.openapi(archiveEntityFieldDefinitionRoute, async (c) => {
|
|
76
|
+
const result = await kernel.services.catalog.archiveEntityFieldDefinition(
|
|
77
|
+
c.req.param("id"),
|
|
78
|
+
c.get("actor"),
|
|
79
|
+
);
|
|
80
|
+
if (!result.ok)
|
|
81
|
+
return c.json(
|
|
82
|
+
mapErrorToResponse(result.error),
|
|
83
|
+
mapErrorToStatus(result.error),
|
|
84
|
+
);
|
|
85
|
+
return c.json({ data: result.value });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return router;
|
|
89
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { Kernel } from "../../../../runtime/kernel.js";
|
|
|
3
3
|
import type { CommerceConfig } from "../../../../config/types.js";
|
|
4
4
|
import { assertPermission } from "../../../../auth/permissions.js";
|
|
5
5
|
import { listAdminPermissionsRoute } from "../../schemas/admin-permissions.js";
|
|
6
|
-
import type
|
|
6
|
+
import { type AppEnv, requirePerm } from "../../utils.js";
|
|
7
7
|
|
|
8
8
|
function flattenCoreRolePermissions(config: CommerceConfig): string[] {
|
|
9
9
|
const roles = config.auth?.roles ?? {};
|
|
@@ -19,6 +19,8 @@ function flattenCoreRolePermissions(config: CommerceConfig): string[] {
|
|
|
19
19
|
export function adminPermissionsRoutes(kernel: Kernel) {
|
|
20
20
|
const router = new OpenAPIHono<AppEnv>();
|
|
21
21
|
|
|
22
|
+
router.use("/permissions", requirePerm("admin"));
|
|
23
|
+
|
|
22
24
|
router.openapi(listAdminPermissionsRoute, (c) => {
|
|
23
25
|
const actor = c.get("actor");
|
|
24
26
|
assertPermission(actor, "admin");
|