@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.
Files changed (289) hide show
  1. package/dist/auth/auth-schema-guard.d.ts +2444 -0
  2. package/dist/auth/auth-schema-guard.d.ts.map +1 -0
  3. package/dist/auth/auth-schema-guard.js +113 -0
  4. package/dist/auth/auth-schema.d.ts +228 -0
  5. package/dist/auth/auth-schema.d.ts.map +1 -1
  6. package/dist/auth/auth-schema.js +24 -2
  7. package/dist/auth/middleware.d.ts +1 -0
  8. package/dist/auth/middleware.d.ts.map +1 -1
  9. package/dist/auth/middleware.js +13 -5
  10. package/dist/auth/org.d.ts +8 -2
  11. package/dist/auth/org.d.ts.map +1 -1
  12. package/dist/auth/org.js +12 -4
  13. package/dist/auth/organization-guard.d.ts +5 -0
  14. package/dist/auth/organization-guard.d.ts.map +1 -0
  15. package/dist/auth/organization-guard.js +124 -0
  16. package/dist/auth/permissions.d.ts +10 -0
  17. package/dist/auth/permissions.d.ts.map +1 -1
  18. package/dist/auth/permissions.js +31 -7
  19. package/dist/auth/role-authority.d.ts +44 -0
  20. package/dist/auth/role-authority.d.ts.map +1 -0
  21. package/dist/auth/role-authority.js +85 -0
  22. package/dist/auth/setup.d.ts.map +1 -1
  23. package/dist/auth/setup.js +17 -0
  24. package/dist/auth/strict-org-resolution.d.ts.map +1 -1
  25. package/dist/auth/strict-org-resolution.js +9 -1
  26. package/dist/auth/types.d.ts +1 -1
  27. package/dist/auth/types.d.ts.map +1 -1
  28. package/dist/config/defaults.d.ts.map +1 -1
  29. package/dist/config/defaults.js +2 -0
  30. package/dist/config/types.d.ts +30 -4
  31. package/dist/config/types.d.ts.map +1 -1
  32. package/dist/hooks/checkout.d.ts.map +1 -1
  33. package/dist/hooks/checkout.js +10 -9
  34. package/dist/index.d.ts +6 -5
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +4 -3
  37. package/dist/interfaces/rest/audit-middleware.d.ts.map +1 -1
  38. package/dist/interfaces/rest/audit-middleware.js +2 -0
  39. package/dist/interfaces/rest/customer-portal.d.ts.map +1 -1
  40. package/dist/interfaces/rest/customer-portal.js +9 -8
  41. package/dist/interfaces/rest/route-coverage.d.ts +14 -0
  42. package/dist/interfaces/rest/route-coverage.d.ts.map +1 -0
  43. package/dist/interfaces/rest/route-coverage.js +81 -0
  44. package/dist/interfaces/rest/router.d.ts +7 -2
  45. package/dist/interfaces/rest/router.d.ts.map +1 -1
  46. package/dist/interfaces/rest/router.js +8 -4
  47. package/dist/interfaces/rest/routes/admin/compensation-failures.d.ts.map +1 -1
  48. package/dist/interfaces/rest/routes/admin/compensation-failures.js +7 -5
  49. package/dist/interfaces/rest/routes/admin/custom-field-proposals.js +2 -2
  50. package/dist/interfaces/rest/routes/admin/permissions.d.ts +1 -1
  51. package/dist/interfaces/rest/routes/admin/permissions.d.ts.map +1 -1
  52. package/dist/interfaces/rest/routes/admin/permissions.js +2 -0
  53. package/dist/interfaces/rest/routes/admin/staff.d.ts.map +1 -1
  54. package/dist/interfaces/rest/routes/admin/staff.js +126 -66
  55. package/dist/interfaces/rest/routes/admin-jobs.js +3 -3
  56. package/dist/interfaces/rest/routes/audit.js +3 -3
  57. package/dist/interfaces/rest/routes/carts.d.ts.map +1 -1
  58. package/dist/interfaces/rest/routes/carts.js +13 -10
  59. package/dist/interfaces/rest/routes/catalog.d.ts.map +1 -1
  60. package/dist/interfaces/rest/routes/catalog.js +10 -2
  61. package/dist/interfaces/rest/routes/checkout.d.ts.map +1 -1
  62. package/dist/interfaces/rest/routes/checkout.js +30 -35
  63. package/dist/interfaces/rest/routes/documents.d.ts.map +1 -1
  64. package/dist/interfaces/rest/routes/documents.js +10 -5
  65. package/dist/interfaces/rest/routes/inventory.d.ts.map +1 -1
  66. package/dist/interfaces/rest/routes/inventory.js +2 -0
  67. package/dist/interfaces/rest/routes/media.d.ts.map +1 -1
  68. package/dist/interfaces/rest/routes/media.js +7 -3
  69. package/dist/interfaces/rest/routes/orders.d.ts.map +1 -1
  70. package/dist/interfaces/rest/routes/orders.js +26 -8
  71. package/dist/interfaces/rest/routes/pricing.js +2 -2
  72. package/dist/interfaces/rest/routes/promotions.d.ts.map +1 -1
  73. package/dist/interfaces/rest/routes/promotions.js +13 -10
  74. package/dist/interfaces/rest/routes/search.d.ts.map +1 -1
  75. package/dist/interfaces/rest/routes/search.js +2 -1
  76. package/dist/interfaces/rest/schemas/carts.d.ts +7 -0
  77. package/dist/interfaces/rest/schemas/carts.d.ts.map +1 -1
  78. package/dist/interfaces/rest/schemas/customer-portal.d.ts +35 -0
  79. package/dist/interfaces/rest/schemas/customer-portal.d.ts.map +1 -1
  80. package/dist/interfaces/rest/schemas/orders.d.ts +204 -0
  81. package/dist/interfaces/rest/schemas/orders.d.ts.map +1 -1
  82. package/dist/interfaces/rest/schemas/responses.d.ts +71 -0
  83. package/dist/interfaces/rest/schemas/responses.d.ts.map +1 -1
  84. package/dist/interfaces/rest/utils.d.ts +15 -0
  85. package/dist/interfaces/rest/utils.d.ts.map +1 -1
  86. package/dist/interfaces/rest/utils.js +45 -2
  87. package/dist/kernel/compensation/executor.js +2 -2
  88. package/dist/kernel/database/tx-context.d.ts +8 -0
  89. package/dist/kernel/database/tx-context.d.ts.map +1 -1
  90. package/dist/kernel/database/tx-context.js +13 -0
  91. package/dist/kernel/hooks/create-context.d.ts +2 -0
  92. package/dist/kernel/hooks/create-context.d.ts.map +1 -1
  93. package/dist/kernel/hooks/create-context.js +1 -0
  94. package/dist/kernel/hooks/types.d.ts +2 -0
  95. package/dist/kernel/hooks/types.d.ts.map +1 -1
  96. package/dist/kernel/plugin/manifest.d.ts.map +1 -1
  97. package/dist/kernel/plugin/manifest.js +9 -5
  98. package/dist/modules/analytics/service.js +2 -2
  99. package/dist/modules/audit/service.js +3 -3
  100. package/dist/modules/cart/repository/index.d.ts +13 -7
  101. package/dist/modules/cart/repository/index.d.ts.map +1 -1
  102. package/dist/modules/cart/repository/index.js +16 -10
  103. package/dist/modules/cart/schema.d.ts +17 -0
  104. package/dist/modules/cart/schema.d.ts.map +1 -1
  105. package/dist/modules/cart/schema.js +4 -0
  106. package/dist/modules/cart/service.d.ts +22 -9
  107. package/dist/modules/cart/service.d.ts.map +1 -1
  108. package/dist/modules/cart/service.js +57 -33
  109. package/dist/modules/catalog/brand-service.js +7 -7
  110. package/dist/modules/catalog/category-service.js +7 -7
  111. package/dist/modules/catalog/entity-service.d.ts +14 -7
  112. package/dist/modules/catalog/entity-service.d.ts.map +1 -1
  113. package/dist/modules/catalog/entity-service.js +109 -31
  114. package/dist/modules/catalog/read-policy.d.ts +9 -0
  115. package/dist/modules/catalog/read-policy.d.ts.map +1 -0
  116. package/dist/modules/catalog/read-policy.js +8 -0
  117. package/dist/modules/catalog/repository/index.d.ts +3 -2
  118. package/dist/modules/catalog/repository/index.d.ts.map +1 -1
  119. package/dist/modules/catalog/repository/index.js +14 -4
  120. package/dist/modules/catalog/service.d.ts +15 -13
  121. package/dist/modules/catalog/service.d.ts.map +1 -1
  122. package/dist/modules/catalog/service.js +25 -18
  123. package/dist/modules/customers/module.d.ts.map +1 -1
  124. package/dist/modules/customers/module.js +1 -0
  125. package/dist/modules/customers/service.d.ts +2 -0
  126. package/dist/modules/customers/service.d.ts.map +1 -1
  127. package/dist/modules/customers/service.js +21 -20
  128. package/dist/modules/documents/module.d.ts.map +1 -1
  129. package/dist/modules/documents/module.js +1 -0
  130. package/dist/modules/documents/service.d.ts +18 -4
  131. package/dist/modules/documents/service.d.ts.map +1 -1
  132. package/dist/modules/documents/service.js +54 -16
  133. package/dist/modules/fulfillment/module.d.ts.map +1 -1
  134. package/dist/modules/fulfillment/module.js +1 -0
  135. package/dist/modules/fulfillment/service.d.ts +2 -0
  136. package/dist/modules/fulfillment/service.d.ts.map +1 -1
  137. package/dist/modules/fulfillment/service.js +15 -6
  138. package/dist/modules/inventory/service.d.ts.map +1 -1
  139. package/dist/modules/inventory/service.js +15 -14
  140. package/dist/modules/media/service.js +6 -6
  141. package/dist/modules/orders/guest-access.d.ts +27 -0
  142. package/dist/modules/orders/guest-access.d.ts.map +1 -0
  143. package/dist/modules/orders/guest-access.js +46 -0
  144. package/dist/modules/orders/module.d.ts.map +1 -1
  145. package/dist/modules/orders/module.js +1 -0
  146. package/dist/modules/orders/quote.d.ts.map +1 -1
  147. package/dist/modules/orders/quote.js +1 -0
  148. package/dist/modules/orders/repository/index.d.ts +1 -1
  149. package/dist/modules/orders/repository/index.d.ts.map +1 -1
  150. package/dist/modules/orders/repository/index.js +2 -2
  151. package/dist/modules/orders/schema.d.ts +17 -0
  152. package/dist/modules/orders/schema.d.ts.map +1 -1
  153. package/dist/modules/orders/schema.js +5 -3
  154. package/dist/modules/orders/service.d.ts +16 -7
  155. package/dist/modules/orders/service.d.ts.map +1 -1
  156. package/dist/modules/orders/service.js +184 -55
  157. package/dist/modules/pricing/module.d.ts.map +1 -1
  158. package/dist/modules/pricing/module.js +1 -0
  159. package/dist/modules/pricing/service.d.ts +2 -0
  160. package/dist/modules/pricing/service.d.ts.map +1 -1
  161. package/dist/modules/pricing/service.js +12 -11
  162. package/dist/modules/promotions/module.d.ts.map +1 -1
  163. package/dist/modules/promotions/module.js +1 -0
  164. package/dist/modules/promotions/service.d.ts +3 -0
  165. package/dist/modules/promotions/service.d.ts.map +1 -1
  166. package/dist/modules/promotions/service.js +19 -11
  167. package/dist/modules/search/adapter.d.ts +6 -0
  168. package/dist/modules/search/adapter.d.ts.map +1 -1
  169. package/dist/modules/search/module.d.ts.map +1 -1
  170. package/dist/modules/search/module.js +1 -0
  171. package/dist/modules/search/service.d.ts +1 -0
  172. package/dist/modules/search/service.d.ts.map +1 -1
  173. package/dist/modules/search/service.js +57 -6
  174. package/dist/modules/settings/module.d.ts.map +1 -1
  175. package/dist/modules/settings/module.js +1 -0
  176. package/dist/modules/settings/service.d.ts +3 -0
  177. package/dist/modules/settings/service.d.ts.map +1 -1
  178. package/dist/modules/settings/service.js +6 -4
  179. package/dist/modules/shipping/service.js +9 -9
  180. package/dist/modules/tax/module.d.ts.map +1 -1
  181. package/dist/modules/tax/module.js +1 -0
  182. package/dist/modules/tax/service.d.ts +3 -0
  183. package/dist/modules/tax/service.d.ts.map +1 -1
  184. package/dist/modules/tax/service.js +11 -9
  185. package/dist/modules/webhooks/hook.js +2 -2
  186. package/dist/modules/webhooks/module.d.ts.map +1 -1
  187. package/dist/modules/webhooks/module.js +1 -0
  188. package/dist/modules/webhooks/service.d.ts +2 -0
  189. package/dist/modules/webhooks/service.d.ts.map +1 -1
  190. package/dist/modules/webhooks/service.js +4 -4
  191. package/dist/runtime/server.d.ts.map +1 -1
  192. package/dist/runtime/server.js +10 -2
  193. package/dist/test-utils/create-pglite-adapter.d.ts.map +1 -1
  194. package/dist/test-utils/create-pglite-adapter.js +35 -13
  195. package/dist/test-utils/create-test-config.d.ts.map +1 -1
  196. package/dist/test-utils/create-test-config.js +4 -0
  197. package/dist/test-utils/rest-api-test-utils.d.ts.map +1 -1
  198. package/dist/test-utils/rest-api-test-utils.js +2 -0
  199. package/dist/test-utils/test-actors.js +2 -2
  200. package/dist/utils/id.d.ts +2 -0
  201. package/dist/utils/id.d.ts.map +1 -1
  202. package/dist/utils/id.js +11 -0
  203. package/package.json +6 -5
  204. package/src/auth/auth-schema-guard.ts +143 -0
  205. package/src/auth/auth-schema.ts +50 -19
  206. package/src/auth/middleware.ts +17 -5
  207. package/src/auth/org.ts +15 -3
  208. package/src/auth/organization-guard.ts +158 -0
  209. package/src/auth/permissions.ts +31 -8
  210. package/src/auth/role-authority.ts +107 -0
  211. package/src/auth/setup.ts +17 -0
  212. package/src/auth/strict-org-resolution.ts +7 -1
  213. package/src/auth/types.ts +1 -1
  214. package/src/config/defaults.ts +2 -0
  215. package/src/config/types.ts +29 -4
  216. package/src/hooks/checkout.ts +19 -12
  217. package/src/index.ts +16 -6
  218. package/src/interfaces/rest/audit-middleware.ts +2 -0
  219. package/src/interfaces/rest/customer-portal.ts +31 -24
  220. package/src/interfaces/rest/route-coverage.ts +103 -0
  221. package/src/interfaces/rest/router.ts +16 -10
  222. package/src/interfaces/rest/routes/admin/compensation-failures.ts +8 -5
  223. package/src/interfaces/rest/routes/admin/custom-field-proposals.ts +2 -2
  224. package/src/interfaces/rest/routes/admin/permissions.ts +3 -1
  225. package/src/interfaces/rest/routes/admin/staff.ts +161 -72
  226. package/src/interfaces/rest/routes/admin-jobs.ts +3 -3
  227. package/src/interfaces/rest/routes/audit.ts +3 -3
  228. package/src/interfaces/rest/routes/carts.ts +17 -7
  229. package/src/interfaces/rest/routes/catalog.ts +11 -0
  230. package/src/interfaces/rest/routes/checkout.ts +41 -38
  231. package/src/interfaces/rest/routes/documents.ts +15 -1
  232. package/src/interfaces/rest/routes/inventory.ts +2 -0
  233. package/src/interfaces/rest/routes/media.ts +8 -3
  234. package/src/interfaces/rest/routes/orders.ts +27 -8
  235. package/src/interfaces/rest/routes/pricing.ts +2 -2
  236. package/src/interfaces/rest/routes/promotions.ts +12 -9
  237. package/src/interfaces/rest/routes/search.ts +3 -1
  238. package/src/interfaces/rest/utils.ts +61 -2
  239. package/src/kernel/compensation/executor.ts +2 -2
  240. package/src/kernel/database/tx-context.ts +25 -0
  241. package/src/kernel/hooks/create-context.ts +3 -0
  242. package/src/kernel/hooks/types.ts +2 -0
  243. package/src/kernel/plugin/manifest.ts +9 -5
  244. package/src/modules/analytics/service.ts +2 -2
  245. package/src/modules/audit/service.ts +3 -3
  246. package/src/modules/cart/repository/index.ts +22 -8
  247. package/src/modules/cart/schema.ts +4 -0
  248. package/src/modules/cart/service.ts +62 -27
  249. package/src/modules/catalog/brand-service.ts +7 -7
  250. package/src/modules/catalog/category-service.ts +7 -7
  251. package/src/modules/catalog/entity-service.ts +117 -35
  252. package/src/modules/catalog/read-policy.ts +16 -0
  253. package/src/modules/catalog/repository/index.ts +19 -3
  254. package/src/modules/catalog/service.ts +46 -31
  255. package/src/modules/customers/module.ts +2 -0
  256. package/src/modules/customers/service.ts +23 -22
  257. package/src/modules/documents/module.ts +2 -0
  258. package/src/modules/documents/service.ts +74 -11
  259. package/src/modules/fulfillment/module.ts +2 -0
  260. package/src/modules/fulfillment/service.ts +17 -6
  261. package/src/modules/inventory/service.ts +15 -24
  262. package/src/modules/media/service.ts +6 -6
  263. package/src/modules/orders/guest-access.ts +55 -0
  264. package/src/modules/orders/module.ts +1 -0
  265. package/src/modules/orders/quote.ts +1 -0
  266. package/src/modules/orders/repository/index.ts +2 -0
  267. package/src/modules/orders/schema.ts +5 -3
  268. package/src/modules/orders/service.ts +302 -52
  269. package/src/modules/pricing/module.ts +2 -0
  270. package/src/modules/pricing/service.ts +14 -16
  271. package/src/modules/promotions/module.ts +2 -0
  272. package/src/modules/promotions/service.ts +25 -16
  273. package/src/modules/search/adapter.ts +6 -0
  274. package/src/modules/search/module.ts +1 -0
  275. package/src/modules/search/service.ts +55 -6
  276. package/src/modules/settings/module.ts +2 -0
  277. package/src/modules/settings/service.ts +8 -4
  278. package/src/modules/shipping/service.ts +9 -9
  279. package/src/modules/tax/module.ts +1 -0
  280. package/src/modules/tax/service.ts +13 -9
  281. package/src/modules/webhooks/hook.ts +2 -2
  282. package/src/modules/webhooks/module.ts +2 -0
  283. package/src/modules/webhooks/service.ts +6 -4
  284. package/src/runtime/server.ts +16 -2
  285. package/src/test-utils/create-pglite-adapter.ts +34 -12
  286. package/src/test-utils/create-test-config.ts +10 -6
  287. package/src/test-utils/rest-api-test-utils.ts +2 -0
  288. package/src/test-utils/test-actors.ts +2 -2
  289. package/src/utils/id.ts +20 -0
