Skip to content

[post-v3 DX] Make server trust surfaces capability-explicit #249

Description

@olliethedev

Context

Follow-up from the retained RC3 application validation in better-stack-web#37 and the finalized server surfaces from #202.

This is a post-v3 incremental DX improvement. It must not block or reopen v3.

Friction

RC3's separation between request-authorized, trusted, and raw operations is sound, but the property names do not communicate enough at a security-sensitive call site:

myStack.forRequest(request).operations.blog.createPost(...)
myStack.trusted.blog.createPost(...)
myStack.raw.blog.createPost(...)

A developer must consult declarations/docs to remember that:

  • request operations resolve identity, derive trusted facts, and enforce policy;
  • trusted operations intentionally skip caller authorization but preserve validation, domain behavior, and lifecycle hooks;
  • raw access bypasses more of the composition contract and is not the normal application API.

trusted does not show why bypassing authorization is justified, and raw understates the danger. Both are easy to autocomplete into ordinary application code.

Proposed better alternative

Add capability-explicit APIs in a backward-compatible minor release:

const system = myStack.asTrusted({
  reason: "HMAC-verified blog generation webhook",
})
await system.operations.blog.createPost(input)

await myStack.unsafe.raw.blog.createPost(input)

Preferred shape:

  1. Keep forRequest(request).operations as the authoritative caller surface.
  2. Add asTrusted({ reason, actor? }).operations so bypass intent is explicit and available to logs/hooks.
  3. Move the low-level escape hatch under unsafe.raw or expose unsafeRaw; the name should clearly state that composition guarantees are being bypassed.
  4. Retain .trusted and .raw as deprecated aliases through the next major release.
  5. Put the exact guarantees on every surface in generated JSDoc/hover text and link to one capability matrix.
  6. Brand trusted/raw capabilities as server-only so they cannot enter the browser-safe projection.

The reason should be lightweight application context, not an authorization mechanism. It improves reviewability and optional audit logging without pretending to make a trusted call safe by itself.

Acceptance criteria

  • A call site communicates whether it is request-authorized, application-trusted, or unsafe/raw without external documentation.
  • Trusted calls require or strongly encourage a human-readable reason.
  • Trusted context can be observed by lifecycle/audit hooks without changing operation inputs.
  • Unsafe/raw access has an unmistakable name and remains server-only.
  • Type and runtime tests prove which validation, authorization, domain, transaction, and lifecycle layers each capability preserves.
  • Existing .trusted and .raw consumers remain source-compatible with deprecation guidance.
  • The generated API reference includes one guarantees/bypass matrix.

Relationship to existing docs work

#175 should document the RC3 surfaces. This issue improves the interface itself so the trust decision remains clear during autocomplete and code review after those docs are no longer in view.

Release boundary

Post-v3 enhancement only. Do not hold v3 publication or require an RC4 for this issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions