jev-devtools 0.5.2 → 0.5.3

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 CHANGED
@@ -1,10 +1,10 @@
1
1
  # Jev DevTools
2
2
 
3
- [![npm version 0.5.2](https://img.shields.io/badge/npm-v0.5.2-E551BA?labelColor=0D0A0F&logo=npm)](https://www.npmjs.com/package/jev-devtools/v/0.5.2)
3
+ [![npm version 0.5.3](https://img.shields.io/badge/npm-v0.5.3-E551BA?labelColor=0D0A0F&logo=npm)](https://www.npmjs.com/package/jev-devtools/v/0.5.3)
4
4
 
5
5
  A React drawer and Node adapter for inspecting TypeSafe Jev requests with animated diagrams. Includes request history, context, questions, typed answers, transport attempts, and raw snapshots.
6
6
 
7
- **Source version: 0.5.2 — pending publication.** npm currently provides 0.5.1. Check the [release history](https://github.com/diegoag64/jev-devtools/blob/main/CHANGELOG.md) for compatibility notes. To try this release candidate, install the local archive below. **Experimental (pre-1.0).** React 18/19 and Node 22.12+ are supported. APIs may change before 1.0. Verification uses sample responses through the real TypeSafe SDK, not live inference.
7
+ **Package version: 0.5.3.** [See release notes for verified publication status.](https://github.com/diegoag64/jev-devtools/releases/tag/v0.5.3) Check the [release history](https://github.com/diegoag64/jev-devtools/blob/main/CHANGELOG.md) for compatibility notes. To try newer source changes, install the local archive below. **Experimental (pre-1.0).** React 18/19 and Node 22.12+ are supported. APIs may change before 1.0. Verification uses sample responses through the real TypeSafe SDK, not live inference.
8
8
 
9
9
  [Website](https://jevtools.dev/) · [Documentation](https://docs.jevtools.dev/) · [Quick start](https://docs.jevtools.dev/getting-started/) · [API reference](https://docs.jevtools.dev/api/reference/) · [Release history](https://docs.jevtools.dev/changelog/)
10
10
 
@@ -48,7 +48,7 @@ To try local changes before a future release:
48
48
  npm ci
49
49
  npm run pack:devtools
50
50
  # From the consuming app:
51
- npm install /absolute/path/to/jev-devtools-0.5.2.tgz
51
+ npm install /absolute/path/to/jev-devtools-0.5.3.tgz
52
52
  ```
53
53
 
54
54
  Mount once. The drawer loads its own styles; no CSS import is needed:
@@ -73,6 +73,60 @@ export function createJevDevtools(options) {
73
73
  scheduled = undefined;
74
74
  }
75
75
  }
76
+ const pendingFlows = new Set();
77
+ let scheduledFlows;
78
+ const encodeFlowUpdate = (session, cursor, knownDefinitions) => {
79
+ const update = flows.changes(session, cursor, knownDefinitions);
80
+ return {
81
+ bytes: encoder.encode(`event: flows\ndata: ${JSON.stringify(update.data)}\n\n`),
82
+ revision: update.revision,
83
+ retainedDefinitionIds: update.retainedDefinitionIds,
84
+ };
85
+ };
86
+ function scheduleFlow(flush) {
87
+ pendingFlows.add(flush);
88
+ if (scheduledFlows)
89
+ return;
90
+ scheduledFlows = setImmediate(() => {
91
+ scheduledFlows = undefined;
92
+ const batch = [...pendingFlows];
93
+ pendingFlows.clear();
94
+ // A lone reader has nothing to share; keep its direct encoding path and
95
+ // avoid allocating a cache or copying an otherwise unshared buffer.
96
+ if (batch.length === 1) {
97
+ batch[0](encodeFlowUpdate);
98
+ return;
99
+ }
100
+ // Scope sharing to this synchronous turn: no snapshots survive a later
101
+ // update/clear. Different cursors or definition knowledge need their own
102
+ // projection, even when the authorized session matches.
103
+ const encoded = new Map();
104
+ const updateFor = (session, cursor, knownDefinitions) => {
105
+ const key = JSON.stringify([
106
+ session,
107
+ cursor,
108
+ [...knownDefinitions].sort(),
109
+ ]);
110
+ let update = encoded.get(key);
111
+ if (!update) {
112
+ update = encodeFlowUpdate(session, cursor, knownDefinitions);
113
+ encoded.set(key, update);
114
+ }
115
+ // Response consumers can mutate/transfer their chunk. Never expose the
116
+ // cached backing buffer to a reader.
117
+ return { ...update, bytes: update.bytes.slice() };
118
+ };
119
+ for (const deliver of batch)
120
+ deliver(updateFor);
121
+ });
122
+ }
123
+ function unscheduleFlow(flush) {
124
+ pendingFlows.delete(flush);
125
+ if (!pendingFlows.size && scheduledFlows) {
126
+ clearImmediate(scheduledFlows);
127
+ scheduledFlows = undefined;
128
+ }
129
+ }
76
130
  let disposed = false;
77
131
  const enabled = () => options.enabled === true && !disposed;
78
132
  const sessionFor = async (request) => {
@@ -112,15 +166,14 @@ export function createJevDevtools(options) {
112
166
  let stop = () => { };
113
167
  const body = new ReadableStream({
114
168
  start(controller) {
115
- let closed = false, dirty = true, cursor, timer;
169
+ let closed = false, dirty = true, cursor;
116
170
  let knownDefinitions = new Set();
117
- const flush = () => {
118
- timer = undefined;
171
+ const flush = (updateFor) => {
119
172
  if (closed || !dirty || (controller.desiredSize ?? 0) <= 0)
120
173
  return;
121
174
  try {
122
- const update = flows.changes(session, cursor, knownDefinitions);
123
- controller.enqueue(encoder.encode(`event: flows\ndata: ${JSON.stringify(update.data)}\n\n`));
175
+ const update = updateFor(session, cursor, knownDefinitions);
176
+ controller.enqueue(update.bytes);
124
177
  // Match the browser's pruning after this delivered order. A clear
125
178
  // coalesced away under backpressure must not discard reader state.
126
179
  knownDefinitions = update.retainedDefinitionIds;
@@ -134,8 +187,8 @@ export function createJevDevtools(options) {
134
187
  }
135
188
  };
136
189
  const wake = () => {
137
- if (!closed && dirty && !timer)
138
- timer = setImmediate(flush);
190
+ if (!closed && dirty && (controller.desiredSize ?? 0) > 0)
191
+ scheduleFlow(flush);
139
192
  };
140
193
  const unsubscribe = flows.subscribe((sessions) => {
141
194
  if (sessions.has(session)) {
@@ -151,9 +204,9 @@ export function createJevDevtools(options) {
151
204
  if (closed)
152
205
  return;
153
206
  closed = true;
154
- knownDefinitions.clear();
207
+ knownDefinitions = new Set();
155
208
  unsubscribe();
156
- clearImmediate(timer);
209
+ unscheduleFlow(flush);
157
210
  clearInterval(heartbeat);
158
211
  request.signal.removeEventListener("abort", stop);
159
212
  streams.delete(stop);
@@ -168,7 +221,7 @@ export function createJevDevtools(options) {
168
221
  if (request.signal.aborted)
169
222
  stop();
170
223
  else
171
- flush();
224
+ flush(encodeFlowUpdate);
172
225
  },
173
226
  pull() {
174
227
  flowPull();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jev-devtools",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22.12"
@@ -19,7 +19,7 @@ Inspect the app's package manager/lockfile, React and Node versions, root compon
19
19
 
20
20
  Install `jev-devtools` using the app's existing package manager (npm: `npm install jev-devtools @typesafe-ai/sdk`; pnpm: `pnpm add jev-devtools @typesafe-ai/sdk`; Yarn: `yarn add jev-devtools @typesafe-ai/sdk`; Bun: `bun add jev-devtools @typesafe-ai/sdk`). `@typesafe-ai/sdk` is a peer dependency: keep the app's existing SDK version when it satisfies the peer range. Install in the workspace(s) that actually import it. It is a regular dependency when application modules import it, even though capture/display are development-only. Do not replace the app's framework or upgrade unrelated dependencies to force compatibility.
21
21
 
22
- ### Consumer compatibility (0.5.2)
22
+ ### Consumer compatibility (0.5.3)
23
23
 
24
24
  | Requirement | Contract |
25
25
  | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
@@ -35,7 +35,7 @@ Import application APIs from `jev-devtools` (React and browser-safe capture help
35
35
 
36
36
  ## Optional connected flow API
37
37
 
38
- When asked to build or inspect connected calls, read [references/flows.md](references/flows.md) after the framework recipe. For 0.5.2 it covers requests, server function tasks, runtime request factories, parallel checks, terminal branches, returning conditionals, bounded collections, stateful loops, captured-answer replay, and fixture comparison. It includes sample verification, scope/execution rules, and privacy limits. For an older installation, use its bundled recipe and declarations rather than assuming these operations exist. Preserve existing application policies; do not convert unrelated calls just to install the drawer. Flow execution is server-only and continues even with the inspector disabled.
38
+ When asked to build or inspect connected calls, read [references/flows.md](references/flows.md) after the framework recipe. For 0.5.3 it covers requests, server function tasks, runtime request factories, parallel checks, terminal branches, returning conditionals, bounded collections, stateful loops, captured-answer replay, and fixture comparison. It includes sample verification, scope/execution rules, and privacy limits. For an older installation, use its bundled recipe and declarations rather than assuming these operations exist. Preserve existing application policies; do not convert unrelated calls just to install the drawer. Flow execution is server-only and continues even with the inspector disabled.
39
39
 
40
40
  ## Integration invariants
41
41
 
@@ -1,6 +1,6 @@
1
1
  # Build and inspect a Jev flow
2
2
 
3
- For `jev-devtools` **0.5.2**. Check the repository changelog for publication status when installing from source. Read the installed package version and `lib/flow/index.d.ts` first; online `main` may describe newer APIs. Use this recipe when the user asks to connect multiple Jev requests, inspect branches, run server function steps, or visualize parallel checks, collections, and loops. Adding the inspector alone does not require converting existing calls to flows.
3
+ For `jev-devtools` **0.5.3**. Check the [release notes](https://github.com/diegoag64/jev-devtools/releases/tag/v0.5.3) for verified publication status when installing from source. Read the installed package version and `lib/flow/index.d.ts` first; online `main` may describe newer APIs. Use this recipe when the user asks to connect multiple Jev requests, inspect branches, run server function steps, or visualize parallel checks, collections, and loops. Adding the inspector alone does not require converting existing calls to flows.
4
4
 
5
5
  ## Plan the integration
6
6
 
@@ -9,7 +9,7 @@ For `jev-devtools` **0.5.2**. Check the repository changelog for publication sta
9
9
  3. Import `defineJevFlow` (and `all`, `any`, `not` when needed) from **server-only** `jev-devtools/flow`. Define the graph once at module scope and call `run()` from the existing Node handler/action. In Next.js, mark the module `server-only` and keep the executing route/segment on the Node runtime. No new client provider or root component is needed.
10
10
  4. A named output returns data and does not execute an action. Existing business actions can remain in the application after the returned outcome; use `task()` when the user wants application-owned server work included in the flow. Preserve authorization, idempotency, input validation, and error handling. Cancellation cannot undo side effects.
11
11
 
12
- If importing question helpers as below, install `@typesafe-ai/sdk` as a direct dependency in the server workspace using its package manager. Version 0.5.2 requires SDK `>=0.7.0 <0.8.0` and is verified with 0.7.0; preserve a compatible existing version rather than silently changing SDK semantics. The flow also accepts ordinary SDK question objects.
12
+ If importing question helpers as below, install `@typesafe-ai/sdk` as a direct dependency in the server workspace using its package manager. Version 0.5.3 requires SDK `>=0.7.0 <0.8.0` and is verified with 0.7.0; preserve a compatible existing version rather than silently changing SDK semantics. The flow also accepts ordinary SDK question objects.
13
13
 
14
14
  ## Complete example: parallel checks, one decision, two outcomes
15
15