@open-mercato/core 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2

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 (163) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +13 -1
  3. package/dist/helpers/integration/api.js +29 -16
  4. package/dist/helpers/integration/api.js.map +2 -2
  5. package/dist/helpers/integration/auth.js +11 -6
  6. package/dist/helpers/integration/auth.js.map +3 -3
  7. package/dist/modules/auth/commands/roles.js +9 -12
  8. package/dist/modules/auth/commands/roles.js.map +2 -2
  9. package/dist/modules/catalog/ai-agents-context.js +147 -0
  10. package/dist/modules/catalog/ai-agents-context.js.map +7 -0
  11. package/dist/modules/catalog/ai-agents.js +383 -0
  12. package/dist/modules/catalog/ai-agents.js.map +7 -0
  13. package/dist/modules/catalog/ai-tools/_shared.js +318 -0
  14. package/dist/modules/catalog/ai-tools/_shared.js.map +7 -0
  15. package/dist/modules/catalog/ai-tools/authoring-pack.js +391 -0
  16. package/dist/modules/catalog/ai-tools/authoring-pack.js.map +7 -0
  17. package/dist/modules/catalog/ai-tools/categories-pack.js +167 -0
  18. package/dist/modules/catalog/ai-tools/categories-pack.js.map +7 -0
  19. package/dist/modules/catalog/ai-tools/configuration-pack.js +120 -0
  20. package/dist/modules/catalog/ai-tools/configuration-pack.js.map +7 -0
  21. package/dist/modules/catalog/ai-tools/media-tags-pack.js +107 -0
  22. package/dist/modules/catalog/ai-tools/media-tags-pack.js.map +7 -0
  23. package/dist/modules/catalog/ai-tools/merchandising-pack.js +429 -0
  24. package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +7 -0
  25. package/dist/modules/catalog/ai-tools/mutation-pack.js +576 -0
  26. package/dist/modules/catalog/ai-tools/mutation-pack.js.map +7 -0
  27. package/dist/modules/catalog/ai-tools/prices-offers-pack.js +208 -0
  28. package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +7 -0
  29. package/dist/modules/catalog/ai-tools/products-pack.js +298 -0
  30. package/dist/modules/catalog/ai-tools/products-pack.js.map +7 -0
  31. package/dist/modules/catalog/ai-tools/stats-pack.js +57 -0
  32. package/dist/modules/catalog/ai-tools/stats-pack.js.map +7 -0
  33. package/dist/modules/catalog/ai-tools/types.js +10 -0
  34. package/dist/modules/catalog/ai-tools/types.js.map +7 -0
  35. package/dist/modules/catalog/ai-tools/variants-pack.js +75 -0
  36. package/dist/modules/catalog/ai-tools/variants-pack.js.map +7 -0
  37. package/dist/modules/catalog/ai-tools.js +28 -0
  38. package/dist/modules/catalog/ai-tools.js.map +7 -0
  39. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +466 -0
  40. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +7 -0
  41. package/dist/modules/catalog/backend/catalog/products/page.js +7 -1
  42. package/dist/modules/catalog/backend/catalog/products/page.js.map +2 -2
  43. package/dist/modules/catalog/components/CatalogStatsCard.js +91 -0
  44. package/dist/modules/catalog/components/CatalogStatsCard.js.map +7 -0
  45. package/dist/modules/catalog/components/products/ProductsDataTable.js +23 -3
  46. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  47. package/dist/modules/catalog/events.js +7 -4
  48. package/dist/modules/catalog/events.js.map +2 -2
  49. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +59 -0
  50. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +7 -0
  51. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js +17 -0
  52. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js.map +7 -0
  53. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +1 -1
  54. package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
  55. package/dist/modules/catalog/widgets/injection-table.js +13 -1
  56. package/dist/modules/catalog/widgets/injection-table.js.map +2 -2
  57. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js +94 -0
  58. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js.map +7 -0
  59. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js +17 -0
  60. package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js.map +7 -0
  61. package/dist/modules/customer_accounts/widgets/injection-table.js +9 -0
  62. package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
  63. package/dist/modules/customers/ai-agents-context.js +96 -0
  64. package/dist/modules/customers/ai-agents-context.js.map +7 -0
  65. package/dist/modules/customers/ai-agents.js +244 -0
  66. package/dist/modules/customers/ai-agents.js.map +7 -0
  67. package/dist/modules/customers/ai-tools/activities-tasks-pack.js +1015 -0
  68. package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +7 -0
  69. package/dist/modules/customers/ai-tools/addresses-tags-pack.js +134 -0
  70. package/dist/modules/customers/ai-tools/addresses-tags-pack.js.map +7 -0
  71. package/dist/modules/customers/ai-tools/companies-pack.js +249 -0
  72. package/dist/modules/customers/ai-tools/companies-pack.js.map +7 -0
  73. package/dist/modules/customers/ai-tools/deals-pack.js +348 -0
  74. package/dist/modules/customers/ai-tools/deals-pack.js.map +7 -0
  75. package/dist/modules/customers/ai-tools/people-pack.js +261 -0
  76. package/dist/modules/customers/ai-tools/people-pack.js.map +7 -0
  77. package/dist/modules/customers/ai-tools/settings-pack.js +102 -0
  78. package/dist/modules/customers/ai-tools/settings-pack.js.map +7 -0
  79. package/dist/modules/customers/ai-tools/types.js +10 -0
  80. package/dist/modules/customers/ai-tools/types.js.map +7 -0
  81. package/dist/modules/customers/ai-tools.js +20 -0
  82. package/dist/modules/customers/ai-tools.js.map +7 -0
  83. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +469 -0
  84. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +7 -0
  85. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +17 -0
  86. package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +7 -0
  87. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js +117 -0
  88. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js.map +7 -0
  89. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js +17 -0
  90. package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js.map +7 -0
  91. package/dist/modules/customers/widgets/injection-table.js +26 -0
  92. package/dist/modules/customers/widgets/injection-table.js.map +7 -0
  93. package/dist/modules/inbox_ops/ai-tools.js +4 -0
  94. package/dist/modules/inbox_ops/ai-tools.js.map +2 -2
  95. package/dist/modules/inbox_ops/lib/llmProvider.js +52 -7
  96. package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
  97. package/dist/modules/notifications/setup.js +13 -0
  98. package/dist/modules/notifications/setup.js.map +7 -0
  99. package/jest.config.cjs +1 -0
  100. package/jest.setup.ts +18 -0
  101. package/package.json +5 -3
  102. package/src/helpers/integration/api.ts +38 -16
  103. package/src/helpers/integration/auth.ts +13 -6
  104. package/src/modules/auth/commands/roles.ts +10 -12
  105. package/src/modules/catalog/AGENTS.md +11 -0
  106. package/src/modules/catalog/ai-agents-context.ts +239 -0
  107. package/src/modules/catalog/ai-agents.ts +525 -0
  108. package/src/modules/catalog/ai-tools/_shared.ts +487 -0
  109. package/src/modules/catalog/ai-tools/authoring-pack.ts +600 -0
  110. package/src/modules/catalog/ai-tools/categories-pack.ts +192 -0
  111. package/src/modules/catalog/ai-tools/configuration-pack.ts +218 -0
  112. package/src/modules/catalog/ai-tools/media-tags-pack.ts +127 -0
  113. package/src/modules/catalog/ai-tools/merchandising-pack.ts +608 -0
  114. package/src/modules/catalog/ai-tools/mutation-pack.ts +761 -0
  115. package/src/modules/catalog/ai-tools/prices-offers-pack.ts +376 -0
  116. package/src/modules/catalog/ai-tools/products-pack.ts +387 -0
  117. package/src/modules/catalog/ai-tools/stats-pack.ts +84 -0
  118. package/src/modules/catalog/ai-tools/types.ts +81 -0
  119. package/src/modules/catalog/ai-tools/variants-pack.ts +147 -0
  120. package/src/modules/catalog/ai-tools.ts +78 -0
  121. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +597 -0
  122. package/src/modules/catalog/backend/catalog/products/page.tsx +23 -2
  123. package/src/modules/catalog/components/CatalogStatsCard.tsx +118 -0
  124. package/src/modules/catalog/components/products/ProductsDataTable.tsx +54 -6
  125. package/src/modules/catalog/events.ts +7 -4
  126. package/src/modules/catalog/i18n/de.json +17 -0
  127. package/src/modules/catalog/i18n/en.json +17 -0
  128. package/src/modules/catalog/i18n/es.json +17 -0
  129. package/src/modules/catalog/i18n/pl.json +17 -0
  130. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +109 -0
  131. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.ts +29 -0
  132. package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +1 -1
  133. package/src/modules/catalog/widgets/injection-table.ts +12 -0
  134. package/src/modules/customer_accounts/i18n/de.json +5 -0
  135. package/src/modules/customer_accounts/i18n/en.json +5 -0
  136. package/src/modules/customer_accounts/i18n/es.json +5 -0
  137. package/src/modules/customer_accounts/i18n/pl.json +5 -0
  138. package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.tsx +136 -0
  139. package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.ts +43 -0
  140. package/src/modules/customer_accounts/widgets/injection-table.ts +9 -0
  141. package/src/modules/customers/AGENTS.md +13 -0
  142. package/src/modules/customers/ai-agents-context.ts +150 -0
  143. package/src/modules/customers/ai-agents.ts +355 -0
  144. package/src/modules/customers/ai-tools/activities-tasks-pack.ts +1248 -0
  145. package/src/modules/customers/ai-tools/addresses-tags-pack.ts +145 -0
  146. package/src/modules/customers/ai-tools/companies-pack.ts +362 -0
  147. package/src/modules/customers/ai-tools/deals-pack.ts +505 -0
  148. package/src/modules/customers/ai-tools/people-pack.ts +369 -0
  149. package/src/modules/customers/ai-tools/settings-pack.ts +121 -0
  150. package/src/modules/customers/ai-tools/types.ts +76 -0
  151. package/src/modules/customers/ai-tools.ts +34 -0
  152. package/src/modules/customers/i18n/de.json +25 -0
  153. package/src/modules/customers/i18n/en.json +25 -0
  154. package/src/modules/customers/i18n/es.json +25 -0
  155. package/src/modules/customers/i18n/pl.json +25 -0
  156. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +580 -0
  157. package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +36 -0
  158. package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.tsx +191 -0
  159. package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.ts +37 -0
  160. package/src/modules/customers/widgets/injection-table.ts +41 -0
  161. package/src/modules/inbox_ops/ai-tools.ts +4 -0
  162. package/src/modules/inbox_ops/lib/llmProvider.ts +83 -7
  163. package/src/modules/notifications/setup.ts +11 -0
