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
|
-
[](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
|
-
**
|
|
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.
|
|
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:
|
package/lib/server/index.js
CHANGED
|
@@ -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
|
|
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 =
|
|
123
|
-
controller.enqueue(
|
|
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 &&
|
|
138
|
-
|
|
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
|
|
207
|
+
knownDefinitions = new Set();
|
|
155
208
|
unsubscribe();
|
|
156
|
-
|
|
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
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|