Skip to content

fix(runtime): no-arg action commands fail to type-check in consumers#8

Merged
Tam2 merged 2 commits into
mainfrom
fix/void-command-handler-arity
Jul 15, 2026
Merged

fix(runtime): no-arg action commands fail to type-check in consumers#8
Tam2 merged 2 commits into
mainfrom
fix/void-command-handler-arity

Conversation

@Tam2

@Tam2 Tam2 commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Follow-up to #5. 0.1.9's generator emits a no-argument command for endpoints with no path params and no request body:

export const postBillingReactivateCommand = command(
  z.void(),
  async () => handlePostCommand('/billing/reactivate'),   // 1-argument call
);

But handlePostCommand(path, input) declared input as required, so the generated file itself failed to type-check in the consuming app:

error TS2554: Expected 2 arguments, but got 1.

(It worked at runtime — input was just undefined — so only type-check / CI was affected.)

Fix

Make input optional on handlePostCommand/handlePatchCommand/handlePutCommand. buildRequestOptions(undefined) already yields no params and no body, so behavior is unchanged. No regeneration needed to adopt — existing 0.1.9 output type-checks as soon as the handler is optional.

Verified

  • Unit test: handlePostCommand('/x') (1 arg) → client.POST('/x', {}).
  • Against a real consumer app: temporarily dropped in the built dist and re-ran svelte-check — the "Expected 2 arguments" errors went from N to 0.
  • Build + 108 tests + typecheck all green.

Note

This slipped through because the library doesn't type-check its own generated output — only the generator's string output and the runtime handlers, separately. Worth a follow-up: compile a generated fixture in CI so consumer-facing type breaks are caught here. No version bump.

Tam2 added 2 commits July 15, 2026 19:14
…ands)

0.1.9 generates `command(z.void(), async () => handlePostCommand(path))` for endpoints
with no path params and no request body — a 1-argument call. But the handler's `input`
was required, so the *generated* file failed to type-check in the consumer ('Expected 2
arguments, but got 1'). Make `input` optional (runtime already tolerates undefined).

No regen needed to adopt — existing 0.1.9 output type-checks once the handler is optional.
Verified against a real consumer: the errors go from N to 0.
Adds an integration test that generates remote functions from a fixture and compiles
them (tsc) against the real createRemoteHandlers signatures + a SvelteKit $app/server
stub. This catches consumer-facing type breaks in generated code — e.g. the no-arg
z.void() command calling a 2-arg handler — which previously slipped through because the
generator's string output and the handlers were only tested separately.

New edge-cases fixture covers every shape (incl. the no-path/no-body z.void() case that
none of the real fixtures exercise). Verified: reverting the handler fix makes this test
fail with the exact 'Expected 2 arguments' error.
@Tam2

Tam2 commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

Addressed the note in this PR (d75bfb2): added a generated-output type-check test that generates from an edge-cases fixture (covering every shape, incl. the no-path/no-body z.void() case that none of the real fixtures had) and compiles the output with tsc against the real createRemoteHandlers signatures + a $app/server stub. Verified it fails with the exact Expected 2 arguments error when the handler fix is reverted — so this class of consumer-facing type break is now caught in CI, not downstream.

@Tam2 Tam2 merged commit 8c1ba09 into main Jul 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant