Skip to content

fix(sdk): PipeRef.fetch accepts a limit option it silently ignores #464

Description

@EricAndrechek

Area: sdk — silent no-op · found by CodeRabbit on #456

PipeRef.fetch(opts?: RequestOptions) accepts the same per-call options type as the query builder, which carries limit — but it forwards only signal:

// clients/ts/src/pipes.ts:28-37
async fetch(opts?: RequestOptions): Promise<Result<Row[]>> {
  const { data, error } = await request<Row[]>(this._ctx, {
    method: "POST",
    path: `/v1/pipes/${encodeURIComponent(this._name)}`,
    body: this._params ?? {},
    signal: opts?.signal,        // <- opts.limit is never read
  });

So wh.pipe('top_pages').fetch({ limit: 10 }) type-checks, runs, and returns whatever the pipe's own SQL returns. The caller gets no error and no indication the bound was ignored.

The other two implementations of the same signature do honour it — QueryBuilder.fetch (query-builder.ts:141, opts?.limit ?? this._state.limit ?? DEFAULT_LIMIT) and TableRef.fetch (table.ts:63, .limit(opts?.limit ?? 1000)) — so the inconsistency is within one shared type, which is what makes it easy to hit.

Limiting a pipe genuinely requires an operator-defined {{limit}} SQL parameter supplied via wh.pipe(name, params); a client-side row cap isn't something the pipes endpoint offers. So the fix is about the surface, not adding a feature.

Pre-existing, not introduced by #456: origin/main has the identical body with the type spelled FetchOptions. #456 only renamed the type, so it neither caused nor worsened this — filing rather than folding it in, to keep that PR's diff about the HTTP-customization surface.

Options

  1. Give PipeRef.fetch a signal-only parameter type (Pick<RequestOptions, "signal">, or a named AbortOptions). Honest surface; a caller passing limit gets a compile error pointing at the real mechanism. Technically breaking for anyone passing limit today, though it never did anything.
  2. Honour it client-side by truncating the returned rows. Cheap, but invents a semantic the endpoint doesn't have and hides how much work the server did.
  3. Document it only. Weakest — the type still advertises it.

Option 1 looks right, ideally with the JSDoc naming wh.pipe(name, { limit }) as the actual route.

Same class as #280 (QueryBuilder.cacheTTL() is a silent no-op) — worth checking whether any other per-call option is accepted and dropped while someone is in here.

— Filed by Claude Opus 5, via Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/sdkTypeScript SDK (clients/ts/)bugSomething isn't working

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions