// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 // The modules that deploy to the Convex backend on this profile, derived from the app's one // module list (modules/index.ts) -- named exclusions, not a second list. // // Why a module is excluded: its callable procedure graph needs a Node-only runtime or a workflow // that has not been composed here. These are explicit gaps, not inferred from the module // importing a package which has unrelated Node-only exports. Auth is included: its procedure // handlers use Web Crypto; the OIDC redirects and sealed session storage remain in the trusted // Next BFF, which invokes Convex functions with server-only admin auth and a verified identity. // // Convex actions have no ctx.db, so the runtime cannot run an effect procedure that changes the // app's own rows in an action. File upload and delete have explicit action→mutation compositions // in files.ts; other effects remain omitted until they have an equivalent state-machine workflow. export const CONVEX_EXCLUDED_MODULES = new Map([]) // The modules whose effect procedures are generated as Convex actions (convex/lib/effects.ts): // each effect is one call to a platform service through the module's own port and owns no app // row, so it needs no transaction -- except the account module's, whose rows are reached through // its bound store, one transaction per resumable step. The kernel still resolves the tenant scope and checks the // permission, against ctx.db in an internal query (convex/effectScope.ts), and the handler's // nested reads and writes run as the generated queries and mutations they always are. export const CONVEX_ACTION_EFFECT_MODULES = new Map() CONVEX_ACTION_EFFECT_MODULES.set("guides", "Guides runtime calls through GUIDES_PLATFORM; no app rows") // kit:guides CONVEX_ACTION_EFFECT_MODULES.set("support", "Support session/contact calls through SUPPORT_PLATFORM") // kit:support // The account module's export and deletion compose every module's share (platform calls) and own the // deletion ledger, which they reach through ACCOUNT_STORE: one internal query or mutation per step. CONVEX_ACTION_EFFECT_MODULES.set("account", "account export/deletion; ledger steps through convex/account.ts") export const CONVEX_EXCLUDED_PROCEDURES = new Map([ ["branding.logo.set", "logo decoding and Blob writes require an audited action workflow"], ["branding.logo.clear", "logo record updates and concurrent Blob cleanup require an action workflow"], ["branding.logo.get", "logo bytes require an authorized Blob action workflow"], ["files.file.delete", "the BFF composes the object delete action with internal mutations"], ]) // kit:guides:begin -- a survey file's bytes are the streamed body of a PUT, which cannot be a Convex // action's argument, and no BFF composition streams it to the platform on this profile yet. CONVEX_EXCLUDED_PROCEDURES.set( "guides.runtime.uploadFile", "a streamed request body cannot be a Convex action argument", ) // kit:guides:end const modulesFor = (appModules, includeBffFileEffects) => appModules .filter((module) => !CONVEX_EXCLUDED_MODULES.has(module.id)) .map((module) => { const procedures = (module.procedures ?? []).filter((procedure) => { const composedBffFileProcedure = includeBffFileEffects && module.id === "files" && procedure.name.startsWith("files.file.") const runnable = procedure.kind !== "effect" || CONVEX_ACTION_EFFECT_MODULES.has(module.id) return composedBffFileProcedure || (runnable && !CONVEX_EXCLUDED_PROCEDURES.has(procedure.name)) }) // Requirements name callable operations. Filtering a procedure must also remove its // requirement entry, or the projected registry refuses the now-unknown operation. // Keep metadata for retained procedures and own jobs without changing the source manifest. // Unknown source operations remain so registry validation still refuses invalid declarations. const retained = new Set(procedures.map(({ name }) => name)) const removed = new Set( (module.procedures ?? []).filter(({ name }) => !retained.has(name)).map(({ name }) => name), ) return { ...module, procedures, ...(module.serviceRequirements === undefined ? {} : { serviceRequirements: module.serviceRequirements .map((requirement) => ({ ...requirement, operations: Object.fromEntries( Object.entries(requirement.operations).filter( ([name]) => !removed.has(name) || Object.hasOwn(module.jobs ?? {}, name), ), ), })) .filter((requirement) => Object.keys(requirement.operations).length > 0), }), } }) // The backend generator and deployment registry omit procedures that are composed as actions by // the BFF. The web HTTP registry keeps those file contracts so their routes still validate input, // tenancy, permissions, rate limits and CSRF before the caller invokes the action workflow. export const convexModules = (appModules) => modulesFor(appModules, false) export const convexBffModules = (appModules) => modulesFor(appModules, true)