ConusAI vendor v0.1.0-beta.114
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-beta.114
2026-11-14 09:56:45 +00:00
commit 1ce8d23c35
867 changed files with 122104 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
// What the catalog module does, as pure TypeScript over the port in ports.ts.
//
// Products are the organization's: every project of the app sees the same ones (a multi-tenant app keeps
// all its tenants' products in its deployment's one organization; partitioning by app tenant is an open
// owner decision, B-wave contract §11.4).
import type { ProjectScope } from "@conusai-kit/core"
import {
type ImportOutcomeView,
type ImportRow,
type ImportView,
PAGE_LIMIT,
type ProductSearchField,
type ProductView,
} from "../contract/index.js"
import type { CatalogReads, CatalogService, Page } from "./ports.js"
/** The service's idempotency key of a request: one project's request id never answers another's. */
export const requestKey = (scope: Pick<ProjectScope, "projectId">, requestId: string): string =>
`app-project:${scope.projectId}:${requestId}`
const cursor = (after: string | undefined) => (after === undefined ? {} : { after })
export function listProducts(
reads: CatalogReads,
query: { after?: string; limit?: number },
): Promise<Page<ProductView>> {
return reads.listProducts({ ...cursor(query.after), limit: query.limit ?? PAGE_LIMIT })
}
export function searchProducts(
reads: CatalogReads,
query: { q: string; by?: ProductSearchField; after?: string; limit?: number },
): Promise<Page<ProductView>> {
const q = query.q.trim()
const by = query.by ?? "name"
const limit = query.limit ?? PAGE_LIMIT
if (by === "name") return reads.searchProducts({ q, ...cursor(query.after), limit })
return reads.listProducts({ search: { by, q }, ...cursor(query.after), limit })
}
export function listImports(reads: CatalogReads, query: { after?: string; limit?: number }): Promise<Page<ImportView>> {
return reads.listImports({ ...cursor(query.after), limit: query.limit ?? PAGE_LIMIT })
}
export function applyImport(
service: CatalogService,
scope: ProjectScope,
input: {
fileHash: string
sourceName: string
format: "csv" | "xlsx" | "json"
chunk: number
finalChunk: boolean
revision?: string
rows: readonly ImportRow[]
requestId: string
},
): Promise<ImportOutcomeView> {
return service.applyImport({
fileHash: input.fileHash,
sourceName: input.sourceName.trim(),
format: input.format,
chunk: input.chunk,
finalChunk: input.finalChunk,
...(input.revision === undefined ? {} : { revision: input.revision }),
rows: input.rows,
key: requestKey(scope, input.requestId),
})
}