ITADN

bug(datastar): `readSignals` reads GET signals from header instead of query parameter

#4020Closed987Nabil 创建于 2026-03-13
9
987Nabilcommented
## Bug Description `readSignals` for GET requests reads signals from the `datastar` **header**, but the Datastar JS client sends them as a **query parameter** `?datastar={...}`. ## Current Behavior (wrong) ```scala // DatastarPackageBase.scala def readSignals[T: Schema](request: Request): IO[String, T] = if (request.method == Method.GET) { ZIO.fromEither { request .header[String]("datastar") // ← reads from HEADER ``` ## Expected Behavior For GET requests, Datastar sends signals as a query parameter, not a header. From the Datastar source ([`fetch.ts:113-115`](https://github.com/starfederation/datastar/blob/main/library/src/plugins/actions/fetch.ts)): ```typescript if (method === 'GET') { queryParams.set('datastar', body) // ← sends as QUERY PARAMETER } else { req.body = body // ← body for POST/PUT/PATCH/DELETE } ``` The `Datastar-Request: true` header is just a boolean flag indicating the request comes from Datastar — it does NOT contain the signal data. ## Fix ```scala def readSignals[T: Schema](request: Request): IO[String, T] = if (request.method == Method.GET) { ZIO.fromEither { request .queryParam("datastar") // ← read from query parameter .toRight(new Exception("Missing 'datastar' query parameter")) .left.map(_.getMessage()) .flatMap(_.fromJson[T](zio.schema.codec.JsonCodec.jsonDecoder(Schema[T]))) } } else { request.body.asJson[T].mapError(_.getMessage) } ``` ## Test Fix `ReadSignalsSpec` also needs to be updated — it currently adds signals as a header in test requests, which matches the buggy implementation: ```scala // Current (wrong — matches buggy code): val request = Request .get(URL.root / "test") .addHeader(Header.Custom("datastar", jsonData)) // Should be: val request = Request .get((URL.root / "test").withQueryParams(QueryParams("datastar" -> jsonData))) ``` ## Additional Bugs Found While reviewing the datastar SDK, the following additional bugs were identified: 1. **`DatastarRetry` is missing 2 of 4 valid values** — Datastar supports `'auto' | 'error' | 'always' | 'never'` but the SDK only models `Auto` and `Error`. 2. **`DatastarRequestCancellation` has invalid `Cleanup` value** — Datastar only supports `'auto' | 'disabled' | AbortController`. Also uses PascalCase (`"Auto"`) but Datastar expects lowercase (`"auto"`). 3. **`Signal.ref` throws for non-primitive types** — Datastar `$signalName` works for any type. The runtime restriction is incorrect. 4. **`SignalUpdate.astToExpression` doesn't escape `'` in strings** — generates broken JS for values containing single quotes.
关闭于 2026-03-14 0 条评论