package console import ( "context" "github.com/carlosframework/platform/internal/hostops" "github.com/carlosframework/platform/internal/release" ) // claimAppCall runs one independent app mutation as a joined exclusive // app-mutation operation through the data boundary's runner // (hostops RunAppMutation via release.WithAppMutation). The whole walk is // one durable effect; its permit is what lets the walk's bucket, SQL and // backend writes through the boundaries. The runner settles a callback // error "not-applied" (and reopens) only when no boundary marked a write or // backend call issued, so an ordinary validation or stale-etag refusal does // not hold the app. Once anything was issued, failure stays uncertain and // keeps the operation closed for fenced reconciliation; it never expires // like a registration. // // Restore is NOT routed here: the SQL agent's claim_restore.go owns the // receipt-first restore door on the same typed API (BeginExclusive, // PrepareRestore, CompleteRestore, RecoverMutation). func claimAppCall[T any](s *Server, ctx context.Context, acct *Account, app, action string, call func(context.Context) (T, error)) (T, error) { var result T if !s.cfg.HostClaim { return call(ctx) } // Fail closed: a plain bucket would run the call with no operation. if _, ok := s.cfg.Releases.(release.AppMutationRunner); !ok { return result, hostops.ErrContract } err := release.WithAppMutation(ctx, s.cfg.Releases, acct.Sqid, app, action, func(callCtx context.Context) error { var callErr error result, callErr = call(callCtx) return callErr }) return result, err } func (s *Server) claimAppMutation(ctx context.Context, acct *Account, app, action string, call func(context.Context) error) error { _, err := claimAppCall(s, ctx, acct, app, action, func(ctx context.Context) (struct{}, error) { return struct{}{}, call(ctx) }) return err } // claimProjection runs one per-console SQL projection of open-admission // bucket evidence (restore receipt, tombstone) inside its own short // exclusive operation, so purge cannot start between the evidence read and // the SQL write. fn receives the permitted context for RestoreProjection / // TrashProjection and the SQL view. func (s *Server) claimProjection(ctx context.Context, acct *Account, app string, fn func(context.Context) error) error { return s.claimAppMutation(ctx, acct, app, "projection", fn) }