@@ -0,0 +1,318 @@
1
+ import {
2
+ findOneWithDecryption,
3
+ findWithDecryption
4
+ } from "@open-mercato/shared/lib/encryption/find";
5
+ import {
6
+ loadCustomFieldDefinitionIndex,
7
+ loadCustomFieldValues
8
+ } from "@open-mercato/shared/lib/crud/custom-fields";
9
+ import { E } from "../../../generated/entities.ids.generated.js";
10
+ import { Attachment } from "@open-mercato/core/modules/attachments/data/entities";
11
+ import {
12
+ CatalogPriceKind,
13
+ CatalogProduct,
14
+ CatalogProductCategoryAssignment,
15
+ CatalogProductPrice,
16
+ CatalogProductTagAssignment,
17
+ CatalogProductUnitConversion,
18
+ CatalogProductVariant
19
+ } from "../data/entities.js";
20
+ function resolveEm(ctx) {
21
+ return ctx.container.resolve("em");
22
+ }
23
+ function buildScope(ctx, tenantId) {
24
+ return { tenantId, organizationId: ctx.organizationId };
25
+ }
26
+ async function listPriceKindsCore(ctx, input, tenantId) {
27
+ const em = resolveEm(ctx);
28
+ const limit = input.limit ?? 50;
29
+ const offset = input.offset ?? 0;
30
+ const where = { tenantId, deletedAt: null };
31
+ if (ctx.organizationId) {
32
+ where.$or = [{ organizationId: ctx.organizationId }, { organizationId: null }];
33
+ }
34
+ const [rows, total] = await Promise.all([
35
+ findWithDecryption(
36
+ em,
37
+ CatalogPriceKind,
38
+ where,
39
+ { limit, offset, orderBy: { code: "asc" } },
40
+ buildScope(ctx, tenantId)
41
+ ),
42
+ em.count(CatalogPriceKind, where)
43
+ ]);
44
+ const filtered = rows.filter((row) => row.tenantId === tenantId);
45
+ return {
46
+ items: filtered.map((row) => ({
47
+ id: row.id,
48
+ code: row.code,
49
+ title: row.title,
50
+ displayMode: row.displayMode,
51
+ currencyCode: row.currencyCode ?? null,
52
+ isPromotion: !!row.isPromotion,
53
+ isActive: !!row.isActive,
54
+ organizationId: row.organizationId ?? null,
55
+ tenantId: row.tenantId ?? null,
56
+ createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,
57
+ updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null
58
+ })),
59
+ total,
60
+ limit,
61
+ offset
62
+ };
63
+ }
64
+ function toProductSummary(row) {
65
+ return {
66
+ id: row.id,
67
+ title: row.title,
68
+ subtitle: row.subtitle ?? null,
69
+ sku: row.sku ?? null,
70
+ handle: row.handle ?? null,
71
+ productType: row.productType,
72
+ statusEntryId: row.statusEntryId ?? null,
73
+ primaryCurrencyCode: row.primaryCurrencyCode ?? null,
74
+ defaultMediaId: row.defaultMediaId ?? null,
75
+ defaultMediaUrl: row.defaultMediaUrl ?? null,
76
+ imageUrl: row.defaultMediaUrl ?? null,
77
+ isActive: !!row.isActive,
78
+ isConfigurable: !!row.isConfigurable,
79
+ organizationId: row.organizationId ?? null,
80
+ tenantId: row.tenantId ?? null,
81
+ createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,
82
+ updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,
83
+ // `description` is a product field used by D18 authoring tools to seed
84
+ // extract-attributes-from-description; falls back to null when absent.
85
+ description: row.description ?? null
86
+ };
87
+ }
88
+ function toPriceNumeric(value) {
89
+ if (value === null || value === void 0) return null;
90
+ const parsed = Number(value);
91
+ return Number.isFinite(parsed) ? parsed : null;
92
+ }
93
+ function summarizeDefinitionAsField(summary, scope) {
94
+ return {
95
+ key: summary.key,
96
+ label: summary.label ?? null,
97
+ type: summary.kind ?? null,
98
+ required: false,
99
+ options: null,
100
+ scope
101
+ };
102
+ }
103
+ async function resolveAttributeSchema(ctx, tenantId, productId, categoryId) {
104
+ const em = resolveEm(ctx);
105
+ const organizationIds = ctx.organizationId ? [ctx.organizationId] : [];
106
+ const moduleDefs = await loadCustomFieldDefinitionIndex({
107
+ em,
108
+ entityIds: [E.catalog.catalog_product, E.catalog.catalog_product_category],
109
+ tenantId,
110
+ organizationIds
111
+ });
112
+ const fields = [];
113
+ moduleDefs.forEach((entries) => {
114
+ const pick = entries[0];
115
+ if (!pick) return;
116
+ const scope = pick.organizationId ? "product" : "module";
117
+ fields.push(summarizeDefinitionAsField(pick, scope));
118
+ });
119
+ return {
120
+ fields,
121
+ resolvedFor: {
122
+ ...productId ? { productId } : {},
123
+ ...categoryId ? { categoryId } : {}
124
+ }
125
+ };
126
+ }
127
+ function resolvePricingService(ctx) {
128
+ try {
129
+ return ctx.container.resolve("catalogPricingService");
130
+ } catch {
131
+ return null;
132
+ }
133
+ }
134
+ async function buildProductBundle(em, ctx, tenantId, productId) {
135
+ const where = {
136
+ id: productId,
137
+ tenantId,
138
+ deletedAt: null
139
+ };
140
+ if (ctx.organizationId) where.organizationId = ctx.organizationId;
141
+ const product = await findOneWithDecryption(
142
+ em,
143
+ CatalogProduct,
144
+ where,
145
+ void 0,
146
+ buildScope(ctx, tenantId)
147
+ );
148
+ if (!product || product.tenantId !== tenantId) {
149
+ return { found: false, productId };
150
+ }
151
+ const scope = buildScope(ctx, tenantId);
152
+ const [
153
+ categoryAssignments,
154
+ tagAssignments,
155
+ variants,
156
+ prices,
157
+ mediaAttachments,
158
+ unitConversions,
159
+ customFieldValues,
160
+ attributeSchema
161
+ ] = await Promise.all([
162
+ findWithDecryption(
163
+ em,
164
+ CatalogProductCategoryAssignment,
165
+ { tenantId, product: product.id },
166
+ { limit: 100, populate: ["category"] },
167
+ scope
168
+ ),
169
+ findWithDecryption(
170
+ em,
171
+ CatalogProductTagAssignment,
172
+ { tenantId, product: product.id },
173
+ { limit: 100, populate: ["tag"] },
174
+ scope
175
+ ),
176
+ findWithDecryption(
177
+ em,
178
+ CatalogProductVariant,
179
+ { tenantId, product: product.id, deletedAt: null },
180
+ { limit: 100, orderBy: { createdAt: "asc" } },
181
+ scope
182
+ ),
183
+ findWithDecryption(
184
+ em,
185
+ CatalogProductPrice,
186
+ { tenantId, product: product.id },
187
+ { limit: 100, orderBy: { createdAt: "asc" } },
188
+ scope
189
+ ),
190
+ findWithDecryption(
191
+ em,
192
+ Attachment,
193
+ { tenantId, entityId: E.catalog.catalog_product, recordId: product.id },
194
+ { limit: 100, orderBy: { createdAt: "asc" } },
195
+ scope
196
+ ),
197
+ findWithDecryption(
198
+ em,
199
+ CatalogProductUnitConversion,
200
+ { tenantId, product: product.id, deletedAt: null },
201
+ { limit: 100, orderBy: { sortOrder: "asc", createdAt: "asc" } },
202
+ scope
203
+ ),
204
+ loadCustomFieldValues({
205
+ em,
206
+ entityId: E.catalog.catalog_product,
207
+ recordIds: [product.id],
208
+ tenantIdByRecord: { [product.id]: product.tenantId ?? null },
209
+ organizationIdByRecord: { [product.id]: product.organizationId ?? null },
210
+ tenantFallbacks: [product.tenantId ?? tenantId].filter((value) => !!value)
211
+ }),
212
+ resolveAttributeSchema(ctx, tenantId, product.id, void 0)
213
+ ]);
214
+ const categories = categoryAssignments.map((assignment) => {
215
+ const category = assignment.category;
216
+ if (!category || typeof category === "string") {
217
+ const fallbackId = typeof category === "string" ? category : null;
218
+ return fallbackId ? { id: fallbackId, name: null, slug: null, path: null } : null;
219
+ }
220
+ return {
221
+ id: category.id,
222
+ name: category.name ?? null,
223
+ slug: category.slug ?? null,
224
+ path: category.treePath ?? null
225
+ };
226
+ }).filter((value) => value !== null);
227
+ const tags = tagAssignments.map((assignment) => {
228
+ const tag = assignment.tag;
229
+ if (!tag || typeof tag === "string") return null;
230
+ return { id: tag.id, label: tag.label, slug: tag.slug };
231
+ }).filter((value) => value !== null);
232
+ const priceRows = prices.map((row) => ({
233
+ id: row.id,
234
+ priceKindId: row.priceKind && typeof row.priceKind === "object" ? row.priceKind.id : row.priceKind ?? null,
235
+ currencyCode: row.currencyCode,
236
+ kind: row.kind,
237
+ minQuantity: row.minQuantity,
238
+ maxQuantity: row.maxQuantity ?? null,
239
+ unitPriceNet: row.unitPriceNet ?? null,
240
+ unitPriceGross: row.unitPriceGross ?? null,
241
+ taxRate: row.taxRate ?? null,
242
+ taxAmount: row.taxAmount ?? null,
243
+ channelId: row.channelId ?? null,
244
+ offerId: row.offer && typeof row.offer === "object" ? row.offer.id : row.offer ?? null,
245
+ variantId: row.variant && typeof row.variant === "object" ? row.variant.id : row.variant ?? null,
246
+ startsAt: row.startsAt ? new Date(row.startsAt).toISOString() : null,
247
+ endsAt: row.endsAt ? new Date(row.endsAt).toISOString() : null
248
+ }));
249
+ let bestPrice = null;
250
+ const pricingService = resolvePricingService(ctx);
251
+ if (pricingService && prices.length > 0) {
252
+ const pricingContext = {
253
+ quantity: 1,
254
+ date: /* @__PURE__ */ new Date()
255
+ };
256
+ try {
257
+ const resolved = await pricingService.resolvePrice(prices, pricingContext);
258
+ if (resolved) {
259
+ bestPrice = {
260
+ id: resolved.id,
261
+ currencyCode: resolved.currencyCode,
262
+ kind: resolved.kind,
263
+ unitPriceNet: resolved.unitPriceNet ?? null,
264
+ unitPriceGross: resolved.unitPriceGross ?? null
265
+ };
266
+ }
267
+ } catch (error) {
268
+ console.warn("[catalog.get_product_bundle] resolvePrice failed, omitting best price", error);
269
+ }
270
+ }
271
+ return {
272
+ found: true,
273
+ id: product.id,
274
+ product: toProductSummary(product),
275
+ categories,
276
+ tags,
277
+ variants: variants.map((variant) => ({
278
+ id: variant.id,
279
+ name: variant.name ?? null,
280
+ sku: variant.sku ?? null,
281
+ barcode: variant.barcode ?? null,
282
+ optionValues: variant.optionValues ?? null,
283
+ defaultMediaId: variant.defaultMediaId ?? null,
284
+ defaultMediaUrl: variant.defaultMediaUrl ?? null,
285
+ isDefault: !!variant.isDefault,
286
+ isActive: !!variant.isActive
287
+ })),
288
+ prices: {
289
+ all: priceRows,
290
+ best: bestPrice
291
+ },
292
+ media: mediaAttachments.map((attachment) => ({
293
+ mediaId: attachment.id,
294
+ attachmentId: attachment.id,
295
+ fileName: attachment.fileName,
296
+ mediaType: attachment.mimeType,
297
+ size: attachment.fileSize,
298
+ altText: null,
299
+ sortOrder: 0
300
+ })),
301
+ customFields: customFieldValues[product.id] ?? {},
302
+ attributeSchema,
303
+ // No translation resolver exists for catalog (no `translations.ts` at
304
+ // module root yet); returning null is an explicit null-surface contract
305
+ // and a hint for Step 5+ to add the translations resolver.
306
+ translations: null
307
+ };
308
+ }
309
+ export {
310
+ buildProductBundle,
311
+ buildScope,
312
+ listPriceKindsCore,
313
+ resolveAttributeSchema,
314
+ resolveEm,
315
+ toPriceNumeric,
316
+ toProductSummary
317
+ };
318
+ //# sourceMappingURL=_shared.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/catalog/ai-tools/_shared.ts"],
4
+ "sourcesContent": ["/**\n * Shared helpers for catalog AI tool packs (Phase 1 WS-C, Steps 3.10 / 3.11 / 3.12).\n *\n * Step 3.10/3.11 centralized the price-kind enumeration query used by both the\n * base tool (`catalog.list_price_kinds_base`) and the D18 spec-named tool\n * (`catalog.list_price_kinds`).\n *\n * Step 3.12 lifts the **product-bundle builder** (and the merged\n * attribute-schema resolver) here too, so the D18 AI-authoring tools\n * (`draft_description_from_attributes`, `extract_attributes_from_description`,\n * `draft_description_from_media`, `suggest_title_variants`,\n * `suggest_price_adjustment`) can reuse them verbatim without either\n * duplicating the logic or depending on an internal symbol in\n * `merchandising-pack.ts`. Both packs (`merchandising-pack.ts` and\n * `authoring-pack.ts`) consume these helpers; neither pack owns the bundle\n * loader any more.\n *\n * Keeping the shared pieces query-shaped (not tool-shaped) means each tool is\n * free to project its own output shape without leaking concerns between packs.\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n findOneWithDecryption,\n findWithDecryption,\n} from '@open-mercato/shared/lib/encryption/find'\nimport {\n loadCustomFieldDefinitionIndex,\n loadCustomFieldValues,\n type CustomFieldDefinitionSummary,\n} from '@open-mercato/shared/lib/crud/custom-fields'\nimport { E } from '#generated/entities.ids.generated'\nimport { Attachment } from '@open-mercato/core/modules/attachments/data/entities'\nimport {\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductTag,\n CatalogProductTagAssignment,\n CatalogProductUnitConversion,\n CatalogProductVariant,\n} from '../data/entities'\nimport type { CatalogPricingService } from '../services/catalogPricingService'\nimport type { PriceRow, PricingContext } from '../lib/pricing'\nimport type { CatalogToolContext } from './types'\n\n/* -------------------------------------------------------------------------- */\n/* Price-kind enumeration shared core */\n/* -------------------------------------------------------------------------- */\n\nexport type ListPriceKindsCoreInput = {\n limit?: number\n offset?: number\n}\n\nexport type ListPriceKindsCoreRow = {\n id: string\n code: string\n title: string\n displayMode: string\n currencyCode: string | null\n isPromotion: boolean\n isActive: boolean\n organizationId: string | null\n tenantId: string | null\n createdAt: string | null\n updatedAt: string | null\n}\n\nexport type ListPriceKindsCoreResult = {\n items: ListPriceKindsCoreRow[]\n total: number\n limit: number\n offset: number\n}\n\nexport function resolveEm(ctx: CatalogToolContext): EntityManager {\n return ctx.container.resolve<EntityManager>('em')\n}\n\nexport function buildScope(ctx: CatalogToolContext, tenantId: string) {\n return { tenantId, organizationId: ctx.organizationId }\n}\n\n/**\n * Shared tenant-scoped enumeration of `CatalogPriceKind` rows.\n *\n * Uses `findWithDecryption` + post-filter. Price kinds are tenant-owned and\n * can be either organization-scoped (match `ctx.organizationId`) or\n * null-scoped (shared across the tenant); the `$or` below mirrors the\n * filter the base tool used pre-refactor so behavior stays identical.\n */\nexport async function listPriceKindsCore(\n ctx: CatalogToolContext,\n input: ListPriceKindsCoreInput,\n tenantId: string,\n): Promise<ListPriceKindsCoreResult> {\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId, deletedAt: null }\n if (ctx.organizationId) {\n where.$or = [{ organizationId: ctx.organizationId }, { organizationId: null }]\n }\n const [rows, total] = await Promise.all([\n findWithDecryption<CatalogPriceKind>(\n em,\n CatalogPriceKind,\n where as any,\n { limit, offset, orderBy: { code: 'asc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CatalogPriceKind, where as any),\n ])\n const filtered = rows.filter((row) => row.tenantId === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n code: row.code,\n title: row.title,\n displayMode: row.displayMode,\n currencyCode: row.currencyCode ?? null,\n isPromotion: !!row.isPromotion,\n isActive: !!row.isActive,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Product summary + bundle builder */\n/* -------------------------------------------------------------------------- */\n\nexport type ProductSummary = {\n id: string\n title: string\n subtitle: string | null\n sku: string | null\n handle: string | null\n productType: string\n statusEntryId: string | null\n primaryCurrencyCode: string | null\n defaultMediaId: string | null\n defaultMediaUrl: string | null\n /**\n * Alias of `defaultMediaUrl`. Surfaced under the same key the\n * `open-mercato:product` record card consumes so the model can pass it\n * straight through without renaming. Null when the product has no\n * default media.\n */\n imageUrl: string | null\n isActive: boolean\n isConfigurable: boolean\n organizationId: string | null\n tenantId: string | null\n createdAt: string | null\n updatedAt: string | null\n description: string | null\n}\n\nexport function toProductSummary(row: CatalogProduct): ProductSummary {\n return {\n id: row.id,\n title: row.title,\n subtitle: row.subtitle ?? null,\n sku: row.sku ?? null,\n handle: row.handle ?? null,\n productType: row.productType,\n statusEntryId: row.statusEntryId ?? null,\n primaryCurrencyCode: row.primaryCurrencyCode ?? null,\n defaultMediaId: row.defaultMediaId ?? null,\n defaultMediaUrl: row.defaultMediaUrl ?? null,\n imageUrl: row.defaultMediaUrl ?? null,\n isActive: !!row.isActive,\n isConfigurable: !!row.isConfigurable,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n updatedAt: row.updatedAt ? new Date(row.updatedAt).toISOString() : null,\n // `description` is a product field used by D18 authoring tools to seed\n // extract-attributes-from-description; falls back to null when absent.\n description: (row as any).description ?? null,\n }\n}\n\nexport function toPriceNumeric(value: string | null | undefined): number | null {\n if (value === null || value === undefined) return null\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : null\n}\n\nexport type AttributeSchemaField = {\n key: string\n label: string | null\n type: string | null\n required: boolean\n options: unknown | null\n scope: 'module' | 'category' | 'product'\n}\n\nexport type AttributeSchemaResult = {\n fields: AttributeSchemaField[]\n resolvedFor: { productId?: string; categoryId?: string }\n}\n\nfunction summarizeDefinitionAsField(\n summary: CustomFieldDefinitionSummary,\n scope: AttributeSchemaField['scope'],\n): AttributeSchemaField {\n return {\n key: summary.key,\n label: summary.label ?? null,\n type: summary.kind ?? null,\n required: false,\n options: null,\n scope,\n }\n}\n\nexport async function resolveAttributeSchema(\n ctx: CatalogToolContext,\n tenantId: string,\n productId?: string,\n categoryId?: string,\n): Promise<AttributeSchemaResult> {\n const em = resolveEm(ctx)\n const organizationIds = ctx.organizationId ? [ctx.organizationId] : []\n const moduleDefs = await loadCustomFieldDefinitionIndex({\n em,\n entityIds: [E.catalog.catalog_product, E.catalog.catalog_product_category],\n tenantId,\n organizationIds,\n })\n const fields: AttributeSchemaField[] = []\n moduleDefs.forEach((entries) => {\n const pick = entries[0]\n if (!pick) return\n const scope: AttributeSchemaField['scope'] = pick.organizationId ? 'product' : 'module'\n fields.push(summarizeDefinitionAsField(pick, scope))\n })\n return {\n fields,\n resolvedFor: {\n ...(productId ? { productId } : {}),\n ...(categoryId ? { categoryId } : {}),\n },\n }\n}\n\nexport type ProductBundleMediaEntry = {\n mediaId: string\n attachmentId: string\n fileName: string\n mediaType: string | null\n size: number | null\n altText: string | null\n sortOrder: number\n}\n\nexport type ProductBundle = {\n found: true\n id: string\n product: ProductSummary\n categories: Array<{ id: string; name: string | null; slug: string | null; path: string | null }>\n tags: Array<{ id: string; label: string; slug: string }>\n variants: Array<Record<string, unknown>>\n prices: {\n all: Array<Record<string, unknown>>\n best: Record<string, unknown> | null\n }\n media: ProductBundleMediaEntry[]\n customFields: Record<string, unknown>\n attributeSchema: AttributeSchemaResult\n translations: null\n}\n\nexport type ProductBundleResult = ProductBundle | { found: false; productId: string }\n\nfunction resolvePricingService(ctx: CatalogToolContext): CatalogPricingService | null {\n try {\n return ctx.container.resolve<CatalogPricingService>('catalogPricingService')\n } catch {\n return null\n }\n}\n\nexport async function buildProductBundle(\n em: EntityManager,\n ctx: CatalogToolContext,\n tenantId: string,\n productId: string,\n): Promise<ProductBundleResult> {\n const where: Record<string, unknown> = {\n id: productId,\n tenantId,\n deletedAt: null,\n }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const product = await findOneWithDecryption<CatalogProduct>(\n em,\n CatalogProduct,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!product || product.tenantId !== tenantId) {\n return { found: false as const, productId }\n }\n const scope = buildScope(ctx, tenantId)\n const [\n categoryAssignments,\n tagAssignments,\n variants,\n prices,\n mediaAttachments,\n unitConversions,\n customFieldValues,\n attributeSchema,\n ] = await Promise.all([\n findWithDecryption<CatalogProductCategoryAssignment>(\n em,\n CatalogProductCategoryAssignment,\n { tenantId, product: product.id } as any,\n { limit: 100, populate: ['category'] as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductTagAssignment>(\n em,\n CatalogProductTagAssignment,\n { tenantId, product: product.id } as any,\n { limit: 100, populate: ['tag'] as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductVariant>(\n em,\n CatalogProductVariant,\n { tenantId, product: product.id, deletedAt: null } as any,\n { limit: 100, orderBy: { createdAt: 'asc' } as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductPrice>(\n em,\n CatalogProductPrice,\n { tenantId, product: product.id } as any,\n { limit: 100, orderBy: { createdAt: 'asc' } as any } as any,\n scope,\n ),\n findWithDecryption<Attachment>(\n em,\n Attachment,\n { tenantId, entityId: E.catalog.catalog_product, recordId: product.id } as any,\n { limit: 100, orderBy: { createdAt: 'asc' } as any } as any,\n scope,\n ),\n findWithDecryption<CatalogProductUnitConversion>(\n em,\n CatalogProductUnitConversion,\n { tenantId, product: product.id, deletedAt: null } as any,\n { limit: 100, orderBy: { sortOrder: 'asc', createdAt: 'asc' } as any } as any,\n scope,\n ),\n loadCustomFieldValues({\n em,\n entityId: E.catalog.catalog_product,\n recordIds: [product.id],\n tenantIdByRecord: { [product.id]: product.tenantId ?? null },\n organizationIdByRecord: { [product.id]: product.organizationId ?? null },\n tenantFallbacks: [product.tenantId ?? tenantId].filter((value): value is string => !!value),\n }),\n resolveAttributeSchema(ctx, tenantId, product.id, undefined),\n ])\n\n const categories = categoryAssignments\n .map((assignment) => {\n const category = (assignment as any).category\n if (!category || typeof category === 'string') {\n const fallbackId = typeof category === 'string' ? category : null\n return fallbackId ? { id: fallbackId, name: null, slug: null, path: null } : null\n }\n return {\n id: category.id,\n name: category.name ?? null,\n slug: category.slug ?? null,\n path: category.treePath ?? null,\n }\n })\n .filter((value): value is { id: string; name: string | null; slug: string | null; path: string | null } => value !== null)\n\n const tags = tagAssignments\n .map((assignment) => {\n const tag = (assignment as any).tag as CatalogProductTag | string | null\n if (!tag || typeof tag === 'string') return null\n return { id: tag.id, label: tag.label, slug: tag.slug }\n })\n .filter((value): value is { id: string; label: string; slug: string } => value !== null)\n\n const priceRows = prices.map((row) => ({\n id: row.id,\n priceKindId: (row as any).priceKind && typeof (row as any).priceKind === 'object'\n ? (row as any).priceKind.id\n : (row as any).priceKind ?? null,\n currencyCode: row.currencyCode,\n kind: row.kind,\n minQuantity: row.minQuantity,\n maxQuantity: row.maxQuantity ?? null,\n unitPriceNet: row.unitPriceNet ?? null,\n unitPriceGross: row.unitPriceGross ?? null,\n taxRate: row.taxRate ?? null,\n taxAmount: row.taxAmount ?? null,\n channelId: row.channelId ?? null,\n offerId: (row as any).offer && typeof (row as any).offer === 'object'\n ? (row as any).offer.id\n : (row as any).offer ?? null,\n variantId: (row as any).variant && typeof (row as any).variant === 'object'\n ? (row as any).variant.id\n : (row as any).variant ?? null,\n startsAt: row.startsAt ? new Date(row.startsAt).toISOString() : null,\n endsAt: row.endsAt ? new Date(row.endsAt).toISOString() : null,\n }))\n\n let bestPrice: Record<string, unknown> | null = null\n const pricingService = resolvePricingService(ctx)\n if (pricingService && prices.length > 0) {\n const pricingContext: PricingContext = {\n quantity: 1,\n date: new Date(),\n }\n try {\n const resolved = await pricingService.resolvePrice(prices as unknown as PriceRow[], pricingContext)\n if (resolved) {\n bestPrice = {\n id: (resolved as any).id,\n currencyCode: (resolved as any).currencyCode,\n kind: (resolved as any).kind,\n unitPriceNet: (resolved as any).unitPriceNet ?? null,\n unitPriceGross: (resolved as any).unitPriceGross ?? null,\n }\n }\n } catch (error) {\n console.warn('[catalog.get_product_bundle] resolvePrice failed, omitting best price', error)\n }\n }\n\n return {\n found: true,\n id: product.id,\n product: toProductSummary(product),\n categories,\n tags,\n variants: variants.map((variant) => ({\n id: variant.id,\n name: variant.name ?? null,\n sku: variant.sku ?? null,\n barcode: variant.barcode ?? null,\n optionValues: variant.optionValues ?? null,\n defaultMediaId: variant.defaultMediaId ?? null,\n defaultMediaUrl: variant.defaultMediaUrl ?? null,\n isDefault: !!variant.isDefault,\n isActive: !!variant.isActive,\n })),\n prices: {\n all: priceRows,\n best: bestPrice,\n },\n media: mediaAttachments.map((attachment) => ({\n mediaId: attachment.id,\n attachmentId: attachment.id,\n fileName: attachment.fileName,\n mediaType: attachment.mimeType,\n size: attachment.fileSize,\n altText: null,\n sortOrder: 0,\n })),\n customFields: customFieldValues[product.id] ?? {},\n attributeSchema,\n // No translation resolver exists for catalog (no `translations.ts` at\n // module root yet); returning null is an explicit null-surface contract\n // and a hint for Step 5+ to add the translations resolver.\n translations: null,\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }