// Create a project — the SaaS bundle in ONE handler. The billing plugin // auto-merges its typed `EntitlementExceeded` (+ `BillingError`) into this // procedure's wire-error union, so the client decodes the over-quota failure // typed WITHOUT a manual `error:` declaration here. import { defineMutation } from '@voltro/protocol' import { Schema } from 'effect' export const createProject = defineMutation({ name: 'projects.create', target: { table: 'projects', op: 'insert' }, // An entitlement check is not an access decision. `requireEntitlement` // answers HOW MANY the tenant has paid for; `guards:` / `openAccess:` answer // WHO MAY CALL IT. A quota gate refuses the fourth project and cheerfully // allows the first three — from anyone. // // Open because this template ships no auth strategy and no rbac (it is the // billing bundle; `api-saas-starter` is the same domain WITH auth, and it // guards these procedures). With no identity, every caller is an anonymous // Subject holding no scopes and a `guards: [{ scope }]` would deny all of them. openAccess: 'inserts a project named by the caller into the request\'s tenant, after the billing ' + 'entitlement gate. A quota bounds HOW MANY, never WHO — see `api-saas-starter` for the ' + 'same procedure with an auth strategy and a `projects:write` guard.', input: Schema.Struct({ name: Schema.NonEmptyString }), output: Schema.Struct({ id: Schema.String, name: Schema.String, tenantId: Schema.String, }), })