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
+22
View File
@@ -0,0 +1,22 @@
// The module's names, in a file with no import: a browser bundle can take them without the schemas.
/** The platform service this module is a client of (B-wave contract §3.14). */
export const CATALOG_SERVICE_NAME = "catalog"
/** The app permissions of the module. */
export const CATALOG_PERMISSIONS = {
read: "catalog.product.read",
write: "catalog.product.write",
} as const
/** What a search looks in: the name, the start of the code, or one identifier. */
export const PRODUCT_SEARCH_FIELDS = ["name", "code", "gtin", "erp"] as const
/** The most rows one page of a list asks the service for. */
export const PAGE_LIMIT = 50
/** The most rows one import chunk carries: the service's own limit. */
export const IMPORT_CHUNK_ROWS = 200
/** The largest file the import form reads in the browser. */
export const MAX_IMPORT_BYTES = 5_000_000
+26
View File
@@ -0,0 +1,26 @@
// The public API of the catalog module: what a page, another module and the OpenAPI document may import.
// Nothing here reaches core/, adapters/ or a service client.
export {
CATALOG_PERMISSIONS,
CATALOG_SERVICE_NAME,
IMPORT_CHUNK_ROWS,
MAX_IMPORT_BYTES,
PAGE_LIMIT,
PRODUCT_SEARCH_FIELDS,
} from "./constants.js"
export {
type ImportOutcomeView,
type ImportRow,
type ImportView,
importApply,
importList,
importOutcomeSchema,
importViewSchema,
type ProductSearchField,
type ProductView,
productGet,
productList,
productSearch,
productViewSchema,
} from "./procedures.js"
+132
View File
@@ -0,0 +1,132 @@
// The procedure contracts of the catalog module: schemas and names, no handler and no port.
//
// The module is a client of the platform's Catalog service (B-wave contract §3.14): products and their
// imports live there, in the deployment's organization, and every procedure is one service call. A read
// reads; an import is an `effect` (it calls an external service and writes nothing of this app's own).
// The service's int64 fields are plain values here, so what a page loads is JSON: a revision is its digits,
// a count a number.
import { procedure } from "@conusai-kit/core"
import { z } from "zod"
import { CATALOG_PERMISSIONS, IMPORT_CHUNK_ROWS, PRODUCT_SEARCH_FIELDS } from "./constants.js"
const inProject = { org: z.string(), workspace: z.string(), project: z.string() }
const page = { after: z.string().max(64).optional(), limit: z.number().int().min(1).max(200).optional() }
/** What a form generates once per submission, so a retried request applies once. */
const requestId = z.string().uuid()
const productId = z.string().min(1).max(64)
/** A revision as its digits: the service's are 64-bit. */
const revision = z.string().regex(/^\d{1,19}$/)
export const productViewSchema = z.object({
productId: z.string(),
code: z.string(),
name: z.string(),
description: z.string(),
/** A UN/CEFACT Recommendation 20 unit code. */
baseUnit: z.string(),
status: z.enum(["active", "archived", "deleted"]),
groupCode: z.string().nullable(),
identifiers: z.array(z.object({ kind: z.string(), value: z.string() })),
revision,
})
export type ProductView = z.output<typeof productViewSchema>
export const importViewSchema = z.object({
importId: z.string(),
sourceName: z.string(),
format: z.string(),
status: z.string(),
revision,
created: z.number().int(),
updated: z.number().int(),
unchanged: z.number().int(),
refused: z.number().int(),
})
export type ImportView = z.output<typeof importViewSchema>
export const importOutcomeSchema = z.object({
import: importViewSchema,
rows: z.array(
z.object({
sourceRow: z.number().int(),
outcome: z.string(),
productId: z.string().nullable(),
reason: z.string().nullable(),
}),
),
})
export type ImportOutcomeView = z.output<typeof importOutcomeSchema>
const importRowSchema = z.object({
/** The line of the source file, which the service keeps as the row's provenance. */
sourceRow: z.number().int().min(1),
/** The revision the row replaces, for a product that exists. */
revision: revision.optional(),
product: z.object({
code: z.string().min(1).max(64),
name: z.string().min(1).max(200),
baseUnit: z.string().min(1).max(3),
description: z.string().max(4000).optional(),
}),
})
export type ImportRow = z.output<typeof importRowSchema>
const productPage = z.object({ rows: z.array(productViewSchema), after: z.string().optional() })
export const productList = procedure("catalog.product.list")
.kind("read")
.scope("project")
.permission(CATALOG_PERMISSIONS.read)
.input(z.object({ ...inProject, ...page }))
.output(productPage)
.contract()
const searchField = z.enum(PRODUCT_SEARCH_FIELDS)
export type ProductSearchField = z.output<typeof searchField>
export const productSearch = procedure("catalog.product.search")
.kind("read")
.scope("project")
.permission(CATALOG_PERMISSIONS.read)
.input(z.object({ ...inProject, q: z.string().trim().min(1).max(200), by: searchField.optional(), ...page }))
.output(productPage)
.contract()
export const productGet = procedure("catalog.product.get")
.kind("read")
.scope("project")
.permission(CATALOG_PERMISSIONS.read)
.input(z.object({ ...inProject, productId }))
.output(productViewSchema)
.contract()
export const importList = procedure("catalog.import.list")
.kind("read")
.scope("project")
.permission(CATALOG_PERMISSIONS.read)
.input(z.object({ ...inProject, ...page }))
.output(z.object({ rows: z.array(importViewSchema), after: z.string().optional() }))
.contract()
export const importApply = procedure("catalog.import.apply")
.kind("effect")
.scope("project")
.permission(CATALOG_PERMISSIONS.write)
.input(
z.object({
...inProject,
/** The source file's lower-case SHA-256: one file is one import, however many chunks it takes. */
fileHash: z.string().regex(/^[0-9a-f]{64}$/),
sourceName: z.string().trim().min(1).max(200),
format: z.enum(["csv", "xlsx", "json"]),
chunk: z.number().int().min(0),
finalChunk: z.boolean(),
/** The revision of the import, from the chunk before; absent on the first. */
revision: revision.optional(),
rows: z.array(importRowSchema).min(1).max(IMPORT_CHUNK_ROWS),
requestId,
}),
)
.output(importOutcomeSchema)
.contract()