// Reads one user by id — including a deactivated one. This is the whole point // of deactivation() vs softDelete(): after deactivation the row is STILL here // and readable, just stamped with `deactivatedAt`. (softDelete() would make // this return null.) import { defineAction } from '@voltro/protocol' import { Schema } from 'effect' export const getUser = defineAction({ name: 'users.get', // Reads one `users` row by id and returns its email — so read the reason // literally, not as a shrug. `users` carries `deactivation()` and NOT // `tenant()`, so nothing scopes this read to a caller. It is open because the // whole table is this demo's own output: the template ships no seed and // `users.create` below is the only writer, both on the same unauthenticated // surface. There is no third party's address in here to leak. // // The moment you point this at real accounts that stops being true. Wire an // auth strategy (see `api-auth`) and replace this line with // `guards: [{ scope: 'users:read' }]` in the same change. openAccess: 'reads one row of this demo\'s own `users` table by id; the table has no seed and no ' + 'writer but `users.create` on this same open surface, so it holds no third party\'s data. ' + 'Guard it before real accounts land here.', input: Schema.Struct({ id: Schema.String }), output: Schema.NullOr(Schema.Struct({ id: Schema.String, email: Schema.String, name: Schema.String, deactivatedAt: Schema.NullOr(Schema.Date), })), })