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
+92
View File
@@ -0,0 +1,92 @@
// What the inventory module does, as pure TypeScript over the port in ports.ts.
//
// Items belong to the credential-bound app tenant and environment. Reservations
// additionally belong to the resolved app project; another project's reservation
// is not found. Platform project IDs never substitute for immutable binding IDs.
import { projectRef } from "@conusai-kit/business"
import { notFound, type ProjectScope } from "@conusai-kit/core"
import { type AvailabilityView, type ItemView, PAGE_LIMIT, type ReservationView } from "../contract/index.js"
import type { InventoryReads, InventoryService, Page } from "./ports.js"
/** Canonical partition and resolved-project reference, shared with the service parser. */
export const projectReference = (bindingId: string, projectId: string): string => projectRef(bindingId, projectId)
/** 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}`
export function listItems(
reads: InventoryReads,
query: { q?: string; after?: string; limit?: number },
): Promise<Page<ItemView>> {
const q = query.q?.trim()
return reads.listItems({
...(q ? { q } : {}),
...(query.after === undefined ? {} : { after: query.after }),
limit: query.limit ?? PAGE_LIMIT,
})
}
export function createItem(
service: InventoryService,
input: { sku: string; name: string; unit: string; description?: string },
): Promise<ItemView> {
const description = input.description?.trim()
return service.createItem({
sku: input.sku,
name: input.name.trim(),
unit: input.unit,
...(description ? { description } : {}),
})
}
export async function itemAvailability(
reads: InventoryReads,
itemId: string,
): Promise<{ item: ItemView; availability: AvailabilityView }> {
const [item, availability] = await Promise.all([reads.getItem(itemId), reads.availability(itemId)])
return { item, availability }
}
export function listProjectReservations(
reads: InventoryReads,
scope: ProjectScope,
query: { status?: "open" | "closed"; after?: string; limit?: number },
): Promise<Page<ReservationView>> {
return reads.listReservations({
reference: projectReference(reads.bindingId, scope.projectId),
...(query.status === undefined ? {} : { status: query.status }),
...(query.after === undefined ? {} : { after: query.after }),
limit: query.limit ?? PAGE_LIMIT,
})
}
export function reserveStock(
service: InventoryService,
scope: ProjectScope,
input: { itemId: string; locationId: string; quantity: number; requestId: string },
): Promise<ReservationView> {
return service.reserve({
itemId: input.itemId,
locationId: input.locationId,
quantity: input.quantity,
reference: projectReference(service.bindingId, scope.projectId),
key: requestKey(scope, input.requestId),
})
}
export async function releaseStock(
service: InventoryService,
scope: ProjectScope,
input: { reservationId: string; quantity?: number; requestId: string },
): Promise<ReservationView> {
const { reference } = await service.getReservation(input.reservationId)
// Another project's reservation is not found, never forbidden: its existence does not leak.
if (reference !== projectReference(service.bindingId, scope.projectId)) throw notFound("no such reservation")
return service.release({
reservationId: input.reservationId,
...(input.quantity === undefined ? {} : { quantity: input.quantity }),
key: requestKey(scope, input.requestId),
})
}