@electric-sql/client 1.5.0 → 1.5.1
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/dist/cjs/index.cjs +17 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.legacy-esm.js +17 -2
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +17 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +29 -2
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.
|
|
4
|
+
"version": "1.5.1",
|
|
5
5
|
"author": "ElectricSQL team and contributors.",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/electric-sql/electric/issues"
|
package/src/client.ts
CHANGED
|
@@ -1118,13 +1118,16 @@ export class ShapeStream<T extends Row<unknown> = Row>
|
|
|
1118
1118
|
`Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key.`
|
|
1119
1119
|
)
|
|
1120
1120
|
} else {
|
|
1121
|
+
// We already have a valid handle, so ignore the stale response entirely
|
|
1122
|
+
// to prevent a mismatch between our current handle and the stale offset.
|
|
1121
1123
|
console.warn(
|
|
1122
1124
|
`[Electric] Received stale cached response with expired shape handle. ` +
|
|
1123
1125
|
`This should not happen and indicates a proxy/CDN caching misconfiguration. ` +
|
|
1124
1126
|
`The response contained handle "${shapeHandle}" which was previously marked as expired. ` +
|
|
1125
1127
|
`Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. ` +
|
|
1126
|
-
`Ignoring the stale
|
|
1128
|
+
`Ignoring the stale response and continuing with handle "${this.#shapeHandle}".`
|
|
1127
1129
|
)
|
|
1130
|
+
return
|
|
1128
1131
|
}
|
|
1129
1132
|
}
|
|
1130
1133
|
|
|
@@ -1687,8 +1690,32 @@ export class ShapeStream<T extends Row<unknown> = Row>
|
|
|
1687
1690
|
fetchOptions = { headers: result.requestHeaders }
|
|
1688
1691
|
}
|
|
1689
1692
|
|
|
1690
|
-
|
|
1693
|
+
// Capture handle before fetch to avoid race conditions if it changes during the request
|
|
1694
|
+
const usedHandle = this.#shapeHandle
|
|
1695
|
+
|
|
1696
|
+
let response: Response
|
|
1697
|
+
try {
|
|
1698
|
+
response = await this.#fetchClient(fetchUrl.toString(), fetchOptions)
|
|
1699
|
+
} catch (e) {
|
|
1700
|
+
// Handle 409 "must-refetch" - shape handle changed/expired.
|
|
1701
|
+
// The fetch wrapper throws FetchError for non-OK responses, so we catch here.
|
|
1702
|
+
// Unlike #requestShape, we don't call #reset() here as that would
|
|
1703
|
+
// clear #activeSnapshotRequests and break requestSnapshot's pause/resume logic.
|
|
1704
|
+
if (e instanceof FetchError && e.status === 409) {
|
|
1705
|
+
if (usedHandle) {
|
|
1706
|
+
const shapeKey = canonicalShapeKey(fetchUrl)
|
|
1707
|
+
expiredShapesCache.markExpired(shapeKey, usedHandle)
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
this.#shapeHandle =
|
|
1711
|
+
e.headers[SHAPE_HANDLE_HEADER] || `${usedHandle ?? `handle`}-next`
|
|
1712
|
+
|
|
1713
|
+
return this.fetchSnapshot(opts)
|
|
1714
|
+
}
|
|
1715
|
+
throw e
|
|
1716
|
+
}
|
|
1691
1717
|
|
|
1718
|
+
// Handle non-OK responses from custom fetch clients that bypass the wrapper chain
|
|
1692
1719
|
if (!response.ok) {
|
|
1693
1720
|
throw await FetchError.fromResponse(response, fetchUrl.toString())
|
|
1694
1721
|
}
|