Repository navigation
Match charset parameter values case-insensitively - #24
Open
rvolosatovs wants to merge 1 commit into
Open
rvolosatovs wants to merge 1 commit into
rvolosatovs wants to merge 1 commit into
Conversation
RFC 9110 section 8.3.2 defines charset names as case-insensitive, so `Accept: text/plain;charset=utf-8` must match an available `text/plain;charset=UTF-8`. Other parameter values are still compared exactly. Assisted-by: anthropic:claude-opus-5-5 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. With `?index=INDEX`, optionally qualified by `&transaction=DIGEST`, it instead returns a `starstream:ledger` package holding only the `utxo` interface for that unspent output: the UTXO's methods, decoded from its contract, as the freestanding functions `/rpc` invokes, taking the output reference before the method parameters. Unused types are pruned and the packages the interface depends on are printed nested. The world of the contract is dropped from its package, so a UTXO interface using types defined in the contract's own package does not make the two packages depend on each other. The output reference parameters are named `transaction` and `index`, prefixed with `utxo-` for as long as they clash with a method parameter. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The UTXO WIT of every instance a contract exports is built, printed and encoded once, when the contract is published, and served from memory. Publishing therefore now rejects, with 400, Wasm that is not a component and contracts that themselves define a `starstream:ledger` package. Validation and WIT extraction run on a blocking thread, and only once the publisher has been charged, so a rejected contract consumes its nonce and fee, and a duplicate one is rejected before any work is done. The ledger package is encoded to Wasm once, by a build script, only when the `server` feature is enabled. In the query, `index` is a `u32` and `transaction` must be a digest; omitting it refers to the genesis block. A query naming `index` or `transaction` more than once is rejected with 400, and an empty query (`GET /rpc?`) is treated as no query. `headers-accept` is pinned to the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the server responds with. Matching `charset=utf-8` against it additionally requires case-insensitive charset comparison in `headers-accept` (maxcountryman/headers-accept#24), so lowercase charsets get 406 until that lands. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT from the endpoint, in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from that endpoint, encoded as Wasm, instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. Ledger tests cover parameter name clashes, `q` values, `HEAD`, rejection of an empty `transaction`, index overflow and a UTXO interface using types of the contract's package. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. With `?index=INDEX`, optionally qualified by `&transaction=DIGEST`, it instead returns a `starstream:ledger` package holding only the `utxo` interface for that unspent output: the UTXO's methods, decoded from its contract, as the freestanding functions `/rpc` invokes, taking the output reference before the method parameters. Unused types are pruned and the packages the interface depends on are printed nested. The world of the contract is dropped from its package, so a UTXO interface using types defined in the contract's own package does not make the two packages depend on each other. The output reference parameters are named `transaction` and `index`, prefixed with `utxo-` for as long as they clash with a method parameter. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The UTXO WIT of every instance a contract exports is built, printed and encoded once, when the contract is published, and served from memory. Publishing therefore now rejects, with 400, Wasm that is not a component and contracts that themselves define a `starstream:ledger` package. Validation and WIT extraction run only once the publisher has been charged, so a rejected contract consumes its nonce and fee, and a duplicate one is rejected before any work is done. The ledger package is encoded to Wasm once, by a build script, only when the `server` feature is enabled. In the query, `index` is a `u32` and `transaction` must be a digest; omitting it refers to the genesis block. A query naming `index` or `transaction` more than once is rejected with 400, and an empty query (`GET /rpc?`) is treated as no query. `headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the server responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT from the endpoint, in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from that endpoint, encoded as Wasm, instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. Ledger tests cover parameter name clashes, lowercase charsets, `q` values, `HEAD`, rejection of an empty `transaction`, index overflow and a UTXO interface using types of the contract's package. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. With `?index=INDEX`, optionally qualified by `&transaction=DIGEST`, it instead returns a `starstream:ledger` package holding only the `utxo` interface for that unspent output: the UTXO's methods, decoded from its contract, as the freestanding functions `/rpc` invokes, taking the output reference before the method parameters. Unused types are pruned and the packages the interface depends on are printed nested. The world of the contract is dropped from its package, so a UTXO interface using types defined in the contract's own package does not make the two packages depend on each other. The output reference parameters are named `transaction` and `index`, prefixed with `utxo-` for as long as they clash with a method parameter. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The UTXO WIT of every instance a contract exports is built, printed and encoded once, when the contract is published, and served from memory. Publishing therefore now rejects, with 400, Wasm that is not a component and contracts that themselves define a `starstream:ledger` package. Validation and WIT extraction run only once the publisher has been charged, so a rejected contract consumes its nonce and fee, and a duplicate one is rejected before any work is done. The ledger package is encoded to Wasm once, by a build script, only when the `server` feature is enabled. In the query, `index` is a `u32` and `transaction` must be a digest; omitting it refers to the genesis block. A query naming `index` or `transaction` more than once is rejected with 400, and an empty query (`GET /rpc?`) is treated as no query. `headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the server responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT from the endpoint, in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from that endpoint, encoded as Wasm, instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. Ledger tests cover parameter name clashes, lowercase charsets, `q` values, `HEAD`, rejection of an empty `transaction`, index overflow and a UTXO interface using types of the contract's package. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. With `?index=INDEX`, optionally qualified by `&transaction=DIGEST`, it instead returns a `starstream:ledger` package holding only the `utxo` interface for that unspent output: the UTXO's methods, decoded from its contract, as the freestanding functions `/rpc` invokes, taking the output reference before the method parameters. Unused types are pruned and the packages the interface depends on are printed nested. The world of the contract is dropped from its package, so a UTXO interface using types defined in the contract's own package does not make the two packages depend on each other. The output reference parameters are named `transaction` and `index`, prefixed with `utxo-` for as long as they clash with a method parameter. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The UTXO WIT of every UTXO instance a contract exports, that is every exported interface defining a `utxo` resource, whether named by the contract or a WIT interface, is built, printed and encoded once, when the contract is published, and served from memory, keyed by export name as `POST /rpc` resolves it. Publishing therefore now rejects, with 400, Wasm that is not a component and contracts that themselves define a `starstream:ledger` package. As before, a rejected contract consumes neither nonce nor fee: validation and WIT extraction run before the publisher is charged, which happens under the contracts write lock, so of concurrent publishes of the same contract only one is charged. A contract already published is rejected before any of that work. The ledger package is encoded to Wasm once, by a build script, only when the `server` feature is enabled. In the query, `index` is a `u32` and `transaction` must be a digest; omitting it refers to the genesis block. A query naming `index` or `transaction` more than once is rejected with 400, and a query without parameters (`GET /rpc?`, `GET /rpc?&`) is treated as no query. `headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the server responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT from the endpoint, in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from that endpoint, encoded as Wasm, instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. Ledger tests cover parameter name clashes, lowercase charsets, `q` values, `HEAD`, queries without parameters, rejection of an empty `transaction`, index overflow, a UTXO interface using types of the contract's package and a UTXO exported as a WIT interface next to a non-UTXO export. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. With `?index=INDEX`, optionally qualified by `&transaction=DIGEST`, it instead returns a `starstream:ledger` package holding only the `utxo` interface for that unspent output: the UTXO's methods, decoded from its contract, as the freestanding functions `/rpc` invokes, taking the output reference before the method parameters. The `utxo` interface is a new interface, holding only the types its functions use: imported from the UTXO interface of the contract if that is named, moved out of it otherwise. The contract's interfaces are left in place and its world is dropped from its package, so no package of the contract depends on `starstream:ledger`, even if another of its interfaces uses the UTXO interface. The packages the `utxo` interface depends on are printed nested. The output reference parameters are named `transaction` and `index`, prefixed with `utxo-` for as long as they clash with a method parameter. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The UTXO WIT of every UTXO instance a contract exports, that is every exported interface defining a `utxo` resource, whether named by the contract or a WIT interface, is built, printed and encoded once, when the contract is published, and served from memory, keyed by export name as `POST /rpc` resolves it. Publishing therefore now rejects, with 400, Wasm that is not a component and contracts that themselves define an unversioned `starstream:ledger` package, whose name the served package would clash with; a versioned one is printed nested next to it. As before, a rejected contract consumes neither nonce nor fee: validation and WIT extraction run before the publisher is charged, which happens under the contracts write lock, so of concurrent publishes of the same contract only one is charged. A contract already published is rejected before any of that work. The ledger package is encoded to Wasm once, by a build script, only when the `server` feature is enabled. In the query, `index` is a `u32` and `transaction` must be a digest; omitting it refers to the genesis block. A query naming `index` or `transaction` more than once is rejected with 400, and a query without parameters (`GET /rpc?`, `GET /rpc?&`) is treated as no query. `headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the server responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT from the endpoint, in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from that endpoint, encoded as Wasm, instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. Ledger tests cover parameter name clashes, lowercase charsets, `q` values, `HEAD`, queries without parameters, rejection of an empty `transaction`, index overflow, a UTXO interface using types of the contract's package, a UTXO exported as a WIT interface next to a non-UTXO export and a UTXO interface used by a sibling interface. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. With `?index=INDEX`, optionally qualified by `&transaction=DIGEST`, it instead returns a `starstream:ledger` package holding only the `utxo` interface for that unspent output: the UTXO's methods, decoded from its contract, as the freestanding functions `/rpc` invokes, taking the output reference before the method parameters. The `utxo` interface is a new interface, holding only the types its functions use: imported from the UTXO interface of the contract if that is named, moved out of it otherwise. The contract's interfaces are left in place and its world is dropped from its package, so no package of the contract depends on `starstream:ledger`, even if another of its interfaces uses the UTXO interface. The packages the `utxo` interface depends on are printed nested. The output reference parameters are named `transaction` and `index`, prefixed with `utxo-` for as long as they clash with a method parameter. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The `GET` and `HEAD` handlers of `/contracts`, `/transactions` and `/rpc` are merged into one handler each, which omits the body on `HEAD`. The UTXO WIT of every UTXO instance a contract exports, that is every exported interface exporting a `utxo` resource, defined by it or used from another interface, as the runtime identifies UTXO instances, whether named by the contract or a WIT interface, is built, printed and encoded once, when the contract is published, and served from memory, keyed by export name as `POST /rpc` resolves it. Publishing therefore now rejects, with 400, Wasm that is not a component and contracts that themselves define an unversioned `starstream:ledger` package, whose name the served package would clash with; a versioned one is printed nested next to it. As before, a rejected contract consumes neither nonce nor fee: validation and WIT extraction run before the publisher is charged, which happens under the contracts write lock, so of concurrent publishes of the same contract only one is charged. A contract already published is rejected before any of that work. The ledger package is encoded to Wasm once, by a build script, only when the `server` feature is enabled. In the query, `index` is a `u32` and `transaction` must be a digest; omitting it refers to the genesis block. A query naming `index` or `transaction` more than once is rejected with 400, and a query without parameters (`GET /rpc?`, `GET /rpc?&`) is treated as no query. `headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the server responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT from the endpoint, in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from that endpoint, encoded as Wasm, instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. Ledger tests cover parameter name clashes, lowercase charsets, `q` values, `HEAD`, queries without parameters, rejection of an empty `transaction`, index overflow, a UTXO interface using types of the contract's package, a UTXO exported as a WIT interface next to a non-UTXO export, a UTXO interface used by a sibling interface and an interface using the `utxo` resource of another. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`GET /rpc` returns the `starstream:ledger` package describing the ledger queries `POST /rpc` accepts. With `?index=INDEX`, optionally qualified by `&transaction=DIGEST`, it instead returns a `starstream:ledger` package holding only the `utxo` interface for that unspent output: the UTXO's methods, decoded from its contract, as the freestanding functions `/rpc` invokes, taking the output reference before the method parameters. The `utxo` interface is a new interface, holding only the types its functions use: imported from the UTXO interface of the contract if that is named, with the functions referring to the imports, or moved out of it otherwise, together with the functions of the resources among them. Types whose names clash with a method are prefixed with `utxo-`. The contract's interfaces are left in place and its world is dropped from its package, so no package of the contract depends on `starstream:ledger`, even if another of its interfaces uses the UTXO interface. The packages the `utxo` interface depends on are printed nested. The output reference parameters are named `transaction` and `index`, prefixed with `utxo-` for as long as they clash with a method parameter. Both are served as WIT text by default, or encoded as Wasm on `Accept: application/wasm`, so clients can generate wRPC bindings without decoding the contract themselves. `HEAD /rpc` returns the headers of the same response. The `GET` and `HEAD` handlers of `/contracts`, `/transactions` and `/rpc` are merged into one handler each, which omits the body on `HEAD`. The UTXO WIT of every UTXO instance a contract exports, that is every exported interface exporting a `utxo` resource, defined by it or used from another interface, as the runtime identifies UTXO instances, whether named by the contract or a WIT interface, is built, printed and encoded once, when the contract is published, and served from memory, keyed by export name as `POST /rpc` resolves it. Publishing therefore now rejects, with 400, Wasm that is not a component. If the contract already uses an unversioned `starstream:ledger` package, for example by importing `starstream:ledger/types`, the `utxo` interface is added to it; the contract is rejected if that package already has a `utxo` interface, or if the `utxo` interface would make the package depend on itself, because the named UTXO interface uses it. A versioned `starstream:ledger` package is printed nested next to it. As before, a rejected contract consumes neither nonce nor fee: validation and WIT extraction run before the publisher is charged, which happens under the contracts write lock, so of concurrent publishes of the same contract only one is charged. A contract already published is rejected before any of that work. The ledger package is encoded to Wasm once, by a build script, only when the `server` feature is enabled. In the query, `index` is a `u32` and `transaction` must be a digest; omitting it refers to the genesis block. A query naming `index` or `transaction` more than once is rejected with 400, and a query without parameters (`GET /rpc?`, `GET /rpc?&`) is treated as no query. `headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the server responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The ledger client gains `build_utxo_wit_request` and `Client::get_utxo_wit`, which takes an optional `Accept` media type and returns the raw body. GET request builders share a helper. `TransactionInput` gains `genesis` and `new` constructors. The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`, printing a UTXO's WIT from the endpoint, in the shape `ledger utxo call` invokes it. `ledger utxo call` now resolves the method type from that endpoint, encoded as Wasm, instead of downloading and decoding the whole contract. The CLI e2e test now starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. Ledger tests cover parameter name clashes, lowercase charsets, `q` values, `HEAD`, queries without parameters, rejection of an empty `transaction`, index overflow, a UTXO interface using types of the contract's package, a UTXO exported as a WIT interface next to a non-UTXO export, a UTXO interface used by a sibling interface, an interface using the `utxo` resource of another, method and type name clashes, resources with methods, an imported `starstream:ledger` package and rejection of a package depending on itself. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 19, 2026
`headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the ledger responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 20, 2026
`headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the ledger responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The revision is fetched from the upstream repository, which holds the PR head, rather than from the fork it was pushed to. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 20, 2026
`headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the ledger responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The revision is fetched from the upstream repository, which holds the PR head, rather than from the fork it was pushed to. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 21, 2026
`headers-accept` is pinned to the head of maxcountryman/headers-accept#24, on top of the unreleased upstream main, whose media range matching ignores `q` when comparing parameters, so `Accept: text/plain;q=0.9` matches the `text/plain; charset=UTF-8` the ledger responds with. The PR additionally compares charset values case-insensitively, so `charset=utf-8` matches it too. The revision is fetched from the upstream repository, which holds the PR head, rather than from the fork it was pushed to. Assisted-by: anthropic:claude-opus-5-5 Assisted-by: anthropic:claude-fable-5-1 Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
rvolosatovs
added a commit
to LFDT-Nightstream/Starstream
that referenced
this pull request
Oct 21, 2026
## Serve invocation WIT on `GET /rpc` Clients can now fetch WIT describing what `POST /rpc` accepts and generate wRPC bindings from it, without having to decode contracts themselves. - `GET /rpc` returns the `starstream:ledger` package that describes the ledger queries. - `GET /rpc?index=INDEX[&transaction=DIGEST]` returns a `starstream:ledger` package with only a `utxo` interface for that unspent output. Its functions are the UTXO's methods. Each takes the output reference (`transaction`, `index`) followed by the method parameters, which get an `arg-` prefix so names can't clash. If `transaction` is omitted, it refers to the genesis block. Repeating a parameter returns 400, and an empty query (`?`, `?&`) counts as no query. - Responses are WIT text by default, or Wasm with `Accept: application/wasm`. `HEAD /rpc` is supported. The `GET`/`HEAD` handlers for `/contracts`, `/transactions` and `/rpc` are merged into one handler each, generic over `HEAD`. - When a contract is published, the UTXO WIT for each exported instance with a `utxo` resource is built once and served from memory. It is converted from the component types that publish validation already computes, so the contract's WIT is never decoded with wit-parser. That decoder overflows the stack on valid components whose imported packages depend on each other, which would abort the node. - The client gains `build_utxo_wit_request` and `Client::get_utxo_wit`. `TransactionInput` gains `genesis` and `new` constructors. - The CLI gains `ledger utxo wit [--transaction DIGEST] <INDEX>`. `ledger utxo call` now gets the method type from this endpoint instead of downloading and decoding the whole contract. ### Behaviour changes - Publishing now returns 400 for Wasm that isn't a component. It also returns 400 for contracts whose UTXO methods take or return anything other than booleans, integers, or options, results and tuples of those (e.g. a UTXO handle). The error names the offending parameter or result. These are the only shapes the compiler currently produces: structs and enums in UTXO method signatures don't componentize yet. - `Contract::utxos` now treats an instance as a UTXO instance only if its `utxo` export is a resource. This matches what `get_utxo_typed` already required. ### Dependency pins (temporary) - `headers-accept` is pinned to maxcountryman/headers-accept#24, so `Accept` matching ignores `q` and compares charsets case-insensitively. Switch back once it's merged and released. ### Tests - The CLI e2e test starts the ledger with the outputs of the simulated `example` call as genesis, prints the UTXO's WIT and calls one of its methods. - The ledger tests cover `GET /rpc` and the UTXO WIT of a compiled contract using options, results and tuples, with parameters named `index` and `transaction`. They also check that a UTXO method taking a UTXO is rejected, and that a component whose imported packages form a cycle publishes. --------- Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC 9110 section 8.3.2 defines charset names as case-insensitive, so
Accept: text/plain;charset=utf-8must match an availabletext/plain;charset=UTF-8. Other parameter values are still compared exactly.https://www.rfc-editor.org/rfc/rfc9110.html#section-8.3.2-1