@open-mercato/core 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3043.1a796c3920
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +13 -1
- package/dist/helpers/integration/api.js +29 -16
- package/dist/helpers/integration/api.js.map +2 -2
- package/dist/helpers/integration/auth.js +11 -6
- package/dist/helpers/integration/auth.js.map +3 -3
- package/dist/modules/auth/commands/roles.js +9 -12
- package/dist/modules/auth/commands/roles.js.map +2 -2
- package/dist/modules/catalog/ai-agents-context.js +147 -0
- package/dist/modules/catalog/ai-agents-context.js.map +7 -0
- package/dist/modules/catalog/ai-agents.js +383 -0
- package/dist/modules/catalog/ai-agents.js.map +7 -0
- package/dist/modules/catalog/ai-tools/_shared.js +318 -0
- package/dist/modules/catalog/ai-tools/_shared.js.map +7 -0
- package/dist/modules/catalog/ai-tools/authoring-pack.js +391 -0
- package/dist/modules/catalog/ai-tools/authoring-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/categories-pack.js +167 -0
- package/dist/modules/catalog/ai-tools/categories-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/configuration-pack.js +120 -0
- package/dist/modules/catalog/ai-tools/configuration-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/media-tags-pack.js +107 -0
- package/dist/modules/catalog/ai-tools/media-tags-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +429 -0
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/mutation-pack.js +576 -0
- package/dist/modules/catalog/ai-tools/mutation-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/prices-offers-pack.js +208 -0
- package/dist/modules/catalog/ai-tools/prices-offers-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/products-pack.js +298 -0
- package/dist/modules/catalog/ai-tools/products-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/stats-pack.js +57 -0
- package/dist/modules/catalog/ai-tools/stats-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools/types.js +10 -0
- package/dist/modules/catalog/ai-tools/types.js.map +7 -0
- package/dist/modules/catalog/ai-tools/variants-pack.js +75 -0
- package/dist/modules/catalog/ai-tools/variants-pack.js.map +7 -0
- package/dist/modules/catalog/ai-tools.js +28 -0
- package/dist/modules/catalog/ai-tools.js.map +7 -0
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +466 -0
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +7 -0
- package/dist/modules/catalog/backend/catalog/products/page.js +7 -1
- package/dist/modules/catalog/backend/catalog/products/page.js.map +2 -2
- package/dist/modules/catalog/components/CatalogStatsCard.js +91 -0
- package/dist/modules/catalog/components/CatalogStatsCard.js.map +7 -0
- package/dist/modules/catalog/components/products/ProductsDataTable.js +23 -3
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/events.js +7 -4
- package/dist/modules/catalog/events.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +59 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js +17 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js +1 -1
- package/dist/modules/catalog/widgets/injection/product-seo/widget.client.js.map +2 -2
- package/dist/modules/catalog/widgets/injection-table.js +13 -1
- package/dist/modules/catalog/widgets/injection-table.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js +94 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js +17 -0
- package/dist/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js +9 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
- package/dist/modules/customers/ai-agents-context.js +96 -0
- package/dist/modules/customers/ai-agents-context.js.map +7 -0
- package/dist/modules/customers/ai-agents.js +244 -0
- package/dist/modules/customers/ai-agents.js.map +7 -0
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js +1015 -0
- package/dist/modules/customers/ai-tools/activities-tasks-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/addresses-tags-pack.js +134 -0
- package/dist/modules/customers/ai-tools/addresses-tags-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/companies-pack.js +249 -0
- package/dist/modules/customers/ai-tools/companies-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/deals-pack.js +348 -0
- package/dist/modules/customers/ai-tools/deals-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/people-pack.js +261 -0
- package/dist/modules/customers/ai-tools/people-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/settings-pack.js +102 -0
- package/dist/modules/customers/ai-tools/settings-pack.js.map +7 -0
- package/dist/modules/customers/ai-tools/types.js +10 -0
- package/dist/modules/customers/ai-tools/types.js.map +7 -0
- package/dist/modules/customers/ai-tools.js +20 -0
- package/dist/modules/customers/ai-tools.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js +469 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js +17 -0
- package/dist/modules/customers/widgets/injection/ai-assistant-trigger/widget.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js +117 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.js.map +7 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js +17 -0
- package/dist/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.js.map +7 -0
- package/dist/modules/customers/widgets/injection-table.js +26 -0
- package/dist/modules/customers/widgets/injection-table.js.map +7 -0
- package/dist/modules/inbox_ops/ai-tools.js +4 -0
- package/dist/modules/inbox_ops/ai-tools.js.map +2 -2
- package/dist/modules/inbox_ops/lib/llmProvider.js +52 -7
- package/dist/modules/inbox_ops/lib/llmProvider.js.map +2 -2
- package/dist/modules/notifications/setup.js +13 -0
- package/dist/modules/notifications/setup.js.map +7 -0
- package/jest.config.cjs +1 -0
- package/jest.setup.ts +18 -0
- package/package.json +5 -3
- package/src/helpers/integration/api.ts +38 -16
- package/src/helpers/integration/auth.ts +13 -6
- package/src/modules/auth/commands/roles.ts +10 -12
- package/src/modules/catalog/AGENTS.md +11 -0
- package/src/modules/catalog/ai-agents-context.ts +239 -0
- package/src/modules/catalog/ai-agents.ts +525 -0
- package/src/modules/catalog/ai-tools/_shared.ts +487 -0
- package/src/modules/catalog/ai-tools/authoring-pack.ts +600 -0
- package/src/modules/catalog/ai-tools/categories-pack.ts +192 -0
- package/src/modules/catalog/ai-tools/configuration-pack.ts +218 -0
- package/src/modules/catalog/ai-tools/media-tags-pack.ts +127 -0
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +608 -0
- package/src/modules/catalog/ai-tools/mutation-pack.ts +761 -0
- package/src/modules/catalog/ai-tools/prices-offers-pack.ts +376 -0
- package/src/modules/catalog/ai-tools/products-pack.ts +387 -0
- package/src/modules/catalog/ai-tools/stats-pack.ts +84 -0
- package/src/modules/catalog/ai-tools/types.ts +81 -0
- package/src/modules/catalog/ai-tools/variants-pack.ts +147 -0
- package/src/modules/catalog/ai-tools.ts +78 -0
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +597 -0
- package/src/modules/catalog/backend/catalog/products/page.tsx +23 -2
- package/src/modules/catalog/components/CatalogStatsCard.tsx +118 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +54 -6
- package/src/modules/catalog/events.ts +7 -4
- package/src/modules/catalog/i18n/de.json +17 -0
- package/src/modules/catalog/i18n/en.json +17 -0
- package/src/modules/catalog/i18n/es.json +17 -0
- package/src/modules/catalog/i18n/pl.json +17 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +109 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.ts +29 -0
- package/src/modules/catalog/widgets/injection/product-seo/widget.client.tsx +1 -1
- package/src/modules/catalog/widgets/injection-table.ts +12 -0
- package/src/modules/customer_accounts/i18n/de.json +5 -0
- package/src/modules/customer_accounts/i18n/en.json +5 -0
- package/src/modules/customer_accounts/i18n/es.json +5 -0
- package/src/modules/customer_accounts/i18n/pl.json +5 -0
- package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.client.tsx +136 -0
- package/src/modules/customer_accounts/widgets/injection/portal-ai-assistant-trigger/widget.ts +43 -0
- package/src/modules/customer_accounts/widgets/injection-table.ts +9 -0
- package/src/modules/customers/AGENTS.md +13 -0
- package/src/modules/customers/ai-agents-context.ts +150 -0
- package/src/modules/customers/ai-agents.ts +355 -0
- package/src/modules/customers/ai-tools/activities-tasks-pack.ts +1248 -0
- package/src/modules/customers/ai-tools/addresses-tags-pack.ts +145 -0
- package/src/modules/customers/ai-tools/companies-pack.ts +362 -0
- package/src/modules/customers/ai-tools/deals-pack.ts +505 -0
- package/src/modules/customers/ai-tools/people-pack.ts +369 -0
- package/src/modules/customers/ai-tools/settings-pack.ts +121 -0
- package/src/modules/customers/ai-tools/types.ts +76 -0
- package/src/modules/customers/ai-tools.ts +34 -0
- package/src/modules/customers/i18n/de.json +25 -0
- package/src/modules/customers/i18n/en.json +25 -0
- package/src/modules/customers/i18n/es.json +25 -0
- package/src/modules/customers/i18n/pl.json +25 -0
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.client.tsx +580 -0
- package/src/modules/customers/widgets/injection/ai-assistant-trigger/widget.ts +36 -0
- package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.client.tsx +191 -0
- package/src/modules/customers/widgets/injection/ai-deal-detail-trigger/widget.ts +37 -0
- package/src/modules/customers/widgets/injection-table.ts +41 -0
- package/src/modules/inbox_ops/ai-tools.ts +4 -0
- package/src/modules/inbox_ops/lib/llmProvider.ts +83 -7
- package/src/modules/notifications/setup.ts +11 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/ai-tools/categories-pack.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * `catalog.list_categories` + `catalog.get_category` (Phase 1 WS-C, Step 3.10).\n *\n * Read-only category tools scoped by tenant + organization. `parentId: null`\n * returns root nodes; any concrete UUID restricts to direct children.\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { E } from '#generated/entities.ids.generated'\nimport { CatalogProductCategory } from '../data/entities'\nimport { assertTenantScope, type CatalogAiToolDefinition, type CatalogToolContext } from './types'\n\nfunction resolveEm(ctx: CatalogToolContext): EntityManager {\n return ctx.container.resolve<EntityManager>('em')\n}\n\nfunction buildScope(ctx: CatalogToolContext, tenantId: string) {\n return { tenantId, organizationId: ctx.organizationId }\n}\n\nconst listCategoriesInput = z\n .object({\n parentId: z\n .union([z.string().uuid(), z.null()])\n .optional()\n .describe('Parent category id; pass `null` to list root nodes. Omit to list every category in scope.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n includeArchived: z\n .boolean()\n .optional()\n .describe('When true, include soft-deleted categories. Defaults to active-only.'),\n })\n .passthrough()\n\nconst listCategoriesTool: CatalogAiToolDefinition = {\n name: 'catalog.list_categories',\n displayName: 'List categories',\n description:\n 'List catalog categories scoped to tenant + organization. Use `parentId: null` to list roots or a specific uuid to fetch direct children.',\n inputSchema: listCategoriesInput,\n requiredFeatures: ['catalog.categories.view'],\n tags: ['read', 'catalog'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listCategoriesInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = { tenantId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n if (!input.includeArchived) where.deletedAt = null\n if ('parentId' in input) {\n where.parentId = input.parentId ?? null\n }\n const [rows, total] = await Promise.all([\n findWithDecryption<CatalogProductCategory>(\n em,\n CatalogProductCategory,\n where as any,\n { limit, offset, orderBy: { depth: 'asc', name: 'asc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(CatalogProductCategory, 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 name: row.name,\n slug: row.slug ?? null,\n description: row.description ?? null,\n parentId: row.parentId ?? null,\n rootId: row.rootId ?? null,\n treePath: row.treePath ?? null,\n depth: row.depth,\n childIds: Array.isArray(row.childIds) ? row.childIds : [],\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 })),\n total,\n limit,\n offset,\n }\n },\n}\n\nconst getCategoryInput = z.object({\n categoryId: z.string().uuid().describe('Category id (UUID).'),\n includeRelated: z\n .boolean()\n .optional()\n .describe(\n 'When true, include direct children (capped at 100) and inherited ancestor refs. Custom fields are always included.',\n ),\n})\n\nconst getCategoryTool: CatalogAiToolDefinition = {\n name: 'catalog.get_category',\n displayName: 'Get category',\n description:\n 'Fetch a catalog category by id with core fields and (optionally) children + ancestor inheritance + custom fields. Returns { found: false } when missing or cross-tenant.',\n inputSchema: getCategoryInput,\n requiredFeatures: ['catalog.categories.view'],\n tags: ['read', 'catalog'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = getCategoryInput.parse(rawInput)\n const em = resolveEm(ctx)\n const where: Record<string, unknown> = {\n id: input.categoryId,\n tenantId,\n deletedAt: null,\n }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const category = await findOneWithDecryption<CatalogProductCategory>(\n em,\n CatalogProductCategory,\n where as any,\n undefined,\n buildScope(ctx, tenantId),\n )\n if (!category || category.tenantId !== tenantId) {\n return { found: false as const, categoryId: input.categoryId }\n }\n const customFieldValues = await loadCustomFieldValues({\n em,\n entityId: E.catalog.catalog_product_category,\n recordIds: [category.id],\n tenantIdByRecord: { [category.id]: category.tenantId ?? null },\n organizationIdByRecord: { [category.id]: category.organizationId ?? null },\n tenantFallbacks: [category.tenantId ?? tenantId].filter((value): value is string => !!value),\n })\n const customFields = customFieldValues[category.id] ?? {}\n let related: Record<string, unknown> | null = null\n if (input.includeRelated) {\n const scope = buildScope(ctx, tenantId)\n const children = await findWithDecryption<CatalogProductCategory>(\n em,\n CatalogProductCategory,\n { tenantId, parentId: category.id, deletedAt: null } as any,\n { limit: 100, orderBy: { name: 'asc' } as any } as any,\n scope,\n )\n related = {\n children: children\n .filter((row) => row.tenantId === tenantId)\n .map((row) => ({\n id: row.id,\n name: row.name,\n slug: row.slug ?? null,\n depth: row.depth,\n isActive: !!row.isActive,\n })),\n ancestorIds: Array.isArray(category.ancestorIds) ? [...category.ancestorIds] : [],\n descendantIds: Array.isArray(category.descendantIds) ? [...category.descendantIds] : [],\n }\n }\n return {\n found: true as const,\n category: {\n id: category.id,\n name: category.name,\n slug: category.slug ?? null,\n description: category.description ?? null,\n parentId: category.parentId ?? null,\n rootId: category.rootId ?? null,\n treePath: category.treePath ?? null,\n depth: category.depth,\n childIds: Array.isArray(category.childIds) ? [...category.childIds] : [],\n ancestorIds: Array.isArray(category.ancestorIds) ? [...category.ancestorIds] : [],\n descendantIds: Array.isArray(category.descendantIds) ? [...category.descendantIds] : [],\n metadata: category.metadata ?? null,\n isActive: !!category.isActive,\n organizationId: category.organizationId ?? null,\n tenantId: category.tenantId ?? null,\n createdAt: category.createdAt ? new Date(category.createdAt).toISOString() : null,\n updatedAt: category.updatedAt ? new Date(category.updatedAt).toISOString() : null,\n },\n customFields,\n related,\n }\n },\n}\n\nexport const categoriesAiTools: CatalogAiToolDefinition[] = [listCategoriesTool, getCategoryTool]\n\nexport default categoriesAiTools\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineApiBackedAiTool } from "@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool";
|
|
3
|
+
import { assertTenantScope } from "./types.js";
|
|
4
|
+
const listOptionSchemasInput = z.object({
|
|
5
|
+
limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
|
|
6
|
+
offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
|
|
7
|
+
}).passthrough();
|
|
8
|
+
const listOptionSchemasTool = defineApiBackedAiTool({
|
|
9
|
+
name: "catalog.list_option_schemas",
|
|
10
|
+
displayName: "List option schemas",
|
|
11
|
+
description: "List product option schemas (variant axes, e.g. size/color definitions) for the caller tenant + organization.",
|
|
12
|
+
inputSchema: listOptionSchemasInput,
|
|
13
|
+
requiredFeatures: ["catalog.products.view"],
|
|
14
|
+
toOperation: (input, ctx) => {
|
|
15
|
+
assertTenantScope(ctx);
|
|
16
|
+
const limit = input.limit ?? 50;
|
|
17
|
+
const offset = input.offset ?? 0;
|
|
18
|
+
const page = Math.floor(offset / limit) + 1;
|
|
19
|
+
const operation = {
|
|
20
|
+
method: "GET",
|
|
21
|
+
path: "/catalog/option-schemas",
|
|
22
|
+
query: { page, pageSize: limit }
|
|
23
|
+
};
|
|
24
|
+
return operation;
|
|
25
|
+
},
|
|
26
|
+
mapResponse: (response, input) => {
|
|
27
|
+
const limit = input.limit ?? 50;
|
|
28
|
+
const offset = input.offset ?? 0;
|
|
29
|
+
const data = response.data ?? {};
|
|
30
|
+
const rawItems = Array.isArray(data.items) ? data.items : [];
|
|
31
|
+
return {
|
|
32
|
+
items: rawItems.map((row) => {
|
|
33
|
+
const createdAtRaw = row.created_at ?? row.createdAt ?? null;
|
|
34
|
+
const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null;
|
|
35
|
+
return {
|
|
36
|
+
id: row.id,
|
|
37
|
+
code: row.code,
|
|
38
|
+
name: row.name,
|
|
39
|
+
description: row.description ?? null,
|
|
40
|
+
schema: row.schema,
|
|
41
|
+
metadata: row.metadata ?? null,
|
|
42
|
+
isActive: !!(row.is_active ?? row.isActive),
|
|
43
|
+
organizationId: row.organization_id ?? row.organizationId ?? null,
|
|
44
|
+
tenantId: row.tenant_id ?? row.tenantId ?? null,
|
|
45
|
+
createdAt
|
|
46
|
+
};
|
|
47
|
+
}),
|
|
48
|
+
total: typeof data.total === "number" ? data.total : 0,
|
|
49
|
+
limit,
|
|
50
|
+
offset
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const listUnitConversionsInput = z.object({
|
|
55
|
+
productId: z.string().uuid().optional().describe("Restrict to unit conversions for this product."),
|
|
56
|
+
limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
|
|
57
|
+
offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
|
|
58
|
+
}).passthrough();
|
|
59
|
+
const listUnitConversionsTool = defineApiBackedAiTool({
|
|
60
|
+
name: "catalog.list_unit_conversions",
|
|
61
|
+
displayName: "List unit conversions",
|
|
62
|
+
description: "List product unit conversions (alternate units with `toBaseFactor`) for the caller tenant + organization. Optionally narrow by product.",
|
|
63
|
+
inputSchema: listUnitConversionsInput,
|
|
64
|
+
requiredFeatures: ["catalog.products.view"],
|
|
65
|
+
toOperation: (input, ctx) => {
|
|
66
|
+
assertTenantScope(ctx);
|
|
67
|
+
const limit = input.limit ?? 50;
|
|
68
|
+
const offset = input.offset ?? 0;
|
|
69
|
+
const page = Math.floor(offset / limit) + 1;
|
|
70
|
+
const query = {
|
|
71
|
+
page,
|
|
72
|
+
pageSize: limit
|
|
73
|
+
};
|
|
74
|
+
if (input.productId) query.productId = input.productId;
|
|
75
|
+
const operation = {
|
|
76
|
+
method: "GET",
|
|
77
|
+
path: "/catalog/product-unit-conversions",
|
|
78
|
+
query
|
|
79
|
+
};
|
|
80
|
+
return operation;
|
|
81
|
+
},
|
|
82
|
+
mapResponse: (response, input) => {
|
|
83
|
+
const limit = input.limit ?? 50;
|
|
84
|
+
const offset = input.offset ?? 0;
|
|
85
|
+
const data = response.data ?? {};
|
|
86
|
+
const rawItems = Array.isArray(data.items) ? data.items : [];
|
|
87
|
+
return {
|
|
88
|
+
items: rawItems.map((row) => {
|
|
89
|
+
const createdAtRaw = row.created_at ?? row.createdAt ?? null;
|
|
90
|
+
const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null;
|
|
91
|
+
const toBaseFactor = row.to_base_factor ?? row.toBaseFactor ?? null;
|
|
92
|
+
return {
|
|
93
|
+
id: row.id,
|
|
94
|
+
unitCode: row.unit_code ?? row.unitCode ?? null,
|
|
95
|
+
toBaseFactor: toBaseFactor === null ? null : String(toBaseFactor),
|
|
96
|
+
sortOrder: row.sort_order ?? row.sortOrder ?? 0,
|
|
97
|
+
isActive: !!(row.is_active ?? row.isActive),
|
|
98
|
+
productId: row.product_id ?? row.productId ?? null,
|
|
99
|
+
metadata: row.metadata ?? null,
|
|
100
|
+
organizationId: row.organization_id ?? row.organizationId ?? null,
|
|
101
|
+
tenantId: row.tenant_id ?? row.tenantId ?? null,
|
|
102
|
+
createdAt
|
|
103
|
+
};
|
|
104
|
+
}),
|
|
105
|
+
total: typeof data.total === "number" ? data.total : 0,
|
|
106
|
+
limit,
|
|
107
|
+
offset
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
const configurationAiTools = [
|
|
112
|
+
listOptionSchemasTool,
|
|
113
|
+
listUnitConversionsTool
|
|
114
|
+
];
|
|
115
|
+
var configuration_pack_default = configurationAiTools;
|
|
116
|
+
export {
|
|
117
|
+
configurationAiTools,
|
|
118
|
+
configuration_pack_default as default
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=configuration-pack.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/ai-tools/configuration-pack.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * `catalog.list_option_schemas` + `catalog.list_unit_conversions` (Phase 1\n * WS-C, Step 3.10).\n *\n * Product-configuration surface: option schemas (variant axes) and unit\n * conversions (UoM factors).\n *\n * Phase 3c of `.ai/specs/2026-04-27-ai-tools-api-backed-dry-refactor.md`:\n * both tools are now API-backed wrappers over the documented CRUD list\n * routes (`GET /api/catalog/option-schemas` and\n * `GET /api/catalog/product-unit-conversions`). Tool names, schemas,\n * requiredFeatures, and output shapes are unchanged.\n */\nimport { z } from 'zod'\nimport { defineApiBackedAiTool } from '@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool'\nimport type {\n AiApiOperationRequest,\n AiToolExecutionContext,\n} from '@open-mercato/ai-assistant/modules/ai_assistant/lib/ai-api-operation-runner'\nimport { assertTenantScope, type CatalogAiToolDefinition, type CatalogToolContext } from './types'\n\nconst listOptionSchemasInput = z\n .object({\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\ntype ListOptionSchemasInput = z.infer<typeof listOptionSchemasInput>\n\ntype ListOptionSchemasApiItem = {\n id?: string\n code?: string | null\n name?: string | null\n description?: string | null\n schema?: unknown\n metadata?: unknown\n is_active?: boolean | null\n isActive?: boolean | null\n organization_id?: string | null\n organizationId?: string | null\n tenant_id?: string | null\n tenantId?: string | null\n created_at?: string | null\n createdAt?: string | null\n}\n\ntype ListOptionSchemasApiResponse = {\n items?: ListOptionSchemasApiItem[]\n total?: number\n}\n\ntype ListOptionSchemasOutput = {\n items: Array<Record<string, unknown>>\n total: number\n limit: number\n offset: number\n}\n\nconst listOptionSchemasTool = defineApiBackedAiTool<\n ListOptionSchemasInput,\n ListOptionSchemasApiResponse,\n ListOptionSchemasOutput\n>({\n name: 'catalog.list_option_schemas',\n displayName: 'List option schemas',\n description:\n 'List product option schemas (variant axes, e.g. size/color definitions) for the caller tenant + organization.',\n inputSchema: listOptionSchemasInput,\n requiredFeatures: ['catalog.products.view'],\n toOperation: (input, ctx) => {\n assertTenantScope(ctx as unknown as CatalogToolContext)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const page = Math.floor(offset / limit) + 1\n const operation: AiApiOperationRequest = {\n method: 'GET',\n path: '/catalog/option-schemas',\n query: { page, pageSize: limit },\n }\n return operation\n },\n mapResponse: (response, input) => {\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const data = (response.data ?? {}) as ListOptionSchemasApiResponse\n const rawItems: ListOptionSchemasApiItem[] = Array.isArray(data.items) ? data.items : []\n return {\n items: rawItems.map((row) => {\n const createdAtRaw = row.created_at ?? row.createdAt ?? null\n const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null\n return {\n id: row.id,\n code: row.code,\n name: row.name,\n description: row.description ?? null,\n schema: row.schema,\n metadata: row.metadata ?? null,\n isActive: !!(row.is_active ?? row.isActive),\n organizationId: row.organization_id ?? row.organizationId ?? null,\n tenantId: row.tenant_id ?? row.tenantId ?? null,\n createdAt,\n }\n }),\n total: typeof data.total === 'number' ? data.total : 0,\n limit,\n offset,\n }\n },\n}) as unknown as CatalogAiToolDefinition\n\nconst listUnitConversionsInput = z\n .object({\n productId: z.string().uuid().optional().describe('Restrict to unit conversions for this product.'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\ntype ListUnitConversionsInput = z.infer<typeof listUnitConversionsInput>\n\ntype ListUnitConversionsApiItem = {\n id?: string\n product_id?: string | null\n productId?: string | null\n unit_code?: string | null\n unitCode?: string | null\n to_base_factor?: string | number | null\n toBaseFactor?: string | number | null\n sort_order?: number | null\n sortOrder?: number | null\n is_active?: boolean | null\n isActive?: boolean | null\n metadata?: unknown\n organization_id?: string | null\n organizationId?: string | null\n tenant_id?: string | null\n tenantId?: string | null\n created_at?: string | null\n createdAt?: string | null\n}\n\ntype ListUnitConversionsApiResponse = {\n items?: ListUnitConversionsApiItem[]\n total?: number\n}\n\ntype ListUnitConversionsOutput = {\n items: Array<Record<string, unknown>>\n total: number\n limit: number\n offset: number\n}\n\nconst listUnitConversionsTool = defineApiBackedAiTool<\n ListUnitConversionsInput,\n ListUnitConversionsApiResponse,\n ListUnitConversionsOutput\n>({\n name: 'catalog.list_unit_conversions',\n displayName: 'List unit conversions',\n description:\n 'List product unit conversions (alternate units with `toBaseFactor`) for the caller tenant + organization. Optionally narrow by product.',\n inputSchema: listUnitConversionsInput,\n requiredFeatures: ['catalog.products.view'],\n toOperation: (input, ctx) => {\n assertTenantScope(ctx as unknown as CatalogToolContext)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const page = Math.floor(offset / limit) + 1\n const query: Record<string, string | number | boolean | null | undefined> = {\n page,\n pageSize: limit,\n }\n if (input.productId) query.productId = input.productId\n const operation: AiApiOperationRequest = {\n method: 'GET',\n path: '/catalog/product-unit-conversions',\n query,\n }\n return operation\n },\n mapResponse: (response, input) => {\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const data = (response.data ?? {}) as ListUnitConversionsApiResponse\n const rawItems: ListUnitConversionsApiItem[] = Array.isArray(data.items) ? data.items : []\n return {\n items: rawItems.map((row) => {\n const createdAtRaw = row.created_at ?? row.createdAt ?? null\n const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null\n const toBaseFactor = row.to_base_factor ?? row.toBaseFactor ?? null\n return {\n id: row.id,\n unitCode: row.unit_code ?? row.unitCode ?? null,\n toBaseFactor: toBaseFactor === null ? null : String(toBaseFactor),\n sortOrder: row.sort_order ?? row.sortOrder ?? 0,\n isActive: !!(row.is_active ?? row.isActive),\n productId: row.product_id ?? row.productId ?? null,\n metadata: row.metadata ?? null,\n organizationId: row.organization_id ?? row.organizationId ?? null,\n tenantId: row.tenant_id ?? row.tenantId ?? null,\n createdAt,\n }\n }),\n total: typeof data.total === 'number' ? data.total : 0,\n limit,\n offset,\n }\n },\n}) as unknown as CatalogAiToolDefinition\n\nexport const configurationAiTools: CatalogAiToolDefinition[] = [\n listOptionSchemasTool,\n listUnitConversionsTool,\n]\n\nexport default configurationAiTools\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
3
|
+
import { E } from "../../../generated/entities.ids.generated.js";
|
|
4
|
+
import { Attachment } from "@open-mercato/core/modules/attachments/data/entities";
|
|
5
|
+
import { CatalogProductTagAssignment } from "../data/entities.js";
|
|
6
|
+
import { assertTenantScope } from "./types.js";
|
|
7
|
+
function resolveEm(ctx) {
|
|
8
|
+
return ctx.container.resolve("em");
|
|
9
|
+
}
|
|
10
|
+
function buildScope(ctx, tenantId) {
|
|
11
|
+
return { tenantId, organizationId: ctx.organizationId };
|
|
12
|
+
}
|
|
13
|
+
const listProductMediaInput = z.object({
|
|
14
|
+
productId: z.string().uuid().describe("Catalog product id (UUID)."),
|
|
15
|
+
limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
|
|
16
|
+
offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
|
|
17
|
+
}).passthrough();
|
|
18
|
+
const listProductMediaTool = {
|
|
19
|
+
name: "catalog.list_product_media",
|
|
20
|
+
displayName: "List product media",
|
|
21
|
+
description: "Enumerate media attachments (metadata only) associated with a catalog product. Use the attachment bridge (Step 3.7) to fetch bytes.",
|
|
22
|
+
inputSchema: listProductMediaInput,
|
|
23
|
+
requiredFeatures: ["catalog.products.view"],
|
|
24
|
+
tags: ["read", "catalog"],
|
|
25
|
+
handler: async (rawInput, ctx) => {
|
|
26
|
+
const { tenantId } = assertTenantScope(ctx);
|
|
27
|
+
const input = listProductMediaInput.parse(rawInput);
|
|
28
|
+
const em = resolveEm(ctx);
|
|
29
|
+
const limit = input.limit ?? 50;
|
|
30
|
+
const offset = input.offset ?? 0;
|
|
31
|
+
const where = {
|
|
32
|
+
tenantId,
|
|
33
|
+
entityId: E.catalog.catalog_product,
|
|
34
|
+
recordId: input.productId
|
|
35
|
+
};
|
|
36
|
+
if (ctx.organizationId) where.organizationId = ctx.organizationId;
|
|
37
|
+
const [rows, total] = await Promise.all([
|
|
38
|
+
findWithDecryption(
|
|
39
|
+
em,
|
|
40
|
+
Attachment,
|
|
41
|
+
where,
|
|
42
|
+
{ limit, offset, orderBy: { createdAt: "asc" } },
|
|
43
|
+
buildScope(ctx, tenantId)
|
|
44
|
+
),
|
|
45
|
+
em.count(Attachment, where)
|
|
46
|
+
]);
|
|
47
|
+
const filtered = rows.filter((row) => (row.tenantId ?? null) === tenantId);
|
|
48
|
+
return {
|
|
49
|
+
items: filtered.map((row) => ({
|
|
50
|
+
id: row.id,
|
|
51
|
+
fileName: row.fileName,
|
|
52
|
+
mimeType: row.mimeType,
|
|
53
|
+
fileSize: row.fileSize,
|
|
54
|
+
url: row.url,
|
|
55
|
+
storageDriver: row.storageDriver,
|
|
56
|
+
partitionCode: row.partitionCode,
|
|
57
|
+
entityId: row.entityId,
|
|
58
|
+
recordId: row.recordId,
|
|
59
|
+
organizationId: row.organizationId ?? null,
|
|
60
|
+
tenantId: row.tenantId ?? null,
|
|
61
|
+
createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null
|
|
62
|
+
})),
|
|
63
|
+
total,
|
|
64
|
+
limit,
|
|
65
|
+
offset
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const listProductTagsInput = z.object({
|
|
70
|
+
productId: z.string().uuid().describe("Catalog product id (UUID).")
|
|
71
|
+
}).passthrough();
|
|
72
|
+
const listProductTagsTool = {
|
|
73
|
+
name: "catalog.list_product_tags",
|
|
74
|
+
displayName: "List product tags",
|
|
75
|
+
description: "Enumerate tags assigned to a catalog product (label + slug). Returns { items, total }.",
|
|
76
|
+
inputSchema: listProductTagsInput,
|
|
77
|
+
requiredFeatures: ["catalog.products.view"],
|
|
78
|
+
tags: ["read", "catalog"],
|
|
79
|
+
handler: async (rawInput, ctx) => {
|
|
80
|
+
const { tenantId } = assertTenantScope(ctx);
|
|
81
|
+
const input = listProductTagsInput.parse(rawInput);
|
|
82
|
+
const em = resolveEm(ctx);
|
|
83
|
+
const where = { tenantId, product: input.productId };
|
|
84
|
+
if (ctx.organizationId) where.organizationId = ctx.organizationId;
|
|
85
|
+
const assignments = await findWithDecryption(
|
|
86
|
+
em,
|
|
87
|
+
CatalogProductTagAssignment,
|
|
88
|
+
where,
|
|
89
|
+
{ populate: ["tag"] },
|
|
90
|
+
buildScope(ctx, tenantId)
|
|
91
|
+
);
|
|
92
|
+
const filtered = assignments.filter((assignment) => assignment.tenantId === tenantId);
|
|
93
|
+
const items = filtered.map((assignment) => {
|
|
94
|
+
const tag = assignment.tag;
|
|
95
|
+
if (!tag || typeof tag === "string") return null;
|
|
96
|
+
return { id: tag.id, label: tag.label, slug: tag.slug };
|
|
97
|
+
}).filter((value) => value !== null);
|
|
98
|
+
return { items, total: items.length };
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const mediaTagsAiTools = [listProductMediaTool, listProductTagsTool];
|
|
102
|
+
var media_tags_pack_default = mediaTagsAiTools;
|
|
103
|
+
export {
|
|
104
|
+
media_tags_pack_default as default,
|
|
105
|
+
mediaTagsAiTools
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=media-tags-pack.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/catalog/ai-tools/media-tags-pack.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * `catalog.list_product_media` + `catalog.list_product_tags` (Phase 1 WS-C,\n * Step 3.10).\n *\n * Media tool returns metadata only \u2014 bytes flow through the Step 3.7\n * attachment bridge, not this enumeration. Tags tool mirrors the existing\n * `/api/catalog/tags` GET surface (feature-gated the same way).\n */\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { E } from '#generated/entities.ids.generated'\nimport { Attachment } from '@open-mercato/core/modules/attachments/data/entities'\nimport { CatalogProductTag, CatalogProductTagAssignment } from '../data/entities'\nimport { assertTenantScope, type CatalogAiToolDefinition, type CatalogToolContext } from './types'\n\nfunction resolveEm(ctx: CatalogToolContext): EntityManager {\n return ctx.container.resolve<EntityManager>('em')\n}\n\nfunction buildScope(ctx: CatalogToolContext, tenantId: string) {\n return { tenantId, organizationId: ctx.organizationId }\n}\n\nconst listProductMediaInput = z\n .object({\n productId: z.string().uuid().describe('Catalog product id (UUID).'),\n limit: z.number().int().min(1).max(100).optional().describe('Max rows (default 50, max 100).'),\n offset: z.number().int().min(0).optional().describe('Rows to skip (default 0).'),\n })\n .passthrough()\n\nconst listProductMediaTool: CatalogAiToolDefinition = {\n name: 'catalog.list_product_media',\n displayName: 'List product media',\n description:\n 'Enumerate media attachments (metadata only) associated with a catalog product. Use the attachment bridge (Step 3.7) to fetch bytes.',\n inputSchema: listProductMediaInput,\n requiredFeatures: ['catalog.products.view'],\n tags: ['read', 'catalog'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listProductMediaInput.parse(rawInput)\n const em = resolveEm(ctx)\n const limit = input.limit ?? 50\n const offset = input.offset ?? 0\n const where: Record<string, unknown> = {\n tenantId,\n entityId: E.catalog.catalog_product,\n recordId: input.productId,\n }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const [rows, total] = await Promise.all([\n findWithDecryption<Attachment>(\n em,\n Attachment,\n where as any,\n { limit, offset, orderBy: { createdAt: 'asc' } as any } as any,\n buildScope(ctx, tenantId),\n ),\n em.count(Attachment, where as any),\n ])\n const filtered = rows.filter((row) => (row.tenantId ?? null) === tenantId)\n return {\n items: filtered.map((row) => ({\n id: row.id,\n fileName: row.fileName,\n mimeType: row.mimeType,\n fileSize: row.fileSize,\n url: row.url,\n storageDriver: row.storageDriver,\n partitionCode: row.partitionCode,\n entityId: row.entityId,\n recordId: row.recordId,\n organizationId: row.organizationId ?? null,\n tenantId: row.tenantId ?? null,\n createdAt: row.createdAt ? new Date(row.createdAt).toISOString() : null,\n })),\n total,\n limit,\n offset,\n }\n },\n}\n\nconst listProductTagsInput = z\n .object({\n productId: z.string().uuid().describe('Catalog product id (UUID).'),\n })\n .passthrough()\n\nconst listProductTagsTool: CatalogAiToolDefinition = {\n name: 'catalog.list_product_tags',\n displayName: 'List product tags',\n description:\n 'Enumerate tags assigned to a catalog product (label + slug). Returns { items, total }.',\n inputSchema: listProductTagsInput,\n requiredFeatures: ['catalog.products.view'],\n tags: ['read', 'catalog'],\n handler: async (rawInput, ctx) => {\n const { tenantId } = assertTenantScope(ctx)\n const input = listProductTagsInput.parse(rawInput)\n const em = resolveEm(ctx)\n const where: Record<string, unknown> = { tenantId, product: input.productId }\n if (ctx.organizationId) where.organizationId = ctx.organizationId\n const assignments = await findWithDecryption<CatalogProductTagAssignment>(\n em,\n CatalogProductTagAssignment,\n where as any,\n { populate: ['tag'] as any } as any,\n buildScope(ctx, tenantId),\n )\n const filtered = assignments.filter((assignment) => assignment.tenantId === tenantId)\n const items = filtered\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 return { items, total: items.length }\n },\n}\n\nexport const mediaTagsAiTools: CatalogAiToolDefinition[] = [listProductMediaTool, listProductTagsTool]\n\nexport default mediaTagsAiTools\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|