@pramen/client 0.0.13 → 0.0.14

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/index.js CHANGED
@@ -22,6 +22,12 @@ export function createClient(opts) {
22
22
  const doFetch = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
23
23
  const WS = opts.WebSocketImpl ?? globalThis.WebSocket;
24
24
  let token = opts.token;
25
+ // D1 read-your-writes: when the backend runs on the D1 store it returns an
26
+ // `x-pramen-d1-bookmark` header marking the latest write this client has observed.
27
+ // We stash it and echo it on the next request so a fresh D1 session anchors there and
28
+ // reads our own writes (even off a lagging replica). The DO path never sets the
29
+ // header, so `d1Bookmark` stays undefined there and nothing changes.
30
+ let d1Bookmark;
25
31
  const subs = new Map();
26
32
  let ws = null;
27
33
  let counter = 0;
@@ -34,11 +40,17 @@ export function createClient(opts) {
34
40
  headers.authorization = `Bearer ${token}`;
35
41
  if (opts.tenant)
36
42
  headers["x-pramen-tenant"] = opts.tenant;
43
+ if (d1Bookmark)
44
+ headers["x-pramen-d1-bookmark"] = d1Bookmark;
37
45
  const res = await doFetch(`${opts.url}/rpc/${name}`, {
38
46
  method: "POST",
39
47
  headers,
40
48
  body: JSON.stringify(input ?? {}),
41
49
  });
50
+ // Capture the D1 read-your-writes bookmark (D1 store only; absent on the DO path).
51
+ const bookmark = res.headers.get("x-pramen-d1-bookmark");
52
+ if (bookmark)
53
+ d1Bookmark = bookmark;
42
54
  const body = (await res.json().catch(() => ({})));
43
55
  if (!res.ok || body.ok === false) {
44
56
  throw new PramenError(body.error ?? `request failed (${res.status})`, body.code ?? "error", res.status);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pramen/client",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Typed client for a pramen backend — RPC over HTTP + live queries over WebSocket.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/index.ts CHANGED
@@ -79,6 +79,13 @@ export function createClient<Api = Record<string, never>>(opts: ClientOptions):
79
79
  const WS = opts.WebSocketImpl ?? (globalThis as { WebSocket?: typeof WebSocket }).WebSocket;
80
80
  let token = opts.token;
81
81
 
82
+ // D1 read-your-writes: when the backend runs on the D1 store it returns an
83
+ // `x-pramen-d1-bookmark` header marking the latest write this client has observed.
84
+ // We stash it and echo it on the next request so a fresh D1 session anchors there and
85
+ // reads our own writes (even off a lagging replica). The DO path never sets the
86
+ // header, so `d1Bookmark` stays undefined there and nothing changes.
87
+ let d1Bookmark: string | undefined;
88
+
82
89
  const subs = new Map<string, Sub>();
83
90
  let ws: WebSocket | null = null;
84
91
  let counter = 0;
@@ -90,11 +97,15 @@ export function createClient<Api = Record<string, never>>(opts: ClientOptions):
90
97
  const headers: Record<string, string> = { "content-type": "application/json" };
91
98
  if (token) headers.authorization = `Bearer ${token}`;
92
99
  if (opts.tenant) headers["x-pramen-tenant"] = opts.tenant;
100
+ if (d1Bookmark) headers["x-pramen-d1-bookmark"] = d1Bookmark;
93
101
  const res = await doFetch(`${opts.url}/rpc/${name}`, {
94
102
  method: "POST",
95
103
  headers,
96
104
  body: JSON.stringify(input ?? {}),
97
105
  });
106
+ // Capture the D1 read-your-writes bookmark (D1 store only; absent on the DO path).
107
+ const bookmark = res.headers.get("x-pramen-d1-bookmark");
108
+ if (bookmark) d1Bookmark = bookmark;
98
109
  const body = (await res.json().catch(() => ({}))) as { ok?: boolean; result?: unknown; error?: string; code?: string };
99
110
  if (!res.ok || body.ok === false) {
100
111
  throw new PramenError(body.error ?? `request failed (${res.status})`, body.code ?? "error", res.status);