@ferricstore/ferricstore 0.11.11 → 0.12.0
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/README.md +16 -1
- package/dist/durability-DlDCsdlo.d.cts +16 -0
- package/dist/durability-DplL0SbW.d.ts +16 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -162
- package/dist/index.d.ts +5 -162
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal-lEEDZpPH.d.cts +4 -0
- package/dist/internal-lEEDZpPH.d.ts +4 -0
- package/dist/langgraph.cjs +1278 -0
- package/dist/langgraph.cjs.map +1 -0
- package/dist/langgraph.d.cts +148 -0
- package/dist/langgraph.d.ts +148 -0
- package/dist/langgraph.js +1252 -0
- package/dist/langgraph.js.map +1 -0
- package/dist/openai-agents.cjs +580 -0
- package/dist/openai-agents.cjs.map +1 -0
- package/dist/openai-agents.d.cts +44 -0
- package/dist/openai-agents.d.ts +44 -0
- package/dist/openai-agents.js +555 -0
- package/dist/openai-agents.js.map +1 -0
- package/dist/outcomes-BbFDp3AH.d.ts +160 -0
- package/dist/outcomes-DmBwnq0Y.d.cts +160 -0
- package/docs/agent-frameworks.md +159 -0
- package/docs/api/assets/highlight.css +12 -12
- package/docs/api/classes/ClaimHydrationError.html +2 -2
- package/docs/api/classes/ConnectionClosedError.html +2 -2
- package/docs/api/classes/FerricStoreError.html +2 -2
- package/docs/api/classes/FlowAlreadyExistsError.html +2 -2
- package/docs/api/classes/FlowBatchError.html +2 -2
- package/docs/api/classes/FlowNotFoundError.html +2 -2
- package/docs/api/classes/FlowQueryError.html +2 -2
- package/docs/api/classes/FlowWrongStateError.html +2 -2
- package/docs/api/classes/HTTPTransportError.html +2 -2
- package/docs/api/classes/InvalidCommandError.html +2 -2
- package/docs/api/classes/LeaseRenewalError.html +2 -2
- package/docs/api/classes/LockHeldError.html +2 -2
- package/docs/api/classes/LockNotOwnedError.html +2 -2
- package/docs/api/classes/OverloadedError.html +2 -2
- package/docs/api/classes/QueueCompletionError.html +2 -2
- package/docs/api/classes/RequestTimeoutError.html +2 -2
- package/docs/api/classes/RerouteError.html +2 -2
- package/docs/api/classes/StaleLeaseError.html +2 -2
- package/docs/api/classes/StalePolicyGenerationError.html +2 -2
- package/docs/api/index.html +34 -24
- package/docs/api/media/agent-frameworks.md +159 -0
- package/docs/api/media/langgraph.ts +23 -0
- package/docs/api/media/openai-agents-session.ts +13 -0
- package/docs/api/variables/FERRICSTORE_SDK_VERSION.html +1 -1
- package/package.json +41 -2
package/docs/api/index.html
CHANGED
|
@@ -19,8 +19,16 @@
|
|
|
19
19
|
</code><button type="button">Copy</button></pre>
|
|
20
20
|
|
|
21
21
|
<p>Requires Node.js 22.22 or newer. The SDK ships ESM and CommonJS builds and is tested with Node 22, 24, and 26.</p>
|
|
22
|
+
<p>Agent framework adapters are optional:</p>
|
|
23
|
+
<pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">install</span><span class="hl-1"> </span><span class="hl-2">@ferricstore/ferricstore</span><span class="hl-1"> </span><span class="hl-2">@langchain/langgraph</span><span class="hl-1"> </span><span class="hl-2">@langchain/core</span><br/><span class="hl-3"># or</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">install</span><span class="hl-1"> </span><span class="hl-2">@ferricstore/ferricstore</span><span class="hl-1"> </span><span class="hl-2">@openai/agents</span>
|
|
24
|
+
</code><button type="button">Copy</button></pre>
|
|
25
|
+
|
|
26
|
+
<p>Use <code>@ferricstore/ferricstore/langgraph</code> for a LangGraph.js checkpointer,
|
|
27
|
+
long-term <code>BaseStore</code>, and FerricFlow handler bridge. Use
|
|
28
|
+
<code>@ferricstore/ferricstore/openai-agents</code> for an atomic, idempotent OpenAI
|
|
29
|
+
Agents SDK <code>Session</code>. See <a href="media/agent-frameworks.md">docs/agent-frameworks.md</a>.</p>
|
|
22
30
|
<h2 id="compatibility" class="tsd-anchor-link">Compatibility<a href="#compatibility" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
23
|
-
<p>TypeScript SDK <code>0.
|
|
31
|
+
<p>TypeScript SDK <code>0.12.0</code> requires FerricStore server <code>0.11.4</code> or newer. With
|
|
24
32
|
FerricStore 0.11.11 it negotiates compact Stream mode 34 for homogeneous auto-ID
|
|
25
33
|
<code>XADD</code> pipelines and compact Pub/Sub mode 35 for homogeneous <code>PUBLISH</code>
|
|
26
34
|
pipelines. Native wire protocol v1 and the generic fallback are unchanged.
|
|
@@ -28,21 +36,21 @@ Capabilities and response-size limits are negotiated
|
|
|
28
36
|
per connection from the HELLO-shaped startup response rather than inferred from
|
|
29
37
|
a server version table.</p>
|
|
30
38
|
<p>ESM:</p>
|
|
31
|
-
<pre><code class="ts"><span class="hl-
|
|
39
|
+
<pre><code class="ts"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">, </span><span class="hl-5">JsonCodec</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"@ferricstore/ferricstore"</span><span class="hl-1">;</span>
|
|
32
40
|
</code><button type="button">Copy</button></pre>
|
|
33
41
|
|
|
34
42
|
<p>CommonJS:</p>
|
|
35
|
-
<pre><code class="js"><span class="hl-
|
|
43
|
+
<pre><code class="js"><span class="hl-6">const</span><span class="hl-1"> { </span><span class="hl-7">FerricStoreClient</span><span class="hl-1">, </span><span class="hl-7">JsonCodec</span><span class="hl-1"> } = </span><span class="hl-0">require</span><span class="hl-1">(</span><span class="hl-2">"@ferricstore/ferricstore"</span><span class="hl-1">);</span>
|
|
36
44
|
</code><button type="button">Copy</button></pre>
|
|
37
45
|
|
|
38
46
|
<h2 id="run-ferricstore-locally" class="tsd-anchor-link">Run FerricStore Locally<a href="#run-ferricstore-locally" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
39
|
-
<pre><code class="bash"><span class="hl-0">docker</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-
|
|
47
|
+
<pre><code class="bash"><span class="hl-0">docker</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-6">-p</span><span class="hl-1"> </span><span class="hl-2">6388:6388</span><span class="hl-1"> </span><span class="hl-8">\</span><br/><span class="hl-1"> </span><span class="hl-6">-e</span><span class="hl-1"> </span><span class="hl-2">FERRICSTORE_PROTECTED_MODE=</span><span class="hl-6">false</span><span class="hl-1"> </span><span class="hl-8">\</span><br/><span class="hl-1"> </span><span class="hl-6">-v</span><span class="hl-1"> </span><span class="hl-2">ferricstore_data:/data</span><span class="hl-1"> </span><span class="hl-8">\</span><br/><span class="hl-1"> </span><span class="hl-2">quay.io/ferricstore/ferricstore:0.11.11@sha256:d9f488539f0d6c1a513d2315e7a9c2947cc795b393f3774c9de8ba5e5b5c21b5</span>
|
|
40
48
|
</code><button type="button">Copy</button></pre>
|
|
41
49
|
|
|
42
50
|
<h2 id="query-durable-runs" class="tsd-anchor-link">Query durable runs<a href="#query-durable-runs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
43
51
|
<p>Use parameterized FQL for bounded, partition-scoped reads. Cursors are opaque
|
|
44
52
|
and must be reused with the same query and parameters.</p>
|
|
45
|
-
<pre><code class="ts"><span class="hl-
|
|
53
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">client</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://127.0.0.1:6388"</span><span class="hl-1">);</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">query</span><span class="hl-1"> = </span><span class="hl-2">`FROM runs</span><br/><span class="hl-2">WHERE partition_key = @partition AND type = @type AND state = @state</span><br/><span class="hl-2">ORDER BY updated_at_ms ASC LIMIT 25 RETURN RECORDS`</span><span class="hl-1">;</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">params</span><span class="hl-1"> = { </span><span class="hl-5">partition:</span><span class="hl-1"> </span><span class="hl-2">"partition-a"</span><span class="hl-1">, </span><span class="hl-5">type:</span><span class="hl-1"> </span><span class="hl-2">"invoice"</span><span class="hl-1">, </span><span class="hl-5">state:</span><span class="hl-1"> </span><span class="hl-2">"queued"</span><span class="hl-1"> };</span><br/><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">result</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-0">query</span><span class="hl-1">(</span><span class="hl-5">query</span><span class="hl-1">, </span><span class="hl-5">params</span><span class="hl-1">);</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">plan</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-0">explain</span><span class="hl-1">(</span><span class="hl-5">query</span><span class="hl-1">, </span><span class="hl-5">params</span><span class="hl-1">);</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">indexes</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-0">queryIndexes</span><span class="hl-1">();</span>
|
|
46
54
|
</code><button type="button">Copy</button></pre>
|
|
47
55
|
|
|
48
56
|
<p>Each index reports <code>coveringFields</code>, which identifies the built-in and dynamic
|
|
@@ -57,14 +65,14 @@ complete public record. Projection runs after authorization, authoritative
|
|
|
57
65
|
recheck, ordering, and cursor calculation: it reduces retained result data,
|
|
58
66
|
encoding, network, and client decoding work, but not index scans or hydration.</p>
|
|
59
67
|
<p>Use the source-aware builder to avoid hand-quoting result selectors:</p>
|
|
60
|
-
<pre><code class="ts"><span class="hl-
|
|
68
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">projected</span><span class="hl-1"> = </span><span class="hl-0">projectFlowQuery</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-2">"FROM runs WHERE partition_key = @partition AND run_id = @run"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"record"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">FlowProjection</span><span class="hl-1">.</span><span class="hl-5">run</span><span class="hl-1">.</span><span class="hl-5">id</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">FlowProjection</span><span class="hl-1">.</span><span class="hl-5">run</span><span class="hl-1">.</span><span class="hl-5">state</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">FlowProjection</span><span class="hl-1">.</span><span class="hl-5">run</span><span class="hl-1">.</span><span class="hl-0">attribute</span><span class="hl-1">(</span><span class="hl-2">"customer"</span><span class="hl-1">)</span><br/><span class="hl-1">);</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">result</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-0">query</span><span class="hl-1">(</span><span class="hl-5">projected</span><span class="hl-1">, { </span><span class="hl-5">partition:</span><span class="hl-1"> </span><span class="hl-2">"partition-a"</span><span class="hl-1">, </span><span class="hl-5">run:</span><span class="hl-1"> </span><span class="hl-2">"run-1"</span><span class="hl-1"> });</span>
|
|
61
69
|
</code><button type="button">Copy</button></pre>
|
|
62
70
|
|
|
63
71
|
<h2 id="http-transport" class="tsd-anchor-link">HTTP transport<a href="#http-transport" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
64
72
|
<p><code>fromUrl</code> accepts <code>http://</code> and <code>https://</code> without changing the command API.
|
|
65
73
|
HTTP/1.1 uses a persistent keep-alive pool. Set <code>http2: true</code> to use one
|
|
66
74
|
multiplexed HTTP/2 session per origin:</p>
|
|
67
|
-
<pre><code class="ts"><span class="hl-
|
|
75
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">client</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-2">"https://ferricstore-http.example.com"</span><span class="hl-1">,</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">httpOptions:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">username:</span><span class="hl-1"> </span><span class="hl-2">"default"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">password</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">http2:</span><span class="hl-1"> </span><span class="hl-6">true</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">);</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-0">ping</span><span class="hl-1">();</span>
|
|
68
76
|
</code><button type="button">Copy</button></pre>
|
|
69
77
|
|
|
70
78
|
<p>Use <code>bearerToken</code> for Bearer authentication. Basic username/password
|
|
@@ -86,7 +94,7 @@ trust. Use <code>ferric://</code> or <code>ferrics://</code> whenever connection
|
|
|
86
94
|
required.</p>
|
|
87
95
|
<p>Run the complete HTTP-compatible integration surface through a real TLS
|
|
88
96
|
listener with ACL authentication using:</p>
|
|
89
|
-
<pre><code class="bash"><span class="hl-
|
|
97
|
+
<pre><code class="bash"><span class="hl-5">FERRICSTORE_IMAGE</span><span class="hl-1">=</span><span class="hl-2">quay.io/ferricstore/ferricstore:0.11.11@sha256:d9f488539f0d6c1a513d2315e7a9c2947cc795b393f3774c9de8ba5e5b5c21b5</span><span class="hl-1"> </span><span class="hl-0">\</span><br/><span class="hl-1"> </span><span class="hl-2">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">test:integration:http</span>
|
|
90
98
|
</code><button type="button">Copy</button></pre>
|
|
91
99
|
|
|
92
100
|
<p>The runner creates a private CA, verifies that unauthenticated access and a
|
|
@@ -103,7 +111,7 @@ fan-out; atomic multi-key commands are never split client-side. Pass
|
|
|
103
111
|
<code>{ ordered: true }</code> as the second argument to <code>client.pipeline()</code> when later
|
|
104
112
|
commands depend on earlier ones and the transport may need an individual or
|
|
105
113
|
cross-route fallback.</p>
|
|
106
|
-
<pre><code class="ts"><span class="hl-
|
|
114
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">flow</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrls</span><span class="hl-1">(</span><br/><span class="hl-1"> [</span><br/><span class="hl-1"> </span><span class="hl-2">"ferric://fs0.example.com:6388"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"ferric://fs1.example.com:6388"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"ferric://fs2.example.com:6388"</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">codec:</span><span class="hl-1"> </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">JsonCodec</span><span class="hl-1">(),</span><br/><span class="hl-1"> </span><span class="hl-5">nativeOptions:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">// Use "any" only inside a trusted private network.</span><br/><span class="hl-1"> </span><span class="hl-5">endpointPolicy:</span><span class="hl-1"> </span><span class="hl-2">"seed_hosts"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">// Bound client-side route fan-out; freed slots refill immediately.</span><br/><span class="hl-1"> </span><span class="hl-5">topologyConcurrency:</span><span class="hl-1"> </span><span class="hl-9">16</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">warmConnections:</span><span class="hl-1"> </span><span class="hl-6">true</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">);</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">refreshTopology</span><span class="hl-1">();</span><br/><span class="hl-5">console</span><span class="hl-1">.</span><span class="hl-0">log</span><span class="hl-1">(</span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">route</span><span class="hl-1">(</span><span class="hl-2">"tenant-a:order-1"</span><span class="hl-1">));</span>
|
|
107
115
|
</code><button type="button">Copy</button></pre>
|
|
108
116
|
|
|
109
117
|
<p>Learned topology endpoints are checked before connection. The default
|
|
@@ -160,7 +168,7 @@ subscriptions instead.</p>
|
|
|
160
168
|
<p>The default integration suite targets one local development server. Real HA,
|
|
161
169
|
TLS, and authentication deployments can be verified with the opt-in deployment
|
|
162
170
|
suite:</p>
|
|
163
|
-
<pre><code class="bash"><span class="hl-
|
|
171
|
+
<pre><code class="bash"><span class="hl-5">FERRICSTORE_HA_URLS</span><span class="hl-1">=</span><span class="hl-2">ferric://fs0:6388,ferric://fs1:6388</span><span class="hl-1"> </span><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">test:integration:deployment</span><br/><br/><span class="hl-5">FERRICSTORE_TLS_URL</span><span class="hl-1">=</span><span class="hl-2">ferrics://fs0:6389</span><span class="hl-1"> </span><span class="hl-0">\</span><br/><span class="hl-1">FERRICSTORE_TLS_CA_FILE=/path/to/ca.pem </span><span class="hl-8">\</span><br/><span class="hl-1">npm </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">test:integration:deployment</span><br/><br/><span class="hl-5">FERRICSTORE_AUTH_URL</span><span class="hl-1">=</span><span class="hl-2">ferric://app:secret@fs0:6388</span><span class="hl-1"> </span><span class="hl-0">\</span><br/><span class="hl-1">npm </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">test:integration:deployment</span>
|
|
164
172
|
</code><button type="button">Copy</button></pre>
|
|
165
173
|
|
|
166
174
|
<p>The HA fixture must advertise at least two reachable leader endpoints. The auth
|
|
@@ -170,7 +178,7 @@ rejects its plaintext listener. HA TLS/auth options are available through
|
|
|
170
178
|
<code>FERRICSTORE_HA_TLS_CA_FILE</code>, <code>FERRICSTORE_HA_TLS_SERVERNAME</code>,
|
|
171
179
|
<code>FERRICSTORE_HA_USERNAME</code>, and <code>FERRICSTORE_HA_PASSWORD</code>.</p>
|
|
172
180
|
<p>You can also keep one primary URL and add seeds:</p>
|
|
173
|
-
<pre><code class="ts"><span class="hl-
|
|
181
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">flow</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://fs0.example.com:6388"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">nativeOptions:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">haRouting:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">seeds:</span><span class="hl-1"> [</span><span class="hl-2">"ferric://fs1.example.com:6388"</span><span class="hl-1">, </span><span class="hl-2">"ferric://fs2.example.com:6388"</span><span class="hl-1">]</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">});</span>
|
|
174
182
|
</code><button type="button">Copy</button></pre>
|
|
175
183
|
|
|
176
184
|
<p>Native connections honor the flow-control windows advertised by the
|
|
@@ -192,11 +200,11 @@ bounded client queue. Set <code>nativeOptions.maxQueuedWriteBytes</code> to cont
|
|
|
192
200
|
queue (default 64 MiB, or <code>0</code> to reject subsequent writes immediately). Healthy
|
|
193
201
|
socket writes still go directly to <code>socket.write</code> without entering the queue.</p>
|
|
194
202
|
<h2 id="durable-queue" class="tsd-anchor-link">Durable Queue<a href="#durable-queue" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
195
|
-
<pre><code class="ts"><span class="hl-
|
|
203
|
+
<pre><code class="ts"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">, </span><span class="hl-5">JsonCodec</span><span class="hl-1">, </span><span class="hl-5">QueueClient</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"@ferricstore/ferricstore"</span><span class="hl-1">;</span><br/><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">flow</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://127.0.0.1:6388"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">codec:</span><span class="hl-1"> </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">JsonCodec</span><span class="hl-1">()</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">emails</span><span class="hl-1"> = </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">QueueClient</span><span class="hl-1">(</span><span class="hl-5">flow</span><span class="hl-1">).</span><span class="hl-0">queue</span><span class="hl-1">(</span><span class="hl-2">"email"</span><span class="hl-1">);</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">emails</span><span class="hl-1">.</span><span class="hl-0">enqueue</span><span class="hl-1">(</span><span class="hl-2">"email-1"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">idempotent:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">payload:</span><span class="hl-1"> { </span><span class="hl-5">template:</span><span class="hl-1"> </span><span class="hl-2">"welcome"</span><span class="hl-1">, </span><span class="hl-5">userId:</span><span class="hl-1"> </span><span class="hl-2">"user-1"</span><span class="hl-1"> }</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">emails</span><span class="hl-1">.</span><span class="hl-0">enqueueMany</span><span class="hl-1">([{ </span><span class="hl-5">id:</span><span class="hl-1"> </span><span class="hl-2">"email-2"</span><span class="hl-1">, </span><span class="hl-5">payload:</span><span class="hl-1"> { </span><span class="hl-5">template:</span><span class="hl-1"> </span><span class="hl-2">"receipt"</span><span class="hl-1"> } }], {</span><br/><span class="hl-1"> </span><span class="hl-5">autoPartitionBatchSize:</span><span class="hl-1"> </span><span class="hl-9">1_000</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">autoPartitionConcurrency:</span><span class="hl-1"> </span><span class="hl-9">8</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">emails</span><span class="hl-1">.</span><span class="hl-0">worker</span><span class="hl-1">({ </span><span class="hl-5">batchSize:</span><span class="hl-1"> </span><span class="hl-9">100</span><span class="hl-1">, </span><span class="hl-5">concurrency:</span><span class="hl-1"> </span><span class="hl-9">16</span><span class="hl-1">, </span><span class="hl-5">worker:</span><span class="hl-1"> </span><span class="hl-2">"email-worker-1"</span><span class="hl-1"> }).</span><span class="hl-0">run</span><span class="hl-1">(</span><span class="hl-6">async</span><span class="hl-1"> (</span><span class="hl-5">job</span><span class="hl-1">) </span><span class="hl-6">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">console</span><span class="hl-1">.</span><span class="hl-0">log</span><span class="hl-1">(</span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">id</span><span class="hl-1">, </span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">payload</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> { </span><span class="hl-5">sent:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1"> };</span><br/><span class="hl-1">});</span>
|
|
196
204
|
</code><button type="button">Copy</button></pre>
|
|
197
205
|
|
|
198
206
|
<h2 id="explicit-workflow" class="tsd-anchor-link">Explicit Workflow<a href="#explicit-workflow" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
199
|
-
<pre><code class="ts"><span class="hl-
|
|
207
|
+
<pre><code class="ts"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">, </span><span class="hl-5">JsonCodec</span><span class="hl-1">, </span><span class="hl-5">WorkflowClient</span><span class="hl-1">, </span><span class="hl-5">complete</span><span class="hl-1">, </span><span class="hl-5">transition</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"@ferricstore/ferricstore"</span><span class="hl-1">;</span><br/><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">flow</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://127.0.0.1:6388"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">codec:</span><span class="hl-1"> </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">JsonCodec</span><span class="hl-1">()</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">order</span><span class="hl-1"> = </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">WorkflowClient</span><span class="hl-1">(</span><span class="hl-5">flow</span><span class="hl-1">).</span><span class="hl-0">workflow</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">initialState:</span><span class="hl-1"> </span><span class="hl-2">"created"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">type:</span><span class="hl-1"> </span><span class="hl-2">"order"</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">order</span><span class="hl-1">.</span><span class="hl-0">state</span><span class="hl-1">(</span><span class="hl-2">"created"</span><span class="hl-1">, </span><span class="hl-6">async</span><span class="hl-1"> (</span><span class="hl-5">ctx</span><span class="hl-1">) </span><span class="hl-6">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-0">chargeCard</span><span class="hl-1">(</span><span class="hl-5">ctx</span><span class="hl-1">.</span><span class="hl-5">payload</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-0">transition</span><span class="hl-1">(</span><span class="hl-2">"charged"</span><span class="hl-1">);</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">order</span><span class="hl-1">.</span><span class="hl-0">state</span><span class="hl-1">(</span><span class="hl-2">"charged"</span><span class="hl-1">, </span><span class="hl-6">async</span><span class="hl-1"> (</span><span class="hl-5">ctx</span><span class="hl-1">) </span><span class="hl-6">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-0">sendReceipt</span><span class="hl-1">(</span><span class="hl-5">ctx</span><span class="hl-1">.</span><span class="hl-5">id</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-0">complete</span><span class="hl-1">({ </span><span class="hl-5">result:</span><span class="hl-1"> { </span><span class="hl-5">ok:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1"> } });</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">order</span><span class="hl-1">.</span><span class="hl-0">start</span><span class="hl-1">(</span><span class="hl-2">"order-1"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">idempotent:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">payload:</span><span class="hl-1"> { </span><span class="hl-5">amount:</span><span class="hl-1"> </span><span class="hl-9">42</span><span class="hl-1">, </span><span class="hl-5">userId:</span><span class="hl-1"> </span><span class="hl-2">"user-1"</span><span class="hl-1"> }</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">order</span><span class="hl-1">.</span><span class="hl-0">worker</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">batchSize:</span><span class="hl-1"> </span><span class="hl-9">50</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">concurrency:</span><span class="hl-1"> </span><span class="hl-9">8</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">states:</span><span class="hl-1"> [</span><span class="hl-2">"created"</span><span class="hl-1">, </span><span class="hl-2">"charged"</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-5">worker:</span><span class="hl-1"> </span><span class="hl-2">"order-worker-1"</span><br/><span class="hl-1">}).</span><span class="hl-0">run</span><span class="hl-1">();</span>
|
|
200
208
|
</code><button type="button">Copy</button></pre>
|
|
201
209
|
|
|
202
210
|
<p>Handlers return explicit durable outcomes:</p>
|
|
@@ -242,12 +250,12 @@ unchanged; all fenced mutation APIs accept the exported <code>FencingToken</code
|
|
|
242
250
|
and native compact claim and batch paths preserve its signed 64-bit value
|
|
243
251
|
exactly.</p>
|
|
244
252
|
<h2 id="low-level-flow-commands" class="tsd-anchor-link">Low-Level Flow Commands<a href="#low-level-flow-commands" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
245
|
-
<pre><code class="ts"><span class="hl-
|
|
253
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">flow</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://127.0.0.1:6388"</span><span class="hl-1">);</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">create</span><span class="hl-1">(</span><span class="hl-2">"order-1"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">type:</span><span class="hl-1"> </span><span class="hl-2">"order"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">state:</span><span class="hl-1"> </span><span class="hl-2">"created"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">payload:</span><span class="hl-1"> </span><span class="hl-5">Buffer</span><span class="hl-1">.</span><span class="hl-0">from</span><span class="hl-1">(</span><span class="hl-2">"order payload"</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">idempotent:</span><span class="hl-1"> </span><span class="hl-6">true</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">jobs</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">claimDue</span><span class="hl-1">(</span><span class="hl-2">"order"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">state:</span><span class="hl-1"> </span><span class="hl-2">"created"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">worker:</span><span class="hl-1"> </span><span class="hl-2">"worker-1"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">leaseMs:</span><span class="hl-1"> </span><span class="hl-9">30_000</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">limit:</span><span class="hl-1"> </span><span class="hl-9">10</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">payload:</span><span class="hl-1"> </span><span class="hl-6">true</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">for</span><span class="hl-1"> (</span><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">job</span><span class="hl-1"> </span><span class="hl-6">of</span><span class="hl-1"> </span><span class="hl-5">jobs</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">transition</span><span class="hl-1">(</span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">id</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">fromState:</span><span class="hl-1"> </span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">state</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">toState:</span><span class="hl-1"> </span><span class="hl-2">"charged"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">leaseToken:</span><span class="hl-1"> </span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">leaseToken</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">fencingToken:</span><span class="hl-1"> </span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">fencingToken</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">partitionKey:</span><span class="hl-1"> </span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">partitionKey</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">}</span>
|
|
246
254
|
</code><button type="button">Copy</button></pre>
|
|
247
255
|
|
|
248
256
|
<p>Flow attributes can be returned without hydrating each record and can be
|
|
249
257
|
updated atomically with the fenced state mutation:</p>
|
|
250
|
-
<pre><code class="ts"><span class="hl-
|
|
258
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">attributed</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">claimDue</span><span class="hl-1">(</span><span class="hl-2">"order"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">includeAttributes:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">jobOnly:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">state:</span><span class="hl-1"> </span><span class="hl-2">"created"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">worker:</span><span class="hl-1"> </span><span class="hl-2">"worker-1"</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">transition</span><span class="hl-1">(</span><span class="hl-5">attributed</span><span class="hl-1">[</span><span class="hl-9">0</span><span class="hl-1">]!.</span><span class="hl-5">id</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">attributesDelete:</span><span class="hl-1"> [</span><span class="hl-2">"temporary"</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-5">attributesMerge:</span><span class="hl-1"> { </span><span class="hl-5">processor:</span><span class="hl-1"> </span><span class="hl-2">"payments-v2"</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-5">fencingToken:</span><span class="hl-1"> </span><span class="hl-5">attributed</span><span class="hl-1">[</span><span class="hl-9">0</span><span class="hl-1">]!.</span><span class="hl-5">fencingToken</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">fromState:</span><span class="hl-1"> </span><span class="hl-2">"created"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">leaseToken:</span><span class="hl-1"> </span><span class="hl-5">attributed</span><span class="hl-1">[</span><span class="hl-9">0</span><span class="hl-1">]!.</span><span class="hl-5">leaseToken</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">toState:</span><span class="hl-1"> </span><span class="hl-2">"charged"</span><br/><span class="hl-1">});</span>
|
|
251
259
|
</code><button type="button">Copy</button></pre>
|
|
252
260
|
|
|
253
261
|
<p>The low-level client also exposes the fused <code>startAndClaim</code>, <code>stepContinue</code>,
|
|
@@ -255,13 +263,13 @@ and <code>runStepsMany</code> operations, schedule administration, Flow statisti
|
|
|
255
263
|
attribute queries, effects, approvals, circuits, budgets, and distributed
|
|
256
264
|
limits. History supports the complete server filter surface, including event,
|
|
257
265
|
time, and version bounds plus cold/consistent reads and payload hydration:</p>
|
|
258
|
-
<pre><code class="ts"><span class="hl-
|
|
266
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">events</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">history</span><span class="hl-1">(</span><span class="hl-2">"order-1"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">consistentProjection:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">fromVersion:</span><span class="hl-1"> </span><span class="hl-9">2</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">includeCold:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">payloadMaxBytes:</span><span class="hl-1"> </span><span class="hl-9">64_000</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">toVersion:</span><span class="hl-1"> </span><span class="hl-9">8</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">values:</span><span class="hl-1"> </span><span class="hl-6">true</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">scheduleCreate</span><span class="hl-1">(</span><span class="hl-2">"orders-every-five-minutes"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">cron:</span><span class="hl-1"> </span><span class="hl-2">"*/5 * * * *"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">kind:</span><span class="hl-1"> </span><span class="hl-2">"cron"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">target:</span><span class="hl-1"> { </span><span class="hl-5">state:</span><span class="hl-1"> </span><span class="hl-2">"created"</span><span class="hl-1">, </span><span class="hl-5">type:</span><span class="hl-1"> </span><span class="hl-2">"order"</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-5">timezone:</span><span class="hl-1"> </span><span class="hl-2">"UTC"</span><br/><span class="hl-1">});</span>
|
|
259
267
|
</code><button type="button">Copy</button></pre>
|
|
260
268
|
|
|
261
269
|
<p>Overdue interval schedules use bounded <code>fire_once</code> catch-up. Recovery creates
|
|
262
270
|
one target, coalesces additional elapsed periods in constant time, and sets the
|
|
263
271
|
next run one full interval after recovery:</p>
|
|
264
|
-
<pre><code class="ts"><span class="hl-
|
|
272
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">schedule</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">scheduleCreate</span><span class="hl-1">(</span><span class="hl-2">"billing-sweep"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">catchupPolicy:</span><span class="hl-1"> </span><span class="hl-2">"fire_once"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">everyMs:</span><span class="hl-1"> </span><span class="hl-9">60_000</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">kind:</span><span class="hl-1"> </span><span class="hl-2">"interval"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">overlapPolicy:</span><span class="hl-1"> </span><span class="hl-2">"queue_after_previous"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">target:</span><span class="hl-1"> { </span><span class="hl-5">id_prefix:</span><span class="hl-1"> </span><span class="hl-2">"billing-sweep"</span><span class="hl-1">, </span><span class="hl-5">type:</span><span class="hl-1"> </span><span class="hl-2">"billing"</span><span class="hl-1"> }</span><br/><span class="hl-1">});</span>
|
|
265
273
|
</code><button type="button">Copy</button></pre>
|
|
266
274
|
|
|
267
275
|
<p><code>ScheduleRecord</code> exposes the complete recurrence configuration through
|
|
@@ -288,7 +296,7 @@ When planning fails, <code>state</code> is <code>"failed"</code>, <cod
|
|
|
288
296
|
<code>"planning_failed"</code>, and <code>last_planning_error</code> contains the actionable error.
|
|
289
297
|
<code>scheduleDelete()</code> resolves to <code>undefined</code> only after an <code>OK</code> server reply.</p>
|
|
290
298
|
<p>FIFO Flow state policy is opt-in per state:</p>
|
|
291
|
-
<pre><code class="ts"><span class="hl-
|
|
299
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">policy</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">installPolicy</span><span class="hl-1">(</span><span class="hl-2">"email"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">states:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">queued:</span><span class="hl-1"> { </span><span class="hl-5">mode:</span><span class="hl-1"> </span><span class="hl-2">"fifo"</span><span class="hl-1"> }</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-3">// Direct writes deep-patch by default. Fence concurrent editors with generation CAS.</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">updated</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">installPolicy</span><span class="hl-1">(</span><span class="hl-2">"email"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">expectedGeneration:</span><span class="hl-1"> </span><span class="hl-5">policy</span><span class="hl-1">.</span><span class="hl-5">generation</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">maxActiveMs:</span><span class="hl-1"> </span><span class="hl-9">300_000</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-3">// Full replacement is explicit on the client API.</span><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">installPolicy</span><span class="hl-1">(</span><span class="hl-2">"email"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">expectedGeneration:</span><span class="hl-1"> </span><span class="hl-5">updated</span><span class="hl-1">.</span><span class="hl-5">generation</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">replace:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">states:</span><span class="hl-1"> { </span><span class="hl-5">queued:</span><span class="hl-1"> { </span><span class="hl-5">mode:</span><span class="hl-1"> </span><span class="hl-2">"fifo"</span><span class="hl-1"> } }</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">flow</span><span class="hl-1">.</span><span class="hl-0">create</span><span class="hl-1">(</span><span class="hl-2">"email-3"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">partitionKey:</span><span class="hl-1"> </span><span class="hl-2">"tenant-a:email"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">payload:</span><span class="hl-1"> </span><span class="hl-5">Buffer</span><span class="hl-1">.</span><span class="hl-0">from</span><span class="hl-1">(</span><span class="hl-2">"welcome"</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">state:</span><span class="hl-1"> </span><span class="hl-2">"queued"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">type:</span><span class="hl-1"> </span><span class="hl-2">"email"</span><br/><span class="hl-1">});</span>
|
|
292
300
|
</code><button type="button">Copy</button></pre>
|
|
293
301
|
|
|
294
302
|
<p>FIFO states require a <code>partitionKey</code>; priority is for parallel states.
|
|
@@ -298,7 +306,7 @@ FIFO ordering is enforced by the server per <code>(type, state, partitionKey)</c
|
|
|
298
306
|
concurrency remains available across different partitions.</p>
|
|
299
307
|
<h2 id="ferricstore-kv-and-data-structures" class="tsd-anchor-link">FerricStore KV And Data Structures<a href="#ferricstore-kv-and-data-structures" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
300
308
|
<p>The same client exposes typed helpers for FerricStore's Redis-compatible store commands:</p>
|
|
301
|
-
<pre><code class="ts"><span class="hl-
|
|
309
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">client</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://127.0.0.1:6388"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">codec:</span><span class="hl-1"> </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">JsonCodec</span><span class="hl-1">()</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">kv</span><span class="hl-1">.</span><span class="hl-0">set</span><span class="hl-1">(</span><span class="hl-2">"user:1"</span><span class="hl-1">, { </span><span class="hl-5">name:</span><span class="hl-1"> </span><span class="hl-2">"Ada"</span><span class="hl-1"> }, { </span><span class="hl-5">px:</span><span class="hl-1"> </span><span class="hl-9">60_000</span><span class="hl-1"> });</span><br/><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">user</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">kv</span><span class="hl-1">.</span><span class="hl-0">get</span><span class="hl-1">(</span><span class="hl-2">"user:1"</span><span class="hl-1">);</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">hash</span><span class="hl-1">.</span><span class="hl-0">hset</span><span class="hl-1">(</span><span class="hl-2">"user:1:profile"</span><span class="hl-1">, { </span><span class="hl-5">email:</span><span class="hl-1"> </span><span class="hl-2">"ada@example.com"</span><span class="hl-1"> });</span><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">lists</span><span class="hl-1">.</span><span class="hl-0">lpush</span><span class="hl-1">(</span><span class="hl-2">"jobs"</span><span class="hl-1">, { </span><span class="hl-5">id:</span><span class="hl-1"> </span><span class="hl-2">"job-1"</span><span class="hl-1"> });</span><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">sets</span><span class="hl-1">.</span><span class="hl-0">sadd</span><span class="hl-1">(</span><span class="hl-2">"seen-users"</span><span class="hl-1">, </span><span class="hl-2">"user:1"</span><span class="hl-1">);</span><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">zset</span><span class="hl-1">.</span><span class="hl-0">zadd</span><span class="hl-1">(</span><span class="hl-2">"leaderboard"</span><span class="hl-1">, [{ </span><span class="hl-5">score:</span><span class="hl-1"> </span><span class="hl-9">42</span><span class="hl-1">, </span><span class="hl-5">member:</span><span class="hl-1"> </span><span class="hl-2">"user:1"</span><span class="hl-1"> }]);</span><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">stream</span><span class="hl-1">.</span><span class="hl-0">xadd</span><span class="hl-1">(</span><span class="hl-2">"events"</span><span class="hl-1">, </span><span class="hl-2">"*"</span><span class="hl-1">, { </span><span class="hl-5">type:</span><span class="hl-1"> </span><span class="hl-2">"created"</span><span class="hl-1">, </span><span class="hl-5">id:</span><span class="hl-1"> </span><span class="hl-2">"user:1"</span><span class="hl-1"> });</span><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">bloom</span><span class="hl-1">.</span><span class="hl-0">add</span><span class="hl-1">(</span><span class="hl-2">"seen-filter"</span><span class="hl-1">, </span><span class="hl-2">"user:1"</span><span class="hl-1">);</span>
|
|
302
310
|
</code><button type="button">Copy</button></pre>
|
|
303
311
|
|
|
304
312
|
<p>Large unambiguous scalar batches accept an array without spreading, for example
|
|
@@ -328,12 +336,12 @@ apply mutations.</p>
|
|
|
328
336
|
<h2 id="auto-batching" class="tsd-anchor-link">Auto-Batching<a href="#auto-batching" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
329
337
|
<p>The default client is latency-first: each SDK call sends its own native request.</p>
|
|
330
338
|
<p>For high-throughput services that issue many independent calls concurrently, enable SDK auto-batching:</p>
|
|
331
|
-
<pre><code class="ts"><span class="hl-
|
|
339
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">client</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://127.0.0.1:6388"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">autoBatch:</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">enabled:</span><span class="hl-1"> </span><span class="hl-6">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">maxCommands:</span><span class="hl-1"> </span><span class="hl-9">512</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">maxDelayMs:</span><span class="hl-1"> </span><span class="hl-9">0</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-10">Promise</span><span class="hl-1">.</span><span class="hl-0">all</span><span class="hl-1">([</span><br/><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">kv</span><span class="hl-1">.</span><span class="hl-0">set</span><span class="hl-1">(</span><span class="hl-2">"a"</span><span class="hl-1">, </span><span class="hl-2">"1"</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">kv</span><span class="hl-1">.</span><span class="hl-0">set</span><span class="hl-1">(</span><span class="hl-2">"b"</span><span class="hl-1">, </span><span class="hl-2">"2"</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">client</span><span class="hl-1">.</span><span class="hl-5">hash</span><span class="hl-1">.</span><span class="hl-0">hset</span><span class="hl-1">(</span><span class="hl-2">"user:1"</span><span class="hl-1">, { </span><span class="hl-5">email:</span><span class="hl-1"> </span><span class="hl-2">"ada@example.com"</span><span class="hl-1"> })</span><br/><span class="hl-1">]);</span>
|
|
332
340
|
</code><button type="button">Copy</button></pre>
|
|
333
341
|
|
|
334
342
|
<p>Auto-batching groups eligible concurrent commands into native <code>PIPELINE</code> frames and resolves each original promise independently. Across frames and individual-request fallbacks, same-key write dependencies retain invocation order, while read-only and disjoint-key work remains concurrent. Commands whose direct native representation uses a custom binary body are safely wrapped as typed <code>COMMAND_EXEC</code> pipeline items, preserving one pipeline request instead of issuing each command separately. Blocking/session and control commands such as <code>FLOW.CLAIM_DUE</code>, <code>BLPOP</code>, <code>XREAD</code>, <code>AUTH</code>, <code>PING</code>, <code>OPTIONS</code>, and <code>QUIT</code> bypass auto-batching. Explicit pipelines issue unsupported or connection-blocking items individually; blocking fallbacks and state-changing controls are sequenced with dependent data commands. Other fallbacks remain concurrent unless <code>client.pipeline(commands, { ordered: true })</code> is requested. Individual fallbacks continuously refill a bounded pool instead of starting every request at once; the default limit is 64 and <code>fallbackConcurrency</code> on the pipeline options can tune it per call. Native pipeline paths are unchanged. Reconnecting and topology executors reject connection-local mutations before dispatch, and an uncertain native pipeline is never replayed automatically.</p>
|
|
335
343
|
<p>Queue workers are latency-first by default. For high-throughput queue workers, use one profile flag:</p>
|
|
336
|
-
<pre><code class="ts"><span class="hl-
|
|
344
|
+
<pre><code class="ts"><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">emails</span><span class="hl-1">.</span><span class="hl-0">worker</span><span class="hl-1">({ </span><span class="hl-5">profile:</span><span class="hl-1"> </span><span class="hl-2">"throughput"</span><span class="hl-1">, </span><span class="hl-5">concurrency:</span><span class="hl-1"> </span><span class="hl-9">32</span><span class="hl-1"> }).</span><span class="hl-0">run</span><span class="hl-1">(</span><span class="hl-6">async</span><span class="hl-1"> (</span><span class="hl-5">job</span><span class="hl-1">) </span><span class="hl-6">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-0">sendEmail</span><span class="hl-1">(</span><span class="hl-5">job</span><span class="hl-1">.</span><span class="hl-5">id</span><span class="hl-1">);</span><br/><span class="hl-1">});</span>
|
|
337
345
|
</code><button type="button">Copy</button></pre>
|
|
338
346
|
|
|
339
347
|
<p>The throughput profile uses compact claims, a larger batch ceiling, and concurrent completion batching. Per-job claim credit follows currently available <code>concurrency</code> (or its <code>workers</code> alias), capped by <code>batchSize</code>; explicit worker options override profile defaults.</p>
|
|
@@ -346,10 +354,12 @@ apply mutations.</p>
|
|
|
346
354
|
<li><a href="media/signals.ts">signals.ts</a></li>
|
|
347
355
|
<li><a href="media/value-refs.ts">value-refs.ts</a></li>
|
|
348
356
|
<li><a href="media/kv-store.ts">kv-store.ts</a></li>
|
|
357
|
+
<li><a href="media/langgraph.ts">langgraph.ts</a></li>
|
|
358
|
+
<li><a href="media/openai-agents-session.ts">openai-agents-session.ts</a></li>
|
|
349
359
|
</ul>
|
|
350
360
|
<h2 id="codecs" class="tsd-anchor-link">Codecs<a href="#codecs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
351
361
|
<p><code>RawCodec</code> is the default and works with <code>Buffer</code>, <code>Uint8Array</code>, and strings. Use <code>JsonCodec</code> for language-neutral structured payloads and results.</p>
|
|
352
|
-
<pre><code class="ts"><span class="hl-
|
|
362
|
+
<pre><code class="ts"><span class="hl-6">const</span><span class="hl-1"> </span><span class="hl-7">flow</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">FerricStoreClient</span><span class="hl-1">.</span><span class="hl-0">fromUrl</span><span class="hl-1">(</span><span class="hl-2">"ferric://127.0.0.1:6388"</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">codec:</span><span class="hl-1"> </span><span class="hl-6">new</span><span class="hl-1"> </span><span class="hl-0">JsonCodec</span><span class="hl-1">()</span><br/><span class="hl-1">});</span>
|
|
353
363
|
</code><button type="button">Copy</button></pre>
|
|
354
364
|
|
|
355
365
|
<h2 id="design-notes" class="tsd-anchor-link">Design Notes<a href="#design-notes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2>
|
|
@@ -367,13 +377,13 @@ apply mutations.</p>
|
|
|
367
377
|
|
|
368
378
|
<p><code>npm run check</code> runs strict TypeScript, ESLint, Vitest, and the package build.</p>
|
|
369
379
|
<p>Use Docker Compose for local integration testing:</p>
|
|
370
|
-
<pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">integration:up</span><br/><span class="hl-
|
|
380
|
+
<pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">integration:up</span><br/><span class="hl-5">FERRICSTORE_INTEGRATION</span><span class="hl-1">=</span><span class="hl-2">1</span><span class="hl-1"> </span><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">test:integration</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">integration:down</span>
|
|
371
381
|
</code><button type="button">Copy</button></pre>
|
|
372
382
|
|
|
373
383
|
<p>Benchmark raw FQL and the record convenience layer against a live server. The default
|
|
374
384
|
comparison interleaves both paths and fails if either performs more than one <code>FLOW.QUERY</code>
|
|
375
385
|
or any <code>FLOW.GET</code> hydration per operation:</p>
|
|
376
|
-
<pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">build</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">bench:flow-query</span><span class="hl-1"> </span><span class="hl-
|
|
386
|
+
<pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">build</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">bench:flow-query</span><span class="hl-1"> </span><span class="hl-6">--</span><span class="hl-1"> </span><span class="hl-6">--requests</span><span class="hl-1"> </span><span class="hl-9">500</span><span class="hl-1"> </span><span class="hl-6">--concurrency</span><span class="hl-1"> </span><span class="hl-9">2</span><span class="hl-1"> </span><span class="hl-6">--rows</span><span class="hl-1"> </span><span class="hl-9">100</span><span class="hl-1"> </span><span class="hl-6">--pretty</span>
|
|
377
387
|
</code><button type="button">Copy</button></pre>
|
|
378
388
|
|
|
379
389
|
<p>Generate API docs with:</p>
|