@porulle/core 0.11.0 → 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 +30 -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 +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -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/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.js +2 -2
- 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 +10 -2
- 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 +2 -1
- 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/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/responses.d.ts +71 -0
- package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
- 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 +14 -7
- package/dist/modules/catalog/entity-service.d.ts.map +1 -1
- package/dist/modules/catalog/entity-service.js +109 -31
- 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 +3 -2
- package/dist/modules/catalog/repository/index.d.ts.map +1 -1
- package/dist/modules/catalog/repository/index.js +14 -4
- package/dist/modules/catalog/service.d.ts +15 -13
- package/dist/modules/catalog/service.d.ts.map +1 -1
- package/dist/modules/catalog/service.js +25 -18
- 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/service.js +6 -6
- 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/service.d.ts +2 -0
- package/dist/modules/pricing/service.d.ts.map +1 -1
- package/dist/modules/pricing/service.js +12 -11
- 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 +6 -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 +1 -0
- package/dist/modules/search/service.d.ts +1 -0
- package/dist/modules/search/service.d.ts.map +1 -1
- package/dist/modules/search/service.js +57 -6
- 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/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 +29 -4
- package/src/hooks/checkout.ts +19 -12
- package/src/index.ts +16 -6
- package/src/interfaces/rest/audit-middleware.ts +2 -0
- package/src/interfaces/rest/customer-portal.ts +31 -24
- 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 +2 -2
- 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 +11 -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 +3 -1
- 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 +117 -35
- package/src/modules/catalog/read-policy.ts +16 -0
- package/src/modules/catalog/repository/index.ts +19 -3
- package/src/modules/catalog/service.ts +46 -31
- 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/service.ts +6 -6
- 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/service.ts +14 -16
- package/src/modules/promotions/module.ts +2 -0
- package/src/modules/promotions/service.ts +25 -16
- package/src/modules/search/adapter.ts +6 -0
- package/src/modules/search/module.ts +1 -0
- package/src/modules/search/service.ts +55 -6
- 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
|
@@ -3,11 +3,11 @@ import { runAfterHooks } from "../../kernel/hooks/executor.js";
|
|
|
3
3
|
import { createHookContext } from "../../kernel/hooks/create-context.js";
|
|
4
4
|
import { Err, Ok } from "../../kernel/result.js";
|
|
5
5
|
import { createLogger } from "../../utils/logger.js";
|
|
6
|
-
import { resolveOrgId } from "../../auth/org.js";
|
|
6
|
+
import { resolveOrgId, resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
7
7
|
// PromotionType is derived from the zod enum (single source of truth) in
|
|
8
8
|
// ./schemas.js; re-export it here for backwards-compatible imports.
|
|
9
9
|
import { promotionTypeEnum } from "./schemas.js";
|
|
10
|
-
function hookContext(actor, services, database, tx) {
|
|
10
|
+
function hookContext(actor, services, database, config, tx) {
|
|
11
11
|
return createHookContext({
|
|
12
12
|
actor,
|
|
13
13
|
tx,
|
|
@@ -15,6 +15,7 @@ function hookContext(actor, services, database, tx) {
|
|
|
15
15
|
services,
|
|
16
16
|
context: { moduleName: "promotions" },
|
|
17
17
|
database: { db: database.db },
|
|
18
|
+
commerceConfig: config,
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
21
|
function matchesWindow(promotion, timestamp) {
|
|
@@ -70,6 +71,12 @@ export class PromotionService {
|
|
|
70
71
|
this.catalogRepo = deps.catalogRepository;
|
|
71
72
|
this.ordersRepo = deps.ordersRepository;
|
|
72
73
|
}
|
|
74
|
+
resolveEvaluationOrgId(ctx, explicitOrgId) {
|
|
75
|
+
if (explicitOrgId) {
|
|
76
|
+
return resolveOrgId(ctx?.actor ?? null, explicitOrgId);
|
|
77
|
+
}
|
|
78
|
+
return resolveOrgIdForCommerce(ctx?.actor ?? null, this.deps.config);
|
|
79
|
+
}
|
|
73
80
|
async create(input, actor, ctx) {
|
|
74
81
|
if (!input.name) {
|
|
75
82
|
return Err(new CommerceValidationError("Promotion name is required."));
|
|
@@ -82,7 +89,7 @@ export class PromotionService {
|
|
|
82
89
|
if (!validTypes.includes(input.type)) {
|
|
83
90
|
return Err(new CommerceValidationError(`Invalid promotion type "${input.type}". Must be one of: ${validTypes.join(", ")}`));
|
|
84
91
|
}
|
|
85
|
-
const orgId =
|
|
92
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
86
93
|
if (input.code) {
|
|
87
94
|
const normalized = input.code.trim().toUpperCase();
|
|
88
95
|
const existing = await this.repo.findByCode(orgId, normalized, ctx);
|
|
@@ -109,7 +116,7 @@ export class PromotionService {
|
|
|
109
116
|
validUntil: input.validUntil ?? null,
|
|
110
117
|
}, ctx);
|
|
111
118
|
const afterHooks = this.deps.hooks.resolve("promotions.afterCreate");
|
|
112
|
-
const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
|
|
119
|
+
const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
113
120
|
await runAfterHooks(afterHooks, null, promotion, "create", hctx);
|
|
114
121
|
return Ok(promotion);
|
|
115
122
|
}
|
|
@@ -123,7 +130,8 @@ export class PromotionService {
|
|
|
123
130
|
return Err(new CommerceNotFoundError("Promotion not found."));
|
|
124
131
|
}
|
|
125
132
|
const afterHooks = this.deps.hooks.resolve("promotions.afterUpdate");
|
|
126
|
-
|
|
133
|
+
// Actor-less by design; resolves to the deployment's declared organization.
|
|
134
|
+
const hctx = hookContext(null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
127
135
|
await runAfterHooks(afterHooks, promotion, updated, "update", hctx);
|
|
128
136
|
return Ok(updated);
|
|
129
137
|
}
|
|
@@ -192,12 +200,12 @@ export class PromotionService {
|
|
|
192
200
|
return Err(new CommerceNotFoundError("Promotion not found."));
|
|
193
201
|
}
|
|
194
202
|
const afterHooks = this.deps.hooks.resolve("promotions.afterUpdate");
|
|
195
|
-
const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
|
|
203
|
+
const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
|
|
196
204
|
await runAfterHooks(afterHooks, existing, updated, "update", hctx);
|
|
197
205
|
return Ok(updated);
|
|
198
206
|
}
|
|
199
207
|
async list(filter, actor, ctx) {
|
|
200
|
-
const orgId =
|
|
208
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
201
209
|
const all = await this.repo.findAll(orgId, ctx);
|
|
202
210
|
const now = new Date();
|
|
203
211
|
if (!filter?.status)
|
|
@@ -218,7 +226,7 @@ export class PromotionService {
|
|
|
218
226
|
return Ok(sortByPriority(filtered));
|
|
219
227
|
}
|
|
220
228
|
async listActive(actor, timestamp = new Date(), ctx) {
|
|
221
|
-
const orgId =
|
|
229
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
222
230
|
const active = await this.repo.findActive(orgId, ctx);
|
|
223
231
|
// Further filter by timestamp in case repo returns slightly stale results
|
|
224
232
|
const filtered = active.filter((p) => matchesWindow(p, timestamp));
|
|
@@ -226,7 +234,7 @@ export class PromotionService {
|
|
|
226
234
|
}
|
|
227
235
|
async validate(code, context, ctx) {
|
|
228
236
|
const normalized = code.trim().toUpperCase();
|
|
229
|
-
const evalOrgId =
|
|
237
|
+
const evalOrgId = this.resolveEvaluationOrgId(ctx, context.orgId);
|
|
230
238
|
const promotion = await this.repo.findByCode(evalOrgId, normalized, ctx);
|
|
231
239
|
if (!promotion) {
|
|
232
240
|
return Err(new CommerceNotFoundError(`Promotion code ${normalized} not found.`));
|
|
@@ -251,7 +259,7 @@ export class PromotionService {
|
|
|
251
259
|
}
|
|
252
260
|
async applyPromotions(context, ctx) {
|
|
253
261
|
const timestamp = context.timestamp ?? new Date();
|
|
254
|
-
const applyOrgId =
|
|
262
|
+
const applyOrgId = this.resolveEvaluationOrgId(ctx, context.orgId);
|
|
255
263
|
const result = {
|
|
256
264
|
totalDiscount: 0,
|
|
257
265
|
freeShipping: false,
|
|
@@ -341,7 +349,7 @@ export class PromotionService {
|
|
|
341
349
|
if (!context.customerId) {
|
|
342
350
|
return "First-order promotion requires authenticated customer.";
|
|
343
351
|
}
|
|
344
|
-
const orders = await this.ordersRepo.findByCustomerId(
|
|
352
|
+
const orders = await this.ordersRepo.findByCustomerId(this.resolveEvaluationOrgId(ctx, context.orgId), context.customerId, ctx);
|
|
345
353
|
if (orders.length > 0) {
|
|
346
354
|
return "Promotion is valid for first order only.";
|
|
347
355
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Result } from "../../kernel/result.js";
|
|
2
2
|
export interface SearchDocument {
|
|
3
3
|
id: string;
|
|
4
|
+
organizationId?: string;
|
|
4
5
|
type: string;
|
|
5
6
|
slug: string;
|
|
6
7
|
title: string;
|
|
7
8
|
description?: string;
|
|
8
9
|
status?: string;
|
|
10
|
+
isVisible?: boolean;
|
|
9
11
|
categories: string[];
|
|
10
12
|
brands: string[];
|
|
11
13
|
text: string;
|
|
@@ -13,6 +15,8 @@ export interface SearchDocument {
|
|
|
13
15
|
payload?: Record<string, unknown>;
|
|
14
16
|
}
|
|
15
17
|
export interface SearchFilters {
|
|
18
|
+
/** Server-supplied tenant constraint; REST callers cannot choose this value. */
|
|
19
|
+
organizationId?: string;
|
|
16
20
|
type?: string;
|
|
17
21
|
category?: string;
|
|
18
22
|
brand?: string;
|
|
@@ -30,6 +34,8 @@ export interface SearchSuggestParams {
|
|
|
30
34
|
prefix: string;
|
|
31
35
|
type?: string;
|
|
32
36
|
limit?: number;
|
|
37
|
+
/** Server-supplied tenant constraint; REST callers cannot choose this value. */
|
|
38
|
+
organizationId?: string;
|
|
33
39
|
}
|
|
34
40
|
export interface SearchHit {
|
|
35
41
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/modules/search/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/modules/search/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;CACjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/search/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/search/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,KAAK,gBAAgB,GAAG;IACtB,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,YAAY,2GAmBxB,CAAC"}
|
|
@@ -9,6 +9,7 @@ export const searchModule = defineModule({
|
|
|
9
9
|
return new SearchService({
|
|
10
10
|
catalogRepository: deps.services.catalog.repository,
|
|
11
11
|
resolveEntityFieldDefinitions: deps.services.catalog.resolveEntityFieldDefinitions.bind(deps.services.catalog),
|
|
12
|
+
config,
|
|
12
13
|
...(config.entities ? { entities: config.entities } : {}),
|
|
13
14
|
...(config.search?.adapter ? { adapter: config.search.adapter } : {}),
|
|
14
15
|
...(config.search?.defaultFacets
|
|
@@ -6,6 +6,7 @@ import type { SearchAdapter, SearchQueryParams, SearchQueryResult, SearchSuggest
|
|
|
6
6
|
import type { EntityFieldDefinitionResolver } from "../catalog/service.js";
|
|
7
7
|
interface SearchServiceDeps {
|
|
8
8
|
catalogRepository: CatalogRepository;
|
|
9
|
+
config: CommerceConfig;
|
|
9
10
|
entities?: CommerceConfig["entities"];
|
|
10
11
|
resolveEntityFieldDefinitions?: EntityFieldDefinitionResolver;
|
|
11
12
|
adapter?: SearchAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/search/service.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/search/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACV,aAAa,EAGb,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAG3E,UAAU,iBAAiB;IACzB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,6BAA6B,CAAC,EAAE,6BAA6B,CAAC;IAC9D,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAoDD,qBAAa,aAAa;IACZ,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,iBAAiB;YAE7B,gBAAgB;YAwBhB,YAAY;YAwBZ,aAAa;YAuEb,YAAY;IAoB1B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,aAAa;IAoEf,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAcpE,KAAK,CACT,MAAM,EAAE,iBAAiB,EACzB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IA8F/B,OAAO,CACX,MAAM,EAAE,mBAAmB,EAC3B,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;CA+C7B"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Ok } from "../../kernel/result.js";
|
|
2
|
-
import {
|
|
1
|
+
import { Err, Ok } from "../../kernel/result.js";
|
|
2
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
3
|
+
import { OrgResolutionError } from "../../kernel/errors.js";
|
|
4
|
+
import { canReadUnpublishedCatalog } from "../catalog/read-policy.js";
|
|
3
5
|
function unique(values) {
|
|
4
6
|
return [...new Set(values)];
|
|
5
7
|
}
|
|
@@ -111,11 +113,13 @@ export class SearchService {
|
|
|
111
113
|
];
|
|
112
114
|
return {
|
|
113
115
|
id: entity.id,
|
|
116
|
+
organizationId: entity.organizationId,
|
|
114
117
|
type: entity.type,
|
|
115
118
|
slug: entity.slug,
|
|
116
119
|
title,
|
|
117
120
|
...(description ? { description } : {}),
|
|
118
121
|
status: entity.status,
|
|
122
|
+
isVisible: entity.isVisible,
|
|
119
123
|
categories,
|
|
120
124
|
brands,
|
|
121
125
|
text: textParts.join(" ").trim(),
|
|
@@ -126,13 +130,23 @@ export class SearchService {
|
|
|
126
130
|
};
|
|
127
131
|
}
|
|
128
132
|
async allDocuments(ctx) {
|
|
129
|
-
const
|
|
130
|
-
|
|
133
|
+
const actor = ctx?.actor;
|
|
134
|
+
if (!actor) {
|
|
135
|
+
// Deliberate exception: this needs an authenticated actor, not merely a
|
|
136
|
+
// resolvable organization, because visibility scoping is decided from the
|
|
137
|
+
// actor's permissions. A declared deployment default would satisfy the
|
|
138
|
+
// organization but not that.
|
|
139
|
+
throw new OrgResolutionError("Organization could not be resolved for a search read.");
|
|
140
|
+
}
|
|
141
|
+
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
142
|
+
const entities = await this.deps.catalogRepository.findEntities(orgId, canReadUnpublishedCatalog(actor) ? undefined : { status: "active", isVisible: true }, ctx);
|
|
131
143
|
return Promise.all(entities.map((entity) => this.buildDocument(entity, ctx)));
|
|
132
144
|
}
|
|
133
145
|
matchesFilters(document, filters) {
|
|
134
146
|
if (!filters)
|
|
135
147
|
return true;
|
|
148
|
+
if (filters.organizationId && document.organizationId !== filters.organizationId)
|
|
149
|
+
return false;
|
|
136
150
|
if (filters.type && document.type !== filters.type)
|
|
137
151
|
return false;
|
|
138
152
|
if (filters.status && document.status !== filters.status)
|
|
@@ -220,11 +234,35 @@ export class SearchService {
|
|
|
220
234
|
// Cap query length to prevent abuse / excessive processing
|
|
221
235
|
const safeQuery = (params.query ?? "").slice(0, 500);
|
|
222
236
|
if (this.deps.adapter) {
|
|
223
|
-
|
|
237
|
+
const actor = ctx?.actor ?? null;
|
|
238
|
+
// Deliberate exception: this needs an authenticated actor, not merely a
|
|
239
|
+
// resolvable organization, because visibility scoping is decided from the
|
|
240
|
+
// actor's permissions. A declared deployment default would satisfy the
|
|
241
|
+
// organization but not that.
|
|
242
|
+
if (!actor)
|
|
243
|
+
return Err(new OrgResolutionError("Organization could not be resolved for a search read."));
|
|
244
|
+
const organizationId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
245
|
+
const result = await this.deps.adapter.search({
|
|
224
246
|
...params,
|
|
225
247
|
query: safeQuery,
|
|
226
248
|
page,
|
|
227
249
|
limit,
|
|
250
|
+
filters: {
|
|
251
|
+
...params.filters,
|
|
252
|
+
organizationId,
|
|
253
|
+
...(!canReadUnpublishedCatalog(actor) ? { status: "active" } : {}),
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
if (!result.ok)
|
|
257
|
+
return result;
|
|
258
|
+
const hits = result.value.hits.filter((hit) => hit.document.organizationId === organizationId &&
|
|
259
|
+
(canReadUnpublishedCatalog(actor) ||
|
|
260
|
+
(hit.document.status === "active" && hit.document.isVisible !== false)));
|
|
261
|
+
return Ok({
|
|
262
|
+
...result.value,
|
|
263
|
+
hits,
|
|
264
|
+
total: hits.length,
|
|
265
|
+
facets: this.computeFacets(hits.map((hit) => hit.document), params.facets),
|
|
228
266
|
});
|
|
229
267
|
}
|
|
230
268
|
// In-memory fallback: require a non-empty query to avoid loading all entities
|
|
@@ -284,11 +322,24 @@ export class SearchService {
|
|
|
284
322
|
if (prefix.length === 0)
|
|
285
323
|
return Ok([]);
|
|
286
324
|
if (this.deps.adapter) {
|
|
287
|
-
|
|
325
|
+
const actor = ctx?.actor ?? null;
|
|
326
|
+
// Deliberate exception: this needs an authenticated actor, not merely a
|
|
327
|
+
// resolvable organization, because visibility scoping is decided from the
|
|
328
|
+
// actor's permissions. A declared deployment default would satisfy the
|
|
329
|
+
// organization but not that.
|
|
330
|
+
if (!actor)
|
|
331
|
+
return Err(new OrgResolutionError("Organization could not be resolved for a search read."));
|
|
332
|
+
const organizationId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
333
|
+
const result = await this.deps.adapter.suggest({
|
|
288
334
|
...params,
|
|
289
335
|
prefix,
|
|
290
336
|
limit,
|
|
337
|
+
organizationId,
|
|
291
338
|
});
|
|
339
|
+
if (!result.ok)
|
|
340
|
+
return result;
|
|
341
|
+
const visibleTitles = new Set((await this.allDocuments(ctx)).map((document) => document.title));
|
|
342
|
+
return Ok(result.value.filter((title) => visibleTitles.has(title)));
|
|
292
343
|
}
|
|
293
344
|
// In-memory fallback: require prefix >= 2 chars to avoid loading all entities
|
|
294
345
|
// (allDocuments triggers N+1 DB queries per entity — unsafe at scale)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/module.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,eAAO,MAAM,cAAc;mBACR,OAAO,aAAa;0CAWrC,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Actor } from "../../auth/types.js";
|
|
2
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
2
3
|
import type { TxContext } from "../../kernel/database/tx-context.js";
|
|
3
4
|
import { type Result } from "../../kernel/result.js";
|
|
4
5
|
import type { SettingsRepository } from "./repository/index.js";
|
|
5
6
|
interface SettingsServiceDeps {
|
|
6
7
|
repository: SettingsRepository;
|
|
8
|
+
config: CommerceConfig;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Org-scoped runtime settings (issue #49).
|
|
@@ -14,6 +16,7 @@ interface SettingsServiceDeps {
|
|
|
14
16
|
*/
|
|
15
17
|
export declare class SettingsService {
|
|
16
18
|
private repository;
|
|
19
|
+
private config;
|
|
17
20
|
constructor(deps: SettingsServiceDeps);
|
|
18
21
|
/** Runtime read for plugins/hooks. Unset groups read as `{}`. */
|
|
19
22
|
read(orgId: string, group: string, ctx?: TxContext): Promise<Record<string, unknown>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,UAAU,mBAAmB;IAC3B,UAAU,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/settings/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,UAAU,mBAAmB;IAC3B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,MAAM,CAAiB;gBAEnB,IAAI,EAAE,mBAAmB;IAKrC,iEAAiE;IAC3D,IAAI,CACR,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAK7B,QAAQ,CACZ,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAKrC,MAAM,CACV,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAQ3D,wEAAwE;IAClE,WAAW,CACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAkB5C"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import { CommerceValidationError } from "../../kernel/errors.js";
|
|
3
3
|
import { Err, Ok } from "../../kernel/result.js";
|
|
4
4
|
const GROUP_NAME_RE = /^[a-z][a-z0-9_-]*$/;
|
|
@@ -11,8 +11,10 @@ const GROUP_NAME_RE = /^[a-z][a-z0-9_-]*$/;
|
|
|
11
11
|
*/
|
|
12
12
|
export class SettingsService {
|
|
13
13
|
repository;
|
|
14
|
+
config;
|
|
14
15
|
constructor(deps) {
|
|
15
16
|
this.repository = deps.repository;
|
|
17
|
+
this.config = deps.config;
|
|
16
18
|
}
|
|
17
19
|
/** Runtime read for plugins/hooks. Unset groups read as `{}`. */
|
|
18
20
|
async read(orgId, group, ctx) {
|
|
@@ -20,11 +22,11 @@ export class SettingsService {
|
|
|
20
22
|
return row?.value ?? {};
|
|
21
23
|
}
|
|
22
24
|
async getGroup(group, actor, ctx) {
|
|
23
|
-
const orgId =
|
|
25
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
24
26
|
return Ok(await this.read(orgId, group, ctx));
|
|
25
27
|
}
|
|
26
28
|
async getAll(actor, ctx) {
|
|
27
|
-
const orgId =
|
|
29
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
28
30
|
const rows = await this.repository.findAll(orgId, ctx);
|
|
29
31
|
const all = {};
|
|
30
32
|
for (const row of rows)
|
|
@@ -36,7 +38,7 @@ export class SettingsService {
|
|
|
36
38
|
if (!GROUP_NAME_RE.test(group)) {
|
|
37
39
|
return Err(new CommerceValidationError("Settings group must match [a-z][a-z0-9_-]* (e.g. general, branding, policies)."));
|
|
38
40
|
}
|
|
39
|
-
const orgId =
|
|
41
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
40
42
|
const current = await this.read(orgId, group, ctx);
|
|
41
43
|
const next = { ...current };
|
|
42
44
|
for (const [key, value] of Object.entries(patch)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
|
|
3
3
|
import { Err, Ok } from "../../kernel/result.js";
|
|
4
4
|
import { calculateShippingCost, computeShippableWeightGrams, } from "./calculator.js";
|
|
@@ -83,7 +83,7 @@ export class ShippingService {
|
|
|
83
83
|
if (input.countries.length === 0) {
|
|
84
84
|
return Err(new CommerceValidationError("A shipping zone requires at least one country (\"*\" matches any)."));
|
|
85
85
|
}
|
|
86
|
-
const orgId =
|
|
86
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
87
87
|
const zone = await this.deps.repository.createZone({
|
|
88
88
|
organizationId: orgId,
|
|
89
89
|
name: input.name,
|
|
@@ -95,11 +95,11 @@ export class ShippingService {
|
|
|
95
95
|
return Ok(zone);
|
|
96
96
|
}
|
|
97
97
|
async listZones(actor, ctx) {
|
|
98
|
-
const orgId =
|
|
98
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
99
99
|
return Ok(await this.deps.repository.findZones(orgId, ctx));
|
|
100
100
|
}
|
|
101
101
|
async updateZone(id, patch, actor, ctx) {
|
|
102
|
-
const orgId =
|
|
102
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
103
103
|
const existing = await this.deps.repository.findZoneById(orgId, id, ctx);
|
|
104
104
|
if (!existing)
|
|
105
105
|
return Err(new CommerceNotFoundError("Shipping zone not found."));
|
|
@@ -117,7 +117,7 @@ export class ShippingService {
|
|
|
117
117
|
return Ok(updated);
|
|
118
118
|
}
|
|
119
119
|
async deleteZone(id, actor, ctx) {
|
|
120
|
-
const orgId =
|
|
120
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
121
121
|
const existing = await this.deps.repository.findZoneById(orgId, id, ctx);
|
|
122
122
|
if (!existing)
|
|
123
123
|
return Err(new CommerceNotFoundError("Shipping zone not found."));
|
|
@@ -125,7 +125,7 @@ export class ShippingService {
|
|
|
125
125
|
return Ok({ deleted: true });
|
|
126
126
|
}
|
|
127
127
|
async createRate(input, actor, ctx) {
|
|
128
|
-
const orgId =
|
|
128
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
129
129
|
const zone = await this.deps.repository.findZoneById(orgId, input.zoneId, ctx);
|
|
130
130
|
if (!zone)
|
|
131
131
|
return Err(new CommerceNotFoundError("Shipping zone not found."));
|
|
@@ -145,11 +145,11 @@ export class ShippingService {
|
|
|
145
145
|
return Ok(rate);
|
|
146
146
|
}
|
|
147
147
|
async listRates(filter, actor, ctx) {
|
|
148
|
-
const orgId =
|
|
148
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
149
149
|
return Ok(await this.deps.repository.findRates(orgId, filter?.zoneId !== undefined ? { zoneId: filter.zoneId } : undefined, ctx));
|
|
150
150
|
}
|
|
151
151
|
async updateRate(id, patch, actor, ctx) {
|
|
152
|
-
const orgId =
|
|
152
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
153
153
|
const existing = await this.deps.repository.findRateById(orgId, id, ctx);
|
|
154
154
|
if (!existing)
|
|
155
155
|
return Err(new CommerceNotFoundError("Shipping rate not found."));
|
|
@@ -169,7 +169,7 @@ export class ShippingService {
|
|
|
169
169
|
return Ok(updated);
|
|
170
170
|
}
|
|
171
171
|
async deleteRate(id, actor, ctx) {
|
|
172
|
-
const orgId =
|
|
172
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
|
|
173
173
|
const existing = await this.deps.repository.findRateById(orgId, id, ctx);
|
|
174
174
|
if (!existing)
|
|
175
175
|
return Err(new CommerceNotFoundError("Shipping rate not found."));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/tax/module.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,eAAO,MAAM,SAAS;cACR,OAAO,QAAQ;gBAAc,OAAO,UAAU;
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/tax/module.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,eAAO,MAAM,SAAS;cACR,OAAO,QAAQ;gBAAc,OAAO,UAAU;qCAY1D,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Actor } from "../../auth/types.js";
|
|
2
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
2
3
|
import type { TxContext } from "../../kernel/database/tx-context.js";
|
|
3
4
|
import { type Result } from "../../kernel/result.js";
|
|
4
5
|
import type { TaxAdapter, TaxCalculationParams, TaxCalculationResult, TaxReportParams, TaxVoidParams } from "./adapter.js";
|
|
@@ -6,10 +7,12 @@ import type { TaxClass, TaxRate, TaxRatesRepository } from "./repository/index.j
|
|
|
6
7
|
interface TaxServiceDeps {
|
|
7
8
|
adapter: TaxAdapter | undefined;
|
|
8
9
|
repository?: TaxRatesRepository;
|
|
10
|
+
config: CommerceConfig;
|
|
9
11
|
}
|
|
10
12
|
export declare class TaxService {
|
|
11
13
|
private adapter;
|
|
12
14
|
private repository;
|
|
15
|
+
private config;
|
|
13
16
|
constructor(deps: TaxServiceDeps);
|
|
14
17
|
/**
|
|
15
18
|
* Calculates tax. Resolution order:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/tax/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEnF,UAAU,cAAc;IACtB,OAAO,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,UAAU,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/tax/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
|
|
3
3
|
import { Err, Ok } from "../../kernel/result.js";
|
|
4
4
|
export class TaxService {
|
|
5
5
|
adapter;
|
|
6
6
|
repository;
|
|
7
|
+
config;
|
|
7
8
|
constructor(deps) {
|
|
8
9
|
this.adapter = deps.adapter;
|
|
9
10
|
this.repository = deps.repository;
|
|
11
|
+
this.config = deps.config;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Calculates tax. Resolution order:
|
|
@@ -117,7 +119,7 @@ export class TaxService {
|
|
|
117
119
|
if (input.rateBps < 0) {
|
|
118
120
|
return Err(new CommerceValidationError("rateBps must be non-negative."));
|
|
119
121
|
}
|
|
120
|
-
const orgId =
|
|
122
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
121
123
|
if (input.isDefault)
|
|
122
124
|
await repo.value.clearDefaultClass(orgId, ctx);
|
|
123
125
|
const created = await repo.value.createClass({
|
|
@@ -133,14 +135,14 @@ export class TaxService {
|
|
|
133
135
|
const repo = this.requireRepository();
|
|
134
136
|
if (!repo.ok)
|
|
135
137
|
return repo;
|
|
136
|
-
const orgId =
|
|
138
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
137
139
|
return Ok(await repo.value.findAllClasses(orgId, ctx));
|
|
138
140
|
}
|
|
139
141
|
async updateTaxClass(id, patch, actor, ctx) {
|
|
140
142
|
const repo = this.requireRepository();
|
|
141
143
|
if (!repo.ok)
|
|
142
144
|
return repo;
|
|
143
|
-
const orgId =
|
|
145
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
144
146
|
const existing = await repo.value.findClassById(orgId, id, ctx);
|
|
145
147
|
if (!existing)
|
|
146
148
|
return Err(new CommerceNotFoundError("Tax class not found."));
|
|
@@ -158,7 +160,7 @@ export class TaxService {
|
|
|
158
160
|
const repo = this.requireRepository();
|
|
159
161
|
if (!repo.ok)
|
|
160
162
|
return repo;
|
|
161
|
-
const orgId =
|
|
163
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
162
164
|
const existing = await repo.value.findClassById(orgId, id, ctx);
|
|
163
165
|
if (!existing)
|
|
164
166
|
return Err(new CommerceNotFoundError("Tax class not found."));
|
|
@@ -207,7 +209,7 @@ export class TaxService {
|
|
|
207
209
|
if (input.rateBps < 0) {
|
|
208
210
|
return Err(new CommerceValidationError("rateBps must be non-negative."));
|
|
209
211
|
}
|
|
210
|
-
const orgId =
|
|
212
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
211
213
|
const rate = await repo.value.create({
|
|
212
214
|
organizationId: orgId,
|
|
213
215
|
name: input.name,
|
|
@@ -224,14 +226,14 @@ export class TaxService {
|
|
|
224
226
|
const repo = this.requireRepository();
|
|
225
227
|
if (!repo.ok)
|
|
226
228
|
return repo;
|
|
227
|
-
const orgId =
|
|
229
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
228
230
|
return Ok(await repo.value.findAll(orgId, ctx));
|
|
229
231
|
}
|
|
230
232
|
async updateTaxRate(id, patch, actor, ctx) {
|
|
231
233
|
const repo = this.requireRepository();
|
|
232
234
|
if (!repo.ok)
|
|
233
235
|
return repo;
|
|
234
|
-
const orgId =
|
|
236
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
235
237
|
const existing = await repo.value.findById(orgId, id, ctx);
|
|
236
238
|
if (!existing)
|
|
237
239
|
return Err(new CommerceNotFoundError("Tax rate not found."));
|
|
@@ -252,7 +254,7 @@ export class TaxService {
|
|
|
252
254
|
const repo = this.requireRepository();
|
|
253
255
|
if (!repo.ok)
|
|
254
256
|
return repo;
|
|
255
|
-
const orgId =
|
|
257
|
+
const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
|
|
256
258
|
const existing = await repo.value.findById(orgId, id, ctx);
|
|
257
259
|
if (!existing)
|
|
258
260
|
return Err(new CommerceNotFoundError("Tax rate not found."));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveOrgIdForCommerce } from "../../auth/org.js";
|
|
2
2
|
/**
|
|
3
3
|
* Webhook delivery hook — enqueues delivery jobs instead of blocking.
|
|
4
4
|
*
|
|
@@ -15,7 +15,7 @@ export const deliverWebhooks = async ({ result, operation, context }) => {
|
|
|
15
15
|
// VAPT r2 (codex) finding: fan-out queried ALL endpoints across the
|
|
16
16
|
// database, so Tenant B's webhooks fired on Tenant A's events —
|
|
17
17
|
// payload-level cross-tenant data leak. Now scoped to the actor's org.
|
|
18
|
-
const orgId =
|
|
18
|
+
const orgId = resolveOrgIdForCommerce(context.actor, context.commerceConfig);
|
|
19
19
|
const endpoints = await webhooksService.getEndpointsForEvent(eventName, orgId);
|
|
20
20
|
if (!endpoints.ok)
|
|
21
21
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/webhooks/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/webhooks/module.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAO9C,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAYzB,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Actor } from "../../auth/types.js";
|
|
2
|
+
import type { CommerceConfig } from "../../config/types.js";
|
|
2
3
|
import { type Result } from "../../kernel/result.js";
|
|
3
4
|
import type { TxContext } from "../../kernel/database/tx-context.js";
|
|
4
5
|
import type { WebhooksRepository, WebhookEndpoint } from "./repository/index.js";
|
|
5
6
|
interface WebhookServiceDeps {
|
|
6
7
|
repository: WebhooksRepository;
|
|
8
|
+
config: CommerceConfig;
|
|
7
9
|
}
|
|
8
10
|
export declare class WebhookService {
|
|
9
11
|
private deps;
|