@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommerceConfig } from "../../config/types.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
3
3
|
import type { Actor } from "../../auth/types.js";
|
|
4
4
|
import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
|
|
5
5
|
import { Err, Ok, type Result } from "../../kernel/result.js";
|
|
@@ -147,7 +147,7 @@ export class ShippingService {
|
|
|
147
147
|
if (input.countries.length === 0) {
|
|
148
148
|
return Err(new CommerceValidationError("A shipping zone requires at least one country (\"*\" matches any)."));
|
|
149
149
|
}
|
|
150
|
-
const orgId =
|
|
150
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
151
151
|
const zone = await this.deps.repository.createZone(
|
|
152
152
|
{
|
|
153
153
|
organizationId: orgId,
|
|
@@ -163,7 +163,7 @@ export class ShippingService {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
async listZones(actor?: Actor | null, ctx?: TxContext): Promise<Result<ShippingZone[]>> {
|
|
166
|
-
const orgId =
|
|
166
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
167
167
|
return Ok(await this.deps.repository.findZones(orgId, ctx));
|
|
168
168
|
}
|
|
169
169
|
|
|
@@ -179,7 +179,7 @@ export class ShippingService {
|
|
|
179
179
|
actor?: Actor | null,
|
|
180
180
|
ctx?: TxContext,
|
|
181
181
|
): Promise<Result<ShippingZone>> {
|
|
182
|
-
const orgId =
|
|
182
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
183
183
|
const existing = await this.deps.repository.findZoneById(orgId, id, ctx);
|
|
184
184
|
if (!existing) return Err(new CommerceNotFoundError("Shipping zone not found."));
|
|
185
185
|
const updated = await this.deps.repository.updateZone(
|
|
@@ -201,7 +201,7 @@ export class ShippingService {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
async deleteZone(id: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<{ deleted: true }>> {
|
|
204
|
-
const orgId =
|
|
204
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
205
205
|
const existing = await this.deps.repository.findZoneById(orgId, id, ctx);
|
|
206
206
|
if (!existing) return Err(new CommerceNotFoundError("Shipping zone not found."));
|
|
207
207
|
await this.deps.repository.deleteZone(id, ctx);
|
|
@@ -224,7 +224,7 @@ export class ShippingService {
|
|
|
224
224
|
actor?: Actor | null,
|
|
225
225
|
ctx?: TxContext,
|
|
226
226
|
): Promise<Result<ShippingRate>> {
|
|
227
|
-
const orgId =
|
|
227
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
228
228
|
const zone = await this.deps.repository.findZoneById(orgId, input.zoneId, ctx);
|
|
229
229
|
if (!zone) return Err(new CommerceNotFoundError("Shipping zone not found."));
|
|
230
230
|
const rate = await this.deps.repository.createRate(
|
|
@@ -251,7 +251,7 @@ export class ShippingService {
|
|
|
251
251
|
actor?: Actor | null,
|
|
252
252
|
ctx?: TxContext,
|
|
253
253
|
): Promise<Result<ShippingRate[]>> {
|
|
254
|
-
const orgId =
|
|
254
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
255
255
|
return Ok(
|
|
256
256
|
await this.deps.repository.findRates(
|
|
257
257
|
orgId,
|
|
@@ -277,7 +277,7 @@ export class ShippingService {
|
|
|
277
277
|
actor?: Actor | null,
|
|
278
278
|
ctx?: TxContext,
|
|
279
279
|
): Promise<Result<ShippingRate>> {
|
|
280
|
-
const orgId =
|
|
280
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
281
281
|
const existing = await this.deps.repository.findRateById(orgId, id, ctx);
|
|
282
282
|
if (!existing) return Err(new CommerceNotFoundError("Shipping rate not found."));
|
|
283
283
|
const updated = await this.deps.repository.updateRate(
|
|
@@ -301,7 +301,7 @@ export class ShippingService {
|
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
async deleteRate(id: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<{ deleted: true }>> {
|
|
304
|
-
const orgId =
|
|
304
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
305
305
|
const existing = await this.deps.repository.findRateById(orgId, id, ctx);
|
|
306
306
|
if (!existing) return Err(new CommerceNotFoundError("Shipping rate not found."));
|
|
307
307
|
await this.deps.repository.deleteRate(id, ctx);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import type { Actor } from "../../auth/types.js";
|
|
3
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
3
4
|
import type { TxContext } from "../../kernel/database/tx-context.js";
|
|
4
5
|
import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
|
|
5
6
|
import { Err, Ok, type Result } from "../../kernel/result.js";
|
|
@@ -15,15 +16,18 @@ import type { TaxClass, TaxRate, TaxRatesRepository } from "./repository/index.j
|
|
|
15
16
|
interface TaxServiceDeps {
|
|
16
17
|
adapter: TaxAdapter | undefined;
|
|
17
18
|
repository?: TaxRatesRepository;
|
|
19
|
+
config: CommerceConfig;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export class TaxService {
|
|
21
23
|
private adapter: TaxAdapter | undefined;
|
|
22
24
|
private repository: TaxRatesRepository | undefined;
|
|
25
|
+
private config: CommerceConfig;
|
|
23
26
|
|
|
24
27
|
constructor(deps: TaxServiceDeps) {
|
|
25
28
|
this.adapter = deps.adapter;
|
|
26
29
|
this.repository = deps.repository;
|
|
30
|
+
this.config = deps.config;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
/**
|
|
@@ -176,7 +180,7 @@ export class TaxService {
|
|
|
176
180
|
if (input.rateBps < 0) {
|
|
177
181
|
return Err(new CommerceValidationError("rateBps must be non-negative."));
|
|
178
182
|
}
|
|
179
|
-
const orgId =
|
|
183
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
180
184
|
if (input.isDefault) await repo.value.clearDefaultClass(orgId, ctx);
|
|
181
185
|
const created = await repo.value.createClass(
|
|
182
186
|
{
|
|
@@ -194,7 +198,7 @@ export class TaxService {
|
|
|
194
198
|
async listTaxClasses(actor?: Actor | null, ctx?: TxContext): Promise<Result<TaxClass[]>> {
|
|
195
199
|
const repo = this.requireRepository();
|
|
196
200
|
if (!repo.ok) return repo;
|
|
197
|
-
const orgId =
|
|
201
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
198
202
|
return Ok(await repo.value.findAllClasses(orgId, ctx));
|
|
199
203
|
}
|
|
200
204
|
|
|
@@ -206,7 +210,7 @@ export class TaxService {
|
|
|
206
210
|
): Promise<Result<TaxClass>> {
|
|
207
211
|
const repo = this.requireRepository();
|
|
208
212
|
if (!repo.ok) return repo;
|
|
209
|
-
const orgId =
|
|
213
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
210
214
|
const existing = await repo.value.findClassById(orgId, id, ctx);
|
|
211
215
|
if (!existing) return Err(new CommerceNotFoundError("Tax class not found."));
|
|
212
216
|
if (patch.isDefault) await repo.value.clearDefaultClass(orgId, ctx);
|
|
@@ -226,7 +230,7 @@ export class TaxService {
|
|
|
226
230
|
async deleteTaxClass(id: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<{ deleted: true }>> {
|
|
227
231
|
const repo = this.requireRepository();
|
|
228
232
|
if (!repo.ok) return repo;
|
|
229
|
-
const orgId =
|
|
233
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
230
234
|
const existing = await repo.value.findClassById(orgId, id, ctx);
|
|
231
235
|
if (!existing) return Err(new CommerceNotFoundError("Tax class not found."));
|
|
232
236
|
await repo.value.deleteClass(id, ctx);
|
|
@@ -297,7 +301,7 @@ export class TaxService {
|
|
|
297
301
|
if (input.rateBps < 0) {
|
|
298
302
|
return Err(new CommerceValidationError("rateBps must be non-negative."));
|
|
299
303
|
}
|
|
300
|
-
const orgId =
|
|
304
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
301
305
|
const rate = await repo.value.create(
|
|
302
306
|
{
|
|
303
307
|
organizationId: orgId,
|
|
@@ -317,7 +321,7 @@ export class TaxService {
|
|
|
317
321
|
async listTaxRates(actor?: Actor | null, ctx?: TxContext): Promise<Result<TaxRate[]>> {
|
|
318
322
|
const repo = this.requireRepository();
|
|
319
323
|
if (!repo.ok) return repo;
|
|
320
|
-
const orgId =
|
|
324
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
321
325
|
return Ok(await repo.value.findAll(orgId, ctx));
|
|
322
326
|
}
|
|
323
327
|
|
|
@@ -337,7 +341,7 @@ export class TaxService {
|
|
|
337
341
|
): Promise<Result<TaxRate>> {
|
|
338
342
|
const repo = this.requireRepository();
|
|
339
343
|
if (!repo.ok) return repo;
|
|
340
|
-
const orgId =
|
|
344
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
341
345
|
const existing = await repo.value.findById(orgId, id, ctx);
|
|
342
346
|
if (!existing) return Err(new CommerceNotFoundError("Tax rate not found."));
|
|
343
347
|
const updated = await repo.value.update(
|
|
@@ -361,7 +365,7 @@ export class TaxService {
|
|
|
361
365
|
async deleteTaxRate(id: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<{ deleted: true }>> {
|
|
362
366
|
const repo = this.requireRepository();
|
|
363
367
|
if (!repo.ok) return repo;
|
|
364
|
-
const orgId =
|
|
368
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
365
369
|
const existing = await repo.value.findById(orgId, id, ctx);
|
|
366
370
|
if (!existing) return Err(new CommerceNotFoundError("Tax rate not found."));
|
|
367
371
|
await repo.value.delete(id, ctx);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import type { AfterHook } from "../../kernel/hooks/types.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -20,7 +20,7 @@ export const deliverWebhooks: AfterHook<unknown> = async ({ result, operation, c
|
|
|
20
20
|
// VAPT r2 (codex) finding: fan-out queried ALL endpoints across the
|
|
21
21
|
// database, so Tenant B's webhooks fired on Tenant A's events —
|
|
22
22
|
// payload-level cross-tenant data leak. Now scoped to the actor's org.
|
|
23
|
-
const orgId =
|
|
23
|
+
const orgId = resolveOrgIdForCommerce(context.actor, context.commerceConfig);
|
|
24
24
|
|
|
25
25
|
const endpoints = await webhooksService.getEndpointsForEvent(eventName, orgId);
|
|
26
26
|
if (!endpoints.ok) return;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
1
2
|
import { defineModule } from "../../kernel/module/index.js";
|
|
2
3
|
import type { DrizzleDatabase } from "../../kernel/database/drizzle-db.js";
|
|
3
4
|
import { WebhooksRepository } from "./repository/index.js";
|
|
@@ -18,5 +19,6 @@ export const webhooksModule = defineModule({
|
|
|
18
19
|
service: (deps) =>
|
|
19
20
|
new WebhookService({
|
|
20
21
|
repository: new WebhooksRepository(deps.db.db as DrizzleDatabase),
|
|
22
|
+
config: deps.config as CommerceConfig,
|
|
21
23
|
}),
|
|
22
24
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import type { Actor } from "../../auth/types.js";
|
|
3
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
3
4
|
import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
|
|
4
5
|
import { Err, Ok, type Result } from "../../kernel/result.js";
|
|
5
6
|
import type { TxContext } from "../../kernel/database/tx-context.js";
|
|
@@ -49,6 +50,7 @@ function isPrivateUrl(urlStr: string): boolean {
|
|
|
49
50
|
|
|
50
51
|
interface WebhookServiceDeps {
|
|
51
52
|
repository: WebhooksRepository;
|
|
53
|
+
config: CommerceConfig;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
export class WebhookService {
|
|
@@ -76,7 +78,7 @@ export class WebhookService {
|
|
|
76
78
|
);
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
const orgId =
|
|
81
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
80
82
|
|
|
81
83
|
const endpoint = await this.repo.createEndpoint(
|
|
82
84
|
{
|
|
@@ -96,7 +98,7 @@ export class WebhookService {
|
|
|
96
98
|
actor?: Actor | null,
|
|
97
99
|
ctx?: TxContext,
|
|
98
100
|
): Promise<Result<WebhookEndpoint[]>> {
|
|
99
|
-
const orgId =
|
|
101
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
100
102
|
const endpoints = await this.repo.findAllEndpoints(orgId, ctx);
|
|
101
103
|
return Ok(endpoints);
|
|
102
104
|
}
|
|
@@ -106,7 +108,7 @@ export class WebhookService {
|
|
|
106
108
|
actor?: Actor | null,
|
|
107
109
|
ctx?: TxContext,
|
|
108
110
|
): Promise<Result<void>> {
|
|
109
|
-
const orgId =
|
|
111
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
110
112
|
const existing = await this.repo.findEndpointById(id, orgId, ctx);
|
|
111
113
|
if (!existing) {
|
|
112
114
|
return Err(new CommerceNotFoundError("Webhook endpoint not found."));
|
package/src/runtime/server.ts
CHANGED
|
@@ -11,6 +11,8 @@ import type { Actor } from "../auth/types.js";
|
|
|
11
11
|
import type { AuthInstance } from "../auth/setup.js";
|
|
12
12
|
import type { CommerceConfig } from "../config/types.js";
|
|
13
13
|
import { authMiddleware } from "../auth/middleware.js";
|
|
14
|
+
import { organizationGuard } from "../auth/organization-guard.js";
|
|
15
|
+
import type { DrizzleDatabase } from "../kernel/database/drizzle-db.js";
|
|
14
16
|
import { CommerceCsrfError } from "../kernel/errors.js";
|
|
15
17
|
import { createRestRoutes } from "../interfaces/rest/index.js";
|
|
16
18
|
import { createCustomerPortalRoutes } from "../interfaces/rest/customer-portal.js";
|
|
@@ -20,6 +22,8 @@ import { createLogger, type Logger } from "./logger.js";
|
|
|
20
22
|
import { createCommerce, type CommerceInstance } from "./commerce.js";
|
|
21
23
|
import { rewriteCommerceAliasRequest } from "./url-alias-rewrite.js";
|
|
22
24
|
import { mapErrorToResponse } from "../kernel/error-mapper.js";
|
|
25
|
+
import { assertRouteCoverage } from "../interfaces/rest/route-coverage.js";
|
|
26
|
+
import { markRoutePermissionGuard } from "../interfaces/rest/utils.js";
|
|
23
27
|
|
|
24
28
|
type ServerEnv = {
|
|
25
29
|
Variables: {
|
|
@@ -320,6 +324,14 @@ export async function createServer(config: CommerceConfig) {
|
|
|
320
324
|
}
|
|
321
325
|
|
|
322
326
|
// ─── Auth ──────────────────────────────────────────────────────────
|
|
327
|
+
// Better Auth's organization endpoints are mounted below but governed here:
|
|
328
|
+
// `admin/staff.ts` owns membership, and this guard keeps the plugin's own
|
|
329
|
+
// paths from minting members outside those rules.
|
|
330
|
+
app.use(
|
|
331
|
+
"/api/auth/organization/*",
|
|
332
|
+
organizationGuard(kernel.database.db as DrizzleDatabase, config),
|
|
333
|
+
);
|
|
334
|
+
|
|
323
335
|
app.use("/api/auth/*", async (c, next) => {
|
|
324
336
|
if (c.req.path.startsWith("/api/auth/pos/")) {
|
|
325
337
|
await next();
|
|
@@ -433,7 +445,7 @@ export async function createServer(config: CommerceConfig) {
|
|
|
433
445
|
// Strategy 1: Built-in cron endpoint for serverless deployments.
|
|
434
446
|
// Point Vercel Cron or Cloudflare Cron Trigger at GET /api/jobs/run
|
|
435
447
|
// Optional query params: ?queue=emails&limit=20
|
|
436
|
-
app.get("/api/jobs/run", async (c) => {
|
|
448
|
+
app.get("/api/jobs/run", markRoutePermissionGuard(async (c) => {
|
|
437
449
|
// Always require admin — cron triggers must authenticate
|
|
438
450
|
const actor = c.get("actor") as { permissions?: string[] } | null;
|
|
439
451
|
if (!actor?.permissions?.includes("*:*")) {
|
|
@@ -450,7 +462,7 @@ export async function createServer(config: CommerceConfig) {
|
|
|
450
462
|
logger.error({ err }, "Job runner endpoint failed");
|
|
451
463
|
return c.json({ error: { code: "INTERNAL_ERROR", message: "Job processing failed" } }, 500);
|
|
452
464
|
}
|
|
453
|
-
});
|
|
465
|
+
}));
|
|
454
466
|
|
|
455
467
|
// Strategy 2: In-process polling for long-running servers (ECS, Cloud Run, Docker).
|
|
456
468
|
// Enable via config.jobs.autorun.enabled = true
|
|
@@ -488,6 +500,8 @@ export async function createServer(config: CommerceConfig) {
|
|
|
488
500
|
}
|
|
489
501
|
}
|
|
490
502
|
|
|
503
|
+
assertRouteCoverage(app);
|
|
504
|
+
|
|
491
505
|
const dispatchFetch = app.fetch.bind(app);
|
|
492
506
|
app.fetch = ((input: RequestInfo | URL, env?: unknown, executionCtx?: unknown) => {
|
|
493
507
|
const req = input instanceof Request ? input : new Request(input);
|
|
@@ -82,20 +82,42 @@ export async function createPGliteTestAdapter(): Promise<{
|
|
|
82
82
|
/**
|
|
83
83
|
* PGlite-compatible transaction wrapper.
|
|
84
84
|
*
|
|
85
|
-
* Drizzle's transaction() method can hang with PGlite due to how
|
|
86
|
-
*
|
|
87
|
-
*
|
|
85
|
+
* Drizzle's transaction() method can hang with PGlite due to how the adapter
|
|
86
|
+
* manages transaction state, so this drives BEGIN/COMMIT manually.
|
|
87
|
+
*
|
|
88
|
+
* PGlite is a single connection, so two transaction bodies awaiting
|
|
89
|
+
* concurrently would otherwise interleave their statements between one
|
|
90
|
+
* BEGIN and one COMMIT — the second BEGIN is a no-op Postgres only warns
|
|
91
|
+
* about. Merged that way, two callers share a snapshot and hold each other's
|
|
92
|
+
* row locks, so an isolation bug reads as if the guard failed. Bodies are
|
|
93
|
+
* queued instead, which is what a connection pool would do to two
|
|
94
|
+
* transactions competing for the same rows.
|
|
95
|
+
*
|
|
96
|
+
* A nested call joins the transaction already open rather than deadlocking
|
|
97
|
+
* on the queue; without savepoints that is the only sound reading.
|
|
88
98
|
*/
|
|
99
|
+
let transactionQueue: Promise<unknown> = Promise.resolve();
|
|
100
|
+
let inTransaction = false;
|
|
101
|
+
|
|
89
102
|
async function transaction<T>(fn: (tx: unknown) => Promise<T>): Promise<T> {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
if (inTransaction) return fn(db);
|
|
104
|
+
|
|
105
|
+
const run = transactionQueue.then(async () => {
|
|
106
|
+
inTransaction = true;
|
|
107
|
+
await pg.exec("BEGIN");
|
|
108
|
+
try {
|
|
109
|
+
const result = await fn(db);
|
|
110
|
+
await pg.exec("COMMIT");
|
|
111
|
+
return result;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
await pg.exec("ROLLBACK");
|
|
114
|
+
throw error;
|
|
115
|
+
} finally {
|
|
116
|
+
inTransaction = false;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
transactionQueue = run.catch(() => undefined);
|
|
120
|
+
return run as Promise<T>;
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
const adapter: DatabaseAdapter = {
|
|
@@ -78,11 +78,13 @@ export async function createTestConfig(
|
|
|
78
78
|
"catalog:update",
|
|
79
79
|
"catalog:delete",
|
|
80
80
|
"catalog:read",
|
|
81
|
+
"catalog:read:unpublished",
|
|
81
82
|
"inventory:adjust",
|
|
82
83
|
"orders:create",
|
|
83
84
|
"orders:read",
|
|
84
85
|
"orders:update",
|
|
85
86
|
"orders:manage",
|
|
87
|
+
"orders:create:on-behalf",
|
|
86
88
|
"cart:create",
|
|
87
89
|
"cart:update",
|
|
88
90
|
"customers:update:self",
|
|
@@ -91,14 +93,16 @@ export async function createTestConfig(
|
|
|
91
93
|
ai_agent: {
|
|
92
94
|
permissions: [
|
|
93
95
|
"catalog:read",
|
|
96
|
+
"catalog:read:unpublished",
|
|
94
97
|
"catalog:create",
|
|
95
98
|
"inventory:read",
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
"inventory:adjust",
|
|
100
|
+
"orders:read",
|
|
101
|
+
"orders:create:on-behalf",
|
|
102
|
+
"cart:create",
|
|
103
|
+
"cart:update",
|
|
104
|
+
],
|
|
105
|
+
},
|
|
102
106
|
},
|
|
103
107
|
customerPermissions: [
|
|
104
108
|
"catalog:read",
|
|
@@ -158,9 +158,11 @@ export const testActor: Actor = {
|
|
|
158
158
|
"catalog:create",
|
|
159
159
|
"catalog:update",
|
|
160
160
|
"catalog:read",
|
|
161
|
+
"catalog:read:unpublished",
|
|
161
162
|
"inventory:adjust",
|
|
162
163
|
"inventory:read",
|
|
163
164
|
"orders:create",
|
|
165
|
+
"orders:create:on-behalf",
|
|
164
166
|
"orders:read",
|
|
165
167
|
"orders:update",
|
|
166
168
|
"orders:manage",
|
|
@@ -31,8 +31,8 @@ export const testStaffActor: Actor = {
|
|
|
31
31
|
organizationId: TEST_ORG_ID,
|
|
32
32
|
role: "staff",
|
|
33
33
|
permissions: [
|
|
34
|
-
"catalog:read", "catalog:create", "catalog:update",
|
|
35
|
-
"inventory:adjust", "orders:read", "orders:create", "orders:update", "orders:manage",
|
|
34
|
+
"catalog:read", "catalog:read:unpublished", "catalog:create", "catalog:update",
|
|
35
|
+
"inventory:adjust", "orders:read", "orders:create", "orders:create:on-behalf", "orders:update", "orders:manage",
|
|
36
36
|
],
|
|
37
37
|
};
|
|
38
38
|
|
package/src/utils/id.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Actor } from "../auth/types.js";
|
|
2
|
+
|
|
1
3
|
export function makeId(): string {
|
|
2
4
|
return crypto.randomUUID();
|
|
3
5
|
}
|
|
@@ -12,3 +14,21 @@ export async function makeDeterministicId(value: string): Promise<string> {
|
|
|
12
14
|
const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
13
15
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
14
16
|
}
|
|
17
|
+
|
|
18
|
+
export async function makeIdempotencyScope(
|
|
19
|
+
actor: Actor | null | undefined,
|
|
20
|
+
guestCredential?: string,
|
|
21
|
+
fallbackBinding?: string,
|
|
22
|
+
): Promise<string> {
|
|
23
|
+
const binding = actor?.userId
|
|
24
|
+
? `actor:${actor.type}:${actor.userId}`
|
|
25
|
+
: guestCredential
|
|
26
|
+
? `guest:${guestCredential}`
|
|
27
|
+
: fallbackBinding
|
|
28
|
+
? `resource:${fallbackBinding}`
|
|
29
|
+
: "anonymous";
|
|
30
|
+
const digest = new Uint8Array(
|
|
31
|
+
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(binding)),
|
|
32
|
+
);
|
|
33
|
+
return [...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
34
|
+
}
|