@triscope/core 0.4.0
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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/compose.d.ts +11 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +152 -0
- package/dist/compose.js.map +1 -0
- package/dist/editor.d.ts +14 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +131 -0
- package/dist/editor.js.map +1 -0
- package/dist/harness.d.ts +199 -0
- package/dist/harness.d.ts.map +1 -0
- package/dist/harness.js +1027 -0
- package/dist/harness.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect.d.ts +94 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +434 -0
- package/dist/inspect.js.map +1 -0
- package/dist/knob-utils.d.ts +22 -0
- package/dist/knob-utils.d.ts.map +1 -0
- package/dist/knob-utils.js +51 -0
- package/dist/knob-utils.js.map +1 -0
- package/dist/lab/css.d.ts +11 -0
- package/dist/lab/css.d.ts.map +1 -0
- package/dist/lab/css.js +57 -0
- package/dist/lab/css.js.map +1 -0
- package/dist/lab/dom.d.ts +13 -0
- package/dist/lab/dom.d.ts.map +1 -0
- package/dist/lab/dom.js +76 -0
- package/dist/lab/dom.js.map +1 -0
- package/dist/motion-probe.d.ts +47 -0
- package/dist/motion-probe.d.ts.map +1 -0
- package/dist/motion-probe.js +122 -0
- package/dist/motion-probe.js.map +1 -0
- package/dist/probe-utils.d.ts +14 -0
- package/dist/probe-utils.d.ts.map +1 -0
- package/dist/probe-utils.js +18 -0
- package/dist/probe-utils.js.map +1 -0
- package/dist/scene-cameras.d.ts +6 -0
- package/dist/scene-cameras.d.ts.map +1 -0
- package/dist/scene-cameras.js +20 -0
- package/dist/scene-cameras.js.map +1 -0
- package/dist/scene-delta.d.ts +21 -0
- package/dist/scene-delta.d.ts.map +1 -0
- package/dist/scene-delta.js +57 -0
- package/dist/scene-delta.js.map +1 -0
- package/dist/scene-introspect.d.ts +78 -0
- package/dist/scene-introspect.d.ts.map +1 -0
- package/dist/scene-introspect.js +164 -0
- package/dist/scene-introspect.js.map +1 -0
- package/dist/scene-registry.d.ts +36 -0
- package/dist/scene-registry.d.ts.map +1 -0
- package/dist/scene-registry.js +64 -0
- package/dist/scene-registry.js.map +1 -0
- package/dist/scene-view.d.ts +52 -0
- package/dist/scene-view.d.ts.map +1 -0
- package/dist/scene-view.js +171 -0
- package/dist/scene-view.js.map +1 -0
- package/dist/source-tag.d.ts +34 -0
- package/dist/source-tag.d.ts.map +1 -0
- package/dist/source-tag.js +120 -0
- package/dist/source-tag.js.map +1 -0
- package/dist/telemetry.d.ts +53 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +302 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +142 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/uniform-access.d.ts +32 -0
- package/dist/uniform-access.d.ts.map +1 -0
- package/dist/uniform-access.js +144 -0
- package/dist/uniform-access.js.map +1 -0
- package/dist/validate.d.ts +2 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +81 -0
- package/dist/validate.js.map +1 -0
- package/dist/vite.d.ts +3 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +4 -0
- package/dist/vite.js.map +1 -0
- package/dist/warnings.d.ts +24 -0
- package/dist/warnings.d.ts.map +1 -0
- package/dist/warnings.js +26 -0
- package/dist/warnings.js.map +1 -0
- package/package.json +60 -0
- package/src/compose.ts +164 -0
- package/src/editor.ts +138 -0
- package/src/harness.ts +1263 -0
- package/src/index.ts +58 -0
- package/src/inspect.ts +498 -0
- package/src/knob-utils.ts +60 -0
- package/src/lab/css.ts +56 -0
- package/src/lab/dom.ts +88 -0
- package/src/motion-probe.ts +135 -0
- package/src/probe-utils.ts +17 -0
- package/src/scene-cameras.ts +33 -0
- package/src/scene-delta.ts +69 -0
- package/src/scene-introspect.ts +230 -0
- package/src/scene-registry.ts +103 -0
- package/src/scene-view.ts +204 -0
- package/src/source-tag.ts +139 -0
- package/src/telemetry.ts +337 -0
- package/src/three-webgpu-shim.d.ts +130 -0
- package/src/types.ts +121 -0
- package/src/uniform-access.ts +152 -0
- package/src/validate.ts +82 -0
- package/src/vite.ts +5 -0
- package/src/warnings.ts +41 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto source-tag for the scene graph.
|
|
3
|
+
*
|
|
4
|
+
* Monkey-patches THREE.Object3D.prototype.add exactly once so every object
|
|
5
|
+
* added to a scene gets a userData.__tris record containing the user
|
|
6
|
+
* source frame (file:line + fn name from V8 stack), the object class, the
|
|
7
|
+
* geometry class, and a material hint.
|
|
8
|
+
*
|
|
9
|
+
* Element authors do not call anything. The tag appears on every mesh
|
|
10
|
+
* added via .add(), Three's standard pattern. The picker in inspect.ts
|
|
11
|
+
* reads this back when the user clicks, so we map "this pixel on screen"
|
|
12
|
+
* to "this exact line in your code" without grep.
|
|
13
|
+
*
|
|
14
|
+
* Stack parsing skips any frame inside three/, @triscope/, or
|
|
15
|
+
* node_modules/. In vite dev mode the stack is already source-mapped,
|
|
16
|
+
* resolving to original .ts source files. Production minified builds
|
|
17
|
+
* lose the precision but triscope is dev-only.
|
|
18
|
+
*/
|
|
19
|
+
import * as THREE from 'three/webgpu';
|
|
20
|
+
/**
|
|
21
|
+
* Note on line accuracy: in browser dev mode, `new Error().stack` returns
|
|
22
|
+
* positions in the file as vite served it (after esbuild's TS-to-JS
|
|
23
|
+
* transform). Vite tries to preserve line counts but TSL `Fn(([uv]) => …)`
|
|
24
|
+
* blocks and other complex constructions can drift by tens of lines.
|
|
25
|
+
* The captured line is therefore "approximate" — close enough for
|
|
26
|
+
* `code --goto` to land in the right neighborhood, but verify visually
|
|
27
|
+
* (or use `parentChain` + `geometry` + `material.color` as cross-checks)
|
|
28
|
+
* before assuming it's exact.
|
|
29
|
+
*/
|
|
30
|
+
let patched = false;
|
|
31
|
+
export function installSourceTagPatch() {
|
|
32
|
+
if (patched)
|
|
33
|
+
return false;
|
|
34
|
+
patched = true;
|
|
35
|
+
const origAdd = THREE.Object3D.prototype.add;
|
|
36
|
+
THREE.Object3D.prototype.add = function (...children) {
|
|
37
|
+
let stack = [];
|
|
38
|
+
try {
|
|
39
|
+
const raw = new Error().stack ?? '';
|
|
40
|
+
stack = parseUserStack(raw);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
/* stack capture is best-effort */
|
|
44
|
+
}
|
|
45
|
+
const source = stack[0] ?? null;
|
|
46
|
+
for (const child of children) {
|
|
47
|
+
if (!child)
|
|
48
|
+
continue;
|
|
49
|
+
const prior = child.userData?.__tris;
|
|
50
|
+
if (prior && prior.source)
|
|
51
|
+
continue;
|
|
52
|
+
const tag = {
|
|
53
|
+
source,
|
|
54
|
+
stack,
|
|
55
|
+
type: child.constructor.name,
|
|
56
|
+
};
|
|
57
|
+
const asMesh = child;
|
|
58
|
+
if (asMesh.geometry)
|
|
59
|
+
tag.geometry = asMesh.geometry.type;
|
|
60
|
+
if (asMesh.material)
|
|
61
|
+
tag.material = extractMaterialHint(asMesh.material);
|
|
62
|
+
if (child.name)
|
|
63
|
+
tag.name = child.name;
|
|
64
|
+
child.userData = child.userData ?? {};
|
|
65
|
+
child.userData.__tris = tag;
|
|
66
|
+
}
|
|
67
|
+
return origAdd.apply(this, children);
|
|
68
|
+
};
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
export const FRAME_RE = /at (?:(?<fn>[^(]+?) \()?(?<url>[^()]+?):(?<line>\d+):(?<col>\d+)\)?$/;
|
|
72
|
+
export const SKIP_PATTERNS = [
|
|
73
|
+
/\/node_modules\//,
|
|
74
|
+
/\/three\//,
|
|
75
|
+
/\/@triscope\//,
|
|
76
|
+
/\/triscope\/packages\//,
|
|
77
|
+
/\/(harness|source-tag|inspect|editor|telemetry)\.[jt]sx?/,
|
|
78
|
+
/^node:/,
|
|
79
|
+
/^(?:webpack|vite):/,
|
|
80
|
+
];
|
|
81
|
+
export function parseUserStack(raw, max = 8) {
|
|
82
|
+
const out = [];
|
|
83
|
+
for (const lineStr of raw.split('\n')) {
|
|
84
|
+
const m = FRAME_RE.exec(lineStr.trim());
|
|
85
|
+
if (!m?.groups)
|
|
86
|
+
continue;
|
|
87
|
+
const url = stripUrl(m.groups.url);
|
|
88
|
+
if (SKIP_PATTERNS.some((p) => p.test(url)))
|
|
89
|
+
continue;
|
|
90
|
+
out.push({
|
|
91
|
+
file: url,
|
|
92
|
+
line: Number(m.groups.line),
|
|
93
|
+
col: Number(m.groups.col),
|
|
94
|
+
fn: m.groups.fn || undefined,
|
|
95
|
+
});
|
|
96
|
+
if (out.length >= max)
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
export function stripUrl(u) {
|
|
102
|
+
return u.replace(/[?#].*$/, '');
|
|
103
|
+
}
|
|
104
|
+
export function extractMaterialHint(material) {
|
|
105
|
+
const m = material;
|
|
106
|
+
const hint = {};
|
|
107
|
+
try {
|
|
108
|
+
if (m?.color?.getHexString)
|
|
109
|
+
hint.color = '#' + m.color.getHexString();
|
|
110
|
+
}
|
|
111
|
+
catch { }
|
|
112
|
+
try {
|
|
113
|
+
const tex = m?.map;
|
|
114
|
+
if (tex)
|
|
115
|
+
hint.map = tex.name || tex.source?.data?.src || null;
|
|
116
|
+
}
|
|
117
|
+
catch { }
|
|
118
|
+
return hint;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=source-tag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-tag.js","sourceRoot":"","sources":["../src/source-tag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAyBtC;;;;;;;;;GASG;AAEH,IAAI,OAAO,GAAG,KAAK,CAAC;AAEpB,MAAM,UAAU,qBAAqB;IACnC,IAAI,OAAO;QAAE,OAAO,KAAK,CAAC;IAC1B,OAAO,GAAG,IAAI,CAAC;IACf,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC;IAC7C,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,GAAG,UAAU,GAAG,QAA0B;QACpE,IAAI,KAAK,GAAkB,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YACpC,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,kCAAkC;QACpC,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,MAA+B,CAAC;YAC9D,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM;gBAAE,SAAS;YACpC,MAAM,GAAG,GAAc;gBACrB,MAAM;gBACN,KAAK;gBACL,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI;aAC7B,CAAC;YACF,MAAM,MAAM,GAAG,KAAmB,CAAC;YACnC,IAAI,MAAM,CAAC,QAAQ;gBAAE,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YACzD,IAAI,MAAM,CAAC,QAAQ;gBAAE,GAAG,CAAC,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACzE,IAAI,KAAK,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YACtC,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;YACrC,KAAK,CAAC,QAAoC,CAAC,MAAM,GAAG,GAAG,CAAC;QAC3D,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAmB,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,sEAAsE,CAAC;AAE/F,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,kBAAkB;IAClB,WAAW;IACX,eAAe;IACf,wBAAwB;IACxB,0DAA0D;IAC1D,QAAQ;IACR,oBAAoB;CACrB,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,GAAG,GAAG,CAAC;IACjD,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,CAAC,EAAE,MAAM;YAAE,SAAS;QACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAAE,SAAS;QACrD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,GAAG;YACT,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;YAC3B,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;YACzB,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,SAAS;SAC7B,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG;YAAE,MAAM;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,OAAO,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAiB;IACnD,MAAM,CAAC,GAAG,QAGT,CAAC;IACF,MAAM,IAAI,GAA4C,EAAE,CAAC;IACzD,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,KAAK,EAAE,YAAY;YAAE,IAAI,CAAC,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,CAAC;QACnB,IAAI,GAAG;YAAE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
interface TelemetryOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Project name used to namespace state files in /tmp.
|
|
5
|
+
* Defaults to the name in package.json (sanitized).
|
|
6
|
+
*/
|
|
7
|
+
project?: string;
|
|
8
|
+
/** Override state file path. */
|
|
9
|
+
statePath?: string;
|
|
10
|
+
/** Override log file path. */
|
|
11
|
+
logPath?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Regex matching files that need a full-reload (instead of HMR) when they
|
|
14
|
+
* change. Default catches TSL material / mesh / element / shader sources,
|
|
15
|
+
* because vite HMR cannot remount a THREE.Material already in the scene.
|
|
16
|
+
* Pass `null` to disable.
|
|
17
|
+
*/
|
|
18
|
+
forceReloadOn?: RegExp | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read a request body to a string with a hard timeout. A broken/slow client
|
|
22
|
+
* could otherwise hold a Vite middleware slot open indefinitely (the original
|
|
23
|
+
* readBody had data/end/error listeners but no timeout). On timeout we destroy
|
|
24
|
+
* the socket so the slot is freed, and reject so the route returns 400.
|
|
25
|
+
* Override the budget with TRISCOPE_READBODY_TIMEOUT_MS.
|
|
26
|
+
*/
|
|
27
|
+
export declare function readRequestBody(req: {
|
|
28
|
+
on: (event: string, cb: (arg: never) => void) => void;
|
|
29
|
+
socket?: {
|
|
30
|
+
destroy?: () => void;
|
|
31
|
+
};
|
|
32
|
+
}, timeoutMs?: number): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Vite plugin that wires the telemetry sink:
|
|
35
|
+
*
|
|
36
|
+
* POST /__state → writes /tmp/<project>-state.json + appends to /tmp/<project>-state.log
|
|
37
|
+
* GET /__state → returns the latest snapshot
|
|
38
|
+
* POST /__knob → stores a pending knob change for the harness to consume
|
|
39
|
+
* GET /__knob → returns and CLEARS the pending knob queue (polled by harness)
|
|
40
|
+
* GET /__manifest → returns the registered element manifest (POSTed by harness on boot)
|
|
41
|
+
* POST /__manifest → harness pushes the live manifest (elements/cameras/knobs)
|
|
42
|
+
*
|
|
43
|
+
* The names start with __ so they cannot collide with user routes.
|
|
44
|
+
*/
|
|
45
|
+
export declare function triscopeTelemetryPlugin(opts?: TelemetryOptions): Plugin;
|
|
46
|
+
export interface TelemetryPaths {
|
|
47
|
+
project: string;
|
|
48
|
+
statePath: string;
|
|
49
|
+
logPath: string;
|
|
50
|
+
}
|
|
51
|
+
export declare function resolveTelemetryPaths(cwd?: string): TelemetryPaths;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,UAAU,gBAAgB;IACxB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE;IACH,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC;IACtD,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CACnC,EACD,SAAS,GAAE,MAAkE,GAC5E,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAgCD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,gBAAqB,GAAG,MAAM,CAyM3E;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAsB,GAAG,cAAc,CAOjF"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Read a request body to a string with a hard timeout. A broken/slow client
|
|
6
|
+
* could otherwise hold a Vite middleware slot open indefinitely (the original
|
|
7
|
+
* readBody had data/end/error listeners but no timeout). On timeout we destroy
|
|
8
|
+
* the socket so the slot is freed, and reject so the route returns 400.
|
|
9
|
+
* Override the budget with TRISCOPE_READBODY_TIMEOUT_MS.
|
|
10
|
+
*/
|
|
11
|
+
export function readRequestBody(req, timeoutMs = Number(process.env.TRISCOPE_READBODY_TIMEOUT_MS ?? 10000)) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
let body = '';
|
|
14
|
+
let done = false;
|
|
15
|
+
const timer = setTimeout(() => {
|
|
16
|
+
if (done)
|
|
17
|
+
return;
|
|
18
|
+
done = true;
|
|
19
|
+
try {
|
|
20
|
+
req.socket?.destroy?.();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
/* best-effort */
|
|
24
|
+
}
|
|
25
|
+
reject(new Error(`request body read timed out after ${timeoutMs}ms`));
|
|
26
|
+
}, timeoutMs);
|
|
27
|
+
// Don't let a pending read keep the process alive.
|
|
28
|
+
timer.unref?.();
|
|
29
|
+
req.on('data', (c) => {
|
|
30
|
+
body += c;
|
|
31
|
+
});
|
|
32
|
+
req.on('end', () => {
|
|
33
|
+
if (done)
|
|
34
|
+
return;
|
|
35
|
+
done = true;
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
resolve(body);
|
|
38
|
+
});
|
|
39
|
+
req.on('error', (e) => {
|
|
40
|
+
if (done)
|
|
41
|
+
return;
|
|
42
|
+
done = true;
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
reject(e);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function readProjectLabs(cwd) {
|
|
49
|
+
try {
|
|
50
|
+
const p = join(cwd, 'package.json');
|
|
51
|
+
if (!existsSync(p))
|
|
52
|
+
return {};
|
|
53
|
+
const pkg = JSON.parse(readFileSync(p, 'utf8'));
|
|
54
|
+
const labs = pkg?.triscope?.labs;
|
|
55
|
+
if (labs && typeof labs === 'object') {
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const [k, v] of Object.entries(labs)) {
|
|
58
|
+
if (typeof v === 'string')
|
|
59
|
+
out[k] = v;
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function readPackageName(cwd) {
|
|
70
|
+
try {
|
|
71
|
+
const p = join(cwd, 'package.json');
|
|
72
|
+
if (!existsSync(p))
|
|
73
|
+
return 'triscope-project';
|
|
74
|
+
const pkg = JSON.parse(readFileSync(p, 'utf8'));
|
|
75
|
+
return String(pkg.name ?? 'triscope-project').replace(/[^A-Za-z0-9._-]/g, '-');
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return 'triscope-project';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Vite plugin that wires the telemetry sink:
|
|
83
|
+
*
|
|
84
|
+
* POST /__state → writes /tmp/<project>-state.json + appends to /tmp/<project>-state.log
|
|
85
|
+
* GET /__state → returns the latest snapshot
|
|
86
|
+
* POST /__knob → stores a pending knob change for the harness to consume
|
|
87
|
+
* GET /__knob → returns and CLEARS the pending knob queue (polled by harness)
|
|
88
|
+
* GET /__manifest → returns the registered element manifest (POSTed by harness on boot)
|
|
89
|
+
* POST /__manifest → harness pushes the live manifest (elements/cameras/knobs)
|
|
90
|
+
*
|
|
91
|
+
* The names start with __ so they cannot collide with user routes.
|
|
92
|
+
*/
|
|
93
|
+
export function triscopeTelemetryPlugin(opts = {}) {
|
|
94
|
+
const project = opts.project ?? readPackageName(process.cwd());
|
|
95
|
+
const statePath = opts.statePath ?? join(tmpdir(), `${project}-state.json`);
|
|
96
|
+
const logPath = opts.logPath ?? join(tmpdir(), `${project}-state.log`);
|
|
97
|
+
// In-memory pending knob queue. Harness polls and drains.
|
|
98
|
+
const pendingKnobs = [];
|
|
99
|
+
// Persisted knob state per element. Survives the harness's full-reload so
|
|
100
|
+
// the harness can re-hydrate to the last user-applied values instead of
|
|
101
|
+
// snapping back to spec defaults. Updated on every POST /__knob, read by
|
|
102
|
+
// the harness via GET /__knob/current on boot.
|
|
103
|
+
const lastKnobValues = {};
|
|
104
|
+
// SDL (set_scene_param): pending camera/knob deltas the harness drains via
|
|
105
|
+
// GET /__scene, plus the merged persisted scene state for re-hydration on
|
|
106
|
+
// reload (GET /__scene/current). Mirrors the /__knob pattern.
|
|
107
|
+
const pendingScene = [];
|
|
108
|
+
const lastSceneState = {
|
|
109
|
+
cameras: {},
|
|
110
|
+
knobs: {},
|
|
111
|
+
};
|
|
112
|
+
// Manifest is a map keyed by element name so multiple labs can co-exist —
|
|
113
|
+
// each harness POSTs its own entry on boot.
|
|
114
|
+
const manifestByElement = {};
|
|
115
|
+
// Pre-seed with package.json#triscope.labs so MCP capture_views works on
|
|
116
|
+
// the very first call (before any browser tab loads a lab).
|
|
117
|
+
for (const [name, labUrl] of Object.entries(readProjectLabs(process.cwd()))) {
|
|
118
|
+
manifestByElement[name] = { element: name, labUrl };
|
|
119
|
+
}
|
|
120
|
+
const forceReloadOn = opts.forceReloadOn === null
|
|
121
|
+
? null
|
|
122
|
+
: (opts.forceReloadOn ?? /(\.tsl|Element|Mesh|Material|Shader)\.(ts|tsx|js|mjs)$/i);
|
|
123
|
+
return {
|
|
124
|
+
name: 'triscope-telemetry',
|
|
125
|
+
configureServer(server) {
|
|
126
|
+
mkdirSync(dirname(statePath), { recursive: true });
|
|
127
|
+
// Clear last session's telemetry on dev-server boot so a previously-open
|
|
128
|
+
// lab's elements don't linger as phantoms (the POST /__state merge is for
|
|
129
|
+
// multiple tabs in the SAME session — it has no cross-session expiry).
|
|
130
|
+
// The harness re-POSTs on mount, so a live tab repopulates immediately.
|
|
131
|
+
try {
|
|
132
|
+
rmSync(statePath, { force: true });
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
/* best-effort — a stale file just merges as before */
|
|
136
|
+
}
|
|
137
|
+
const readBody = (req) => readRequestBody(req);
|
|
138
|
+
server.middlewares.use('/__state', async (req, res, next) => {
|
|
139
|
+
if (!req.method)
|
|
140
|
+
return next();
|
|
141
|
+
try {
|
|
142
|
+
if (req.method === 'POST') {
|
|
143
|
+
const body = await readBody(req);
|
|
144
|
+
const payload = JSON.parse(body);
|
|
145
|
+
// Merge the elements map across labs so two tabs on different
|
|
146
|
+
// lab pages don't clobber each other's telemetry. Top-level
|
|
147
|
+
// fields (perf/time/cameras) still reflect the last writer
|
|
148
|
+
// since they're per-tab — that's expected when read_telemetry
|
|
149
|
+
// is project-scoped, not lab-scoped.
|
|
150
|
+
let merged = payload;
|
|
151
|
+
try {
|
|
152
|
+
if (existsSync(statePath)) {
|
|
153
|
+
const existing = JSON.parse(readFileSync(statePath, 'utf8'));
|
|
154
|
+
merged = {
|
|
155
|
+
...payload,
|
|
156
|
+
elements: { ...(existing?.elements ?? {}), ...(payload?.elements ?? {}) },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
/* corrupt file — overwrite with the new payload */
|
|
162
|
+
}
|
|
163
|
+
writeFileSync(statePath, JSON.stringify(merged, null, 2));
|
|
164
|
+
const ts = new Date().toISOString();
|
|
165
|
+
const fps = payload?.perf?.fps?.toFixed?.(0) ?? '?';
|
|
166
|
+
const cam = payload?.activeCamera ?? '?';
|
|
167
|
+
appendFileSync(logPath, `${ts} fps=${fps} cam=${cam}\n`);
|
|
168
|
+
res.statusCode = 200;
|
|
169
|
+
return res.end('ok');
|
|
170
|
+
}
|
|
171
|
+
if (req.method === 'GET') {
|
|
172
|
+
res.setHeader('content-type', 'application/json');
|
|
173
|
+
return res.end(existsSync(statePath) ? readFileSync(statePath) : '{}');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
res.statusCode = 400;
|
|
178
|
+
return res.end(String(err));
|
|
179
|
+
}
|
|
180
|
+
return next();
|
|
181
|
+
});
|
|
182
|
+
server.middlewares.use('/__knob', async (req, res, next) => {
|
|
183
|
+
if (!req.method)
|
|
184
|
+
return next();
|
|
185
|
+
try {
|
|
186
|
+
// GET /__knob/current → persisted state (sub-path on the same prefix).
|
|
187
|
+
if (req.method === 'GET' && (req.url ?? '').startsWith('/current')) {
|
|
188
|
+
res.setHeader('content-type', 'application/json');
|
|
189
|
+
return res.end(JSON.stringify(lastKnobValues));
|
|
190
|
+
}
|
|
191
|
+
if (req.method === 'POST') {
|
|
192
|
+
const body = await readBody(req);
|
|
193
|
+
const payload = JSON.parse(body);
|
|
194
|
+
const updates = Array.isArray(payload) ? payload : [payload];
|
|
195
|
+
for (const u of updates) {
|
|
196
|
+
if (typeof u?.element === 'string' && typeof u?.key === 'string') {
|
|
197
|
+
lastKnobValues[u.element] ??= {};
|
|
198
|
+
lastKnobValues[u.element][u.key] = u.value;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
pendingKnobs.push(...updates);
|
|
202
|
+
res.statusCode = 200;
|
|
203
|
+
return res.end('ok');
|
|
204
|
+
}
|
|
205
|
+
if (req.method === 'GET') {
|
|
206
|
+
res.setHeader('content-type', 'application/json');
|
|
207
|
+
const drained = pendingKnobs.splice(0, pendingKnobs.length);
|
|
208
|
+
return res.end(JSON.stringify(drained));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
res.statusCode = 400;
|
|
213
|
+
return res.end(String(err));
|
|
214
|
+
}
|
|
215
|
+
return next();
|
|
216
|
+
});
|
|
217
|
+
server.middlewares.use('/__scene', async (req, res, next) => {
|
|
218
|
+
if (!req.method)
|
|
219
|
+
return next();
|
|
220
|
+
try {
|
|
221
|
+
// GET /__scene/current → merged persisted scene state (re-hydration).
|
|
222
|
+
if (req.method === 'GET' && (req.url ?? '').startsWith('/current')) {
|
|
223
|
+
res.setHeader('content-type', 'application/json');
|
|
224
|
+
return res.end(JSON.stringify(lastSceneState));
|
|
225
|
+
}
|
|
226
|
+
if (req.method === 'POST') {
|
|
227
|
+
const body = await readBody(req);
|
|
228
|
+
const delta = JSON.parse(body);
|
|
229
|
+
// Merge into the persisted state so a reload re-applies it.
|
|
230
|
+
if (delta?.cameras && typeof delta.cameras === 'object') {
|
|
231
|
+
for (const [n, c] of Object.entries(delta.cameras)) {
|
|
232
|
+
lastSceneState.cameras[n] = { ...lastSceneState.cameras[n], ...c };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (delta?.knobs && typeof delta.knobs === 'object') {
|
|
236
|
+
for (const [k, v] of Object.entries(delta.knobs))
|
|
237
|
+
lastSceneState.knobs[k] = v;
|
|
238
|
+
}
|
|
239
|
+
pendingScene.push(delta);
|
|
240
|
+
res.statusCode = 200;
|
|
241
|
+
return res.end('ok');
|
|
242
|
+
}
|
|
243
|
+
if (req.method === 'GET') {
|
|
244
|
+
res.setHeader('content-type', 'application/json');
|
|
245
|
+
const drained = pendingScene.splice(0, pendingScene.length);
|
|
246
|
+
return res.end(JSON.stringify(drained));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
res.statusCode = 400;
|
|
251
|
+
return res.end(String(err));
|
|
252
|
+
}
|
|
253
|
+
return next();
|
|
254
|
+
});
|
|
255
|
+
server.middlewares.use('/__manifest', async (req, res, next) => {
|
|
256
|
+
if (!req.method)
|
|
257
|
+
return next();
|
|
258
|
+
try {
|
|
259
|
+
if (req.method === 'POST') {
|
|
260
|
+
const body = await readBody(req);
|
|
261
|
+
const payload = JSON.parse(body);
|
|
262
|
+
if (payload?.element && typeof payload.element === 'string') {
|
|
263
|
+
manifestByElement[payload.element] = payload;
|
|
264
|
+
}
|
|
265
|
+
res.statusCode = 200;
|
|
266
|
+
return res.end('ok');
|
|
267
|
+
}
|
|
268
|
+
if (req.method === 'GET') {
|
|
269
|
+
res.setHeader('content-type', 'application/json');
|
|
270
|
+
return res.end(JSON.stringify({ elements: manifestByElement }));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
res.statusCode = 400;
|
|
275
|
+
return res.end(String(err));
|
|
276
|
+
}
|
|
277
|
+
return next();
|
|
278
|
+
});
|
|
279
|
+
},
|
|
280
|
+
handleHotUpdate({ file, server }) {
|
|
281
|
+
// TSL materials (and any code that ends up baked into the renderer
|
|
282
|
+
// node graph) cannot be remounted via vite HMR because the THREE
|
|
283
|
+
// Material instance is already in the scene. Force full-reload so
|
|
284
|
+
// edits to shader/element/mesh files reach the renderer. All other
|
|
285
|
+
// files (plain ts/css/etc.) continue to HMR normally.
|
|
286
|
+
if (forceReloadOn && forceReloadOn.test(file)) {
|
|
287
|
+
server.ws.send({ type: 'full-reload' });
|
|
288
|
+
return [];
|
|
289
|
+
}
|
|
290
|
+
return undefined;
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
export function resolveTelemetryPaths(cwd = process.cwd()) {
|
|
295
|
+
const project = readPackageName(cwd);
|
|
296
|
+
return {
|
|
297
|
+
project,
|
|
298
|
+
statePath: join(tmpdir(), `${project}-state.json`),
|
|
299
|
+
logPath: join(tmpdir(), `${project}-state.log`),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type * as THREE from 'three/webgpu';
|
|
2
|
+
/** A position+target camera preset for one pane of the lab grid. */
|
|
3
|
+
export interface CameraSpec {
|
|
4
|
+
position: [number, number, number];
|
|
5
|
+
target: [number, number, number];
|
|
6
|
+
/** Vertical FOV in degrees. Default 45. */
|
|
7
|
+
fov?: number;
|
|
8
|
+
/** If true, auto-fit element bounds into the camera frame. */
|
|
9
|
+
fit?: boolean;
|
|
10
|
+
/** Near clip. Default 0.1. */
|
|
11
|
+
near?: number;
|
|
12
|
+
/** Far clip. Default 2000. */
|
|
13
|
+
far?: number;
|
|
14
|
+
}
|
|
15
|
+
/** A tunable knob exposed to the slider editor and the MCP `set_knob` tool. */
|
|
16
|
+
export type Knob = {
|
|
17
|
+
type: 'number';
|
|
18
|
+
min: number;
|
|
19
|
+
max: number;
|
|
20
|
+
step?: number;
|
|
21
|
+
default: number;
|
|
22
|
+
label?: string;
|
|
23
|
+
} | {
|
|
24
|
+
type: 'int';
|
|
25
|
+
min: number;
|
|
26
|
+
max: number;
|
|
27
|
+
default: number;
|
|
28
|
+
label?: string;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'color';
|
|
31
|
+
default: string;
|
|
32
|
+
label?: string;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'boolean';
|
|
35
|
+
default: boolean;
|
|
36
|
+
label?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Action knob — fires `onKnob(handle, key, true)` each time it's set, but
|
|
40
|
+
* does NOT persist a value across reloads and does NOT auto-fire on mount.
|
|
41
|
+
* Use for one-shot triggers (fire cannon, load weapon, request screenshot)
|
|
42
|
+
* where the act of setting is the signal and there is no "current value".
|
|
43
|
+
*/
|
|
44
|
+
| {
|
|
45
|
+
type: 'trigger';
|
|
46
|
+
label?: string;
|
|
47
|
+
};
|
|
48
|
+
/** Context passed to `Element.mount`. */
|
|
49
|
+
export interface MountContext {
|
|
50
|
+
renderer: THREE.WebGPURenderer;
|
|
51
|
+
scene: THREE.Scene;
|
|
52
|
+
/** Shared time uniform (seconds). Updated each frame by the harness. */
|
|
53
|
+
time: {
|
|
54
|
+
value: number;
|
|
55
|
+
};
|
|
56
|
+
/** dt in seconds, last frame. */
|
|
57
|
+
dt: {
|
|
58
|
+
value: number;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** The handle returned by `Element.mount`. */
|
|
62
|
+
export interface MountHandle {
|
|
63
|
+
/** The root Object3D the element added to the scene. */
|
|
64
|
+
root: THREE.Object3D;
|
|
65
|
+
/** Tear-down hook. Must remove the element from the scene and free GPU resources. */
|
|
66
|
+
dispose: () => void;
|
|
67
|
+
/** Element-specific data the telemetry/onKnob callbacks may need. */
|
|
68
|
+
userData?: Record<string, unknown>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A self-describing 3D element. The triscope lab harness consumes this
|
|
72
|
+
* to render a multi-camera grid, drive a tunables UI, post telemetry,
|
|
73
|
+
* and run the smoke test. Composition is just an element whose `mount`
|
|
74
|
+
* mounts other elements.
|
|
75
|
+
*/
|
|
76
|
+
export interface Element {
|
|
77
|
+
name: string;
|
|
78
|
+
mount: (args: {
|
|
79
|
+
parent: THREE.Object3D;
|
|
80
|
+
ctx: MountContext;
|
|
81
|
+
}) => MountHandle;
|
|
82
|
+
/**
|
|
83
|
+
* Optional override for the lab page URL. Either a path relative to the
|
|
84
|
+
* dev server (`/triscope-ship.html`) or a full URL. When set, the harness
|
|
85
|
+
* publishes it on the manifest so the MCP/CLI can route `capture_views`
|
|
86
|
+
* and `run_smoke` to the right page without hardcoding `/labs/<name>.html`.
|
|
87
|
+
*/
|
|
88
|
+
labUrl?: string;
|
|
89
|
+
/** Local-space bounding box. Used for auto-fitting cameras and the scene framing. */
|
|
90
|
+
bounds?: {
|
|
91
|
+
min: [number, number, number];
|
|
92
|
+
max: [number, number, number];
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Named camera presets — each becomes one pane in the lab grid. Pass the
|
|
96
|
+
* literal `'auto'` to have the harness synthesize 4 fitted presets
|
|
97
|
+
* (front/side/top/three-quarter) from `bounds` (see scene-cameras.ts), so an
|
|
98
|
+
* element doesn't have to hand-author cameras.
|
|
99
|
+
*/
|
|
100
|
+
cameras: Record<string, CameraSpec> | 'auto';
|
|
101
|
+
/** Tunable knobs. Rendered as sliders + exposed to MCP `set_knob`. */
|
|
102
|
+
knobs?: Record<string, Knob>;
|
|
103
|
+
/** Live-update hook. Called when a knob changes; must apply the change without rebuilding pipelines. */
|
|
104
|
+
onKnob?: (handle: MountHandle, key: string, value: number | string | boolean) => void;
|
|
105
|
+
/** Per-frame state to publish via the telemetry sink. Return JSON-serializable values. */
|
|
106
|
+
telemetry?: (handle: MountHandle, ctx: MountContext) => Record<string, unknown>;
|
|
107
|
+
/**
|
|
108
|
+
* Named per-frame numeric probes for animated state. The harness samples each
|
|
109
|
+
* every frame, keeps a ring buffer (~2 s at 60 fps), and exposes summary stats
|
|
110
|
+
* under `telemetry.elements.<name>.motion.<probeKey>`:
|
|
111
|
+
* { latest, mean, min, max, peakToPeak, samples: lastN }
|
|
112
|
+
* Use for amplitude (vertex displacement), oscillation rate, particle counts —
|
|
113
|
+
* anything dynamic the Element wants to quantify.
|
|
114
|
+
*/
|
|
115
|
+
motionProbes?: Record<string, (handle: MountHandle, ctx: MountContext) => number>;
|
|
116
|
+
/**
|
|
117
|
+
* Per-frame discrete-event drain. The harness calls this every frame; the
|
|
118
|
+
* element returns events that occurred since the last call (typically by
|
|
119
|
+
* draining an internal queue). The harness appends them to a ring buffer
|
|
120
|
+
* (cap 128) and exposes them via `telemetry.events`. Use for one-shot
|
|
121
|
+
* signals like collisions, weapon fires, state transitions — anything the
|
|
122
|
+
* test script needs to verify a posteriori with `read_telemetry .events`.
|
|
123
|
+
*
|
|
124
|
+
* Implementation MUST drain (return + clear) each call: events returned
|
|
125
|
+
* twice will appear twice in the buffer.
|
|
126
|
+
*/
|
|
127
|
+
events?: (handle: MountHandle, ctx: MountContext) => TriscopeEvent[];
|
|
128
|
+
}
|
|
129
|
+
/** Discrete event emitted by an Element. */
|
|
130
|
+
export interface TriscopeEvent {
|
|
131
|
+
/** Timestamp in seconds. Should reuse `ctx.time.value` for sim-consistent ordering. */
|
|
132
|
+
timestamp: number;
|
|
133
|
+
/** Discriminator — caller-defined (e.g. 'fire' | 'splash' | 'impact'). */
|
|
134
|
+
type: string;
|
|
135
|
+
/** Optional opaque payload — anything JSON-serializable. */
|
|
136
|
+
payload?: Record<string, unknown>;
|
|
137
|
+
}
|
|
138
|
+
/** Default value extracted from a knob spec. Trigger knobs have no
|
|
139
|
+
* default — they are pure action signals; this returns `false` only as a
|
|
140
|
+
* placeholder so callers iterating knob values get a defined entry. */
|
|
141
|
+
export declare function knobDefault(k: Knob): number | string | boolean;
|
|
142
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Default value extracted from a knob spec. Trigger knobs have no
|
|
2
|
+
* default — they are pure action signals; this returns `false` only as a
|
|
3
|
+
* placeholder so callers iterating knob values get a defined entry. */
|
|
4
|
+
export function knobDefault(k) {
|
|
5
|
+
if (k.type === 'trigger')
|
|
6
|
+
return false;
|
|
7
|
+
return k.default;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.js.map
|