@porulle/core 0.11.0 → 0.14.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.
Files changed (300) hide show
  1. package/dist/auth/actor.d.ts +10 -0
  2. package/dist/auth/actor.d.ts.map +1 -0
  3. package/dist/auth/actor.js +91 -0
  4. package/dist/auth/auth-schema-guard.d.ts +2444 -0
  5. package/dist/auth/auth-schema-guard.d.ts.map +1 -0
  6. package/dist/auth/auth-schema-guard.js +113 -0
  7. package/dist/auth/auth-schema.d.ts +228 -0
  8. package/dist/auth/auth-schema.d.ts.map +1 -1
  9. package/dist/auth/auth-schema.js +24 -2
  10. package/dist/auth/middleware.d.ts +1 -0
  11. package/dist/auth/middleware.d.ts.map +1 -1
  12. package/dist/auth/middleware.js +16 -92
  13. package/dist/auth/org.d.ts +8 -2
  14. package/dist/auth/org.d.ts.map +1 -1
  15. package/dist/auth/org.js +12 -4
  16. package/dist/auth/organization-guard.d.ts +5 -0
  17. package/dist/auth/organization-guard.d.ts.map +1 -0
  18. package/dist/auth/organization-guard.js +124 -0
  19. package/dist/auth/permissions.d.ts +10 -0
  20. package/dist/auth/permissions.d.ts.map +1 -1
  21. package/dist/auth/permissions.js +31 -7
  22. package/dist/auth/role-authority.d.ts +44 -0
  23. package/dist/auth/role-authority.d.ts.map +1 -0
  24. package/dist/auth/role-authority.js +85 -0
  25. package/dist/auth/setup.d.ts.map +1 -1
  26. package/dist/auth/setup.js +19 -1
  27. package/dist/auth/strict-org-resolution.d.ts.map +1 -1
  28. package/dist/auth/strict-org-resolution.js +9 -1
  29. package/dist/auth/types.d.ts +1 -1
  30. package/dist/auth/types.d.ts.map +1 -1
  31. package/dist/config/defaults.d.ts.map +1 -1
  32. package/dist/config/defaults.js +2 -0
  33. package/dist/config/types.d.ts +32 -4
  34. package/dist/config/types.d.ts.map +1 -1
  35. package/dist/hooks/checkout.d.ts.map +1 -1
  36. package/dist/hooks/checkout.js +10 -9
  37. package/dist/index.d.ts +7 -5
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +5 -3
  40. package/dist/interfaces/rest/audit-middleware.d.ts.map +1 -1
  41. package/dist/interfaces/rest/audit-middleware.js +2 -0
  42. package/dist/interfaces/rest/customer-portal.d.ts.map +1 -1
  43. package/dist/interfaces/rest/customer-portal.js +9 -8
  44. package/dist/interfaces/rest/route-coverage.d.ts +14 -0
  45. package/dist/interfaces/rest/route-coverage.d.ts.map +1 -0
  46. package/dist/interfaces/rest/route-coverage.js +81 -0
  47. package/dist/interfaces/rest/router.d.ts +7 -2
  48. package/dist/interfaces/rest/router.d.ts.map +1 -1
  49. package/dist/interfaces/rest/router.js +8 -4
  50. package/dist/interfaces/rest/routes/admin/compensation-failures.d.ts.map +1 -1
  51. package/dist/interfaces/rest/routes/admin/compensation-failures.js +7 -5
  52. package/dist/interfaces/rest/routes/admin/custom-field-proposals.js +2 -2
  53. package/dist/interfaces/rest/routes/admin/permissions.d.ts +1 -1
  54. package/dist/interfaces/rest/routes/admin/permissions.d.ts.map +1 -1
  55. package/dist/interfaces/rest/routes/admin/permissions.js +2 -0
  56. package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -1
  57. package/dist/interfaces/rest/routes/admin/staff.js +126 -66
  58. package/dist/interfaces/rest/routes/admin-jobs.js +3 -3
  59. package/dist/interfaces/rest/routes/audit.js +3 -3
  60. package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
  61. package/dist/interfaces/rest/routes/carts.js +13 -10
  62. package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
  63. package/dist/interfaces/rest/routes/catalog.js +10 -2
  64. package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
  65. package/dist/interfaces/rest/routes/checkout.js +30 -35
  66. package/dist/interfaces/rest/routes/documents.d.ts.map +1 -1
  67. package/dist/interfaces/rest/routes/documents.js +10 -5
  68. package/dist/interfaces/rest/routes/inventory.d.ts.map +1 -1
  69. package/dist/interfaces/rest/routes/inventory.js +2 -0
  70. package/dist/interfaces/rest/routes/media.d.ts.map +1 -1
  71. package/dist/interfaces/rest/routes/media.js +7 -3
  72. package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
  73. package/dist/interfaces/rest/routes/orders.js +26 -8
  74. package/dist/interfaces/rest/routes/pricing.js +2 -2
  75. package/dist/interfaces/rest/routes/promotions.d.ts.map +1 -1
  76. package/dist/interfaces/rest/routes/promotions.js +13 -10
  77. package/dist/interfaces/rest/routes/search.d.ts.map +1 -1
  78. package/dist/interfaces/rest/routes/search.js +2 -1
  79. package/dist/interfaces/rest/schemas/carts.d.ts +7 -0
  80. package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
  81. package/dist/interfaces/rest/schemas/customer-portal.d.ts +35 -0
  82. package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +1 -1
  83. package/dist/interfaces/rest/schemas/orders.d.ts +204 -0
  84. package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
  85. package/dist/interfaces/rest/schemas/responses.d.ts +71 -0
  86. package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
  87. package/dist/interfaces/rest/utils.d.ts +15 -0
  88. package/dist/interfaces/rest/utils.d.ts.map +1 -1
  89. package/dist/interfaces/rest/utils.js +45 -2
  90. package/dist/kernel/compensation/executor.js +2 -2
  91. package/dist/kernel/database/plugin-types.d.ts +11 -0
  92. package/dist/kernel/database/plugin-types.d.ts.map +1 -1
  93. package/dist/kernel/database/scoped-db.d.ts +12 -0
  94. package/dist/kernel/database/scoped-db.d.ts.map +1 -1
  95. package/dist/kernel/database/scoped-db.js +12 -0
  96. package/dist/kernel/database/tx-context.d.ts +8 -0
  97. package/dist/kernel/database/tx-context.d.ts.map +1 -1
  98. package/dist/kernel/database/tx-context.js +13 -0
  99. package/dist/kernel/hooks/create-context.d.ts +2 -0
  100. package/dist/kernel/hooks/create-context.d.ts.map +1 -1
  101. package/dist/kernel/hooks/create-context.js +1 -0
  102. package/dist/kernel/hooks/types.d.ts +2 -0
  103. package/dist/kernel/hooks/types.d.ts.map +1 -1
  104. package/dist/kernel/plugin/manifest.d.ts.map +1 -1
  105. package/dist/kernel/plugin/manifest.js +9 -5
  106. package/dist/modules/analytics/service.js +2 -2
  107. package/dist/modules/audit/service.js +3 -3
  108. package/dist/modules/cart/repository/index.d.ts +13 -7
  109. package/dist/modules/cart/repository/index.d.ts.map +1 -1
  110. package/dist/modules/cart/repository/index.js +16 -10
  111. package/dist/modules/cart/schema.d.ts +17 -0
  112. package/dist/modules/cart/schema.d.ts.map +1 -1
  113. package/dist/modules/cart/schema.js +4 -0
  114. package/dist/modules/cart/service.d.ts +22 -9
  115. package/dist/modules/cart/service.d.ts.map +1 -1
  116. package/dist/modules/cart/service.js +57 -33
  117. package/dist/modules/catalog/brand-service.js +7 -7
  118. package/dist/modules/catalog/category-service.js +7 -7
  119. package/dist/modules/catalog/entity-service.d.ts +14 -7
  120. package/dist/modules/catalog/entity-service.d.ts.map +1 -1
  121. package/dist/modules/catalog/entity-service.js +109 -31
  122. package/dist/modules/catalog/read-policy.d.ts +9 -0
  123. package/dist/modules/catalog/read-policy.d.ts.map +1 -0
  124. package/dist/modules/catalog/read-policy.js +8 -0
  125. package/dist/modules/catalog/repository/index.d.ts +3 -2
  126. package/dist/modules/catalog/repository/index.d.ts.map +1 -1
  127. package/dist/modules/catalog/repository/index.js +14 -4
  128. package/dist/modules/catalog/service.d.ts +15 -13
  129. package/dist/modules/catalog/service.d.ts.map +1 -1
  130. package/dist/modules/catalog/service.js +25 -18
  131. package/dist/modules/customers/module.d.ts.map +1 -1
  132. package/dist/modules/customers/module.js +1 -0
  133. package/dist/modules/customers/service.d.ts +2 -0
  134. package/dist/modules/customers/service.d.ts.map +1 -1
  135. package/dist/modules/customers/service.js +21 -20
  136. package/dist/modules/documents/module.d.ts.map +1 -1
  137. package/dist/modules/documents/module.js +1 -0
  138. package/dist/modules/documents/service.d.ts +18 -4
  139. package/dist/modules/documents/service.d.ts.map +1 -1
  140. package/dist/modules/documents/service.js +54 -16
  141. package/dist/modules/fulfillment/module.d.ts.map +1 -1
  142. package/dist/modules/fulfillment/module.js +1 -0
  143. package/dist/modules/fulfillment/service.d.ts +2 -0
  144. package/dist/modules/fulfillment/service.d.ts.map +1 -1
  145. package/dist/modules/fulfillment/service.js +15 -6
  146. package/dist/modules/inventory/service.d.ts.map +1 -1
  147. package/dist/modules/inventory/service.js +15 -14
  148. package/dist/modules/media/service.js +6 -6
  149. package/dist/modules/orders/guest-access.d.ts +27 -0
  150. package/dist/modules/orders/guest-access.d.ts.map +1 -0
  151. package/dist/modules/orders/guest-access.js +46 -0
  152. package/dist/modules/orders/module.d.ts.map +1 -1
  153. package/dist/modules/orders/module.js +1 -0
  154. package/dist/modules/orders/quote.d.ts.map +1 -1
  155. package/dist/modules/orders/quote.js +1 -0
  156. package/dist/modules/orders/repository/index.d.ts +1 -1
  157. package/dist/modules/orders/repository/index.d.ts.map +1 -1
  158. package/dist/modules/orders/repository/index.js +2 -2
  159. package/dist/modules/orders/schema.d.ts +17 -0
  160. package/dist/modules/orders/schema.d.ts.map +1 -1
  161. package/dist/modules/orders/schema.js +5 -3
  162. package/dist/modules/orders/service.d.ts +16 -7
  163. package/dist/modules/orders/service.d.ts.map +1 -1
  164. package/dist/modules/orders/service.js +184 -55
  165. package/dist/modules/pricing/module.d.ts.map +1 -1
  166. package/dist/modules/pricing/module.js +1 -0
  167. package/dist/modules/pricing/service.d.ts +2 -0
  168. package/dist/modules/pricing/service.d.ts.map +1 -1
  169. package/dist/modules/pricing/service.js +12 -11
  170. package/dist/modules/promotions/module.d.ts.map +1 -1
  171. package/dist/modules/promotions/module.js +1 -0
  172. package/dist/modules/promotions/service.d.ts +3 -0
  173. package/dist/modules/promotions/service.d.ts.map +1 -1
  174. package/dist/modules/promotions/service.js +19 -11
  175. package/dist/modules/search/adapter.d.ts +11 -0
  176. package/dist/modules/search/adapter.d.ts.map +1 -1
  177. package/dist/modules/search/module.d.ts.map +1 -1
  178. package/dist/modules/search/module.js +4 -1
  179. package/dist/modules/search/service.d.ts +1 -0
  180. package/dist/modules/search/service.d.ts.map +1 -1
  181. package/dist/modules/search/service.js +57 -6
  182. package/dist/modules/settings/module.d.ts.map +1 -1
  183. package/dist/modules/settings/module.js +1 -0
  184. package/dist/modules/settings/service.d.ts +3 -0
  185. package/dist/modules/settings/service.d.ts.map +1 -1
  186. package/dist/modules/settings/service.js +6 -4
  187. package/dist/modules/shipping/service.js +9 -9
  188. package/dist/modules/tax/module.d.ts.map +1 -1
  189. package/dist/modules/tax/module.js +1 -0
  190. package/dist/modules/tax/service.d.ts +3 -0
  191. package/dist/modules/tax/service.d.ts.map +1 -1
  192. package/dist/modules/tax/service.js +11 -9
  193. package/dist/modules/webhooks/hook.js +2 -2
  194. package/dist/modules/webhooks/module.d.ts.map +1 -1
  195. package/dist/modules/webhooks/module.js +1 -0
  196. package/dist/modules/webhooks/service.d.ts +2 -0
  197. package/dist/modules/webhooks/service.d.ts.map +1 -1
  198. package/dist/modules/webhooks/service.js +4 -4
  199. package/dist/runtime/server.d.ts.map +1 -1
  200. package/dist/runtime/server.js +28 -2
  201. package/dist/test-utils/create-pglite-adapter.d.ts.map +1 -1
  202. package/dist/test-utils/create-pglite-adapter.js +35 -13
  203. package/dist/test-utils/create-test-config.d.ts.map +1 -1
  204. package/dist/test-utils/create-test-config.js +4 -0
  205. package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
  206. package/dist/test-utils/rest-api-test-utils.js +2 -0
  207. package/dist/test-utils/test-actors.js +2 -2
  208. package/dist/utils/id.d.ts +2 -0
  209. package/dist/utils/id.d.ts.map +1 -1
  210. package/dist/utils/id.js +11 -0
  211. package/package.json +6 -5
  212. package/src/auth/actor.ts +110 -0
  213. package/src/auth/auth-schema-guard.ts +143 -0
  214. package/src/auth/auth-schema.ts +50 -19
  215. package/src/auth/middleware.ts +25 -101
  216. package/src/auth/org.ts +15 -3
  217. package/src/auth/organization-guard.ts +158 -0
  218. package/src/auth/permissions.ts +31 -8
  219. package/src/auth/role-authority.ts +107 -0
  220. package/src/auth/setup.ts +19 -1
  221. package/src/auth/strict-org-resolution.ts +7 -1
  222. package/src/auth/types.ts +1 -1
  223. package/src/config/defaults.ts +2 -0
  224. package/src/config/types.ts +31 -4
  225. package/src/hooks/checkout.ts +19 -12
  226. package/src/index.ts +21 -6
  227. package/src/interfaces/rest/audit-middleware.ts +2 -0
  228. package/src/interfaces/rest/customer-portal.ts +31 -24
  229. package/src/interfaces/rest/route-coverage.ts +103 -0
  230. package/src/interfaces/rest/router.ts +16 -10
  231. package/src/interfaces/rest/routes/admin/compensation-failures.ts +8 -5
  232. package/src/interfaces/rest/routes/admin/custom-field-proposals.ts +2 -2
  233. package/src/interfaces/rest/routes/admin/permissions.ts +3 -1
  234. package/src/interfaces/rest/routes/admin/staff.ts +161 -72
  235. package/src/interfaces/rest/routes/admin-jobs.ts +3 -3
  236. package/src/interfaces/rest/routes/audit.ts +3 -3
  237. package/src/interfaces/rest/routes/carts.ts +17 -7
  238. package/src/interfaces/rest/routes/catalog.ts +11 -0
  239. package/src/interfaces/rest/routes/checkout.ts +41 -38
  240. package/src/interfaces/rest/routes/documents.ts +15 -1
  241. package/src/interfaces/rest/routes/inventory.ts +2 -0
  242. package/src/interfaces/rest/routes/media.ts +8 -3
  243. package/src/interfaces/rest/routes/orders.ts +27 -8
  244. package/src/interfaces/rest/routes/pricing.ts +2 -2
  245. package/src/interfaces/rest/routes/promotions.ts +12 -9
  246. package/src/interfaces/rest/routes/search.ts +3 -1
  247. package/src/interfaces/rest/utils.ts +61 -2
  248. package/src/kernel/compensation/executor.ts +2 -2
  249. package/src/kernel/database/plugin-types.ts +11 -0
  250. package/src/kernel/database/scoped-db.ts +12 -0
  251. package/src/kernel/database/tx-context.ts +25 -0
  252. package/src/kernel/hooks/create-context.ts +3 -0
  253. package/src/kernel/hooks/types.ts +2 -0
  254. package/src/kernel/plugin/manifest.ts +9 -5
  255. package/src/modules/analytics/service.ts +2 -2
  256. package/src/modules/audit/service.ts +3 -3
  257. package/src/modules/cart/repository/index.ts +22 -8
  258. package/src/modules/cart/schema.ts +4 -0
  259. package/src/modules/cart/service.ts +62 -27
  260. package/src/modules/catalog/brand-service.ts +7 -7
  261. package/src/modules/catalog/category-service.ts +7 -7
  262. package/src/modules/catalog/entity-service.ts +117 -35
  263. package/src/modules/catalog/read-policy.ts +16 -0
  264. package/src/modules/catalog/repository/index.ts +19 -3
  265. package/src/modules/catalog/service.ts +46 -31
  266. package/src/modules/customers/module.ts +2 -0
  267. package/src/modules/customers/service.ts +23 -22
  268. package/src/modules/documents/module.ts +2 -0
  269. package/src/modules/documents/service.ts +74 -11
  270. package/src/modules/fulfillment/module.ts +2 -0
  271. package/src/modules/fulfillment/service.ts +17 -6
  272. package/src/modules/inventory/service.ts +15 -24
  273. package/src/modules/media/service.ts +6 -6
  274. package/src/modules/orders/guest-access.ts +55 -0
  275. package/src/modules/orders/module.ts +1 -0
  276. package/src/modules/orders/quote.ts +1 -0
  277. package/src/modules/orders/repository/index.ts +2 -0
  278. package/src/modules/orders/schema.ts +5 -3
  279. package/src/modules/orders/service.ts +302 -52
  280. package/src/modules/pricing/module.ts +2 -0
  281. package/src/modules/pricing/service.ts +14 -16
  282. package/src/modules/promotions/module.ts +2 -0
  283. package/src/modules/promotions/service.ts +25 -16
  284. package/src/modules/search/adapter.ts +9 -0
  285. package/src/modules/search/module.ts +5 -1
  286. package/src/modules/search/service.ts +55 -6
  287. package/src/modules/settings/module.ts +2 -0
  288. package/src/modules/settings/service.ts +8 -4
  289. package/src/modules/shipping/service.ts +9 -9
  290. package/src/modules/tax/module.ts +1 -0
  291. package/src/modules/tax/service.ts +13 -9
  292. package/src/modules/webhooks/hook.ts +2 -2
  293. package/src/modules/webhooks/module.ts +2 -0
  294. package/src/modules/webhooks/service.ts +6 -4
  295. package/src/runtime/server.ts +41 -2
  296. package/src/test-utils/create-pglite-adapter.ts +34 -12
  297. package/src/test-utils/create-test-config.ts +10 -6
  298. package/src/test-utils/rest-api-test-utils.ts +2 -0
  299. package/src/test-utils/test-actors.ts +2 -2
  300. package/src/utils/id.ts +20 -0
@@ -1,6 +1,7 @@
1
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
2
  import { assertPermission } from "../../auth/permissions.js";
3
3
  import type { Actor } from "../../auth/types.js";
4
+ import type { CommerceConfig } from "../../config/types.js";
4
5
  import { CommerceNotFoundError, toCommerceError } from "../../kernel/errors.js";
5
6
  import { runAfterHooks } from "../../kernel/hooks/executor.js";
6
7
  import { createHookContext } from "../../kernel/hooks/create-context.js";
@@ -22,6 +23,7 @@ import type {
22
23
  interface CustomerServiceDeps {
23
24
  repository: CustomersRepository;
24
25
  hooks: HookRegistry;
26
+ config: CommerceConfig;
25
27
  services: Record<string, unknown>;
26
28
  database: DatabaseAdapter;
27
29
  }
@@ -30,6 +32,7 @@ function hookContext(
30
32
  actor: Actor | null,
31
33
  services: Record<string, unknown>,
32
34
  database: DatabaseAdapter,
35
+ config: CommerceConfig,
33
36
  tx: unknown,
34
37
  ): HookContext {
35
38
  return createHookContext({
@@ -39,6 +42,7 @@ function hookContext(
39
42
  services,
40
43
  context: { moduleName: "customers" },
41
44
  database: { db: database.db as PluginDb },
45
+ commerceConfig: config,
42
46
  });
43
47
  }
44
48
 
@@ -73,7 +77,7 @@ export class CustomerService {
73
77
  return Err(toCommerceError(error));
74
78
  }
75
79
 
76
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
80
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
77
81
  const isWalkIn = input.userId === undefined;
78
82
  const userId = input.userId ?? `anonymous_${crypto.randomUUID()}`;
79
83
  const metadata = {
@@ -97,7 +101,7 @@ export class CustomerService {
97
101
  const afterHooks = this.deps.hooks.resolve(
98
102
  "customers.afterCreate",
99
103
  ) as AfterHook<Customer>[];
100
- const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
104
+ const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
101
105
  await runAfterHooks(afterHooks, null, customer, "create", hctx);
102
106
 
103
107
  return Ok(customer);
@@ -107,7 +111,7 @@ export class CustomerService {
107
111
 
108
112
  async listInteractions(customerId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<CustomerInteraction[]>> {
109
113
  try { assertPermission(actor ?? null, "customers:read"); } catch (error) { return Err(toCommerceError(error)); }
110
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
114
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
111
115
  return Ok(await this.repo.listInteractions(orgId, customerId, ctx));
112
116
  }
113
117
 
@@ -118,7 +122,7 @@ export class CustomerService {
118
122
  ctx?: TxContext,
119
123
  ): Promise<Result<CustomerInteraction>> {
120
124
  try { assertPermission(actor ?? null, "customers:update"); } catch (error) { return Err(toCommerceError(error)); }
121
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
125
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
122
126
  const customer = await this.repo.findById(orgId, customerId, ctx);
123
127
  if (!customer) return Err(new CommerceNotFoundError("Customer not found."));
124
128
  const interaction = await this.repo.createInteraction(
@@ -144,7 +148,7 @@ export class CustomerService {
144
148
  ctx?: TxContext,
145
149
  ): Promise<Result<CustomerInteraction>> {
146
150
  try { assertPermission(actor ?? null, "customers:update"); } catch (error) { return Err(toCommerceError(error)); }
147
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
151
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
148
152
  const existing = await this.repo.findInteractionById(orgId, interactionId, ctx);
149
153
  if (!existing || existing.customerId !== customerId) return Err(new CommerceNotFoundError("Interaction not found."));
150
154
  const patch = {
@@ -160,7 +164,7 @@ export class CustomerService {
160
164
 
161
165
  async deleteInteraction(customerId: string, interactionId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>> {
162
166
  try { assertPermission(actor ?? null, "customers:update"); } catch (error) { return Err(toCommerceError(error)); }
163
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
167
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
164
168
  const existing = await this.repo.findInteractionById(orgId, interactionId, ctx);
165
169
  if (!existing || existing.customerId !== customerId) return Err(new CommerceNotFoundError("Interaction not found."));
166
170
  await this.repo.deleteInteraction(orgId, interactionId, ctx);
@@ -190,7 +194,7 @@ export class CustomerService {
190
194
  const afterHooks = this.deps.hooks.resolve(
191
195
  "customers.afterCreate",
192
196
  ) as AfterHook<Customer>[];
193
- const hctx = hookContext(actor, this.deps.services, this.deps.database, ctx?.tx ?? null);
197
+ const hctx = hookContext(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
194
198
  await runAfterHooks(afterHooks, null, customer, "create", hctx);
195
199
 
196
200
  return customer;
@@ -200,7 +204,7 @@ export class CustomerService {
200
204
  actor?: Actor | null,
201
205
  ctx?: TxContext,
202
206
  ): Promise<Result<Customer[]>> {
203
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
207
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
204
208
  const customers = await this.repo.findAll(orgId, ctx);
205
209
  return Ok(customers);
206
210
  }
@@ -210,7 +214,7 @@ export class CustomerService {
210
214
  actor?: Actor | null,
211
215
  ctx?: TxContext,
212
216
  ): Promise<Result<Customer>> {
213
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
217
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
214
218
  const customer = await this.repo.findById(orgId, id, ctx);
215
219
  if (!customer) return Err(new CommerceNotFoundError("Customer not found."));
216
220
  return Ok(customer);
@@ -221,7 +225,7 @@ export class CustomerService {
221
225
  actor?: Actor | null,
222
226
  ctx?: TxContext,
223
227
  ): Promise<Result<Customer>> {
224
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
228
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
225
229
  const resolvedActor = actor ?? ctx?.actor ?? null;
226
230
  const customer = await this.getOrCreateByUserId(
227
231
  orgId,
@@ -247,7 +251,7 @@ export class CustomerService {
247
251
  return Err(toCommerceError(error));
248
252
  }
249
253
 
250
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
254
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
251
255
  const existing = await this.repo.findById(orgId, id, ctx);
252
256
  if (!existing) return Err(new CommerceNotFoundError("Customer not found."));
253
257
 
@@ -271,10 +275,7 @@ export class CustomerService {
271
275
  "customers.afterUpdate",
272
276
  ) as AfterHook<Customer>[];
273
277
  const hctx = hookContext(
274
- actor ?? ctx?.actor ?? null,
275
- this.deps.services,
276
- this.deps.database,
277
- ctx?.tx ?? null,
278
+ actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null,
278
279
  );
279
280
  await runAfterHooks(afterHooks, existing, updated, "update", hctx);
280
281
 
@@ -289,7 +290,7 @@ export class CustomerService {
289
290
  actor?: Actor | null,
290
291
  ctx?: TxContext,
291
292
  ): Promise<Result<Customer>> {
292
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
293
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
293
294
  const resolvedActor = actor ?? ctx?.actor ?? null;
294
295
  const customer = await this.getOrCreateByUserId(
295
296
  orgId,
@@ -306,7 +307,7 @@ export class CustomerService {
306
307
  const afterHooks = this.deps.hooks.resolve(
307
308
  "customers.afterUpdate",
308
309
  ) as AfterHook<Customer>[];
309
- const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, ctx?.tx ?? null);
310
+ const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
310
311
  await runAfterHooks(afterHooks, customer, updated, "update", hctx);
311
312
 
312
313
  return Ok(updated);
@@ -317,7 +318,7 @@ export class CustomerService {
317
318
  actor?: Actor | null,
318
319
  ctx?: TxContext,
319
320
  ): Promise<Result<CustomerAddress[]>> {
320
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
321
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
321
322
  const resolvedActor = actor ?? ctx?.actor ?? null;
322
323
  const customer = await this.getOrCreateByUserId(
323
324
  orgId,
@@ -338,7 +339,7 @@ export class CustomerService {
338
339
  actor?: Actor | null,
339
340
  ctx?: TxContext,
340
341
  ): Promise<Result<CustomerAddress>> {
341
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
342
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
342
343
  const resolvedActor = actor ?? ctx?.actor ?? null;
343
344
  const customer = await this.getOrCreateByUserId(
344
345
  orgId,
@@ -376,7 +377,7 @@ export class CustomerService {
376
377
  actor?: Actor | null,
377
378
  ctx?: TxContext,
378
379
  ): Promise<Result<void>> {
379
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
380
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
380
381
  const resolvedActor = actor ?? ctx?.actor ?? null;
381
382
  const customer = await this.getOrCreateByUserId(
382
383
  orgId,
@@ -403,7 +404,7 @@ export class CustomerService {
403
404
  actor?: Actor | null,
404
405
  ctx?: TxContext,
405
406
  ): Promise<{ id: string; name: string } | null> {
406
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
407
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
407
408
  const user = await this.repo.findByPosPin(orgId, hashedPin, ctx);
408
409
  if (!user) return null;
409
410
  return {
@@ -1,3 +1,4 @@
1
+ import type { CommerceConfig } from "../../config/types.js";
1
2
  import type { DrizzleDatabase } from "../../kernel/database/drizzle-db.js";
2
3
  import { defineModule } from "../../kernel/module/index.js";
3
4
  import { DocumentsRepository } from "./repository/index.js";
@@ -15,5 +16,6 @@ export const documentsModule = defineModule<
15
16
  new DocumentsService({
16
17
  repository: new DocumentsRepository(deps.db.db as DrizzleDatabase),
17
18
  services: deps.services as Record<string, unknown>,
19
+ config: deps.config as CommerceConfig,
18
20
  }),
19
21
  });
@@ -1,7 +1,9 @@
1
- import { resolveOrgId } from "../../auth/org.js";
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
- import { CommerceValidationError } from "../../kernel/errors.js";
5
+ import { hasPermission } from "../../auth/permissions.js";
6
+ import { CommerceForbiddenError, CommerceValidationError } from "../../kernel/errors.js";
5
7
  import { Err, Ok, type Result } from "../../kernel/result.js";
6
8
  import type { HydratedOrder, OrderService } from "../orders/service.js";
7
9
  import type { SettingsService } from "../settings/service.js";
@@ -19,6 +21,15 @@ interface DocumentsServiceDeps {
19
21
  // The shared kernel service container — orders/settings/email are resolved
20
22
  // at call time (they may instantiate after this module).
21
23
  services: Record<string, unknown>;
24
+ config: CommerceConfig;
25
+ }
26
+
27
+ interface CustomerLookup {
28
+ getById(
29
+ id: string,
30
+ actor?: Actor | null,
31
+ ctx?: TxContext,
32
+ ): Promise<{ ok: true; value: { email: string | null } } | { ok: false }>;
22
33
  }
23
34
 
24
35
  interface EmailAdapter {
@@ -33,10 +44,12 @@ const DEFAULT_INVOICE_PREFIX = "INV-";
33
44
  export class DocumentsService {
34
45
  private repository: DocumentsRepository;
35
46
  private services: Record<string, unknown>;
47
+ private config: CommerceConfig;
36
48
 
37
49
  constructor(deps: DocumentsServiceDeps) {
38
50
  this.repository = deps.repository;
39
51
  this.services = deps.services;
52
+ this.config = deps.config;
40
53
  }
41
54
 
42
55
  private get orders(): OrderService {
@@ -90,16 +103,18 @@ export class DocumentsService {
90
103
  orderId: string,
91
104
  actor: Actor | null,
92
105
  ctx?: TxContext,
106
+ guestCredential?: string,
93
107
  ): Promise<Result<HydratedOrder>> {
94
- return this.orders.getById(orderId, actor, ctx);
108
+ return this.orders.getById(orderId, actor, ctx, guestCredential);
95
109
  }
96
110
 
97
111
  async renderInvoiceHtml(
98
112
  orderId: string,
99
113
  actor: Actor | null,
100
114
  ctx?: TxContext,
115
+ guestCredential?: string,
101
116
  ): Promise<Result<{ html: string; invoiceNumber: string }>> {
102
- const order = await this.loadOrder(orderId, actor, ctx);
117
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
103
118
  if (!order.ok) return order;
104
119
  const branding = await this.brandingFor(order.value.organizationId, ctx);
105
120
  const doc = await this.issueInvoiceNumber(order.value, ctx);
@@ -113,8 +128,9 @@ export class DocumentsService {
113
128
  orderId: string,
114
129
  actor: Actor | null,
115
130
  ctx?: TxContext,
131
+ guestCredential?: string,
116
132
  ): Promise<Result<{ pdf: Uint8Array; invoiceNumber: string }>> {
117
- const order = await this.loadOrder(orderId, actor, ctx);
133
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
118
134
  if (!order.ok) return order;
119
135
  const branding = await this.brandingFor(order.value.organizationId, ctx);
120
136
  const doc = await this.issueInvoiceNumber(order.value, ctx);
@@ -130,39 +146,86 @@ export class DocumentsService {
130
146
  orderId: string,
131
147
  actor: Actor | null,
132
148
  ctx?: TxContext,
149
+ guestCredential?: string,
133
150
  ): Promise<Result<{ html: string }>> {
134
- const order = await this.loadOrder(orderId, actor, ctx);
151
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
135
152
  if (!order.ok) return order;
136
153
  const branding = await this.brandingFor(order.value.organizationId, ctx);
137
154
  return Ok({ html: receiptHtml({ order: order.value, branding }) });
138
155
  }
139
156
 
157
+ /**
158
+ * The address that belongs to this order: its customer profile's email.
159
+ * A guest order has no customer profile and therefore no address of its own.
160
+ */
161
+ private async orderEmail(
162
+ order: HydratedOrder,
163
+ actor: Actor | null,
164
+ ctx?: TxContext,
165
+ ): Promise<string | null> {
166
+ if (!order.customerId) return null;
167
+ const customers = this.services.customers as CustomerLookup | undefined;
168
+ if (!customers) return null;
169
+ const customer = await customers.getById(order.customerId, actor, ctx);
170
+ return customer.ok ? (customer.value.email ?? null) : null;
171
+ }
172
+
140
173
  /**
141
174
  * Emails the invoice via the configured email adapter. The adapter's
142
175
  * template contract is (template, to, data) — the rendered HTML and the
143
176
  * fiscal number ride in `data` so template-based adapters can use either.
177
+ *
178
+ * The destination is the order's own address, not the caller's choice. A
179
+ * cart secret authorizes reading an order, and a caller-supplied `to` turned
180
+ * that read into delivery: items, totals and shipping address mailed to any
181
+ * address, with nothing left in the shopper's inbox. Only staff holding
182
+ * org-wide `orders:read` may name a different recipient.
144
183
  */
145
184
  async emailInvoice(
146
185
  orderId: string,
147
186
  to: string,
148
187
  actor: Actor | null,
149
188
  ctx?: TxContext,
189
+ guestCredential?: string,
150
190
  ): Promise<Result<{ sent: true; invoiceNumber: string; to: string }>> {
151
191
  const email = this.services.email as EmailAdapter | undefined;
152
192
  if (!email) {
153
193
  return Err(new CommerceValidationError("No email adapter is configured."));
154
194
  }
155
- const rendered = await this.renderInvoiceHtml(orderId, actor, ctx);
195
+ const rendered = await this.renderInvoiceHtml(orderId, actor, ctx, guestCredential);
156
196
  if (!rendered.ok) return rendered;
157
197
 
158
- const order = await this.loadOrder(orderId, actor, ctx);
198
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
159
199
  if (!order.ok) return order;
160
200
 
201
+ const ownAddress = await this.orderEmail(order.value, actor, ctx);
202
+ const mayDirect = hasPermission(actor, "orders:read");
203
+ const requested = to.trim();
204
+
205
+ let destination: string;
206
+ if (mayDirect && requested.length > 0) {
207
+ destination = requested;
208
+ } else if (ownAddress === null) {
209
+ return Err(
210
+ new CommerceValidationError(
211
+ "This order has no email address of its own. Render the invoice instead, or send it as staff.",
212
+ ),
213
+ );
214
+ } else if (requested.length > 0 && requested.toLowerCase() !== ownAddress.toLowerCase()) {
215
+ return Err(
216
+ new CommerceForbiddenError(
217
+ "An invoice can only be emailed to the address on the order.",
218
+ ),
219
+ );
220
+ } else {
221
+ destination = ownAddress;
222
+ }
223
+
161
224
  await email.send({
162
225
  template: "order-invoice",
163
- to,
226
+ to: destination,
164
227
  data: {
165
- orgId: resolveOrgId(actor ?? ctx?.actor ?? null),
228
+ orgId: resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config),
166
229
  orderId,
167
230
  orderNumber: order.value.orderNumber,
168
231
  invoiceNumber: rendered.value.invoiceNumber,
@@ -171,6 +234,6 @@ export class DocumentsService {
171
234
  html: rendered.value.html,
172
235
  },
173
236
  });
174
- return Ok({ sent: true, invoiceNumber: rendered.value.invoiceNumber, to });
237
+ return Ok({ sent: true, invoiceNumber: rendered.value.invoiceNumber, to: destination });
175
238
  }
176
239
  }
@@ -1,3 +1,4 @@
1
+ import type { CommerceConfig } from "../../config/types.js";
1
2
  import type { DrizzleDatabase } from "../../kernel/database/drizzle-db.js";
2
3
  import { defineModule } from "../../kernel/module/index.js";
3
4
  import type { InventoryService } from "../inventory/service.js";
@@ -36,6 +37,7 @@ export const fulfillmentModule = defineModule<
36
37
  ordersRepository: new OrdersRepository(deps.db.db as DrizzleDatabase),
37
38
  inventoryService: deps.services.inventory,
38
39
  hooks: deps.hooks,
40
+ config: deps.config as CommerceConfig,
39
41
  services: deps.services,
40
42
  database: deps.db,
41
43
  }),
@@ -1,10 +1,12 @@
1
1
  import { createHmac } from "node:crypto";
2
- import { resolveOrgId } from "../../auth/org.js";
2
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
3
+ import { assertPermission } from "../../auth/permissions.js";
3
4
  import type { Actor } from "../../auth/types.js";
5
+ import type { CommerceConfig } from "../../config/types.js";
4
6
  import type { DatabaseAdapter } from "../../kernel/database/adapter.js";
5
7
  import type { PluginDb } from "../../kernel/database/plugin-types.js";
6
8
  import type { TxContext } from "../../kernel/database/tx-context.js";
7
- import { CommerceNotFoundError, CommerceValidationError } from "../../kernel/errors.js";
9
+ import { CommerceNotFoundError, CommerceValidationError, toCommerceError } from "../../kernel/errors.js";
8
10
  import { runAfterHooks } from "../../kernel/hooks/executor.js";
9
11
  import { createHookContext } from "../../kernel/hooks/create-context.js";
10
12
  import type { HookRegistry } from "../../kernel/hooks/registry.js";
@@ -48,6 +50,7 @@ interface FulfillmentServiceDeps {
48
50
  ordersRepository: OrdersRepository;
49
51
  inventoryService?: InventoryServiceLike;
50
52
  hooks: HookRegistry;
53
+ config: CommerceConfig;
51
54
  services: Record<string, unknown>;
52
55
  database: DatabaseAdapter;
53
56
  }
@@ -259,7 +262,7 @@ export class FulfillmentService {
259
262
  }
260
263
 
261
264
  async fulfillOrder(orderId: string, actor?: Actor | null, ctx?: TxContext): Promise<Result<void>> {
262
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
265
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
263
266
  const order = await this.deps.ordersRepository.findById(orgId, orderId, ctx);
264
267
  if (!order) return Err(new CommerceNotFoundError("Order not found."));
265
268
 
@@ -326,6 +329,7 @@ export class FulfillmentService {
326
329
  services: this.deps.services,
327
330
  context: { moduleName: "fulfillment" },
328
331
  database: { db: this.deps.database.db as PluginDb },
332
+ commerceConfig: this.deps.config,
329
333
  });
330
334
  await runAfterHooks(afterHooks, null, record, "create", hookCtx);
331
335
 
@@ -365,7 +369,13 @@ export class FulfillmentService {
365
369
  actor?: Actor | null,
366
370
  ctx?: TxContext,
367
371
  ): Promise<Result<FulfillmentRecord>> {
368
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
372
+ try {
373
+ assertPermission(actor ?? null, "orders:update");
374
+ } catch (error) {
375
+ return Err(toCommerceError(error));
376
+ }
377
+
378
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
369
379
  const order = await this.deps.ordersRepository.findById(orgId, input.orderId, ctx);
370
380
  if (!order) return Err(new CommerceNotFoundError("Order not found."));
371
381
 
@@ -432,7 +442,7 @@ export class FulfillmentService {
432
442
  fulfillmentId: created.id,
433
443
  eventType: "created",
434
444
  toStatus: status,
435
- ...(actor?.userId !== undefined ? { actorId: actor.userId } : {}),
445
+ ...(actor?.userId != null ? { actorId: actor.userId } : {}),
436
446
  description: input.trackingNumber
437
447
  ? `Shipment recorded (${input.trackingNumber})`
438
448
  : "Fulfillment recorded",
@@ -478,6 +488,7 @@ export class FulfillmentService {
478
488
  services: this.deps.services,
479
489
  context: { moduleName: "fulfillment" },
480
490
  database: { db: this.deps.database.db as PluginDb },
491
+ commerceConfig: this.deps.config,
481
492
  });
482
493
  await runAfterHooks(afterHooks, null, record, "create", hookCtx);
483
494
 
@@ -563,7 +574,7 @@ export class FulfillmentService {
563
574
  return Err(new CommerceNotFoundError("Digital download not found."));
564
575
  }
565
576
 
566
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
577
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
567
578
  const order = await this.deps.ordersRepository.findById(orgId, orderId, ctx);
568
579
  if (!order || order.customerId !== userId) {
569
580
  return Err(new CommerceNotFoundError("Order not found."));
@@ -1,4 +1,4 @@
1
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
2
  import { assertPermission } from "../../auth/permissions.js";
3
3
  import type { Actor } from "../../auth/types.js";
4
4
  import type { CommerceConfig } from "../../config/types.js";
@@ -57,7 +57,7 @@ export class InventoryService {
57
57
  ): Promise<string> {
58
58
  const orgId =
59
59
  orgIdOverride ??
60
- resolveOrgId(actor ?? ctx?.actor ?? null, undefined, this.deps.config);
60
+ resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
61
61
  const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
62
62
  const sorted = warehouses.sort((a, b) => a.priority - b.priority);
63
63
  if (sorted.length > 0) {
@@ -90,9 +90,8 @@ export class InventoryService {
90
90
  );
91
91
  }
92
92
 
93
- const orgId = resolveOrgId(
93
+ const orgId = resolveOrgIdForCommerce(
94
94
  actor ?? ctx?.actor ?? null,
95
- undefined,
96
95
  this.deps.config,
97
96
  );
98
97
 
@@ -113,9 +112,8 @@ export class InventoryService {
113
112
  }
114
113
 
115
114
  async listWarehouses(actor?: Actor | null, ctx?: TxContext): Promise<Result<Warehouse[]>> {
116
- const orgId = resolveOrgId(
115
+ const orgId = resolveOrgIdForCommerce(
117
116
  actor ?? ctx?.actor ?? null,
118
- undefined,
119
117
  this.deps.config,
120
118
  );
121
119
  const warehouses = await this.repo.findAllWarehouses(orgId, ctx);
@@ -128,9 +126,8 @@ export class InventoryService {
128
126
  ctx?: TxContext,
129
127
  actor?: Actor | null,
130
128
  ): Promise<Result<number>> {
131
- const orgId = resolveOrgId(
129
+ const orgId = resolveOrgIdForCommerce(
132
130
  actor ?? ctx?.actor ?? null,
133
- undefined,
134
131
  this.deps.config,
135
132
  );
136
133
  const available = await this.repo.getAvailableQuantity(
@@ -147,9 +144,8 @@ export class InventoryService {
147
144
  actor?: Actor | null,
148
145
  ctx?: TxContext,
149
146
  ): Promise<Result<InventoryLevel[]>> {
150
- const orgId = resolveOrgId(
147
+ const orgId = resolveOrgIdForCommerce(
151
148
  actor ?? ctx?.actor ?? null,
152
- undefined,
153
149
  this.deps.config,
154
150
  );
155
151
  if (params?.entityId) {
@@ -177,9 +173,8 @@ export class InventoryService {
177
173
  actor?: Actor | null,
178
174
  ctx?: TxContext,
179
175
  ): Promise<Result<Record<string, number>>> {
180
- const orgId = resolveOrgId(
176
+ const orgId = resolveOrgIdForCommerce(
181
177
  actor ?? ctx?.actor ?? null,
182
- undefined,
183
178
  this.deps.config,
184
179
  );
185
180
  const data = await this.repo.getAvailableQuantities(orgId, entityIds, ctx);
@@ -191,9 +186,8 @@ export class InventoryService {
191
186
  ctx?: TxContext,
192
187
  actor?: Actor | null,
193
188
  ): Promise<Result<InventoryLevel[]>> {
194
- const orgId = resolveOrgId(
189
+ const orgId = resolveOrgIdForCommerce(
195
190
  actor ?? ctx?.actor ?? null,
196
- undefined,
197
191
  this.deps.config,
198
192
  );
199
193
  const levels = await this.repo.findLevelsByEntityId(orgId, entityId, ctx);
@@ -213,9 +207,8 @@ export class InventoryService {
213
207
  );
214
208
  }
215
209
 
216
- const orgId = resolveOrgId(
210
+ const orgId = resolveOrgIdForCommerce(
217
211
  actor ?? ctx?.actor ?? null,
218
- undefined,
219
212
  this.deps.config,
220
213
  );
221
214
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
@@ -267,9 +260,8 @@ export class InventoryService {
267
260
  actor?: Actor | null,
268
261
  ctx?: TxContext,
269
262
  ): Promise<Result<void>> {
270
- const orgId = resolveOrgId(
263
+ const orgId = resolveOrgIdForCommerce(
271
264
  actor ?? ctx?.actor ?? null,
272
- undefined,
273
265
  this.deps.config,
274
266
  );
275
267
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
@@ -360,7 +352,7 @@ export class InventoryService {
360
352
  const performedBy = input.performedBy ?? actor?.userId ?? "system";
361
353
 
362
354
  const doAdjust = async (txCtx: TxContext) => {
363
- const orgId = resolveOrgId(actor ?? txCtx.actor ?? null, undefined, this.deps.config);
355
+ const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor ?? null, this.deps.config);
364
356
 
365
357
  // Lock the level first so `before` and the write are atomic.
366
358
  const existing = await this.repo.findLevelForUpdate(
@@ -444,6 +436,7 @@ export class InventoryService {
444
436
  services: this.deps.services,
445
437
  context: { moduleName: "inventory" },
446
438
  database: { db: this.deps.database.db as PluginDb },
439
+ commerceConfig: this.deps.config,
447
440
  });
448
441
 
449
442
  const afterHooks = this.deps.hooks.resolve("inventory.afterAdjust");
@@ -496,9 +489,8 @@ export class InventoryService {
496
489
  ctx?: TxContext,
497
490
  ): Promise<Result<InventoryLevel>> {
498
491
  const warehouseId = input.warehouseId ?? (await this.pickWarehouse(actor, ctx));
499
- const orgId = resolveOrgId(
492
+ const orgId = resolveOrgIdForCommerce(
500
493
  actor ?? ctx?.actor ?? null,
501
- undefined,
502
494
  this.deps.config,
503
495
  );
504
496
 
@@ -551,7 +543,7 @@ export class InventoryService {
551
543
  ): Promise<Result<void>> {
552
544
  const orgId =
553
545
  input.orgId ??
554
- resolveOrgId(ctx?.actor ?? null, undefined, this.deps.config);
546
+ resolveOrgIdForCommerce(ctx?.actor ?? null, this.deps.config);
555
547
  const warehouseId =
556
548
  input.warehouseId ?? (await this.pickWarehouse(null, ctx, orgId));
557
549
  const variantId = input.variantId ?? null;
@@ -602,9 +594,8 @@ export class InventoryService {
602
594
  variantId?: string,
603
595
  ctx?: TxContext,
604
596
  ): Promise<Result<InventoryLevel>> {
605
- const orgId = resolveOrgId(
597
+ const orgId = resolveOrgIdForCommerce(
606
598
  ctx?.actor ?? null,
607
- undefined,
608
599
  this.deps.config,
609
600
  );
610
601
  const level = await this.repo.findLevelByKey(
@@ -1,4 +1,4 @@
1
- import { resolveOrgId } from "../../auth/org.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
2
  import { assertPermission } from "../../auth/permissions.js";
3
3
  import type { Actor } from "../../auth/types.js";
4
4
  import type { CommerceConfig } from "../../config/types.js";
@@ -138,7 +138,7 @@ export class MediaService {
138
138
  );
139
139
  }
140
140
 
141
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
141
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
142
142
  const bytes = new Uint8Array(input.data);
143
143
  const detectedMime = detectMimeFromBuffer(bytes);
144
144
  const allowSvg = this.deps.config.media?.allowSvg === true;
@@ -203,7 +203,7 @@ export class MediaService {
203
203
  actor?: Actor | null,
204
204
  ctx?: TxContext,
205
205
  ): Promise<Result<string>> {
206
- const orgId = resolveOrgId(actor ?? null);
206
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
207
207
  const asset = await this.repo.findAssetById(id, ctx, orgId);
208
208
  if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
209
209
  return this.deps.storage.getUrl(asset.storageKey);
@@ -215,7 +215,7 @@ export class MediaService {
215
215
  actor?: Actor | null,
216
216
  ctx?: TxContext,
217
217
  ): Promise<Result<string>> {
218
- const orgId = resolveOrgId(actor ?? null);
218
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
219
219
  const asset = await this.repo.findAssetById(id, ctx, orgId);
220
220
  if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
221
221
  return this.deps.storage.getSignedUrl(asset.storageKey, expiresIn);
@@ -226,7 +226,7 @@ export class MediaService {
226
226
  actor?: Actor | null,
227
227
  ctx?: TxContext,
228
228
  ): Promise<Result<void>> {
229
- const orgId = resolveOrgId(actor ?? null);
229
+ const orgId = resolveOrgIdForCommerce(actor ?? null, this.deps.config);
230
230
  const asset = await this.repo.findAssetById(id, ctx, orgId);
231
231
  if (!asset) return Err(new CommerceNotFoundError("Media asset not found."));
232
232
 
@@ -257,7 +257,7 @@ export class MediaService {
257
257
  ): Promise<Result<void>> {
258
258
  try {
259
259
  return await this.withTransaction(actor ?? ctx?.actor ?? null, ctx, async (txCtx) => {
260
- const orgId = resolveOrgId(actor ?? txCtx.actor);
260
+ const orgId = resolveOrgIdForCommerce(actor ?? txCtx.actor, this.deps.config);
261
261
  const entity = await this.catalogRepo.findEntityById(input.entityId, txCtx, orgId);
262
262
  if (!entity) return Err(new CommerceNotFoundError("Entity not found."));
263
263