Files
template-app/test/module-profiles.test.ts
T
2026-11-14 09:56:45 +00:00

39 lines
1.9 KiB
TypeScript

// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// A business module is its service: every procedure is a call to it, so the module runs only on the profiles
// its business requirement names, and its manifest says so in `profiles`, which is what the Convex generator
// and the profile tests read (template lesson core-17). Without it, CRM was projected into the Convex backend
// once an app selected it. A native requirement (OCR, AI) is different: the module degrades without it, and
// `documents` deploys to Convex on purpose.
import { existsSync, readdirSync } from "node:fs"
import { join } from "node:path"
import type { ModuleManifest } from "@conusai-kit/core"
import { expect, it } from "vitest"
const modulesDir = join(import.meta.dirname, "..", "modules")
const moduleIds = readdirSync(modulesDir).filter((name) => existsSync(join(modulesDir, name, "index.ts")))
const isManifest = (value: unknown): value is ModuleManifest =>
typeof value === "object" && value !== null && "id" in value && "procedures" in value
it("a business module claims no profile its service does not run on", async () => {
const problems: string[] = []
for (const id of moduleIds) {
const exports = (await import(join(modulesDir, id, "index.ts"))) as Record<string, unknown>
for (const manifest of Object.values(exports).filter(isManifest)) {
for (const requirement of manifest.serviceRequirements ?? []) {
if (requirement.transport !== "business" || requirement.profiles === undefined) continue
const supported = new Set<string>(requirement.profiles)
const claimed = manifest.profiles ?? ["every profile"]
const extra = claimed.filter((profile) => !supported.has(profile))
if (extra.length > 0) {
problems.push(
`${manifest.id}: claims ${extra.join(", ")}; ${requirement.service} runs on ${requirement.profiles.join(", ")}`,
)
}
}
}
}
expect(problems).toEqual([])
}, 120_000)