jev-devtools 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Jev DevTools
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/jev-devtools/v/0.5.1)
|
|
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.
|
|
7
|
+
**Source version: 0.5.1.** Check the [release history](https://github.com/diegoag64/jev-devtools/blob/main/CHANGELOG.md) for npm availability. If trying this source before publication, 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
|
|
|
@@ -39,6 +39,8 @@ Install from npm:
|
|
|
39
39
|
pnpm add jev-devtools @typesafe-ai/sdk
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
Use ESM imports, matching React/React DOM **18.x or 19.x**, Node **22.12+**, and TypeSafe SDK **0.7.x**. TypeScript consumers need **5.4+** and compatible React/Node types. React and React DOM are required package peers even for server-only installations. See [compatibility and all public imports](https://github.com/diegoag64/jev-devtools/blob/main/docs/integration.md#compatibility-and-public-imports); `/server` and `/flow` run only on Node.
|
|
43
|
+
|
|
42
44
|
To try local changes before a future release:
|
|
43
45
|
|
|
44
46
|
```sh
|
|
@@ -46,7 +48,7 @@ To try local changes before a future release:
|
|
|
46
48
|
npm ci
|
|
47
49
|
npm run pack:devtools
|
|
48
50
|
# From the consuming app:
|
|
49
|
-
npm install /absolute/path/to/jev-devtools-0.5.
|
|
51
|
+
npm install /absolute/path/to/jev-devtools-0.5.1.tgz
|
|
50
52
|
```
|
|
51
53
|
|
|
52
54
|
Mount once. The drawer loads its own styles; no CSS import is needed:
|
|
@@ -72,7 +74,7 @@ app.use(inspector.middleware); // Mount at root, before fallback handlers.
|
|
|
72
74
|
// Call inspector.dispose() on shutdown.
|
|
73
75
|
```
|
|
74
76
|
|
|
75
|
-
Only calls through that client are captured. The React component subscribes via same-origin SSE, receiving an initial snapshot followed by changed traces. Older client/server combinations remain compatible through full snapshots. Both sides default to disabled. API keys remain server-side. Browser code is SSR-safe. The drawer uses a Shadow DOM boundary and its own stylesheet so host page selectors cannot alter its internal layout.
|
|
77
|
+
Only calls through that client are captured. The React component subscribes via same-origin SSE, receiving an initial snapshot followed by changed traces. Older client/server combinations remain compatible through full snapshots. Both sides default to disabled. API keys remain server-side. Browser code is SSR-safe. The drawer uses a Shadow DOM boundary and its own stylesheet so host page selectors cannot alter its internal layout. No Tailwind or shadcn installation is required. Drag the Flow canvas to pan, scroll/pinch to zoom, or use Fit.
|
|
76
78
|
|
|
77
79
|
History is bounded to 50 calls in memory by default. API routes and inspector endpoints must share an adapter instance; distributed processes and edge runtimes are not supported. Without `authorize`, the middleware accepts only loopback connections; Web Request handlers can't see the connection's address, so run those servers on `127.0.0.1`. Captures include bounded/redacted context and answers, not hidden model reasoning.
|
|
78
80
|
|
package/lib/flow/index.d.ts
CHANGED
|
@@ -26,7 +26,8 @@ export declare class FlowExpression<T> {
|
|
|
26
26
|
readonly ast: Ast;
|
|
27
27
|
protected readonly [valueTypeBrand]: T;
|
|
28
28
|
constructor(ast: Ast, owner?: object);
|
|
29
|
-
|
|
29
|
+
/** Select an own field from an object or array; primitive properties are unsupported. */
|
|
30
|
+
get<K extends keyof T & (string | number)>(this: FlowExpression<object>, key: K): FlowExpression<T[K]>;
|
|
30
31
|
eq(value: T | FlowExpression<T>): FlowExpression<boolean>;
|
|
31
32
|
lt(this: FlowExpression<number>, value: number | FlowExpression<number>): FlowExpression<boolean>;
|
|
32
33
|
gt(this: FlowExpression<number>, value: number | FlowExpression<number>): FlowExpression<boolean>;
|
package/lib/flow/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export class FlowExpression {
|
|
|
32
32
|
freezeAst(ast);
|
|
33
33
|
Object.freeze(this);
|
|
34
34
|
}
|
|
35
|
+
/** Select an own field from an object or array; primitive properties are unsupported. */
|
|
35
36
|
get(key) {
|
|
36
37
|
return expression({ op: "get", from: this.ast, key: String(key) }, [this]);
|
|
37
38
|
}
|
|
@@ -89,7 +90,7 @@ const plain = (v) => !!v &&
|
|
|
89
90
|
typeof v === "object" &&
|
|
90
91
|
(Object.getPrototypeOf(v) === Object.prototype ||
|
|
91
92
|
Object.getPrototypeOf(v) === null);
|
|
92
|
-
function mapValue(value, ref, seen = new Set(), depth = 0) {
|
|
93
|
+
function mapValue(value, ref, rejectSymbolKeys = false, seen = new Set(), depth = 0) {
|
|
93
94
|
if (depth > 40)
|
|
94
95
|
throw new Error("Flow value nesting exceeds 40");
|
|
95
96
|
if (value instanceof FlowExpression)
|
|
@@ -98,14 +99,17 @@ function mapValue(value, ref, seen = new Set(), depth = 0) {
|
|
|
98
99
|
throw new Error("Flow values cannot contain callbacks");
|
|
99
100
|
if (!Array.isArray(value) && !plain(value))
|
|
100
101
|
return value; // Preserve SDK assets.
|
|
102
|
+
// Task templates must reject keys that copying would otherwise silently discard.
|
|
103
|
+
if (rejectSymbolKeys && Object.getOwnPropertySymbols(value).length)
|
|
104
|
+
throw new TypeError("Task data cannot contain symbol keys");
|
|
101
105
|
if (seen.has(value))
|
|
102
106
|
throw new Error("Cyclic flow value");
|
|
103
107
|
seen.add(value);
|
|
104
108
|
const result = Array.isArray(value)
|
|
105
|
-
? value.map((v) => mapValue(v, ref, seen, depth + 1))
|
|
109
|
+
? value.map((v) => mapValue(v, ref, rejectSymbolKeys, seen, depth + 1))
|
|
106
110
|
: Object.fromEntries(Object.entries(value).map(([k, v]) => [
|
|
107
111
|
k,
|
|
108
|
-
mapValue(v, ref, seen, depth + 1),
|
|
112
|
+
mapValue(v, ref, rejectSymbolKeys, seen, depth + 1),
|
|
109
113
|
]));
|
|
110
114
|
seen.delete(value);
|
|
111
115
|
return result;
|
|
@@ -380,7 +384,7 @@ export function defineJevFlow(name, build) {
|
|
|
380
384
|
task.timeoutMs < 1 ||
|
|
381
385
|
task.timeoutMs > 2_147_483_647))
|
|
382
386
|
throw new Error("Task timeoutMs must be a positive 32-bit integer");
|
|
383
|
-
const frozen = mapValue(task.input, (expr) => expr);
|
|
387
|
+
const frozen = mapValue(task.input, (expr) => expr, true);
|
|
384
388
|
const step = add(id, "task", frozen, display);
|
|
385
389
|
step.input = frozen;
|
|
386
390
|
step.task = task.run;
|
|
@@ -807,7 +811,7 @@ export function defineJevFlow(name, build) {
|
|
|
807
811
|
abortCheck();
|
|
808
812
|
}
|
|
809
813
|
else if (step.kind === "task") {
|
|
810
|
-
const input = jsonSnapshot(mapValue(step.input, (e) => evaluate(e.ast, data, values)));
|
|
814
|
+
const input = jsonSnapshot(mapValue(step.input, (e) => evaluate(e.ast, data, values), true));
|
|
811
815
|
state.data = { input };
|
|
812
816
|
emit();
|
|
813
817
|
value = jsonSnapshot(await runCallback((signal) => step.task(jsonSnapshot(input), {
|
package/package.json
CHANGED
|
@@ -17,16 +17,30 @@ Inspect the app's package manager/lockfile, React and Node versions, root compon
|
|
|
17
17
|
- **React with a Node backend, including Vite:** read [references/react-node.md](references/react-node.md). A browser-only app needs a Node server for Jev; the Vite development-server option is local only.
|
|
18
18
|
- **Other Node frameworks:** use the Web Request/Response or middleware API described in the React/Node reference and verify that framework's routing. Do not assume the Next.js recipe applies to Pages Router. Edge runtimes and cross-process/serverless history aggregation are unsupported.
|
|
19
19
|
|
|
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.
|
|
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
|
+
|
|
22
|
+
### Consumer compatibility (0.5.1)
|
|
23
|
+
|
|
24
|
+
| Requirement | Contract |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| Node.js | 22.12+ for the adapter and flow execution; Edge runtimes are unsupported. |
|
|
27
|
+
| React / React DOM | Matching 18.x or 19.x versions; both remain required peers even for server-only installations. |
|
|
28
|
+
| TypeSafe SDK | `>=0.7.0 <0.8.0`; verified with 0.7.0. |
|
|
29
|
+
| TypeScript | 5.4+ for the public declarations; verified with 5.4.5. The flow API uses built-in `NoInfer`, which 5.3.3 cannot resolve. |
|
|
30
|
+
| Modules | ESM imports with export-aware `Bundler` or `NodeNext` resolution and a matching module setting. There is no CommonJS `require` entry. |
|
|
31
|
+
|
|
32
|
+
Use React types matching the app's React major, Node types compatible with its runtime/compiler, and DOM types for Web `Request`/`Response` APIs. The packed declarations passed strict checks without `skipLibCheck` using TypeScript 5.4.5, SDK 0.7.0, React 19.3.1, `@types/react` 19.3.0, and `@types/node` 22.10.2. Frameworks and newer type packages can require a newer compiler; preserve compatible app dependencies rather than downgrading to this verification baseline.
|
|
33
|
+
|
|
34
|
+
Import application APIs from `jev-devtools` (React and browser-safe capture helpers/types), or the Node-only `jev-devtools/server` and `jev-devtools/flow` entries. Internal paths and `jev-devtools/package.json` are not exported. Inspect the installed version through the package manager, and read declaration/skill files from disk rather than importing internal package paths. Always supply the browser `origin` to the server adapter, including when `enabled: false`.
|
|
21
35
|
|
|
22
36
|
## Optional connected flow API
|
|
23
37
|
|
|
24
|
-
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.1 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.
|
|
25
39
|
|
|
26
40
|
## Integration invariants
|
|
27
41
|
|
|
28
42
|
- Use only public imports: `jev-devtools` and server-only `jev-devtools/server` and `jev-devtools/flow`. No provider, TanStack DevTools shell, Tailwind, or shadcn setup is needed; TanStack Virtual is an internal dependency.
|
|
29
|
-
- Mount `<JevDevtools />` once with an explicit development flag. The drawer injects its own stylesheet into a Shadow DOM host under `document.body`;
|
|
43
|
+
- Mount `<JevDevtools />` once with an explicit development flag. The drawer injects its own stylesheet into a Shadow DOM host under `document.body`; no CSS import is needed. Do not add global `section`/`main` padding overrides to repair the drawer. Keep document-level transforms/filters on an app wrapper rather than `html`/`body`, which can affect fixed overlays. Server capture must also be explicitly enabled for development; both default to off.
|
|
30
44
|
- Create a shared adapter; the inspector routes and application client must use it in the same Node realm/process. Replace existing `new TypeSafeClient(options)` construction with `inspector.createClient(options)` while preserving keys, transport options, retries, and call semantics. Keep existing `systemOne(...)` inputs and application behavior.
|
|
31
45
|
- Browser and server `endpoint` paths must agree (default `/api/jev-devtools`). Route the base path and its subpaths. The server `origin` must exactly match the browser scheme, hostname, and port. A browser endpoint is a same-origin path, not an absolute backend URL.
|
|
32
46
|
- Keep keys in server environment variables, never `VITE_*` or `NEXT_PUBLIC_*`. Use the host's environment loader and an ignored local env file. If a key is unavailable, complete setup and use the clearly labeled sample verification in [references/verify.md](references/verify.md); report that live inference remains unverified.
|
|
@@ -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.1**. 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.
|
|
4
4
|
|
|
5
5
|
## Plan the integration
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ For `jev-devtools` **0.5.0**. 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.1 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
|
|
|
@@ -94,7 +94,7 @@ For custom server-derived sessions, use `await inspector.run(request, () => revi
|
|
|
94
94
|
| `flow.if(id, { when, then, else }, display?)` | Only the selected path executes. Each arm returns an expression; the merged result can feed shared downstream steps. |
|
|
95
95
|
| `flow.map(id, { items, input, concurrency?, maxItems }, buildItem, display?)` | Run a bounded item program over an array; preserve result order. Pass outer values through `input`; return an expression from the item builder. |
|
|
96
96
|
| `flow.loop(id, { initial, input, while, maxIterations }, buildIteration, display?)` | Check a state expression before each iteration; return a same-type state expression from the body. Reject unfinished limit exhaustion with `FlowLoopLimitError`. |
|
|
97
|
-
| `flow.input.get('field')` |
|
|
97
|
+
| `flow.input.get('field')` | Select an own object field, array index, or array `length` as a typed reference resolved during execution. Primitive properties (string length/indexes included) are unsupported; compute them in a task callback. |
|
|
98
98
|
| `result.answer('name')` | Typed answer fields: `.choice`, `.probabilities.get('label')`, `.confidence`, `.noul`, `.score`, `.legend`, or `.box` as supported by that question's SDK result. Select nested fields with `.get(key)`. |
|
|
99
99
|
| `value.eq(other)`, `.lt(number)`, `.gt(number)`, `.gte(number)` | Matching scalar equality or finite numeric comparisons. Noul values are in 0–1; use `0.9`, not `90`. There is no `.lte()` method. |
|
|
100
100
|
| `all(...)`, `any(...)`, `not(...)` | Compose Boolean expressions. Every operand evaluates; missing values are errors even in an otherwise short-circuited expression. Do not use JavaScript `if`, `&&`, or `>=` on expression objects. |
|
|
@@ -170,7 +170,7 @@ Remove temporary verification routes unless requested as a demo. Report the inst
|
|
|
170
170
|
|
|
171
171
|
Use `task()` for application-owned server work and the request-factory overload of `jev()` when later questions depend on earlier results. Both are part of 0.4.0.
|
|
172
172
|
|
|
173
|
-
- `flow.task(id, { input, run, timeoutMs? }, display?)`: resolve nested input references, run server code, and return a typed reference. `run(input, { signal, runId, stepId, executionId })` may return a value or Promise. Inputs/outputs must be plain JSON-compatible values; return null rather than undefined. No implicit retry.
|
|
173
|
+
- `flow.task(id, { input, run, timeoutMs? }, display?)`: resolve nested input references, run server code, and return a typed reference. `run(input, { signal, runId, stepId, executionId })` may return a value or Promise. Inputs/outputs must be plain JSON-compatible values; return null rather than undefined. Task input literals with own symbol keys (including nested objects and arrays) fail during definition; referenced values are checked before the callback runs. No implicit retry.
|
|
174
174
|
- `flow.jev(id, { input, request: resolved => ({ state, questions, ...sdkOptions }) }, display?)`: construct a synchronous SDK request at execution time. Do asynchronous work in a preceding task. Keep Jev calls here to retain full linked diagrams. Never return unresolved flow references or a Promise from the factory.
|
|
175
175
|
- Every Jev step also has `.answers`, a typed reference to the complete answer map. Pass it to a task when a request factory generates question names dynamically; do not create new `.answer()` references inside a runtime callback.
|
|
176
176
|
- Neither callback executes at definition time. Runtime input snapshots protect previous values from mutation. Task timeouts/cancellation stop downstream work and signal the callback, but cannot undo side effects or forcibly interrupt synchronous code.
|