electric-sql / electric-sql/electric

Feature request: keep table query param first in client-generated /v1/shape URLs for easier debugging

Open
#3,435 2 comments 0 reactions 0 assignees View on GitHub
feature request triage
Dominant language
TypeScript
Stars
10.4k
Forks
375
Avg merge
3d 1h
Merged PRs (30d)
18

Description

A small quality-of-life request around how the TypeScript client builds `/v1/shape` URLs.

---

## Summary

When using `@electric-sql/client` + `@electric-sql/react`, the client appears to normalize query parameters by sorting them alphabetically (likely via `URLSearchParams.sort()` or similar) before issuing HTTP requests.

When I'm reading logs, including console.error()s I see this:

```text
GET https://localhost:5133/v1/shape?columns=containers_needed_calculated%2Ccontainers_needed_final%2Ccontainers_needed_override%2Cestimate_item_id%2Cid%2Cis_visible_on_work_order%2Clabor_cost_final%2Cmargin_percent%2Cmaterial_cost_calculated%2Cquantity%2Cstatus%2Ctotal_cost_calculated%2Ctotal_price_final%2Cwork_order_id&expired_handle=120433867-1762814934671321&handle=104274672-1762873237440240&log=full&offset=0_0&table=projects_workitem
```

For debugging (especially when scanning logs or devtools for failing requests), it would be much easier if the `table` parameter always appeared first in the query string:

```text
GET https://localhost:5133/v1/shape?table=projects_workitem&columns=...&offset=0_0&log=full&handle=...&expired_handle=...
```

Functionally this shouldn’t change anything on the server side — just the human readability of the URL.

---

## Environment

* `@electric-sql/client`: `^1.1.4`
* `@electric-sql/react`: `^1.0.19`
* `@tanstack/electric-db-collection`: `^0.2.0`
* Browser: Chrome/Brave
* Usage: `useShape` / `getShapeStream` with `params.table` and other query params (`columns`, `offset`, `log`, `handle`, etc.)

---

## What I *think* is happening in the client

From a quick skim of the TypeScript client (and getting gpt-5.1's take TBH) , it looks like there’s a single URL construction path where:

* A `URL` is created for `/v1/shape`
* `params` are written into `url.searchParams`
* Then the query parameters are sorted (probably via `url.searchParams.sort()`) to give a canonical order, which is nice for cache keys and deduplication.

I didn’t want to assume too much about the internal design, but it *looks* like there’s a single helper / method responsible for this normalization, which would make this easy to tweak.

---

## Proposed behavior (one possible approach)

**Goal:** Keep all the benefits of canonicalization, but ensure `table` is always first in the actual request URL.

One possible implementation sketch:

1. Continue to sort parameters as you do today, *then*:
2. If a `table` param exists, rebuild the query string such that:

* `table` is written first,
* all other params follow in whatever canonical order you already use.

GPT-5.1 sugggested pseudocode (just to illustrate the intent):

```ts
function sortSearchParamsWithTableFirst(url: URL, tableKey = 'table') {
const params = url.searchParams

// Whatever canonicalization you do today
params.sort()

const tableValue = params.get(tableKey)
if (!tableValue) return

// Rebuild so `table` is always first
const ordered = new URLSearchParams()
ordered.set(tableKey, tableValue)

for (const [key, value] of params) {
if (key === tableKey) continue
ordered.append(key, value)
}

url.search = ordered.toString()
}
```

Then the URL construction helper would call `sortSearchParamsWithTableFirst(fetchUrl)` instead of (or in addition to) a plain `.sort()`.

### Alternative / more flexible option

If you’d prefer not to bake this in, another option would be to expose a small extension point, for example:

* A config / option on `ShapeStreamOptions` or the client that allows callers to provide a `normalizeUrl(url: URL): URL` or `rewriteSearchParams(params: URLSearchParams): void` callback.
* The default implementation would keep the existing behavior; users like me could plug in a “table first” implementation without changing defaults.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.