@@ -1,8 +1,8 @@
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 { Err, Ok } from "../../kernel/result.js";
4
4
  import { CommerceConflictError, CommerceNotFoundError, CommerceValidationError, toCommerceError } from "../../kernel/errors.js";
5
- import { createTxContext } from "../../kernel/database/tx-context.js";
5
+ import { createTxContext, isWriteContextTransactional, resolveWriteContextHookContext } from "../../kernel/database/tx-context.js";
6
6
  import { isValidFieldPath, validateFieldPath } from "./ownership.js";
7
7
  import { comparableSerialize } from "./revision.js";
8
8
  import { EntityService } from "./entity-service.js";
@@ -49,7 +49,7 @@ export class CatalogServiceImpl {
49
49
  async resolveEntityFieldDefinitions(entityType, actorOrOrg, ctx) {
50
50
  const orgId = typeof actorOrOrg === "string"
51
51
  ? actorOrOrg
52
- : resolveOrgId(actorOrOrg ?? ctx?.actor ?? null);
52
+ : resolveOrgIdForCommerce(actorOrOrg ?? ctx?.actor ?? null, this.config);
53
53
  const codeFields = this.config.entities?.[entityType]?.fields ?? [];
54
54
  const merged = new Map(codeFields.map((field) => [field.name, { ...field }]));
55
55
  const runtimeFields = await this.repository.findActiveEntityFieldDefinitions(orgId, entityType, ctx);
@@ -70,7 +70,7 @@ export class CatalogServiceImpl {
70
70
  return [...merged.values()].sort((first, second) => (first.sortOrder ?? 0) - (second.sortOrder ?? 0));
71
71
  }
72
72
  listEntityFieldDefinitions(actor, entityType, ctx) {
73
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
73
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
74
74
  return this.withMutationResult(actor ?? ctx?.actor ?? null, ctx, async (txCtx) => Ok(await this.repository.findEntityFieldDefinitions(orgId, entityType, txCtx)));
75
75
  }
76
76
  createEntityFieldDefinition(input, actor, ctx) {
@@ -78,7 +78,7 @@ export class CatalogServiceImpl {
78
78
  return Promise.resolve(Err(new CommerceValidationError("Entity type and field name are required.")));
79
79
  }
80
80
  assertPermission(actor, "catalog:update");
81
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
81
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
82
82
  return this.withMutationResult(actor, ctx, async (txCtx) => {
83
83
  const codeField = this.codeFieldDefinition(input.entityType, input.name);
84
84
  if (codeField && input.type !== codeField.type) {
@@ -110,7 +110,7 @@ export class CatalogServiceImpl {
110
110
  }
111
111
  updateEntityFieldDefinition(id, input, actor, ctx) {
112
112
  assertPermission(actor, "catalog:update");
113
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
113
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
114
114
  return this.withMutationResult(actor, ctx, async (txCtx) => {
115
115
  const existing = await this.repository.findEntityFieldDefinitionById(orgId, id, txCtx);
116
116
  if (!existing)
@@ -138,7 +138,7 @@ export class CatalogServiceImpl {
138
138
  }
139
139
  archiveEntityFieldDefinition(id, actor, ctx) {
140
140
  assertPermission(actor, "catalog:update");
141
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
141
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config);
142
142
  return this.withMutationResult(actor, ctx, async (txCtx) => {
143
143
  const existing = await this.repository.findEntityFieldDefinitionById(orgId, id, txCtx);
144
144
  if (!existing)
@@ -155,11 +155,15 @@ export class CatalogServiceImpl {
155
155
  });
156
156
  }
157
157
  async withMutation(actor, ctx, fn) {
158
- if (ctx?.tx != null)
158
+ if (isWriteContextTransactional(ctx))
159
159
  return fn(ctx);
160
+ const hookContext = resolveWriteContextHookContext(ctx);
160
161
  for (let attempt = 0; attempt < 3; attempt += 1) {
161
162
  try {
162
- return await this.database.transaction(async (tx) => fn(createTxContext(tx, { actor })));
163
+ return await this.database.transaction(async (tx) => fn(createTxContext(tx, {
164
+ actor,
165
+ ...(hookContext ? { hookContext } : {}),
166
+ })));
163
167
  }
164
168
  catch (error) {
165
169
  if (!isUniqueViolation(error) || attempt === 2)
@@ -186,7 +190,7 @@ export class CatalogServiceImpl {
186
190
  const revisionActor = actor ?? ctx.actor;
187
191
  const organizationId = typeof snapshot.entity.organizationId === "string"
188
192
  ? snapshot.entity.organizationId
189
- : resolveOrgId(revisionActor);
193
+ : resolveOrgIdForCommerce(revisionActor, this.config);
190
194
  return this.repository.createRevision({
191
195
  organizationId,
192
196
  entityId,
@@ -205,7 +209,7 @@ export class CatalogServiceImpl {
205
209
  const entity = await this.repository.findEntityById(entityId, txCtx);
206
210
  if (!entity)
207
211
  return Err(new CommerceNotFoundError("Entity not found."));
208
- if (entity.organizationId !== resolveOrgId(revisionActor)) {
212
+ if (entity.organizationId !== resolveOrgIdForCommerce(revisionActor, this.config)) {
209
213
  return Err(new CommerceNotFoundError("Entity not found."));
210
214
  }
211
215
  return Ok(await this.captureRevision(entityId, revisionActor, reason, txCtx));
@@ -305,7 +309,7 @@ export class CatalogServiceImpl {
305
309
  const entity = await this.repository.findEntityById(entityId, txCtx);
306
310
  if (!entity)
307
311
  return Err(new CommerceNotFoundError("Entity not found."));
308
- if (entity.organizationId !== resolveOrgId(revisionActor)) {
312
+ if (entity.organizationId !== resolveOrgIdForCommerce(revisionActor, this.config)) {
309
313
  return Err(new CommerceNotFoundError("Entity not found."));
310
314
  }
311
315
  if (entity.sourceStoreId != null)
@@ -331,7 +335,7 @@ export class CatalogServiceImpl {
331
335
  const revisionActor = actor ?? txCtx.actor;
332
336
  assertPermission(revisionActor, "catalog:update");
333
337
  const cutoff = new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1000);
334
- return Ok(await this.repository.deleteRevisionsOlderThan(resolveOrgId(revisionActor), cutoff, txCtx));
338
+ return Ok(await this.repository.deleteRevisionsOlderThan(resolveOrgIdForCommerce(revisionActor, this.config), cutoff, txCtx));
335
339
  });
336
340
  }
337
341
  catch (error) {
@@ -360,6 +364,9 @@ export class CatalogServiceImpl {
360
364
  getById(id, options, actor, ctx) {
361
365
  return this.entities.getById(id, options, actor, ctx);
362
366
  }
367
+ getByIdForInternalUse(id, organizationId, options, ctx) {
368
+ return this.entities.getByIdForInternalUse(id, organizationId, options, ctx);
369
+ }
363
370
  getBySlug(slug, options, actor, ctx) {
364
371
  return this.entities.getBySlug(slug, options, actor, ctx);
365
372
  }
@@ -404,7 +411,7 @@ export class CatalogServiceImpl {
404
411
  const entity = await this.repository.findEntityById(entityId, txCtx);
405
412
  if (!entity)
406
413
  return Err(new CommerceNotFoundError("Entity not found."));
407
- if (entity.organizationId !== resolveOrgId(setter)) {
414
+ if (entity.organizationId !== resolveOrgIdForCommerce(setter, this.config)) {
408
415
  return Err(new CommerceNotFoundError("Entity not found."));
409
416
  }
410
417
  if (entity.sourceStoreId != null)
@@ -427,7 +434,7 @@ export class CatalogServiceImpl {
427
434
  const entity = await this.repository.findEntityById(entityId, txCtx);
428
435
  if (!entity)
429
436
  return Err(new CommerceNotFoundError("Entity not found."));
430
- if (entity.organizationId !== resolveOrgId(reader)) {
437
+ if (entity.organizationId !== resolveOrgIdForCommerce(reader, this.config)) {
431
438
  return Err(new CommerceNotFoundError("Entity not found."));
432
439
  }
433
440
  return Ok(await this.repository.findFieldOwnership(entityId, txCtx, storeId));
@@ -488,7 +495,7 @@ export class CatalogServiceImpl {
488
495
  const entity = await this.repository.findEntityById(entityId, txCtx);
489
496
  if (!entity)
490
497
  return Err(new CommerceNotFoundError("Entity not found."));
491
- if (entity.organizationId !== resolveOrgId(reviewer)) {
498
+ if (entity.organizationId !== resolveOrgIdForCommerce(reviewer, this.config)) {
492
499
  return Err(new CommerceNotFoundError("Entity not found."));
493
500
  }
494
501
  if (entity.sourceStoreId != null)
@@ -523,8 +530,8 @@ export class CatalogServiceImpl {
523
530
  rejectCustomField(entityId, fieldName, locale, actor, ctx) {
524
531
  return this.reviewCustomField("rejected", entityId, fieldName, locale, actor, ctx);
525
532
  }
526
- getAttributes(entityId, locale, ctx) {
527
- return this.entities.getAttributes(entityId, locale, ctx);
533
+ getAttributes(entityId, locale, actor, ctx) {
534
+ return this.entities.getAttributes(entityId, locale, actor, ctx);
528
535
  }
529
536
  listCategories(ctx, opts) {
530
537
  return this.categories.listCategories(ctx, opts);
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/customers/module.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAQ/C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAe1B,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/customers/module.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAQ/C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAgB1B,CAAC"}
@@ -13,6 +13,7 @@ export const customersModule = defineModule({
13
13
  service: (deps) => new CustomerService({
14
14
  repository: new CustomersRepository(deps.db.db),
15
15
  hooks: deps.hooks,
16
+ config: deps.config,
16
17
  services: deps.services,
17
18
  database: deps.db,
18
19
  }),
@@ -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 { HookRegistry } from "../../kernel/hooks/registry.js";
3
4
  import { type Result } from "../../kernel/result.js";
4
5
  import type { DatabaseAdapter } from "../../kernel/database/adapter.js";
@@ -7,6 +8,7 @@ import type { CustomersRepository, Customer, CustomerAddress, CustomerAddressIns
7
8
  interface CustomerServiceDeps {
8
9
  repository: CustomersRepository;
9
10
  hooks: HookRegistry;
11
+ config: CommerceConfig;
10
12
  services: Record<string, unknown>;
11
13
  database: DatabaseAdapter;
12
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/customers/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/customers/service.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,11 @@
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 { CommerceNotFoundError, toCommerceError } from "../../kernel/errors.js";
4
4
  import { runAfterHooks } from "../../kernel/hooks/executor.js";
5
5
  import { createHookContext } from "../../kernel/hooks/create-context.js";
6
6
  import { Err, Ok } from "../../kernel/result.js";
7
7
  import { createLogger } from "../../utils/logger.js";
8
- function hookContext(actor, services, database, tx) {
8
+ function hookContext(actor, services, database, config, tx) {
9
9
  return createHookContext({
10
10
  actor,
11
11
  tx,
@@ -13,6 +13,7 @@ function hookContext(actor, services, database, tx) {
13
13
  services,
14
14
  context: { moduleName: "customers" },
15
15
  database: { db: database.db },
16
+ commerceConfig: config,
16
17
  });
17
18
  }
18
19
  export class CustomerService {
@@ -35,7 +36,7 @@ export class CustomerService {
35
36
  catch (error) {
36
37
  return Err(toCommerceError(error));
37
38
  }
38
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
39
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
39
40
  const isWalkIn = input.userId === undefined;
40
41
  const userId = input.userId ?? `anonymous_${crypto.randomUUID()}`;
41
42
  const metadata = {
@@ -52,7 +53,7 @@ export class CustomerService {
52
53
  ...(input.email !== undefined ? { email: input.email } : {}),
53
54
  }, ctx);
54
55
  const afterHooks = this.deps.hooks.resolve("customers.afterCreate");
55
- const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
56
+ const hctx = hookContext(actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
56
57
  await runAfterHooks(afterHooks, null, customer, "create", hctx);
57
58
  return Ok(customer);
58
59
  }
@@ -64,7 +65,7 @@ export class CustomerService {
64
65
  catch (error) {
65
66
  return Err(toCommerceError(error));
66
67
  }
67
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
68
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
68
69
  return Ok(await this.repo.listInteractions(orgId, customerId, ctx));
69
70
  }
70
71
  async createInteraction(customerId, input, actor, ctx) {
@@ -74,7 +75,7 @@ export class CustomerService {
74
75
  catch (error) {
75
76
  return Err(toCommerceError(error));
76
77
  }
77
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
78
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
78
79
  const customer = await this.repo.findById(orgId, customerId, ctx);
79
80
  if (!customer)
80
81
  return Err(new CommerceNotFoundError("Customer not found."));
@@ -96,7 +97,7 @@ export class CustomerService {
96
97
  catch (error) {
97
98
  return Err(toCommerceError(error));
98
99
  }
99
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
100
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
100
101
  const existing = await this.repo.findInteractionById(orgId, interactionId, ctx);
101
102
  if (!existing || existing.customerId !== customerId)
102
103
  return Err(new CommerceNotFoundError("Interaction not found."));
@@ -118,7 +119,7 @@ export class CustomerService {
118
119
  catch (error) {
119
120
  return Err(toCommerceError(error));
120
121
  }
121
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
122
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
122
123
  const existing = await this.repo.findInteractionById(orgId, interactionId, ctx);
123
124
  if (!existing || existing.customerId !== customerId)
124
125
  return Err(new CommerceNotFoundError("Interaction not found."));
@@ -136,24 +137,24 @@ export class CustomerService {
136
137
  metadata: {},
137
138
  }, ctx);
138
139
  const afterHooks = this.deps.hooks.resolve("customers.afterCreate");
139
- const hctx = hookContext(actor, this.deps.services, this.deps.database, ctx?.tx ?? null);
140
+ const hctx = hookContext(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
140
141
  await runAfterHooks(afterHooks, null, customer, "create", hctx);
141
142
  return customer;
142
143
  }
143
144
  async list(actor, ctx) {
144
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
145
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
145
146
  const customers = await this.repo.findAll(orgId, ctx);
146
147
  return Ok(customers);
147
148
  }
148
149
  async getById(id, actor, ctx) {
149
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
150
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
150
151
  const customer = await this.repo.findById(orgId, id, ctx);
151
152
  if (!customer)
152
153
  return Err(new CommerceNotFoundError("Customer not found."));
153
154
  return Ok(customer);
154
155
  }
155
156
  async getByUserId(userId, actor, ctx) {
156
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
157
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
157
158
  const resolvedActor = actor ?? ctx?.actor ?? null;
158
159
  const customer = await this.getOrCreateByUserId(orgId, userId, resolvedActor, ctx);
159
160
  return Ok(customer);
@@ -165,7 +166,7 @@ export class CustomerService {
165
166
  catch (error) {
166
167
  return Err(toCommerceError(error));
167
168
  }
168
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
169
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
169
170
  const existing = await this.repo.findById(orgId, id, ctx);
170
171
  if (!existing)
171
172
  return Err(new CommerceNotFoundError("Customer not found."));
@@ -185,12 +186,12 @@ export class CustomerService {
185
186
  if (!updated)
186
187
  return Err(new CommerceNotFoundError("Customer not found."));
187
188
  const afterHooks = this.deps.hooks.resolve("customers.afterUpdate");
188
- const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, ctx?.tx ?? null);
189
+ const hctx = hookContext(actor ?? ctx?.actor ?? null, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
189
190
  await runAfterHooks(afterHooks, existing, updated, "update", hctx);
190
191
  return Ok(updated);
191
192
  }
192
193
  async updateByUserId(userId, updates, actor, ctx) {
193
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
194
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
194
195
  const resolvedActor = actor ?? ctx?.actor ?? null;
195
196
  const customer = await this.getOrCreateByUserId(orgId, userId, resolvedActor, ctx);
196
197
  const updated = await this.repo.update(customer.id, updates, ctx);
@@ -198,19 +199,19 @@ export class CustomerService {
198
199
  return Err(new CommerceNotFoundError("Customer not found."));
199
200
  }
200
201
  const afterHooks = this.deps.hooks.resolve("customers.afterUpdate");
201
- const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, ctx?.tx ?? null);
202
+ const hctx = hookContext(resolvedActor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx ?? null);
202
203
  await runAfterHooks(afterHooks, customer, updated, "update", hctx);
203
204
  return Ok(updated);
204
205
  }
205
206
  async getAddresses(userId, actor, ctx) {
206
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
207
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
207
208
  const resolvedActor = actor ?? ctx?.actor ?? null;
208
209
  const customer = await this.getOrCreateByUserId(orgId, userId, resolvedActor, ctx);
209
210
  const addresses = await this.repo.findAddressesByCustomerId(customer.id, ctx);
210
211
  return Ok(addresses);
211
212
  }
212
213
  async addAddress(userId, input, actor, ctx) {
213
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
214
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
214
215
  const resolvedActor = actor ?? ctx?.actor ?? null;
215
216
  const customer = await this.getOrCreateByUserId(orgId, userId, resolvedActor, ctx);
216
217
  if (input.isDefault) {
@@ -228,7 +229,7 @@ export class CustomerService {
228
229
  return Ok(address);
229
230
  }
230
231
  async deleteAddress(userId, addressId, actor, ctx) {
231
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
232
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
232
233
  const resolvedActor = actor ?? ctx?.actor ?? null;
233
234
  const customer = await this.getOrCreateByUserId(orgId, userId, resolvedActor, ctx);
234
235
  const addresses = await this.repo.findAddressesByCustomerId(customer.id, ctx);
@@ -240,7 +241,7 @@ export class CustomerService {
240
241
  return Ok(undefined);
241
242
  }
242
243
  async findPOSOperatorByPin(hashedPin, actor, ctx) {
243
- const orgId = resolveOrgId(actor ?? ctx?.actor ?? null);
244
+ const orgId = resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.deps.config);
244
245
  const user = await this.repo.findByPosPin(orgId, hashedPin, ctx);
245
246
  if (!user)
246
247
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/documents/module.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,eAAO,MAAM,eAAe;sBACN,OAAO,gBAAgB;oBAAkB,OAAO,cAAc;2CAWlF,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/documents/module.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,eAAO,MAAM,eAAe;sBACN,OAAO,gBAAgB;oBAAkB,OAAO,cAAc;2CAYlF,CAAC"}
@@ -8,5 +8,6 @@ export const documentsModule = defineModule({
8
8
  service: (deps) => new DocumentsService({
9
9
  repository: new DocumentsRepository(deps.db.db),
10
10
  services: deps.services,
11
+ config: deps.config,
11
12
  }),
12
13
  });
@@ -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 { HydratedOrder } from "../orders/service.js";
@@ -6,6 +7,7 @@ import type { DocumentsRepository, OrderDocument } from "./repository/index.js";
6
7
  interface DocumentsServiceDeps {
7
8
  repository: DocumentsRepository;
8
9
  services: Record<string, unknown>;
10
+ config: CommerceConfig;
9
11
  }
10
12
  /**
11
13
  * Order document rendering + fiscal numbering (issue #47).
@@ -13,6 +15,7 @@ interface DocumentsServiceDeps {
13
15
  export declare class DocumentsService {
14
16
  private repository;
15
17
  private services;
18
+ private config;
16
19
  constructor(deps: DocumentsServiceDeps);
17
20
  private get orders();
18
21
  private get settings();
@@ -25,23 +28,34 @@ export declare class DocumentsService {
25
28
  */
26
29
  issueInvoiceNumber(order: HydratedOrder, ctx?: TxContext): Promise<OrderDocument>;
27
30
  private loadOrder;
28
- renderInvoiceHtml(orderId: string, actor: Actor | null, ctx?: TxContext): Promise<Result<{
31
+ renderInvoiceHtml(orderId: string, actor: Actor | null, ctx?: TxContext, guestCredential?: string): Promise<Result<{
29
32
  html: string;
30
33
  invoiceNumber: string;
31
34
  }>>;
32
- renderInvoicePdf(orderId: string, actor: Actor | null, ctx?: TxContext): Promise<Result<{
35
+ renderInvoicePdf(orderId: string, actor: Actor | null, ctx?: TxContext, guestCredential?: string): Promise<Result<{
33
36
  pdf: Uint8Array;
34
37
  invoiceNumber: string;
35
38
  }>>;
36
- renderReceiptHtml(orderId: string, actor: Actor | null, ctx?: TxContext): Promise<Result<{
39
+ renderReceiptHtml(orderId: string, actor: Actor | null, ctx?: TxContext, guestCredential?: string): Promise<Result<{
37
40
  html: string;
38
41
  }>>;
42
+ /**
43
+ * The address that belongs to this order: its customer profile's email.
44
+ * A guest order has no customer profile and therefore no address of its own.
45
+ */
46
+ private orderEmail;
39
47
  /**
40
48
  * Emails the invoice via the configured email adapter. The adapter's
41
49
  * template contract is (template, to, data) — the rendered HTML and the
42
50
  * fiscal number ride in `data` so template-based adapters can use either.
51
+ *
52
+ * The destination is the order's own address, not the caller's choice. A
53
+ * cart secret authorizes reading an order, and a caller-supplied `to` turned
54
+ * that read into delivery: items, totals and shipping address mailed to any
55
+ * address, with nothing left in the shopper's inbox. Only staff holding
56
+ * org-wide `orders:read` may name a different recipient.
43
57
  */
44
- emailInvoice(orderId: string, to: string, actor: Actor | null, ctx?: TxContext): Promise<Result<{
58
+ emailInvoice(orderId: string, to: string, actor: Actor | null, ctx?: TxContext, guestCredential?: string): Promise<Result<{
45
59
  sent: true;
46
60
  invoiceNumber: string;
47
61
  to: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/documents/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,aAAa,EAAgB,MAAM,sBAAsB,CAAC;AASxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEhF,UAAU,oBAAoB;IAC5B,UAAU,EAAE,mBAAmB,CAAC;IAGhC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAQD;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,QAAQ,CAA0B;gBAE9B,IAAI,EAAE,oBAAoB;IAKtC,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,KAAK,QAAQ,GAEnB;YAEa,WAAW;IAIzB;;;;;OAKG;IACG,kBAAkB,CACtB,KAAK,EAAE,aAAa,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,aAAa,CAAC;YA0BX,SAAS;IAQjB,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAWrD,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,GAAG,EAAE,UAAU,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAaxD,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAOpC;;;;OAIG;IACG,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CA0BtE"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/documents/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;AAGrE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,sBAAsB,CAAC;AASxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEhF,UAAU,oBAAoB;IAC5B,UAAU,EAAE,mBAAmB,CAAC;IAGhC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,MAAM,EAAE,cAAc,CAAC;CACxB;AAgBD;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,MAAM,CAAiB;gBAEnB,IAAI,EAAE,oBAAoB;IAMtC,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,KAAK,QAAQ,GAEnB;YAEa,WAAW;IAIzB;;;;;OAKG;IACG,kBAAkB,CACtB,KAAK,EAAE,aAAa,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,aAAa,CAAC;YA0BX,SAAS;IASjB,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAWrD,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;QAAE,GAAG,EAAE,UAAU,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAaxD,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAOpC;;;OAGG;YACW,UAAU;IAYxB;;;;;;;;;;OAUG;IACG,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAiDtE"}
@@ -1,5 +1,6 @@
1
- import { resolveOrgId } from "../../auth/org.js";
2
- import { CommerceValidationError } from "../../kernel/errors.js";
1
+ import { resolveOrgIdForCommerce } from "../../auth/org.js";
2
+ import { hasPermission } from "../../auth/permissions.js";
3
+ import { CommerceForbiddenError, CommerceValidationError } from "../../kernel/errors.js";
3
4
  import { Err, Ok } from "../../kernel/result.js";
4
5
  import { buildPdf } from "./pdf.js";
5
6
  import { invoiceHtml, invoicePdfOps, receiptHtml, } from "./render.js";
@@ -10,9 +11,11 @@ const DEFAULT_INVOICE_PREFIX = "INV-";
10
11
  export class DocumentsService {
11
12
  repository;
12
13
  services;
14
+ config;
13
15
  constructor(deps) {
14
16
  this.repository = deps.repository;
15
17
  this.services = deps.services;
18
+ this.config = deps.config;
16
19
  }
17
20
  get orders() {
18
21
  return this.services.orders;
@@ -51,11 +54,11 @@ export class DocumentsService {
51
54
  throw error;
52
55
  }
53
56
  }
54
- async loadOrder(orderId, actor, ctx) {
55
- return this.orders.getById(orderId, actor, ctx);
57
+ async loadOrder(orderId, actor, ctx, guestCredential) {
58
+ return this.orders.getById(orderId, actor, ctx, guestCredential);
56
59
  }
57
- async renderInvoiceHtml(orderId, actor, ctx) {
58
- const order = await this.loadOrder(orderId, actor, ctx);
60
+ async renderInvoiceHtml(orderId, actor, ctx, guestCredential) {
61
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
59
62
  if (!order.ok)
60
63
  return order;
61
64
  const branding = await this.brandingFor(order.value.organizationId, ctx);
@@ -65,8 +68,8 @@ export class DocumentsService {
65
68
  invoiceNumber: doc.documentNumber,
66
69
  });
67
70
  }
68
- async renderInvoicePdf(orderId, actor, ctx) {
69
- const order = await this.loadOrder(orderId, actor, ctx);
71
+ async renderInvoicePdf(orderId, actor, ctx, guestCredential) {
72
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
70
73
  if (!order.ok)
71
74
  return order;
72
75
  const branding = await this.brandingFor(order.value.organizationId, ctx);
@@ -78,34 +81,69 @@ export class DocumentsService {
78
81
  });
79
82
  return Ok({ pdf: buildPdf(pages), invoiceNumber: doc.documentNumber });
80
83
  }
81
- async renderReceiptHtml(orderId, actor, ctx) {
82
- const order = await this.loadOrder(orderId, actor, ctx);
84
+ async renderReceiptHtml(orderId, actor, ctx, guestCredential) {
85
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
83
86
  if (!order.ok)
84
87
  return order;
85
88
  const branding = await this.brandingFor(order.value.organizationId, ctx);
86
89
  return Ok({ html: receiptHtml({ order: order.value, branding }) });
87
90
  }
91
+ /**
92
+ * The address that belongs to this order: its customer profile's email.
93
+ * A guest order has no customer profile and therefore no address of its own.
94
+ */
95
+ async orderEmail(order, actor, ctx) {
96
+ if (!order.customerId)
97
+ return null;
98
+ const customers = this.services.customers;
99
+ if (!customers)
100
+ return null;
101
+ const customer = await customers.getById(order.customerId, actor, ctx);
102
+ return customer.ok ? (customer.value.email ?? null) : null;
103
+ }
88
104
  /**
89
105
  * Emails the invoice via the configured email adapter. The adapter's
90
106
  * template contract is (template, to, data) — the rendered HTML and the
91
107
  * fiscal number ride in `data` so template-based adapters can use either.
108
+ *
109
+ * The destination is the order's own address, not the caller's choice. A
110
+ * cart secret authorizes reading an order, and a caller-supplied `to` turned
111
+ * that read into delivery: items, totals and shipping address mailed to any
112
+ * address, with nothing left in the shopper's inbox. Only staff holding
113
+ * org-wide `orders:read` may name a different recipient.
92
114
  */
93
- async emailInvoice(orderId, to, actor, ctx) {
115
+ async emailInvoice(orderId, to, actor, ctx, guestCredential) {
94
116
  const email = this.services.email;
95
117
  if (!email) {
96
118
  return Err(new CommerceValidationError("No email adapter is configured."));
97
119
  }
98
- const rendered = await this.renderInvoiceHtml(orderId, actor, ctx);
120
+ const rendered = await this.renderInvoiceHtml(orderId, actor, ctx, guestCredential);
99
121
  if (!rendered.ok)
100
122
  return rendered;
101
- const order = await this.loadOrder(orderId, actor, ctx);
123
+ const order = await this.loadOrder(orderId, actor, ctx, guestCredential);
102
124
  if (!order.ok)
103
125
  return order;
126
+ const ownAddress = await this.orderEmail(order.value, actor, ctx);
127
+ const mayDirect = hasPermission(actor, "orders:read");
128
+ const requested = to.trim();
129
+ let destination;
130
+ if (mayDirect && requested.length > 0) {
131
+ destination = requested;
132
+ }
133
+ else if (ownAddress === null) {
134
+ return Err(new CommerceValidationError("This order has no email address of its own. Render the invoice instead, or send it as staff."));
135
+ }
136
+ else if (requested.length > 0 && requested.toLowerCase() !== ownAddress.toLowerCase()) {
137
+ return Err(new CommerceForbiddenError("An invoice can only be emailed to the address on the order."));
138
+ }
139
+ else {
140
+ destination = ownAddress;
141
+ }
104
142
  await email.send({
105
143
  template: "order-invoice",
106
- to,
144
+ to: destination,
107
145
  data: {
108
- orgId: resolveOrgId(actor ?? ctx?.actor ?? null),
146
+ orgId: resolveOrgIdForCommerce(actor ?? ctx?.actor ?? null, this.config),
109
147
  orderId,
110
148
  orderNumber: order.value.orderNumber,
111
149
  invoiceNumber: rendered.value.invoiceNumber,
@@ -114,6 +152,6 @@ export class DocumentsService {
114
152
  html: rendered.value.html,
115
153
  },
116
154
  });
117
- return Ok({ sent: true, invoiceNumber: rendered.value.invoiceNumber, to });
155
+ return Ok({ sent: true, invoiceNumber: rendered.value.invoiceNumber, to: destination });
118
156
  }
119
157
  }
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/fulfillment/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,iBAAiB;wBAEN,OAAO,kBAAkB;0BACvB,OAAO,oBAAoB;uBAC9B,OAAO,iBAAiB;6CAqB7C,CAAC"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/fulfillment/module.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,iBAAiB;wBAEN,OAAO,kBAAkB;0BACvB,OAAO,oBAAoB;uBAC9B,OAAO,iBAAiB;6CAsB7C,CAAC"}
@@ -16,6 +16,7 @@ export const fulfillmentModule = defineModule({
16
16
  ordersRepository: new OrdersRepository(deps.db.db),
17
17
  inventoryService: deps.services.inventory,
18
18
  hooks: deps.hooks,
19
+ config: deps.config,
19
20
  services: deps.services,
20
21
  database: deps.db,
21
22
  }),
@@ -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 { DatabaseAdapter } from "../../kernel/database/adapter.js";
3
4
  import type { TxContext } from "../../kernel/database/tx-context.js";
4
5
  import type { HookRegistry } from "../../kernel/hooks/registry.js";
@@ -29,6 +30,7 @@ interface FulfillmentServiceDeps {
29
30
  ordersRepository: OrdersRepository;
30
31
  inventoryService?: InventoryServiceLike;
31
32
  hooks: HookRegistry;
33
+ config: CommerceConfig;
32
34
  services: Record<string, unknown>;
33
35
  database: DatabaseAdapter;
34
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/fulfillment/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/fulfillment/service.ts"],"names":[],"mappings":"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"}