ReviewOS

stacks/stx

SSR: client report binding falls through to the server error reporter

#2119
Closed chris opened this 8 days ago ·
8 days ago

During native rendering of Drone workspaces, a client signal named report resolves to the native server-global report() error logger inside interpolation. The all-page renderer emitted 36 empty Unhandled error records, even though the client functions and visible browser controls worked.

Representative component:

<script client>
const report = state(null)
</script>
<template>
  <p>{{ report()?.status }}</p>
</template>

Render with the normal Stacks server globals, where report is the native reporter from @stacksjs/logging/runtime. The captured stack reaches the logging reporter from safe-evaluator.js, evaluateExpression, replaceInterpolations, processExpressions and component rendering. Rendering only the homepage produces zero reports; the workflow render reproduces the fault.

Client-only lexical bindings should remain client-owned during server rendering. Their absence from the server context should not cause a same-named server-global function to execute. Explicit server code must still be able to call the normal native reporter.

Drone's bounded application correction renames these bindings to volumeReport, applicationReport and diagnosticReport. A genuine regression attaches a native observing logging transport, verifies that the real reporter is observable, then renders each real workflow with that reporter installed. Before the correction two cases fail on actual error records; afterward all three pass. All eleven pages then render with zero server errors, and actual browser volume, diagnostics and application controls still pass. This application correction does not establish that the evaluator generally protects client-only names.

Acceptance:

  • Reproduce with a client binding sharing a callable server-global name, including a component render.
  • Prevent server evaluation from falling through that client binding to a global callable, without suppressing ordinary server logging.
  • Preserve client hydration and reactive reads.
  • Cover a genuine native Stacks reporter and an ordinary explicit server expression in regression tests.

Reproduced with installed @stacksjs/stx 0.2.564 and @stacksjs/logging 0.75.221. Application correction: feb1f0b. Source is published on its review branch; exact-head integrated CI is separate qualification.

7 days ago

Fixed on main in 94f3019 (after v0.2.706; not yet published). The early SSR ownership check now covers every read of an authored client signal, including parenthesized, concatenated, ternary, template-literal and built-in-wrapped calls, before any server callable can run. Raw interpolation forms are protected too; server-only expressions still execute normally.

Regression evidence: packages/stx/test/expressions/client-callable-collision.test.ts and packages/stx/test/native/client-callable-collision.test.ts: 18 passing checks covering page and component rendering, a genuine global absent from server context, and native reactive updates. The expression suite also passed. scripts/ssr-reporter-smoke.ts was qualified with the real installed @stacksjs/logging 0.75.280 runtime and an observing transport: zero client-triggered error records, one explicit server error record as expected. No logger suppression or Craft changes.

7 days ago

Release follow-up: shipped and verified in @stacksjs/stx 0.2.707. A clean public-registry installation of 0.2.706 fails scripts/ssr-reporter-smoke.ts; the same harness against installed 0.2.707 passes with the genuine @stacksjs/logging runtime and observing transport: zero client-triggered errors across page/component renders, exactly one explicit server error as expected. Native reactive interpolation regressions remain covered by the maintained suite. Main CI and the exact tagged release-source gate passed.

Sign in to comment on this issue.