@agent-scope/core 1.17.1 → 1.17.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 +590 -0
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
# @agent-scope/core
|
|
2
|
+
|
|
3
|
+
Zero-dependency type foundation for the Scope React instrumentation platform.
|
|
4
|
+
|
|
5
|
+
`@agent-scope/core` defines every shared TypeScript type, the `serialize()` function, a complete set of runtime type-guards, and schema version constants. Nothing in this package references the DOM, React, or any browser API — it is safe to import in any environment (browser, Node.js, edge runtimes, test runners).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @agent-scope/core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## What it does / when to use it
|
|
16
|
+
|
|
17
|
+
`@agent-scope/core` is the contract layer of the Scope monorepo. You need it when:
|
|
18
|
+
|
|
19
|
+
- **Building a consumer** of `PageReport` objects (analytics, DevTools, CI reporters) — import the types and type-guards.
|
|
20
|
+
- **Serialising arbitrary React props or state** — call `serialize()` to produce a safely-serialised `SerializedValue` that handles circular references, depth limiting, and every JavaScript type.
|
|
21
|
+
- **Validating untrusted data** — use the `is*` guards to verify that a stored report still matches the current schema before processing it.
|
|
22
|
+
|
|
23
|
+
`@agent-scope/runtime` and `@agent-scope/sourcemap` both depend on this package and re-export the types they need.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## API Reference
|
|
28
|
+
|
|
29
|
+
### `PageReport`
|
|
30
|
+
|
|
31
|
+
The top-level transport and storage unit. Every other type is a node or sub-node of this structure.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
interface PageReport {
|
|
35
|
+
/** Full URL at capture time (no fragment). */
|
|
36
|
+
url: string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Router-level metadata. null when no routing adapter is installed or
|
|
40
|
+
* the URL could not be matched to a known route.
|
|
41
|
+
*/
|
|
42
|
+
route: RouteInfo | null;
|
|
43
|
+
|
|
44
|
+
/** Unix timestamp (ms) when the capture was initiated. */
|
|
45
|
+
timestamp: number;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Wall-clock time (ms) from capture start to PageReport assembly.
|
|
49
|
+
* Use this to monitor Scope runtime overhead.
|
|
50
|
+
*/
|
|
51
|
+
capturedIn: number;
|
|
52
|
+
|
|
53
|
+
/** Root node of the captured React component tree. */
|
|
54
|
+
tree: ComponentNode;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* All JS errors observed during the capture window:
|
|
58
|
+
* unhandled exceptions, unhandled rejections, ErrorBoundary catches,
|
|
59
|
+
* and console.error calls attributed to an error.
|
|
60
|
+
*/
|
|
61
|
+
errors: CapturedError[];
|
|
62
|
+
|
|
63
|
+
/** All <Suspense> boundaries, flattened for O(1) access. */
|
|
64
|
+
suspenseBoundaries: SuspenseBoundaryInfo[];
|
|
65
|
+
|
|
66
|
+
/** All console.* calls intercepted during the capture window, ascending by timestamp. */
|
|
67
|
+
consoleEntries: ConsoleEntry[];
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Example payload** (from `src/__tests__/types.test.ts`):
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const report: PageReport = {
|
|
75
|
+
url: "https://example.com/dashboard",
|
|
76
|
+
route: {
|
|
77
|
+
pattern: "/dashboard",
|
|
78
|
+
params: null,
|
|
79
|
+
query: {},
|
|
80
|
+
name: "dashboard",
|
|
81
|
+
},
|
|
82
|
+
timestamp: 1700000000000,
|
|
83
|
+
capturedIn: 42,
|
|
84
|
+
tree: {
|
|
85
|
+
id: 1,
|
|
86
|
+
name: "App",
|
|
87
|
+
type: "function",
|
|
88
|
+
source: { fileName: "/app/src/Foo.tsx", lineNumber: 10, columnNumber: 5 },
|
|
89
|
+
props: { type: "object", value: {}, preview: "{}" },
|
|
90
|
+
state: [
|
|
91
|
+
{
|
|
92
|
+
type: "useState",
|
|
93
|
+
name: null,
|
|
94
|
+
value: { type: "string", value: "hello", preview: '"hello"' },
|
|
95
|
+
deps: null,
|
|
96
|
+
hasCleanup: null,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
context: [
|
|
100
|
+
{
|
|
101
|
+
contextName: "ThemeContext",
|
|
102
|
+
value: { type: "string", value: "hello", preview: '"hello"' },
|
|
103
|
+
didTriggerRender: false,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
renderCount: 1,
|
|
107
|
+
renderDuration: 0.5,
|
|
108
|
+
children: [],
|
|
109
|
+
},
|
|
110
|
+
errors: [
|
|
111
|
+
{
|
|
112
|
+
message: "Something went wrong",
|
|
113
|
+
name: "Error",
|
|
114
|
+
stack: "Error: Something\n at App.tsx:42",
|
|
115
|
+
source: { fileName: "/app/src/Foo.tsx", lineNumber: 10, columnNumber: 5 },
|
|
116
|
+
componentName: "App",
|
|
117
|
+
timestamp: 1700000000000,
|
|
118
|
+
capturedBy: "boundary",
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
suspenseBoundaries: [
|
|
122
|
+
{
|
|
123
|
+
id: 5,
|
|
124
|
+
componentName: "LazySection",
|
|
125
|
+
isSuspended: false,
|
|
126
|
+
suspendedDuration: null,
|
|
127
|
+
fallbackName: "Spinner",
|
|
128
|
+
source: { fileName: "/app/src/Foo.tsx", lineNumber: 10, columnNumber: 5 },
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
consoleEntries: [
|
|
132
|
+
{
|
|
133
|
+
level: "warn",
|
|
134
|
+
args: [{ type: "string", value: "hello", preview: '"hello"' }],
|
|
135
|
+
timestamp: 1700000000001,
|
|
136
|
+
componentName: "App",
|
|
137
|
+
preview: "Something is odd",
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### `ComponentNode`
|
|
146
|
+
|
|
147
|
+
One node in the captured component tree, corresponding to a single React fiber.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
interface ComponentNode {
|
|
151
|
+
/** Fiber's internal numeric ID. Stable for the lifetime of a mounted component. */
|
|
152
|
+
id: number;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Resolved display name.
|
|
156
|
+
* Resolution order: displayName → function/class name → JSX tag → "Anonymous".
|
|
157
|
+
*/
|
|
158
|
+
name: string;
|
|
159
|
+
|
|
160
|
+
/** Component implementation strategy. */
|
|
161
|
+
type: ComponentType; // "function" | "class" | "forward_ref" | "memo" | "host"
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Source location from babel's __source prop or DevTools fiber data.
|
|
165
|
+
* null in production builds or for host elements.
|
|
166
|
+
*/
|
|
167
|
+
source: SourceLocation | null;
|
|
168
|
+
|
|
169
|
+
/** Serialized snapshot of the component's props at capture time. */
|
|
170
|
+
props: SerializedValue;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Ordered hook slots (hook call-order, slot 0 = first use* call).
|
|
174
|
+
* Empty for class components and host elements.
|
|
175
|
+
*/
|
|
176
|
+
state: HookState[];
|
|
177
|
+
|
|
178
|
+
/** All React contexts consumed by this component during the capture window. */
|
|
179
|
+
context: ContextConsumption[];
|
|
180
|
+
|
|
181
|
+
/** Number of renders during the capture window (>1 indicates re-renders). */
|
|
182
|
+
renderCount: number;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Total wall-clock time (ms) in this component's render, excluding children.
|
|
186
|
+
* Measured from beginWork to completeWork.
|
|
187
|
+
*/
|
|
188
|
+
renderDuration: number;
|
|
189
|
+
|
|
190
|
+
/** Ordered child nodes (depth-first). Empty array = leaf node. */
|
|
191
|
+
children: ComponentNode[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
type ComponentType = "function" | "class" | "forward_ref" | "memo" | "host";
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### `LightweightComponentNode`
|
|
200
|
+
|
|
201
|
+
A stripped-down node emitted when `capture({ lightweight: true })` is used. Omits `props`, `state`, `context`, `source`, `renderCount`, and `renderDuration`, producing ~99% smaller payloads for large trees.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
interface LightweightComponentNode {
|
|
205
|
+
id: number;
|
|
206
|
+
name: string;
|
|
207
|
+
type: ComponentType;
|
|
208
|
+
/** Total hooks count (no values serialised). */
|
|
209
|
+
hookCount: number;
|
|
210
|
+
/** Hook types in call order, no values. */
|
|
211
|
+
hookTypes: HookType[];
|
|
212
|
+
/** Equals children.length. */
|
|
213
|
+
childCount: number;
|
|
214
|
+
/** Tree depth; root = 0. */
|
|
215
|
+
depth: number;
|
|
216
|
+
children: LightweightComponentNode[];
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### `HookState`
|
|
223
|
+
|
|
224
|
+
A snapshot of a single hook slot.
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
interface HookState {
|
|
228
|
+
/** Hook type. "custom" for third-party / project-local hooks. */
|
|
229
|
+
type: HookType;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Inferred name of a custom hook (e.g. "useTheme").
|
|
233
|
+
* null for built-in hooks where type is already informative.
|
|
234
|
+
*/
|
|
235
|
+
name: string | null;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Serialized current value.
|
|
239
|
+
* - useState/useReducer: current state
|
|
240
|
+
* - useMemo/useCallback: memoized value / function ref
|
|
241
|
+
* - useRef: .current value
|
|
242
|
+
* - useContext: current context value
|
|
243
|
+
* - effect hooks: undefined (no meaningful value)
|
|
244
|
+
*/
|
|
245
|
+
value: SerializedValue;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Serialized dependency array.
|
|
249
|
+
* Present for useEffect, useLayoutEffect, useMemo, useCallback, useSyncExternalStore.
|
|
250
|
+
* null for hooks that do not accept deps.
|
|
251
|
+
*/
|
|
252
|
+
deps: SerializedValue[] | null;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Whether the effect registered a cleanup function on its last run.
|
|
256
|
+
* true = cleanup returned. false = no cleanup. null = not applicable.
|
|
257
|
+
*/
|
|
258
|
+
hasCleanup: boolean | null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
type HookType =
|
|
262
|
+
| "useState" | "useReducer" | "useEffect" | "useLayoutEffect"
|
|
263
|
+
| "useMemo" | "useCallback" | "useRef" | "useContext"
|
|
264
|
+
| "useId" | "useSyncExternalStore" | "useTransition" | "useDeferredValue"
|
|
265
|
+
| "custom";
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Example** (from `src/__tests__/types.test.ts`):
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
// useState
|
|
272
|
+
{ type: "useState", name: null, value: { type: "number", value: 42 }, deps: null, hasCleanup: null }
|
|
273
|
+
|
|
274
|
+
// useEffect with deps and cleanup
|
|
275
|
+
{ type: "useEffect", name: null, value: { type: "undefined" }, deps: [{ type: "string", value: "dep1" }], hasCleanup: true }
|
|
276
|
+
|
|
277
|
+
// custom hook
|
|
278
|
+
{ type: "custom", name: "useTheme", value: { type: "object", preview: '{ mode: "dark" }' }, deps: null, hasCleanup: null }
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### `SerializedValue`
|
|
284
|
+
|
|
285
|
+
An envelope for any JavaScript value that may not round-trip through JSON (functions, symbols, circular references, etc.).
|
|
286
|
+
|
|
287
|
+
```ts
|
|
288
|
+
interface SerializedValue {
|
|
289
|
+
/** Original JavaScript type discriminant. */
|
|
290
|
+
type: SerializedValueType;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Round-trippable value for primitives and simple composites.
|
|
294
|
+
* Absent for function, symbol, circular, truncated — use preview instead.
|
|
295
|
+
*/
|
|
296
|
+
value?: unknown;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Human-readable string for display. Always present when value is absent.
|
|
300
|
+
*/
|
|
301
|
+
preview?: string;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
type SerializedValueType =
|
|
305
|
+
| "string" | "number" | "boolean" | "null" | "undefined"
|
|
306
|
+
| "object" | "array" | "function" | "symbol" | "bigint"
|
|
307
|
+
| "date" | "map" | "set"
|
|
308
|
+
| "circular" // circular reference was detected at this position
|
|
309
|
+
| "truncated"; // value exceeded depth/size limits and was cut off
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Examples** (from `src/__tests__/serialization.test.ts`):
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
// Primitives
|
|
316
|
+
{ type: "null", value: null, preview: "null" }
|
|
317
|
+
{ type: "boolean", value: true, preview: "true" }
|
|
318
|
+
{ type: "number", value: 42, preview: "42" }
|
|
319
|
+
{ type: "string", value: "hi", preview: '"hi"' }
|
|
320
|
+
{ type: "bigint", value: "123n", preview: "123n" }
|
|
321
|
+
|
|
322
|
+
// Function (no value)
|
|
323
|
+
{ type: "function", preview: "function myFunc(a, b) { return a + …" }
|
|
324
|
+
|
|
325
|
+
// Date
|
|
326
|
+
{ type: "date", value: "2024-01-01T00:00:00.000Z", preview: "2024-01-01T00:00:00.000Z" }
|
|
327
|
+
|
|
328
|
+
// Map
|
|
329
|
+
{ type: "map", value: [/* entry objects */], preview: "Map(2)" }
|
|
330
|
+
|
|
331
|
+
// Set
|
|
332
|
+
{ type: "set", value: [/* items */], preview: "Set(3)" }
|
|
333
|
+
|
|
334
|
+
// Circular reference
|
|
335
|
+
{ type: "circular" }
|
|
336
|
+
|
|
337
|
+
// Depth-exceeded
|
|
338
|
+
{ type: "truncated", preview: "Array(50)" }
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
### `serialize(value, options?)`
|
|
344
|
+
|
|
345
|
+
Convert any JavaScript value to a `SerializedValue` snapshot.
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
function serialize(value: unknown, options?: SerializeOptions): SerializedValue;
|
|
349
|
+
|
|
350
|
+
interface SerializeOptions {
|
|
351
|
+
/** Maximum recursion depth for nested objects/arrays. Default: 5. */
|
|
352
|
+
maxDepth?: number;
|
|
353
|
+
/** Maximum string length before truncation. Default: 200. */
|
|
354
|
+
maxStringLength?: number;
|
|
355
|
+
/** Maximum array items to serialize. Default: 100. */
|
|
356
|
+
maxArrayLength?: number;
|
|
357
|
+
/** Maximum object properties to serialize. Default: 50. */
|
|
358
|
+
maxProperties?: number;
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Behaviour summary:**
|
|
363
|
+
|
|
364
|
+
| Input | Output type | Notes |
|
|
365
|
+
|---|---|---|
|
|
366
|
+
| `null` | `"null"` | `value: null` |
|
|
367
|
+
| `undefined` | `"undefined"` | no `value` field |
|
|
368
|
+
| `boolean` | `"boolean"` | |
|
|
369
|
+
| `number` | `"number"` | `NaN`, `Infinity` included |
|
|
370
|
+
| `string` | `"string"` | truncated at `maxStringLength` with `"..."` suffix |
|
|
371
|
+
| `bigint` | `"bigint"` | stored as `"123n"` string |
|
|
372
|
+
| `Symbol` | `"symbol"` | `preview` only, no `value` |
|
|
373
|
+
| `function` | `"function"` | raw source preview, truncated at 50 chars |
|
|
374
|
+
| `Date` | `"date"` | ISO 8601 string in `value` and `preview` |
|
|
375
|
+
| `Map` | `"map"` | entries as objects, truncated at `maxProperties` |
|
|
376
|
+
| `Set` | `"set"` | items as array, truncated at `maxArrayLength` |
|
|
377
|
+
| `Array` | `"array"` | truncated at `maxArrayLength` |
|
|
378
|
+
| `object` | `"object"` | `{key: SerializedValue}` map, truncated at `maxProperties` |
|
|
379
|
+
| `Error` | `"object"` | `{name, message, stack}` extracted |
|
|
380
|
+
| `WeakMap/WeakSet/WeakRef` | `"object"` | opaque, no entries |
|
|
381
|
+
| _circular ref_ | `"circular"` | no `value` or `preview` |
|
|
382
|
+
| _depth exceeded_ | `"truncated"` | `preview` describes the cut-off value |
|
|
383
|
+
|
|
384
|
+
**Circular reference detection** uses a `WeakSet` that tracks the current ancestor chain. The same object can legitimately appear in sibling branches without being flagged as circular (verified by tests).
|
|
385
|
+
|
|
386
|
+
**Depth counting** — depth 0 is the root call. An object value encountered at `depth >= maxDepth` is returned as `{ type: "truncated" }` rather than being expanded.
|
|
387
|
+
|
|
388
|
+
```ts
|
|
389
|
+
// Self-referential object
|
|
390
|
+
const obj: Record<string, unknown> = { a: 1 };
|
|
391
|
+
obj.self = obj;
|
|
392
|
+
serialize(obj);
|
|
393
|
+
// → { type: "object", value: { a: { type: "number", ... }, self: { type: "circular" } } }
|
|
394
|
+
|
|
395
|
+
// Deep nesting with maxDepth: 2
|
|
396
|
+
const deep = { a: { b: { c: "leaf" } } };
|
|
397
|
+
serialize(deep, { maxDepth: 2 });
|
|
398
|
+
// root(depth=0) → a(depth=1) → b is { type: "truncated" } at depth=2
|
|
399
|
+
|
|
400
|
+
// Shared object in sibling branches (NOT flagged as circular)
|
|
401
|
+
const shared = { x: 1 };
|
|
402
|
+
serialize({ left: shared, right: shared });
|
|
403
|
+
// → { left: { type: "object", ... }, right: { type: "object", ... } } ← both are "object"
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### Type Guards
|
|
409
|
+
|
|
410
|
+
All guards accept `unknown` and return a type predicate. Use them to validate data crossing process or storage boundaries.
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
import {
|
|
414
|
+
isPageReport, isPageReportDeep,
|
|
415
|
+
isComponentNode, isComponentNodeDeep,
|
|
416
|
+
isCapturedError, isSuspenseBoundaryInfo,
|
|
417
|
+
isConsoleEntry, isContextConsumption,
|
|
418
|
+
isHookState, isRouteInfo,
|
|
419
|
+
isSerializedValue, isSourceLocation,
|
|
420
|
+
} from "@agent-scope/core";
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
| Guard | Validates | Depth |
|
|
424
|
+
|---|---|---|
|
|
425
|
+
| `isPageReport(v)` | Full `PageReport` shape | Shallow `ComponentNode` |
|
|
426
|
+
| `isPageReportDeep(v)` | Full `PageReport` + entire tree | Recursive |
|
|
427
|
+
| `isComponentNode(v)` | Single `ComponentNode` (children not recursed) | O(1) per node |
|
|
428
|
+
| `isComponentNodeDeep(v)` | `ComponentNode` + all descendants | O(n) |
|
|
429
|
+
| `isCapturedError(v)` | `CapturedError` | — |
|
|
430
|
+
| `isSuspenseBoundaryInfo(v)` | `SuspenseBoundaryInfo` | — |
|
|
431
|
+
| `isConsoleEntry(v)` | `ConsoleEntry` | — |
|
|
432
|
+
| `isContextConsumption(v)` | `ContextConsumption` | — |
|
|
433
|
+
| `isHookState(v)` | `HookState` | — |
|
|
434
|
+
| `isRouteInfo(v)` | `RouteInfo` | — |
|
|
435
|
+
| `isSerializedValue(v)` | `SerializedValue` | — |
|
|
436
|
+
| `isSourceLocation(v)` | `SourceLocation` | — |
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
### Constants
|
|
441
|
+
|
|
442
|
+
Readonly arrays useful for exhaustive `switch`/`if` checks and validation loops.
|
|
443
|
+
|
|
444
|
+
```ts
|
|
445
|
+
import {
|
|
446
|
+
SCHEMA_VERSION, // "0.1.0" — bump on breaking schema changes
|
|
447
|
+
HOOK_TYPES, // readonly HookType[]
|
|
448
|
+
COMPONENT_TYPES, // readonly ComponentType[]
|
|
449
|
+
SERIALIZED_VALUE_TYPES, // readonly SerializedValueType[]
|
|
450
|
+
CONSOLE_LEVELS, // readonly ConsoleLevel[]
|
|
451
|
+
} from "@agent-scope/core";
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
`SCHEMA_VERSION` follows semver; store it in `PageReport` metadata to detect schema drift when loading reports from storage.
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
### Supporting Types
|
|
459
|
+
|
|
460
|
+
<details>
|
|
461
|
+
<summary><code>SourceLocation</code></summary>
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
interface SourceLocation {
|
|
465
|
+
/** Absolute or relative path to the source file. */
|
|
466
|
+
fileName: string;
|
|
467
|
+
/** 1-based line number of the JSX element. */
|
|
468
|
+
lineNumber: number;
|
|
469
|
+
/** 1-based column number of the JSX element. */
|
|
470
|
+
columnNumber: number;
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
Populated from React's `__source` prop (injected by `babel-plugin-transform-react-jsx-source` in development mode).
|
|
475
|
+
</details>
|
|
476
|
+
|
|
477
|
+
<details>
|
|
478
|
+
<summary><code>ContextConsumption</code></summary>
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
interface ContextConsumption {
|
|
482
|
+
/**
|
|
483
|
+
* The context's displayName. null when the context has no display name.
|
|
484
|
+
*/
|
|
485
|
+
contextName: string | null;
|
|
486
|
+
|
|
487
|
+
/** Serialized snapshot of the context value at capture time. */
|
|
488
|
+
value: SerializedValue;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Whether this context consumption triggered a re-render during the
|
|
492
|
+
* capture window (i.e. value changed between previous and current render).
|
|
493
|
+
*/
|
|
494
|
+
didTriggerRender: boolean;
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
</details>
|
|
498
|
+
|
|
499
|
+
<details>
|
|
500
|
+
<summary><code>CapturedError</code></summary>
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
interface CapturedError {
|
|
504
|
+
message: string;
|
|
505
|
+
name: string; // e.g. "TypeError", "RangeError"
|
|
506
|
+
stack: string | null; // raw V8 stack; not source-mapped
|
|
507
|
+
source: SourceLocation | null; // parsed from top stack frame
|
|
508
|
+
componentName: string | null; // nearest React component
|
|
509
|
+
timestamp: number; // Unix ms
|
|
510
|
+
capturedBy: "boundary" | "unhandled" | "rejection" | "console";
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
</details>
|
|
514
|
+
|
|
515
|
+
<details>
|
|
516
|
+
<summary><code>RouteInfo</code></summary>
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
interface RouteInfo {
|
|
520
|
+
pattern: string | null; // e.g. "/users/:id"
|
|
521
|
+
params: Record<string, string> | null; // e.g. { id: "42" }
|
|
522
|
+
query: Record<string, string>; // parsed query string
|
|
523
|
+
name: string | null; // named route from router config
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
</details>
|
|
527
|
+
|
|
528
|
+
<details>
|
|
529
|
+
<summary><code>SuspenseBoundaryInfo</code></summary>
|
|
530
|
+
|
|
531
|
+
```ts
|
|
532
|
+
interface SuspenseBoundaryInfo {
|
|
533
|
+
id: number;
|
|
534
|
+
componentName: string; // nearest named ancestor
|
|
535
|
+
isSuspended: boolean;
|
|
536
|
+
suspendedDuration: number | null; // ms suspended; null if not triggered
|
|
537
|
+
fallbackName: string | null; // name of the fallback element
|
|
538
|
+
source: SourceLocation | null;
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
</details>
|
|
542
|
+
|
|
543
|
+
<details>
|
|
544
|
+
<summary><code>ConsoleEntry</code></summary>
|
|
545
|
+
|
|
546
|
+
```ts
|
|
547
|
+
interface ConsoleEntry {
|
|
548
|
+
level: ConsoleLevel; // "log" | "warn" | "error" | "info" | "debug" | "group" | ...
|
|
549
|
+
args: SerializedValue[]; // each argument, serialized
|
|
550
|
+
timestamp: number; // Unix ms
|
|
551
|
+
componentName: string | null; // attributed React component
|
|
552
|
+
preview: string; // single-line condensed text, trimmed to 200 chars
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
</details>
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Internal Architecture
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
src/
|
|
563
|
+
├── index.ts ← barrel export (types, guards, serialize, constants)
|
|
564
|
+
├── serialization.ts ← serialize() + SerializeOptions
|
|
565
|
+
├── guards.ts ← all is*() type-guard functions
|
|
566
|
+
├── constants.ts ← SCHEMA_VERSION, HOOK_TYPES, COMPONENT_TYPES, …
|
|
567
|
+
└── types/
|
|
568
|
+
├── page-report.ts ← PageReport
|
|
569
|
+
├── component-node.ts ← ComponentNode, ComponentType
|
|
570
|
+
├── lightweight-component-node.ts ← LightweightComponentNode
|
|
571
|
+
├── hook-state.ts ← HookState, HookType
|
|
572
|
+
├── serialized-value.ts ← SerializedValue, SerializedValueType
|
|
573
|
+
├── source-location.ts ← SourceLocation
|
|
574
|
+
├── context.ts ← ContextConsumption
|
|
575
|
+
├── errors.ts ← CapturedError
|
|
576
|
+
├── route.ts ← RouteInfo
|
|
577
|
+
├── console.ts ← ConsoleEntry, ConsoleLevel
|
|
578
|
+
└── suspense.ts ← SuspenseBoundaryInfo
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
The package has **zero runtime dependencies**. It ships both ESM (`dist/index.js`) and CJS (`dist/index.cjs`) builds via `tsup`.
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Used by
|
|
586
|
+
|
|
587
|
+
| Package | How |
|
|
588
|
+
|---|---|
|
|
589
|
+
| `@agent-scope/runtime` | Imports all types; calls `serialize()` for props, state, and context values |
|
|
590
|
+
| `@agent-scope/sourcemap` | Imports `ComponentNode`, `PageReport` to type the resolution input/output |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-scope/core",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.3",
|
|
4
4
|
"description": "Core types, schemas, and serialization for Scope — zero dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"module": "./dist/index.js",
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"files": [
|
|
23
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
24
25
|
],
|
|
25
26
|
"scripts": {
|
|
26
27
|
"build": "tsup",
|