@electric-sql/client 1.5.11 → 1.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/intent.mjs ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ // Auto-generated by @tanstack/intent setup
3
+ // Exposes the intent end-user CLI for consumers of this library.
4
+ // Commit this file, then add to your package.json:
5
+ // "bin": { "intent": "./bin/intent.mjs" }
6
+ await import(`@tanstack/intent/intent-library`)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@electric-sql/client",
3
3
  "description": "Postgres everywhere - your data, in sync, wherever you need it.",
4
- "version": "1.5.11",
4
+ "version": "1.5.12",
5
5
  "author": "ElectricSQL team and contributors.",
6
6
  "bugs": {
7
7
  "url": "https://github.com/electric-sql/electric/issues"
@@ -10,6 +10,7 @@
10
10
  "@microsoft/fetch-event-source": "^2.0.1"
11
11
  },
12
12
  "devDependencies": {
13
+ "@tanstack/intent": "^0.0.9",
13
14
  "@types/pg": "^8.11.6",
14
15
  "@types/uuid": "^10.0.0",
15
16
  "@typescript-eslint/eslint-plugin": "^7.14.1",
@@ -45,9 +46,15 @@
45
46
  }
46
47
  }
47
48
  },
49
+ "bin": {
50
+ "intent": "./bin/intent.mjs"
51
+ },
48
52
  "files": [
49
53
  "dist",
50
- "src"
54
+ "src",
55
+ "skills",
56
+ "bin",
57
+ "!skills/_artifacts"
51
58
  ],
52
59
  "homepage": "https://electric-sql.com",
53
60
  "license": "Apache-2.0",
@@ -0,0 +1,217 @@
1
+ ---
2
+ name: electric-debugging
3
+ description: >
4
+ Troubleshoot Electric sync issues. Covers fast-loop detection from CDN/proxy
5
+ cache key misconfiguration, stale cache diagnosis (StaleCacheError),
6
+ MissingHeadersError from CORS misconfiguration, 409 shape expired handling,
7
+ SSE proxy buffering (nginx proxy_buffering off, Caddy flush_interval -1),
8
+ HTTP/1.1 6-connection limit in local dev (Caddy HTTP/2 proxy), WAL growth
9
+ from replication slots (max_slot_wal_keep_size), Vercel CDN cache issues,
10
+ and onError/backoff behavior. Load when shapes are not receiving updates,
11
+ sync is slow, or errors appear in the console.
12
+ type: lifecycle
13
+ library: electric
14
+ library_version: '1.5.10'
15
+ requires:
16
+ - electric-shapes
17
+ - electric-proxy-auth
18
+ sources:
19
+ - 'electric-sql/electric:packages/typescript-client/src/client.ts'
20
+ - 'electric-sql/electric:packages/typescript-client/src/fetch.ts'
21
+ - 'electric-sql/electric:packages/typescript-client/src/error.ts'
22
+ - 'electric-sql/electric:website/docs/guides/troubleshooting.md'
23
+ ---
24
+
25
+ This skill builds on electric-shapes and electric-proxy-auth. Read those first.
26
+
27
+ # Electric — Debugging Sync Issues
28
+
29
+ ## Setup
30
+
31
+ Enable debug logging to see retry and state machine behavior:
32
+
33
+ ```ts
34
+ import { ShapeStream, FetchError } from '@electric-sql/client'
35
+
36
+ const stream = new ShapeStream({
37
+ url: '/api/todos',
38
+ backoffOptions: {
39
+ initialDelay: 1000,
40
+ maxDelay: 32000,
41
+ multiplier: 2,
42
+ debug: true, // Logs retry attempts
43
+ },
44
+ onError: (error) => {
45
+ if (error instanceof FetchError) {
46
+ console.error(`Sync error: ${error.status} at ${error.url}`, error.json)
47
+ }
48
+ return {} // Always return {} to retry
49
+ },
50
+ })
51
+ ```
52
+
53
+ ## Core Patterns
54
+
55
+ ### Error retry behavior
56
+
57
+ | Error | Auto-retry? | Action |
58
+ | --------------------- | -------------------------- | ------------------------------------------------------------- |
59
+ | 5xx server errors | Yes (exponential backoff) | Wait and retry |
60
+ | 429 rate limit | Yes (respects Retry-After) | Wait and retry |
61
+ | Network errors | Yes (exponential backoff) | Wait and retry |
62
+ | 4xx (non-429) | No | Calls `onError` — return `{}` to retry manually |
63
+ | 409 shape expired | Yes (automatic reset) | Client resets and refetches |
64
+ | `MissingHeadersError` | Never | Fix CORS/proxy — not retryable even if `onError` returns `{}` |
65
+
66
+ ### Diagnosing MissingHeadersError
67
+
68
+ This error means Electric response headers (`electric-offset`, `electric-handle`) are being stripped, usually by CORS:
69
+
70
+ ```
71
+ MissingHeadersError: This is often due to a proxy not setting CORS correctly
72
+ so that all Electric headers can be read by the client.
73
+ ```
74
+
75
+ Fix: expose Electric headers in proxy CORS configuration:
76
+
77
+ ```ts
78
+ headers.set(
79
+ 'Access-Control-Expose-Headers',
80
+ 'electric-offset, electric-handle, electric-schema, electric-cursor'
81
+ )
82
+ ```
83
+
84
+ ### Diagnosing fast-loop detection
85
+
86
+ Console message: "Detected possible fast loop" with diagnostic info.
87
+
88
+ Cause: proxy/CDN cache key doesn't include `handle` and `offset` query params, so the client gets the same stale response repeatedly.
89
+
90
+ Fix: ensure your proxy/CDN includes all query parameters in its cache key.
91
+
92
+ For Vercel, add to `vercel.json`:
93
+
94
+ ```json
95
+ {
96
+ "headers": [
97
+ {
98
+ "source": "/api/(.*)",
99
+ "headers": [
100
+ { "key": "CDN-Cache-Control", "value": "no-store" },
101
+ { "key": "Vercel-CDN-Cache-Control", "value": "no-store" }
102
+ ]
103
+ }
104
+ ]
105
+ }
106
+ ```
107
+
108
+ ## Common Mistakes
109
+
110
+ ### HIGH Proxy or CDN not including query params in cache key
111
+
112
+ Wrong:
113
+
114
+ ```nginx
115
+ # nginx caching without query params in key
116
+ proxy_cache_key $scheme$host$uri;
117
+ ```
118
+
119
+ Correct:
120
+
121
+ ```nginx
122
+ # Include query params (handle, offset) in cache key
123
+ proxy_cache_key $scheme$host$request_uri;
124
+ ```
125
+
126
+ Fast-loop detection fires after 5 requests in 500ms at the same offset. The client auto-clears caches once, then applies backoff, then throws after 5 consecutive detections.
127
+
128
+ Source: `packages/typescript-client/src/client.ts:929-1002`
129
+
130
+ ### HIGH SSE responses buffered by proxy
131
+
132
+ Wrong:
133
+
134
+ ```nginx
135
+ location /v1/shape {
136
+ proxy_pass http://electric:3000;
137
+ # Default: proxy_buffering on — SSE responses delayed
138
+ }
139
+ ```
140
+
141
+ Correct:
142
+
143
+ ```nginx
144
+ location /v1/shape {
145
+ proxy_pass http://electric:3000;
146
+ proxy_buffering off;
147
+ }
148
+ ```
149
+
150
+ For Caddy:
151
+
152
+ ```
153
+ reverse_proxy localhost:3000 {
154
+ flush_interval -1
155
+ }
156
+ ```
157
+
158
+ Nginx and Caddy buffer responses by default, causing long delays for SSE live updates. Disable buffering for Electric endpoints. Do NOT disable caching entirely — Electric uses cache headers for request collapsing.
159
+
160
+ Source: `website/docs/guides/troubleshooting.md:69-109`
161
+
162
+ ### MEDIUM Running 6+ shapes in local dev without HTTP/2
163
+
164
+ Wrong:
165
+
166
+ ```sh
167
+ # Running Electric directly on localhost:3000
168
+ # With 7+ shapes, browser HTTP/1.1 queues all requests (6 connection limit)
169
+ ```
170
+
171
+ Correct:
172
+
173
+ ```sh
174
+ # Run Caddy as HTTP/2 proxy on host (not in Docker — Docker prevents HTTP/2)
175
+ caddy run --config - --adapter caddyfile <<EOF
176
+ localhost:3001 {
177
+ reverse_proxy localhost:3000
178
+ }
179
+ EOF
180
+ ```
181
+
182
+ Browser HTTP/1.1 limits to 6 TCP connections per origin. With many shapes, requests queue behind each other. Use Caddy as a local HTTP/2 proxy.
183
+
184
+ Source: `website/docs/guides/troubleshooting.md:28-53`
185
+
186
+ ### HIGH Leaving replication slot active when Electric is stopped
187
+
188
+ Wrong:
189
+
190
+ ```sh
191
+ docker stop electric
192
+ # Replication slot retains WAL indefinitely — disk fills up
193
+ ```
194
+
195
+ Correct:
196
+
197
+ ```sh
198
+ docker stop electric
199
+
200
+ # Drop slot when stopping for extended periods
201
+ psql -c "SELECT pg_drop_replication_slot('electric_slot_default');"
202
+
203
+ # Or set a safety limit
204
+ psql -c "ALTER SYSTEM SET max_slot_wal_keep_size = '10GB';"
205
+ psql -c "SELECT pg_reload_conf();"
206
+ ```
207
+
208
+ Replication slots retain WAL indefinitely when Electric is disconnected. Postgres disk fills up. Either drop the slot or set `max_slot_wal_keep_size`.
209
+
210
+ Source: `website/docs/guides/troubleshooting.md:203-316`
211
+
212
+ See also: electric-deployment/SKILL.md — Many sync issues stem from deployment configuration.
213
+ See also: electric-shapes/SKILL.md — onError semantics and backoff behavior.
214
+
215
+ ## Version
216
+
217
+ Targets @electric-sql/client v1.5.10.
@@ -0,0 +1,196 @@
1
+ ---
2
+ name: electric-deployment
3
+ description: >
4
+ Deploy Electric via Docker, Docker Compose, or Electric Cloud. Covers
5
+ DATABASE_URL (direct connection, not pooler), ELECTRIC_SECRET (required
6
+ since v1.x), ELECTRIC_INSECURE for dev, wal_level=logical,
7
+ max_replication_slots, ELECTRIC_STORAGE_DIR persistence,
8
+ ELECTRIC_POOLED_DATABASE_URL for pooled queries, IPv6 with
9
+ ELECTRIC_DATABASE_USE_IPV6, Kubernetes readiness probes (200 vs 202),
10
+ replication slot cleanup, and Postgres v14+ requirements. Load when
11
+ deploying Electric or configuring Postgres for logical replication.
12
+ type: lifecycle
13
+ library: electric
14
+ library_version: '1.5.10'
15
+ sources:
16
+ - 'electric-sql/electric:website/docs/guides/deployment.md'
17
+ - 'electric-sql/electric:packages/sync-service/dev/postgres.conf'
18
+ - 'electric-sql/electric:packages/sync-service/CHANGELOG.md'
19
+ ---
20
+
21
+ # Electric — Deployment
22
+
23
+ ## Setup
24
+
25
+ ### Postgres configuration
26
+
27
+ ```conf
28
+ # postgresql.conf
29
+ wal_level = logical
30
+ max_replication_slots = 10
31
+ ```
32
+
33
+ ### Docker Compose
34
+
35
+ ```yaml
36
+ name: 'electric-backend'
37
+ services:
38
+ postgres:
39
+ image: postgres:16-alpine
40
+ environment:
41
+ POSTGRES_DB: electric
42
+ POSTGRES_USER: postgres
43
+ POSTGRES_PASSWORD: password
44
+ ports: ['54321:5432']
45
+ volumes: ['./postgres.conf:/etc/postgresql/postgresql.conf:ro']
46
+ tmpfs: ['/var/lib/postgresql/data', '/tmp']
47
+ command: ['postgres', '-c', 'config_file=/etc/postgresql/postgresql.conf']
48
+
49
+ electric:
50
+ image: electricsql/electric:latest
51
+ environment:
52
+ DATABASE_URL: postgresql://postgres:password@postgres:5432/electric?sslmode=disable
53
+ ELECTRIC_SECRET: ${ELECTRIC_SECRET}
54
+ ports: ['3000:3000']
55
+ volumes: ['electric_data:/var/lib/electric']
56
+ depends_on: ['postgres']
57
+
58
+ volumes:
59
+ electric_data:
60
+ ```
61
+
62
+ ### Electric Cloud
63
+
64
+ ```sh
65
+ npx @electric-sql/start my-app
66
+ pnpm claim && pnpm deploy
67
+ ```
68
+
69
+ ## Core Patterns
70
+
71
+ ### Environment variables
72
+
73
+ | Variable | Required | Description |
74
+ | ------------------------------ | ---------- | --------------------------------------------- |
75
+ | `DATABASE_URL` | Yes | Direct Postgres connection (not pooler) |
76
+ | `ELECTRIC_SECRET` | Yes (prod) | API authentication secret |
77
+ | `ELECTRIC_INSECURE` | Dev only | Set `true` to skip secret requirement |
78
+ | `ELECTRIC_STORAGE_DIR` | No | Persistent shape cache directory |
79
+ | `ELECTRIC_POOLED_DATABASE_URL` | No | Pooled connection for non-replication queries |
80
+ | `ELECTRIC_DATABASE_USE_IPV6` | No | Set `true` for IPv6 Postgres connections |
81
+
82
+ ### Kubernetes health checks
83
+
84
+ ```yaml
85
+ livenessProbe:
86
+ httpGet:
87
+ path: /v1/health
88
+ port: 3000
89
+ readinessProbe:
90
+ exec:
91
+ command: ['curl', '-sf', 'http://localhost:3000/v1/health']
92
+ # Use exec, not httpGet — 202 means "alive but not ready"
93
+ # Only 200 means fully ready for traffic
94
+ ```
95
+
96
+ ### Replication slot cleanup
97
+
98
+ ```sql
99
+ -- When stopping Electric for extended periods:
100
+ SELECT pg_drop_replication_slot('electric_slot_default');
101
+
102
+ -- Prevent unbounded WAL growth:
103
+ ALTER SYSTEM SET max_slot_wal_keep_size = '10GB';
104
+ SELECT pg_reload_conf();
105
+ ```
106
+
107
+ ## Common Mistakes
108
+
109
+ ### CRITICAL Not setting wal_level to logical
110
+
111
+ Wrong:
112
+
113
+ ```conf
114
+ # postgresql.conf (default)
115
+ wal_level = replica
116
+ ```
117
+
118
+ Correct:
119
+
120
+ ```conf
121
+ wal_level = logical
122
+ max_replication_slots = 10
123
+ ```
124
+
125
+ Electric requires logical replication. The default `wal_level = replica` does not support it. Requires Postgres restart after change.
126
+
127
+ Source: `packages/sync-service/dev/postgres.conf`
128
+
129
+ ### CRITICAL Running without ELECTRIC_SECRET in production
130
+
131
+ Wrong:
132
+
133
+ ```sh
134
+ docker run electricsql/electric \
135
+ -e DATABASE_URL=postgres://user:pass@host/db
136
+ ```
137
+
138
+ Correct:
139
+
140
+ ```sh
141
+ docker run electricsql/electric \
142
+ -e DATABASE_URL=postgres://user:pass@host/db \
143
+ -e ELECTRIC_SECRET=my-secret-key
144
+ ```
145
+
146
+ Since v1.x, `ELECTRIC_SECRET` is required. Without it, Electric refuses to start unless `ELECTRIC_INSECURE=true` is set (dev only).
147
+
148
+ Source: `packages/sync-service/CHANGELOG.md:832-834`
149
+
150
+ ### MEDIUM Using ephemeral storage for ELECTRIC_STORAGE_DIR
151
+
152
+ Wrong:
153
+
154
+ ```yaml
155
+ electric:
156
+ image: electricsql/electric:latest
157
+ # No volume — shape cache lost on restart
158
+ ```
159
+
160
+ Correct:
161
+
162
+ ```yaml
163
+ electric:
164
+ image: electricsql/electric:latest
165
+ volumes: ['electric_data:/var/lib/electric']
166
+ ```
167
+
168
+ Electric caches shape logs on disk. Ephemeral storage causes full re-sync on every container restart.
169
+
170
+ Source: `website/docs/guides/deployment.md:133-157`
171
+
172
+ ### MEDIUM Using deprecated ELECTRIC_QUERY_DATABASE_URL
173
+
174
+ Wrong:
175
+
176
+ ```sh
177
+ ELECTRIC_QUERY_DATABASE_URL=postgres://user:pass@pooler:6432/db
178
+ ```
179
+
180
+ Correct:
181
+
182
+ ```sh
183
+ ELECTRIC_POOLED_DATABASE_URL=postgres://user:pass@pooler:6432/db
184
+ ```
185
+
186
+ Renamed from `ELECTRIC_QUERY_DATABASE_URL` to `ELECTRIC_POOLED_DATABASE_URL` in v1.3.x. The old name may stop working in future versions.
187
+
188
+ Source: `packages/sync-service/CHANGELOG.md:415`
189
+
190
+ See also: electric-proxy-auth/SKILL.md — Production requires proxy with ELECTRIC_SECRET.
191
+ See also: electric-postgres-security/SKILL.md — Deployment requires correct Postgres configuration.
192
+ See also: electric-debugging/SKILL.md — Many sync issues stem from deployment configuration.
193
+
194
+ ## Version
195
+
196
+ Targets Electric sync service v1.x.