jev-devtools 0.5.3 → 0.5.5
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 +109 -103
- package/lib/flow/index.d.ts +6 -3
- package/lib/flow/index.js +3 -2
- package/lib/server/recorder.js +11 -9
- package/lib/src/CaptureFields.d.ts +11 -0
- package/lib/src/CaptureFields.js +42 -0
- package/lib/src/ChoiceProbabilities.d.ts +3 -1
- package/lib/src/ChoiceProbabilities.js +2 -2
- package/lib/src/JevDevtools.d.ts +1 -1
- package/lib/src/JevDevtools.js +21 -6
- package/lib/src/Questions.js +10 -5
- package/lib/src/TraceDiagram.js +45 -18
- package/lib/src/capture-view.d.ts +17 -0
- package/lib/src/capture-view.js +266 -0
- package/lib/src/condition-inputs.js +9 -4
- package/lib/src/display-redaction.js +15 -8
- package/lib/src/flow-condition.js +2 -1
- package/lib/src/flow-fixture.js +6 -4
- package/lib/src/flow-model.js +3 -3
- package/lib/src/flow-parser.d.ts +6 -0
- package/lib/src/flow-parser.js +191 -0
- package/lib/src/flow-stream.js +12 -31
- package/lib/src/inspector-styles.js +1 -1
- package/lib/src/inspector.css +1 -0
- package/lib/src/protocol.d.ts +7 -0
- package/lib/src/trace-parser.d.ts +7 -0
- package/lib/src/trace-parser.js +27 -0
- package/lib/src/trace-store.js +16 -24
- package/lib/src/transport-validation.d.ts +20 -0
- package/lib/src/transport-validation.js +45 -0
- package/package.json +1 -1
- package/skills/setup-jev-devtools/SKILL.md +2 -2
- package/skills/setup-jev-devtools/references/flows.md +38 -2
- package/skills/setup-jev-devtools/references/verify.md +42 -33
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2
|
+
export const text = (value) => typeof value === "string";
|
|
3
|
+
export const id = (value) => text(value) && value.length > 0;
|
|
4
|
+
export const finite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
5
|
+
export const nonnegative = (value) => finite(value) && value >= 0;
|
|
6
|
+
export const integer = (value) => nonnegative(value) && Number.isSafeInteger(value);
|
|
7
|
+
export const boolean = (value) => typeof value === "boolean";
|
|
8
|
+
export const literal = (...values) => (value) => values.some((candidate) => candidate === value);
|
|
9
|
+
export const optional = (check) => (value) => value === undefined || check(value);
|
|
10
|
+
export const array = (check, max = Infinity) => (value) => Array.isArray(value) && value.length <= max && value.every(check);
|
|
11
|
+
// Every protocol property, including optional ones, needs a compatible check.
|
|
12
|
+
// Extra wire fields are retained for version-1 forward compatibility.
|
|
13
|
+
export function shape(fields) {
|
|
14
|
+
const checks = fields;
|
|
15
|
+
return (value) => record(value) &&
|
|
16
|
+
Object.entries(checks).every(([key, check]) => check(value[key])) &&
|
|
17
|
+
// Unknown metadata remains visible in Raw, so it must also be safe JSON.
|
|
18
|
+
Object.entries(value).every(([key, extra]) => Object.hasOwn(checks, key) || json(extra));
|
|
19
|
+
}
|
|
20
|
+
export const strings = array(text);
|
|
21
|
+
export const ids = (value) => array(id, 200)(value) && new Set(value).size === value.length;
|
|
22
|
+
export const status = literal("pending", "success", "error", "cancelled");
|
|
23
|
+
// capture() traverses through depth 12 and emits scalar markers at depth 13.
|
|
24
|
+
// Image previews can exceed the ordinary 16,000-character string limit, so
|
|
25
|
+
// validation does not impose that limit on all strings or invent a byte budget.
|
|
26
|
+
export const json = (value) => {
|
|
27
|
+
const visit = (input, depth) => {
|
|
28
|
+
if (input === null || text(input) || boolean(input) || finite(input))
|
|
29
|
+
return true;
|
|
30
|
+
if (depth > 12)
|
|
31
|
+
return false;
|
|
32
|
+
if (Array.isArray(input))
|
|
33
|
+
return (input.length <= 150 &&
|
|
34
|
+
input.every((child) => visit(child, depth + 1)));
|
|
35
|
+
return (record(input) &&
|
|
36
|
+
Object.keys(input).length <= 256 &&
|
|
37
|
+
Object.values(input).every((child) => visit(child, depth + 1)));
|
|
38
|
+
};
|
|
39
|
+
return visit(value, 0);
|
|
40
|
+
};
|
|
41
|
+
export function parse(check, value, name) {
|
|
42
|
+
if (!check(value))
|
|
43
|
+
throw new Error(`Invalid ${name}`);
|
|
44
|
+
return value;
|
|
45
|
+
}
|
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.5)
|
|
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.5 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.5**. Check the [release notes](https://github.com/diegoag64/jev-devtools/releases/tag/v0.5.5) 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.3**. Check the [release notes](https://github.com/diego
|
|
|
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.5 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
|
|
|
@@ -148,6 +148,8 @@ For custom server-derived sessions, use `await inspector.run(request, () => revi
|
|
|
148
148
|
| `flow.output(name, value?, display?)` | Terminal named result, optionally containing nested resolved expressions. Output names are globally unique node IDs. For metadata without a value, pass `undefined` second. |
|
|
149
149
|
| `definition.run(input, { client, devtools?, signal? })` | Returns `{ runId, outcome: string, value?: unknown }`. Narrow/validate values in application code; outcomes are not inferred as a discriminated union. A normal SDK client works without recording. |
|
|
150
150
|
|
|
151
|
+
The bundled declarations reject array methods such as `.get("map")` and non-scalar `.eq()` receivers or operands. Equality supports strings, finite numbers, booleans, and null, including literal and branded types. Scalar unions still need matching resolved types. Array bounds and absent optional fields remain execution checks. Preserve generic field helpers by deriving their key constraint as `K extends keyof T & Parameters<FlowExpression<T>["get"]>[0]`; unrestricted `keyof T` also includes array methods. Older package declarations may accept these invalid operations, so check the installed version.
|
|
152
|
+
|
|
151
153
|
Use the callback's current builder (`lane` or `path`) to add steps; do not call the outer builder inside it. References must belong to the same definition and be available on the current path. Reusing an earlier parent reference is allowed. IDs must be unique across all paths/lanes: 1–80 letters, digits, `_`, or `-`, starting with a letter or digit. Maximum 256 nodes including collection/iteration templates, 16 nested blocks, and 1,024 expanded steps per run. Version 0.4.0 includes tasks, factories, maps, returning conditionals and loops as described below. Plain templates are copied when defining; treat SDK assets as immutable. Define once to avoid a new definition identity on every request; hot reload can still create a new identity.
|
|
152
154
|
|
|
153
155
|
**0.5.2:** expressions are bounded during construction to depth 80 (leaf depth 0), 4,096 expanded nodes, and 256 operands per operation. Reusing a child counts its complete size again: eleven `all(e, e)` doublings of Boolean `flow.input` fit (4,095 nodes), but twelve do not. Split larger logic into tasks or smaller steps. Legacy condition descriptions are capped at 4,096 UTF-16 code units including `[condition truncated]`; structured rules keep their 128-node projection budget. Display truncation never changes accepted expression evaluation.
|
|
@@ -248,6 +250,16 @@ Use `task()` for application-owned server work and the request-factory overload
|
|
|
248
250
|
|
|
249
251
|
Choose an item in the collection card, then **View Flow** to expand its full request/function diagram directly underneath on the same canvas. Changing the selector replaces the inline item flow; **Hide Flow** collapses it. Item values use bounded/redacted capture; don't put runtime data in structural titles. For an executable sample, see `cookbooks/rag-passages/README.md` in the repository checkout. Do not promise embedding search or LLM generation in that sample: it uses fixed retrieved passages, synthetic Jev scores and a deterministic excerpt preview.
|
|
250
252
|
|
|
253
|
+
For a finite chat feed, consult `cookbooks/twitch-chat-filter/README.md` in the repository. Preserve its 29 messages, concurrency-eight input-order map, one category Choice plus toxic/spoiler Nouls per request, and precedence: toxic ≥ 0.70 hides; category hide wins next; spoiler ≥ 0.70 blurs; remaining category action follows. Quiet reapplication reuses answers without requests. The port uses synthetic fixtures and excludes ongoing Twitch ingestion.
|
|
254
|
+
|
|
255
|
+
For independent candidate scoring followed by sorting, use the repository's `cookbooks/reranking` sample at `/?cookbook=reranking`: one query, a 30-candidate authored retrieval fixture, a bounded map with 12 concurrent Noul requests, and a stable descending sorting task. Preserve retrieval order for ties; these independent probabilities are not Choice confidence or a normalized distribution. BM25, CLERC evaluation and live inference are excluded.
|
|
256
|
+
|
|
257
|
+
The checkout also contains `cookbooks/pre-parsed-extraction` at `/?cookbook=pre-parsed-extraction`: preserve sequential helper requests with map concurrency 1, runtime candidate choices, amount-dependent Noul instructions, strict credit `> 0.5`, and empty/none parsing bypasses. Its phone and decimal-string normalization tasks execute locally against fixed documents and synthetic answers.
|
|
258
|
+
|
|
259
|
+
For selected-argument routing, read `cookbooks/function-calling/README.md` in the repository checkout. The sample at `/?cookbook=function-calling` uses one batched request and deterministic omit/fill tasks. Preserve the distinction between selected-label probability, argument decision products, call minimum decision mass and SDK Choice confidence. Its output is a proposed call; executing a tool requires a separate application action.
|
|
260
|
+
|
|
261
|
+
For sequential repeated assessments, the repository’s `cookbooks/consistency-choices/README.md` uses `map` with concurrency one and 15 requests. Keep its original eight-question rubric, fresh uid per repeat, ordered argmax and maximum-probability gate: below 0.60 abstains; exactly 0.60 accepts. Choice confidence is separate. Fixtures are authored demonstrations, not measured consistency; provider comparisons and live inference are excluded.
|
|
262
|
+
|
|
251
263
|
## Returning conditionals: `flow.if()` (0.4.0)
|
|
252
264
|
|
|
253
265
|
Version 0.4.0 includes `flow.if()` and strict numeric `.gt()` comparisons. Use `flow.if(id, { when, then, else }, display?)` for a conditional whose value feeds shared downstream steps. Each arm returns a `FlowExpression`; only the selected arm executes. The result type is the union of both values. An arm may return an earlier expression without adding a task. `output()` and terminal `branch()` arms are rejected. Scope-local refs must not leak; consume the returned conditional reference. Conditionals may nest and run inside parallel lanes or map items.
|
|
@@ -276,6 +288,8 @@ The drawer generates a Selected result merge, highlights only its selected incom
|
|
|
276
288
|
|
|
277
289
|
The repository's `cookbooks/sde-cascade` provides a complete local example at `/?cookbook=sde-cascade`: cheap extraction → runtime field verification → **any per-field probability > 0.70** → stronger extractor or keep cheap → shared comparison. The overall judge is displayed but excluded from the gate. Empty fields receive only `absence_wrong`. All four cases use synthetic probabilities and local extractor fixtures; no real provider performance or original evaluation is reproduced. Do not turn on live extraction just by adding an API key.
|
|
278
290
|
|
|
291
|
+
The repository’s `cookbooks/confidence-fallback` is a sample at `/?cookbook=confidence-fallback`. Preserve its 75 SIC groups, API `confidence >= 0.90` gate and parent-division lookup task. Largest class probability is a separate field, not a replacement for confidence or a Score. Verify below/equal/above boundary cases and one request on both routes; fixtures are synthetic and do not evaluate SEC filings.
|
|
292
|
+
|
|
279
293
|
## Bounded loops: `flow.loop()` (0.4.0)
|
|
280
294
|
|
|
281
295
|
Use `flow.loop()` to carry JSON-compatible state across bounded iterations. Literal initial state, whole-state references and nested reference templates are supported. Whole-state references and scalar initial values preserve their `S` payload, including generic types. For literal/template state, the gate, iteration, body return and final result use `Resolved<S>`, preserving branded primitives: for `initial: { count: flow.input.get("count") }`, task callbacks receive numeric `state.count` and can return `{ count: state.count + 1 }`. Expression methods belong on builder references, not resolved task values. Syntax:
|
|
@@ -307,6 +321,8 @@ Loops may contain one level of map, plus tasks, requests, conditions and paralle
|
|
|
307
321
|
|
|
308
322
|
`cookbooks/hierarchical-classification` is an executable sample at `/?cookbook=hierarchical-classification`. It follows the official executable algorithm’s **separate concurrent requests per frontier node**, despite introductory prose describing batching. Preserve geometric-mean decision-edge scores, epsilon 1e-9, single-child inference bypass, completed-leaf retention and top-k pruning. Samples are a small authored taxonomy and synthetic probabilities, not a replay of official benchmark data. Verify recovery, no-request paths, an initial leaf and intentional depth exhaustion before considering live execution.
|
|
309
323
|
|
|
324
|
+
For guardrail routing, see the repository [LLM guardrails example](https://github.com/diegoag64/jev-devtools/tree/main/cookbooks/guardrails) at `/?cookbook=guardrails`. It screens one input or output message with a single Noul/Score battery, then reuses that assessment in strict/permissive policy tasks. Preserve inclusive action thresholds 0.70/0.85, review 0.35, severity ≥ 2 upgrades of triggered reviews only, and support > block > review > pass precedence. Synthetic fixtures are sample-only; there is no LLM generation or live transport.
|
|
325
|
+
|
|
310
326
|
## Replay captures and compare runs (new in 0.5.0)
|
|
311
327
|
|
|
312
328
|
For human examples, see [the flow reference](https://docs.jevtools.dev/api/flow/) and [API glossary](https://docs.jevtools.dev/api/reference/#fixtures-and-comparison). These operations require 0.5.0 or later; inspect the installed declarations before using them with older packages.
|
|
@@ -315,3 +331,23 @@ For human examples, see [the flow reference](https://docs.jevtools.dev/api/flow/
|
|
|
315
331
|
2. On Node, import `replayClient` from `jev-devtools/flow` and call `await program.run(originalInput, { client: replayClient(fixture) })`. Use the same recipe, input, and stable step IDs. Jev steps use stored answers without a key/network call; tasks and runtime request factories still execute. Avoid uncontrolled effects in test tasks.
|
|
316
332
|
3. For an explicitly requested live comparison, import `compareWithFixture` and `formatComparison` from `jev-devtools/flow`. Call `await compareWithFixture(program, originalInput, fixture, { client: liveClient, devtools: inspector, tolerance: 0.01 })`, then use `formatComparison(result)` for text. Do not run live comparison merely to verify installation; use stored SDK responses for ordinary verification.
|
|
317
333
|
4. Tasks execute on both sides. `changed` tracks outcomes, values, decisions, and executed Jev steps; answer drift alone does not set it. Inspect `answers` separately, and apply numeric tolerance only to answer fields. The result's `liveFixture` contains unredacted live responses: review it before saving or sharing. Replay is not rollback, and incomplete captures cannot recreate missing inference results.
|
|
334
|
+
|
|
335
|
+
For the repository sample at `/?cookbook=parallel-questions`, preserve the five batched requests followed by five 13-item maps with `concurrency: 1`. Choice comparisons use maximum probability, independently of confidence; Score is divided by its top level. Keep the authored document and synthetic answers labeled. The sample provides no usage, cost or model timing data; local drawer durations are not inference benchmarks. See `cookbooks/parallel-questions/README.md` in the checkout for all-answer inspection and fixture limits.
|
|
336
|
+
|
|
337
|
+
## Entity-alignment repository example
|
|
338
|
+
|
|
339
|
+
For a Score-driven matching example, see `cookbooks/entity-alignment/README.md` in the repository checkout and `/?cookbook=entity-alignment` in the local playground. Preserve the source nearest-level rule: Score < 0.5 leaves unlinked, 0.5 ≤ Score < 1.5 requests curator review, and Score ≥ 1.5 proposes sameAs. The three companion Nouls explain field agreement; Score confidence and probabilities are separate evidence, not additional routing gates. The sample uses four attributed pairs and authored synthetic responses, returns proposals without database writes, and is not included in the npm package.
|
|
340
|
+
|
|
341
|
+
## Citation-checking example
|
|
342
|
+
|
|
343
|
+
When adapting citation checks, preserve the distinction between an absent quoted string (fabricated, zero Jev calls, null confidence) and a null quote (assess the named source section). Normalize and locate quotes in a task, then use `if()` to conditionally assess support with Choice. Route on returned API confidence `>= 0.80`, independently of option probabilities. The repository-only `cookbooks/citation-checking` example demonstrates these boundaries at `/?cookbook=citation-checking` with pinned RFC/citation assets and synthetic responses; its code and fixtures are not shipped in the package.
|
|
344
|
+
|
|
345
|
+
### Line-search cookbook in the repository
|
|
346
|
+
|
|
347
|
+
For a complete tagging → runtime request → ranking/lookup → branch example, use `cookbooks/line-search/README.md` at `/?cookbook=line-search`. Preserve one Choice + Noul request per search and document-local line IDs. Route only on Noul existence: `>= 0.70` answered, `< 0.35` absent, otherwise partial. Choice probability and API confidence have separate meanings. The pinned document is complete; responses are synthetic and the server accepts fixed sample queries only. The application result exposes every option beyond bounded DevTools previews.
|
|
348
|
+
|
|
349
|
+
### Date extraction sample
|
|
350
|
+
|
|
351
|
+
The repository’s `cookbooks/date-extraction` runs at `/?cookbook=date-extraction` with synthetic responses only. Preserve the seven Choice questions per role, fixed 2026-07-30 reference date, strict earlier-than-today-minus-31-days missing-year rollover, and Monday-based current/next week conventions. Assemble calendar dates in a task and return ISO strings or `null` across flow boundaries. Route on the minimum available confidence among consumed parts, separately flagging unavailable used confidence for review; label probabilities do not substitute for Choice confidence. The README documents the stricter missing-confidence policy and invalid leap-day handling relative to the source. Verify calendar boundaries, `< 0.60` routing and one request per role before adapting the server transport.
|
|
352
|
+
|
|
353
|
+
For the repository's `cookbooks/consistency-nouls` sample (`/?cookbook=consistency-nouls`), preserve fifteen sequential requests with fourteen Nouls each: `< 0.30` means no, `> 0.70` yes, and both boundaries belong to uncertain. Its tasks compute decisions and descriptive statistics from authored fixture values. Keep deterministic UID variation distinct from independent model draws; no measured consistency or provider comparison is reproduced. The per-run transport records returned models separately from the requested alias; unavailable metadata stays null.
|
|
@@ -7,30 +7,34 @@ Use the host app's typecheck/build commands. Do not run the Jev DevTools monorep
|
|
|
7
7
|
Use this server-only fixture when live inference is not authorized or no key is configured. It exercises the real SDK and recorder with fixed sample data and no external inference call. Create it from the **same inspector** that serves the endpoints. Keep it visibly sample-only; never substitute it for the user's production inference path.
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
const sampleJev = inspector.createClient(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
10
|
+
const sampleJev = inspector.createClient(
|
|
11
|
+
{
|
|
12
|
+
apiKey: "sample-only",
|
|
13
|
+
logLevel: "off",
|
|
14
|
+
fetch: async () =>
|
|
15
|
+
Response.json({
|
|
16
|
+
model: "jev-sample",
|
|
17
|
+
answers: {
|
|
18
|
+
category: {
|
|
19
|
+
type: "choice",
|
|
20
|
+
choice: "billing",
|
|
21
|
+
probabilities: { billing: 0.8, other: 0.2 },
|
|
22
|
+
confidence: 0.7,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
},
|
|
27
|
+
{ label: "Setup verification", source: "sample" },
|
|
28
|
+
);
|
|
25
29
|
|
|
26
30
|
async function runSample() {
|
|
27
31
|
return sampleJev.systemOne({
|
|
28
|
-
state: { message:
|
|
32
|
+
state: { message: "I was charged twice." },
|
|
29
33
|
questions: {
|
|
30
34
|
category: {
|
|
31
|
-
type:
|
|
32
|
-
instructions:
|
|
33
|
-
criteria: { billing:
|
|
35
|
+
type: "choice",
|
|
36
|
+
instructions: "Which team should handle this message?",
|
|
37
|
+
criteria: { billing: "Payment issues", other: "Everything else" },
|
|
34
38
|
},
|
|
35
39
|
},
|
|
36
40
|
});
|
|
@@ -41,12 +45,14 @@ For a Vite/Connect dev plugin, register a temporary local handler after mounting
|
|
|
41
45
|
|
|
42
46
|
```ts
|
|
43
47
|
server.middlewares.use(async (req, res, next) => {
|
|
44
|
-
if (req.url !==
|
|
48
|
+
if (req.url !== "/__jev-setup-sample" || req.method !== "POST") return next();
|
|
45
49
|
try {
|
|
46
50
|
await runSample();
|
|
47
|
-
res
|
|
51
|
+
res
|
|
52
|
+
.writeHead(200, { "content-type": "application/json" })
|
|
53
|
+
.end('{"ok":true}');
|
|
48
54
|
} catch {
|
|
49
|
-
res.writeHead(500).end(
|
|
55
|
+
res.writeHead(500).end("Sample failed");
|
|
50
56
|
}
|
|
51
57
|
});
|
|
52
58
|
```
|
|
@@ -66,16 +72,19 @@ Report HTTP/capture checks separately from visual browser checks, and sample ver
|
|
|
66
72
|
|
|
67
73
|
## Troubleshooting
|
|
68
74
|
|
|
69
|
-
| Symptom
|
|
70
|
-
|
|
|
71
|
-
| No launcher
|
|
72
|
-
| Disconnected or HTML instead of config | Ensure base path **and** subpaths reach the adapter before the SPA fallback; check proxy and Next optional catch-all.
|
|
73
|
-
| 403
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
75
|
+
| Symptom | Check |
|
|
76
|
+
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
77
|
+
| No launcher | Mount once and explicitly enable in development. Styles load automatically; no CSS import is needed. It intentionally renders nothing on the server. |
|
|
78
|
+
| Disconnected or HTML instead of config | Ensure base path **and** subpaths reach the adapter before the SPA fallback; check proxy and Next optional catch-all. |
|
|
79
|
+
| 403 | Match scheme/hostname/port and Host exactly; preserve proxy Host, verify Origin and authorization. Don't disable guards. |
|
|
80
|
+
| Repeated resynchronization | Inspect SSE records against the [wire contract](https://github.com/diegoag64/jev-devtools/blob/main/docs/stream-protocol.md#record-validation-and-compatibility). Malformed structural metadata rejects the whole event. Redacted content remains inspectable; use capture warnings to identify unavailable structured views. Restart both server and browser after upgrading. |
|
|
81
|
+
| Connected but empty | Use the adapter's instrumented client, same adapter/key/process and session. Direct SDK clients are not intercepted. |
|
|
82
|
+
| Clear fails | Browser/server endpoint agreement, same-origin DELETE, exact Origin, authorization and session. |
|
|
83
|
+
| Missing key | SDK needs a server key even with recording off; use the labeled sample transport for offline verification. |
|
|
84
|
+
| Next reload loses or ignores settings | Use a stable `getJevDevtools` key; restart after option changes. Don't dispose during hot reload. |
|
|
85
|
+
| Server import/build errors | Keep `/server` outside client modules. In Next externalize the SDK only. Use a supported Node runtime. |
|
|
86
|
+
| Production 404 | Expected when disabled; app inference remains independent. |
|
|
80
87
|
|
|
81
88
|
Capture is bounded to 50 calls in memory by default. Known credential fields are always redacted, including common API-key, client-secret and session-token aliases (case, hyphens and underscores are ignored). HTTP headers/options are not captured. The `redactAdditionalSensitiveData` component prop defaults to `true` and masks supported email, phone, postal address, SSN and card-number fields **only in DevTools views**. Set it to `false` to inspect those fields; changes apply immediately to existing captures, independently in each viewer, without server requests. These personal values remain in server/stream/browser memory even while masked. Custom server redaction always remains active, and neither credentials nor custom-redacted values can be recovered through the prop. See the [exact policy](https://github.com/diegoag64/jev-devtools/blob/main/docs/integration.md#redaction-policy). Arbitrary secrets in prose and unusual field names still need custom redaction. Verify both modes with synthetic sentinels and confirm SDK/runtime values remain unchanged. Diagrams show captured inputs/outputs, not hidden model reasoning. Routing decisions are recorded only for explicitly defined flows; see [flows.md](flows.md) for flow verification.
|
|
89
|
+
|
|
90
|
+
When configuring a custom redactor, verify replacements that change a field type or the whole request root with synthetic values. The drawer must retain usable siblings beside field-level unavailable placeholders and warnings, retain bounded redacted JSON in `Trace.capture.request` or `Trace.capture.result`, and leave SDK results unchanged. Presence includes `null`; strings such as `[redacted]` remain ordinary content. On the wire, an incompatible request has an empty structured view, and an incompatible response omits `Trace.result`. The drawer can display usable fields from `Trace.capture`; it must not invent values or box overlays from redacted coordinates. Fixture export reports that response as missing and keeps its warnings.
|