@fundamental-engine/core 0.10.1 → 0.10.2
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 +1 -1
- package/dist/.metadata_never_index +0 -0
- package/dist/.noindex +0 -0
- package/dist/config/manual.d.ts.map +1 -1
- package/dist/config/manual.js +18 -0
- package/dist/config/manual.js.map +1 -1
- package/dist/config/presets.d.ts +10 -2
- package/dist/config/presets.d.ts.map +1 -1
- package/dist/config/presets.js +26 -2
- package/dist/config/presets.js.map +1 -1
- package/dist/conformance/experiments.d.ts.map +1 -1
- package/dist/conformance/experiments.js +91 -0
- package/dist/conformance/experiments.js.map +1 -1
- package/dist/conformance/run.d.ts.map +1 -1
- package/dist/conformance/run.js +34 -4
- package/dist/conformance/run.js.map +1 -1
- package/dist/conformance/types.d.ts +12 -0
- package/dist/conformance/types.d.ts.map +1 -1
- package/dist/contracts/passport.d.ts.map +1 -1
- package/dist/contracts/passport.js +1 -0
- package/dist/contracts/passport.js.map +1 -1
- package/dist/diagnostics/probes.d.ts.map +1 -1
- package/dist/diagnostics/probes.js +5 -0
- package/dist/diagnostics/probes.js.map +1 -1
- package/dist/engine/agent-read-share.d.ts +34 -0
- package/dist/engine/agent-read-share.d.ts.map +1 -0
- package/dist/engine/agent-read-share.js +50 -0
- package/dist/engine/agent-read-share.js.map +1 -0
- package/dist/engine/field.d.ts.map +1 -1
- package/dist/engine/field.js +170 -102
- package/dist/engine/field.js.map +1 -1
- package/dist/engine/integrator.d.ts +12 -1
- package/dist/engine/integrator.d.ts.map +1 -1
- package/dist/engine/integrator.js +44 -0
- package/dist/engine/integrator.js.map +1 -1
- package/dist/engine/scalar-grid.d.ts +25 -2
- package/dist/engine/scalar-grid.d.ts.map +1 -1
- package/dist/engine/scalar-grid.js +38 -1
- package/dist/engine/scalar-grid.js.map +1 -1
- package/dist/engine/scanner.d.ts +5 -3
- package/dist/engine/scanner.d.ts.map +1 -1
- package/dist/engine/scanner.js +29 -5
- package/dist/engine/scanner.js.map +1 -1
- package/dist/engine/shadow.d.ts +58 -2
- package/dist/engine/shadow.d.ts.map +1 -1
- package/dist/engine/shadow.js +86 -1
- package/dist/engine/shadow.js.map +1 -1
- package/dist/engine/snapshot-policy.d.ts +28 -0
- package/dist/engine/snapshot-policy.d.ts.map +1 -0
- package/dist/engine/snapshot-policy.js +95 -0
- package/dist/engine/snapshot-policy.js.map +1 -0
- package/dist/engine/streamlines.d.ts +24 -7
- package/dist/engine/streamlines.d.ts.map +1 -1
- package/dist/engine/streamlines.js +96 -5
- package/dist/engine/streamlines.js.map +1 -1
- package/dist/engine/types.d.ts +98 -8
- package/dist/engine/types.d.ts.map +1 -1
- package/dist/forces/extended.d.ts +1 -0
- package/dist/forces/extended.d.ts.map +1 -1
- package/dist/forces/extended.js +68 -0
- package/dist/forces/extended.js.map +1 -1
- package/dist/forces/index.d.ts.map +1 -1
- package/dist/forces/index.js +4 -1
- package/dist/forces/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -6
package/dist/engine/shadow.d.ts
CHANGED
|
@@ -11,11 +11,27 @@
|
|
|
11
11
|
* and builds bodies. The DOM-event wiring lives in `field.ts`.
|
|
12
12
|
*/
|
|
13
13
|
import type { Body } from './types.ts';
|
|
14
|
-
import type
|
|
14
|
+
import { type BodyAttrs } from './scanner.ts';
|
|
15
15
|
/** The registration event names. `composed: true` lets them cross the shadow boundary. */
|
|
16
16
|
export declare const REGISTER_BODY = "field:register-body";
|
|
17
17
|
export declare const UNREGISTER_BODY = "field:unregister-body";
|
|
18
18
|
export declare const UPDATE_BODY = "field:update-body";
|
|
19
|
+
/**
|
|
20
|
+
* Which field(s) a registered host participates in (shadow-dom.md §18). `'global'` — the default,
|
|
21
|
+
* and the pre-scope behaviour — means EVERY field that hears the composed registration event adopts
|
|
22
|
+
* the host. `'nearest'` applies the same nearest-enclosing-field ownership the light-DOM scanner
|
|
23
|
+
* uses (#980): only the field whose scan root is the host's nearest enclosing `data-field-boundary`
|
|
24
|
+
* (a contained field's bounds element) adopts it, or the page field when no boundary encloses it.
|
|
25
|
+
*/
|
|
26
|
+
export type FieldScope = 'nearest' | 'global';
|
|
27
|
+
/**
|
|
28
|
+
* An explicit field target — a portal (shadow-dom.md §17, §19). `'root'` is the page field (the one
|
|
29
|
+
* scanning the document); a selector string or an `Element` names a contained field by its SCAN ROOT
|
|
30
|
+
* (the `bounds:` / `containerHost` element). When set it beats `scope`: the host joins exactly the
|
|
31
|
+
* targeted field regardless of where it sits in the tree, and no field at all if none matches
|
|
32
|
+
* (§17 rung 4 — inert until such a field exists).
|
|
33
|
+
*/
|
|
34
|
+
export type FieldTarget = 'root' | string | Element;
|
|
19
35
|
/** Payload of a `field:register-body` event (shadow-dom.md §7). */
|
|
20
36
|
export interface RegisterBodyDetail {
|
|
21
37
|
/** the public physical element — usually the custom-element host. */
|
|
@@ -27,7 +43,40 @@ export interface RegisterBodyDetail {
|
|
|
27
43
|
attrs?: Record<string, string>;
|
|
28
44
|
/** element that receives the CSS-variable write-back; defaults to `element`. */
|
|
29
45
|
writeTarget?: HTMLElement;
|
|
46
|
+
/** participation scope (§18) — omitted / `'global'`: every field that hears the event adopts the
|
|
47
|
+
* host (the pre-scope behaviour); `'nearest'`: only the nearest enclosing field does. */
|
|
48
|
+
scope?: FieldScope;
|
|
49
|
+
/** explicit field target — a portal (§19). Beats `scope` when set. */
|
|
50
|
+
field?: FieldTarget;
|
|
30
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The nearest enclosing `[data-field-boundary]` of `el` across shadow boundaries (§17): `closest()`
|
|
54
|
+
* inside the current tree, then hop from a shadow root to its host and continue, so a host nested
|
|
55
|
+
* inside another component's shadow tree still resolves to the light-DOM boundary around it. Every
|
|
56
|
+
* DOM capability is feature-detected — an element without `closest` resolves to `null`, and a root
|
|
57
|
+
* node without `host` (the document) ends the walk. Pure: no globals.
|
|
58
|
+
*/
|
|
59
|
+
export declare function nearestFieldBoundary(el: Element): Element | null;
|
|
60
|
+
/**
|
|
61
|
+
* Is `root` the PAGE field's scan root — the document itself (`browserHost`) or its
|
|
62
|
+
* `documentElement` (the platform runtime's scan root)? Anything else (a contained field's bounds
|
|
63
|
+
* element, a fragment, a headless stub) is not. Feature-detected on `nodeType`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function isPageRoot(root: ParentNode): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Does the field scanning `root` adopt this registration (§17 resolution order)?
|
|
68
|
+
* 1. an explicit `field` target wins: `'root'` → the page field only; a selector → the field whose
|
|
69
|
+
* scan root matches it; an `Element` → the field whose scan root IS it.
|
|
70
|
+
* 2. `scope: 'nearest'` → nearest-enclosing-field ownership, mirroring the scanner's
|
|
71
|
+
* `ownedByScanRoot` (#980) but across shadow boundaries: owned when the host's nearest
|
|
72
|
+
* boundary is this root, or when no boundary encloses it and this root is not itself a
|
|
73
|
+
* contained field's (marked) bounds element — a host outside every contained field is the
|
|
74
|
+
* page's. An element without `closest` is always owned (the scanner's rule — ownership only
|
|
75
|
+
* applies where an ancestor chain exists).
|
|
76
|
+
* 3. otherwise (no `field`, no `scope`, or `'global'`) → adopted, the default.
|
|
77
|
+
* Pure of the DOM event system; every DOM method is feature-detected.
|
|
78
|
+
*/
|
|
79
|
+
export declare function fieldAdopts(detail: RegisterBodyDetail, root: ParentNode): boolean;
|
|
31
80
|
/**
|
|
32
81
|
* Component-side helper (shadow-dom.md §31.1) so a custom element joins the field without
|
|
33
82
|
* repeating event boilerplate. Construct with the host (and optional extra detail), then
|
|
@@ -63,7 +112,14 @@ export declare class ShadowRegistry {
|
|
|
63
112
|
* the scanner's `bodyFromElement`; `attrs` (if supplied at registration) override the
|
|
64
113
|
* host's own `data-*`, else the host is read directly. A custom `getRect` and `writeTarget`
|
|
65
114
|
* are attached to the resulting body.
|
|
115
|
+
*
|
|
116
|
+
* `root` — the asking field's scan root — enables scoped participation (§17–§19): a host
|
|
117
|
+
* registered with `scope: 'nearest'` or an explicit `field` target is built only when
|
|
118
|
+
* {@link fieldAdopts} says this root owns it. Omitting `root` (headless / harness hosts), or a
|
|
119
|
+
* detail with neither key, builds every live host exactly as before — the root is never touched
|
|
120
|
+
* on that path. A host this field does not adopt stays registered (it may be adopted later, e.g.
|
|
121
|
+
* once its target field exists) and is still pruned when it disconnects.
|
|
66
122
|
*/
|
|
67
|
-
bodies(build: (el: HTMLElement, attrs?: BodyAttrs) => Body): Body[];
|
|
123
|
+
bodies(build: (el: HTMLElement, attrs?: BodyAttrs) => Body, root?: ParentNode): Body[];
|
|
68
124
|
}
|
|
69
125
|
//# sourceMappingURL=shadow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../src/engine/shadow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../src/engine/shadow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE5F,0FAA0F;AAC1F,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,eAAO,MAAM,eAAe,0BAA0B,CAAC;AACvD,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,OAAO,EAAE,WAAW,CAAC;IACrB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB;iEAC6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,gFAAgF;IAChF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;8FAC0F;IAC1F,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,sEAAsE;IACtE,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAWhE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAQpD;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAiBjF;AAED;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+C;gBAE1D,IAAI,EAAE,WAAW,EAAE,MAAM,GAAE,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,SAAS,CAAM;IAKxF,mEAAmE;IACnE,OAAO,IAAI,IAAI;IAGf,0DAA0D;IAC1D,UAAU,IAAI,IAAI;IAGlB,qEAAqE;IACrE,MAAM,IAAI,IAAI;IAId,OAAO,CAAC,IAAI;CAIb;AAOD;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8C;IAEpE,mDAAmD;IACnD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAI1C,mBAAmB;IACnB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAItC,kFAAkF;IAClF,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,SAAS,KAAK,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,EAAE;CAgBvF"}
|
package/dist/engine/shadow.js
CHANGED
|
@@ -1,7 +1,83 @@
|
|
|
1
|
+
import { FIELD_BOUNDARY_ATTR, FIELD_BOUNDARY_SELECTOR } from "./scanner.js";
|
|
1
2
|
/** The registration event names. `composed: true` lets them cross the shadow boundary. */
|
|
2
3
|
export const REGISTER_BODY = 'field:register-body';
|
|
3
4
|
export const UNREGISTER_BODY = 'field:unregister-body';
|
|
4
5
|
export const UPDATE_BODY = 'field:update-body';
|
|
6
|
+
/**
|
|
7
|
+
* The nearest enclosing `[data-field-boundary]` of `el` across shadow boundaries (§17): `closest()`
|
|
8
|
+
* inside the current tree, then hop from a shadow root to its host and continue, so a host nested
|
|
9
|
+
* inside another component's shadow tree still resolves to the light-DOM boundary around it. Every
|
|
10
|
+
* DOM capability is feature-detected — an element without `closest` resolves to `null`, and a root
|
|
11
|
+
* node without `host` (the document) ends the walk. Pure: no globals.
|
|
12
|
+
*/
|
|
13
|
+
export function nearestFieldBoundary(el) {
|
|
14
|
+
let cur = el;
|
|
15
|
+
while (cur) {
|
|
16
|
+
if (typeof cur.closest !== 'function')
|
|
17
|
+
return null;
|
|
18
|
+
const boundary = cur.closest(FIELD_BOUNDARY_SELECTOR);
|
|
19
|
+
if (boundary)
|
|
20
|
+
return boundary;
|
|
21
|
+
const rootNode = typeof cur.getRootNode === 'function' ? cur.getRootNode() : null;
|
|
22
|
+
const host = rootNode ? (rootNode.host ?? null) : null;
|
|
23
|
+
cur = host && host !== cur ? host : null;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Is `root` the PAGE field's scan root — the document itself (`browserHost`) or its
|
|
29
|
+
* `documentElement` (the platform runtime's scan root)? Anything else (a contained field's bounds
|
|
30
|
+
* element, a fragment, a headless stub) is not. Feature-detected on `nodeType`.
|
|
31
|
+
*/
|
|
32
|
+
export function isPageRoot(root) {
|
|
33
|
+
const n = root.nodeType;
|
|
34
|
+
if (n === 9)
|
|
35
|
+
return true; // Node.DOCUMENT_NODE
|
|
36
|
+
if (n === 1) {
|
|
37
|
+
const doc = root.ownerDocument;
|
|
38
|
+
return !!doc && doc.documentElement === root;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
/** Is `root` a contained field's bounds element (carries the engine-set boundary marker)? */
|
|
43
|
+
function isBoundaryRoot(root) {
|
|
44
|
+
const r = root;
|
|
45
|
+
return typeof r.hasAttribute === 'function' && r.hasAttribute(FIELD_BOUNDARY_ATTR);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Does the field scanning `root` adopt this registration (§17 resolution order)?
|
|
49
|
+
* 1. an explicit `field` target wins: `'root'` → the page field only; a selector → the field whose
|
|
50
|
+
* scan root matches it; an `Element` → the field whose scan root IS it.
|
|
51
|
+
* 2. `scope: 'nearest'` → nearest-enclosing-field ownership, mirroring the scanner's
|
|
52
|
+
* `ownedByScanRoot` (#980) but across shadow boundaries: owned when the host's nearest
|
|
53
|
+
* boundary is this root, or when no boundary encloses it and this root is not itself a
|
|
54
|
+
* contained field's (marked) bounds element — a host outside every contained field is the
|
|
55
|
+
* page's. An element without `closest` is always owned (the scanner's rule — ownership only
|
|
56
|
+
* applies where an ancestor chain exists).
|
|
57
|
+
* 3. otherwise (no `field`, no `scope`, or `'global'`) → adopted, the default.
|
|
58
|
+
* Pure of the DOM event system; every DOM method is feature-detected.
|
|
59
|
+
*/
|
|
60
|
+
export function fieldAdopts(detail, root) {
|
|
61
|
+
const { field, scope, element } = detail;
|
|
62
|
+
if (field !== undefined && field !== null && field !== '') {
|
|
63
|
+
if (field === 'root')
|
|
64
|
+
return isPageRoot(root);
|
|
65
|
+
if (typeof field === 'string') {
|
|
66
|
+
const r = root;
|
|
67
|
+
return typeof r.matches === 'function' && r.matches(field);
|
|
68
|
+
}
|
|
69
|
+
return field === root;
|
|
70
|
+
}
|
|
71
|
+
if (scope === 'nearest') {
|
|
72
|
+
if (typeof element.closest !== 'function')
|
|
73
|
+
return true;
|
|
74
|
+
const boundary = nearestFieldBoundary(element);
|
|
75
|
+
if (boundary === null)
|
|
76
|
+
return !isBoundaryRoot(root);
|
|
77
|
+
return boundary === root;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
5
81
|
/**
|
|
6
82
|
* Component-side helper (shadow-dom.md §31.1) so a custom element joins the field without
|
|
7
83
|
* repeating event boilerplate. Construct with the host (and optional extra detail), then
|
|
@@ -55,14 +131,23 @@ export class ShadowRegistry {
|
|
|
55
131
|
* the scanner's `bodyFromElement`; `attrs` (if supplied at registration) override the
|
|
56
132
|
* host's own `data-*`, else the host is read directly. A custom `getRect` and `writeTarget`
|
|
57
133
|
* are attached to the resulting body.
|
|
134
|
+
*
|
|
135
|
+
* `root` — the asking field's scan root — enables scoped participation (§17–§19): a host
|
|
136
|
+
* registered with `scope: 'nearest'` or an explicit `field` target is built only when
|
|
137
|
+
* {@link fieldAdopts} says this root owns it. Omitting `root` (headless / harness hosts), or a
|
|
138
|
+
* detail with neither key, builds every live host exactly as before — the root is never touched
|
|
139
|
+
* on that path. A host this field does not adopt stays registered (it may be adopted later, e.g.
|
|
140
|
+
* once its target field exists) and is still pruned when it disconnects.
|
|
58
141
|
*/
|
|
59
|
-
bodies(build) {
|
|
142
|
+
bodies(build, root) {
|
|
60
143
|
const out = [];
|
|
61
144
|
for (const [el, detail] of this.hosts) {
|
|
62
145
|
if (!el.isConnected) {
|
|
63
146
|
this.hosts.delete(el);
|
|
64
147
|
continue;
|
|
65
148
|
}
|
|
149
|
+
if (root !== undefined && !fieldAdopts(detail, root))
|
|
150
|
+
continue;
|
|
66
151
|
const attrs = detail.attrs ? attrsView(detail.attrs, el) : undefined;
|
|
67
152
|
const body = build(el, attrs);
|
|
68
153
|
if (detail.getRect)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadow.js","sourceRoot":"","sources":["../../src/engine/shadow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shadow.js","sourceRoot":"","sources":["../../src/engine/shadow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { FieldPolicy, FieldSnapshotOptions } from './types.ts';
|
|
2
|
+
/** Deep-copy a {@link FieldPolicy} (shallow is unsafe — `budgets` is nested). `undefined` → `{}` (the
|
|
3
|
+
* unbounded default). Used on set + read so callers can neither mutate the field's live policy nor
|
|
4
|
+
* observe later mutations of the object they passed in. */
|
|
5
|
+
export declare function clonePolicy(p: FieldPolicy | undefined): FieldPolicy;
|
|
6
|
+
/** Concrete inclusion flags a snapshot resolves to. */
|
|
7
|
+
export interface ResolvedSnapshotInclusion {
|
|
8
|
+
includeParticles: boolean;
|
|
9
|
+
includeRelationships: boolean;
|
|
10
|
+
includeData: boolean;
|
|
11
|
+
includeInfluences: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve {@link FieldSnapshotOptions} — an optional {@link SnapshotProfile} composed with the explicit
|
|
15
|
+
* `include*` flags — to concrete inclusion, TIGHTEST-wins. A profile establishes a baseline; an explicit
|
|
16
|
+
* flag may tighten it further but never widen it (an explicit `true` cannot re-enable what the profile
|
|
17
|
+
* turned off). `includeData` additionally passes through the policy gate at the call site (this only
|
|
18
|
+
* governs whether the CALLER asked for it). Relationships default true when nothing narrows them.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveSnapshotInclusion(opts: FieldSnapshotOptions): ResolvedSnapshotInclusion;
|
|
21
|
+
/**
|
|
22
|
+
* Strip a set of dotted `redactions` paths from a plain reading (query result or snapshot). A top-level
|
|
23
|
+
* key (`'metrics'`, `'relationships'`) deletes that key from the object. A `<prefix>.<key>` path where
|
|
24
|
+
* prefix ∈ {body, relationship, influence, projection} strips `<key>` from each entry of the matching
|
|
25
|
+
* list; `body.data` strips per-body `data`. Mutates the passed object (it's always a fresh result/copy).
|
|
26
|
+
*/
|
|
27
|
+
export declare function applyRedactions<T extends Record<string, unknown>>(reading: T, redactions: readonly string[]): T;
|
|
28
|
+
//# sourceMappingURL=snapshot-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-policy.d.ts","sourceRoot":"","sources":["../../src/engine/snapshot-policy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAmB,MAAM,YAAY,CAAC;AAErF;;4DAE4D;AAC5D,wBAAgB,WAAW,CAAC,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,CAQnE;AAED,uDAAuD;AACvD,MAAM,WAAW,yBAAyB;IACxC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,oBAAoB,GAAG,yBAAyB,CA4B9F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,CAAC,CAwB/G"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Snapshot / query disclosure policy — the three pure helpers that decide what a READER of the field
|
|
2
|
+
// is allowed to see. Extracted verbatim from `engine/field.ts` (#994, behavior-preserving): they are
|
|
3
|
+
// module-level and closure-free, so they were never part of `createField`'s state and read better as
|
|
4
|
+
// their own seam. Pure and type-only-dependent — no runtime import, nothing field-specific.
|
|
5
|
+
//
|
|
6
|
+
// INTERNAL. Not exported from the package surface; `createField` is still the one public entry.
|
|
7
|
+
/** Deep-copy a {@link FieldPolicy} (shallow is unsafe — `budgets` is nested). `undefined` → `{}` (the
|
|
8
|
+
* unbounded default). Used on set + read so callers can neither mutate the field's live policy nor
|
|
9
|
+
* observe later mutations of the object they passed in. */
|
|
10
|
+
export function clonePolicy(p) {
|
|
11
|
+
if (!p)
|
|
12
|
+
return {};
|
|
13
|
+
const out = {};
|
|
14
|
+
if (p.allowBodyDataInSnapshots != null)
|
|
15
|
+
out.allowBodyDataInSnapshots = p.allowBodyDataInSnapshots;
|
|
16
|
+
if (p.allowMotionProjection != null)
|
|
17
|
+
out.allowMotionProjection = p.allowMotionProjection;
|
|
18
|
+
if (p.maxMotionBudget != null)
|
|
19
|
+
out.maxMotionBudget = p.maxMotionBudget;
|
|
20
|
+
if (p.budgets)
|
|
21
|
+
out.budgets = { ...p.budgets };
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve {@link FieldSnapshotOptions} — an optional {@link SnapshotProfile} composed with the explicit
|
|
26
|
+
* `include*` flags — to concrete inclusion, TIGHTEST-wins. A profile establishes a baseline; an explicit
|
|
27
|
+
* flag may tighten it further but never widen it (an explicit `true` cannot re-enable what the profile
|
|
28
|
+
* turned off). `includeData` additionally passes through the policy gate at the call site (this only
|
|
29
|
+
* governs whether the CALLER asked for it). Relationships default true when nothing narrows them.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveSnapshotInclusion(opts) {
|
|
32
|
+
// Per-profile baselines. `debug` = everything; `agent` = structure + attribution, no opaque data;
|
|
33
|
+
// `bug-report` = structural + versions, no data; `public` = ids + shape only.
|
|
34
|
+
const base = {
|
|
35
|
+
debug: { includeParticles: true, includeRelationships: true, includeData: true, includeInfluences: true },
|
|
36
|
+
agent: { includeParticles: false, includeRelationships: true, includeData: false, includeInfluences: true },
|
|
37
|
+
'bug-report': { includeParticles: false, includeRelationships: true, includeData: false, includeInfluences: true },
|
|
38
|
+
public: { includeParticles: false, includeRelationships: false, includeData: false, includeInfluences: false },
|
|
39
|
+
};
|
|
40
|
+
const p = opts.profile;
|
|
41
|
+
if (!p) {
|
|
42
|
+
// No profile: today's defaults — relationships default true, the rest default false.
|
|
43
|
+
return {
|
|
44
|
+
includeParticles: opts.includeParticles === true,
|
|
45
|
+
includeRelationships: opts.includeRelationships !== false,
|
|
46
|
+
includeData: opts.includeData === true,
|
|
47
|
+
includeInfluences: opts.includeInfluences === true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const b = base[p];
|
|
51
|
+
// TIGHTEST wins: a flag is on only if the profile allows it AND the caller didn't explicitly turn it
|
|
52
|
+
// off. An explicit `true` can never widen past the profile's baseline.
|
|
53
|
+
return {
|
|
54
|
+
includeParticles: b.includeParticles && opts.includeParticles !== false,
|
|
55
|
+
includeRelationships: b.includeRelationships && opts.includeRelationships !== false,
|
|
56
|
+
includeData: b.includeData && opts.includeData !== false,
|
|
57
|
+
includeInfluences: b.includeInfluences && opts.includeInfluences !== false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Strip a set of dotted `redactions` paths from a plain reading (query result or snapshot). A top-level
|
|
62
|
+
* key (`'metrics'`, `'relationships'`) deletes that key from the object. A `<prefix>.<key>` path where
|
|
63
|
+
* prefix ∈ {body, relationship, influence, projection} strips `<key>` from each entry of the matching
|
|
64
|
+
* list; `body.data` strips per-body `data`. Mutates the passed object (it's always a fresh result/copy).
|
|
65
|
+
*/
|
|
66
|
+
export function applyRedactions(reading, redactions) {
|
|
67
|
+
const listKeyFor = { body: 'bodies', relationship: 'relationships', influence: 'influences', projection: 'projections' };
|
|
68
|
+
for (const path of redactions) {
|
|
69
|
+
const dot = path.indexOf('.');
|
|
70
|
+
if (dot < 0) {
|
|
71
|
+
delete reading[path];
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const prefix = path.slice(0, dot);
|
|
75
|
+
const key = path.slice(dot + 1);
|
|
76
|
+
const listKey = listKeyFor[prefix];
|
|
77
|
+
if (listKey && Array.isArray(reading[listKey])) {
|
|
78
|
+
for (const entry of reading[listKey]) {
|
|
79
|
+
if (entry && typeof entry === 'object')
|
|
80
|
+
delete entry[key];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (prefix === 'metrics' && reading['metrics'] && typeof reading['metrics'] === 'object') {
|
|
84
|
+
delete reading['metrics'][key];
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// an unrecognized prefix addresses a nested top-level object key.
|
|
88
|
+
const target = reading[prefix];
|
|
89
|
+
if (target && typeof target === 'object')
|
|
90
|
+
delete target[key];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return reading;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=snapshot-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-policy.js","sourceRoot":"","sources":["../../src/engine/snapshot-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Streamlines / vector-field render (§20.6, diagnostic) — instead of the matter, draw
|
|
3
|
-
* the *forces themselves*. At a grid of probe points we measure the net push a
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* see the field they make.
|
|
3
|
+
* the *forces themselves*. At a grid of probe points we measure the net push a still test particle
|
|
4
|
+
* would feel and draw a short arrow along it, so the invisible field a layout creates becomes
|
|
5
|
+
* visible. Invaluable in the Lab: place forces, then see the field they make.
|
|
7
6
|
*
|
|
8
|
-
* `forceAt`
|
|
9
|
-
*
|
|
7
|
+
* `forceAt` mirrors the integrator's body-force loop (same range cull), minus the per-particle
|
|
8
|
+
* modifier pass — a faithful-enough probe for a diagnostic.
|
|
9
|
+
*
|
|
10
|
+
* PURITY (#1155). A probe is an instrument, not matter: it may READ the field and must never write
|
|
11
|
+
* to it. That contract used to be incidental rather than structural — the loop ran each body's real
|
|
12
|
+
* `apply()` against the CALLER'S LIVE ENV, so `sink` advanced a real body's accretion budget and
|
|
13
|
+
* could fire the live `supernova` from a drawing, `diffuse`/`memory` wore the real scalar grids, a
|
|
14
|
+
* source could spawn, and every sample advanced the simulation's seeded rng. Now every sample runs
|
|
15
|
+
* under this module's own `probeEnv`, whose writing services are inert.
|
|
16
|
+
*
|
|
17
|
+
* The two halves are inseparable. `sink`'s guard is `if (p.cap || …) return`, so while the shared
|
|
18
|
+
* probe carried `cap` between samples the leak was self-limiting BY ACCIDENT: a body was
|
|
19
|
+
* over-accreted exactly once, and every later `sink`/`warp` sample silently short-circuited (the
|
|
20
|
+
* drawn field going quietly wrong downstream of the first sink). Clearing `cap` per sample WITHOUT
|
|
21
|
+
* an inert path first would convert that one-off into one accretion per probe point per frame —
|
|
22
|
+
* hundreds a second, racing a real body to capacity. The path is inert first; `cap` is cleared
|
|
23
|
+
* because it is.
|
|
10
24
|
*/
|
|
11
25
|
import type { Body, Env, ForceRegistry } from './types.ts';
|
|
12
26
|
/** Net force a zero-velocity test particle would feel at (x, y) — the field vector.
|
|
13
27
|
* A force that defines a `field()` (its visual/structure field) contributes that instead
|
|
14
28
|
* of its `apply`, so velocity- and charge-dependent forces (magnetism, charge) appear here
|
|
15
|
-
* even though they no-op on a still, neutral probe.
|
|
29
|
+
* even though they no-op on a still, neutral probe.
|
|
30
|
+
*
|
|
31
|
+
* READ-ONLY: `env` supplies the per-frame reading only — the forces run against `probeEnv`, so this
|
|
32
|
+
* never writes to the simulation (#1155). */
|
|
16
33
|
export declare function forceAt(bodies: readonly Body[], forces: ForceRegistry, env: Env, x: number, y: number): {
|
|
17
34
|
fx: number;
|
|
18
35
|
fy: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamlines.d.ts","sourceRoot":"","sources":["../../src/engine/streamlines.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"streamlines.d.ts","sourceRoot":"","sources":["../../src/engine/streamlines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,GAAG,EAAa,aAAa,EAAwB,MAAM,YAAY,CAAC;AAgG5F;;;;;;8CAM8C;AAC9C,wBAAgB,OAAO,CACrB,MAAM,EAAE,SAAS,IAAI,EAAE,EACvB,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,GAAG,EACR,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAgD5B;AAED;;;;iFAIiF;AACjF,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,IAAI,EAAE,EACvB,MAAM,EAAE,aAAa,EACrB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAoB1B"}
|
|
@@ -1,14 +1,105 @@
|
|
|
1
1
|
const probe = { x: 0, y: 0, vx: 0, vy: 0, m: 1, heat: 0, size: 1, cap: null };
|
|
2
|
+
/** The probe's OWN noise, never the simulation's (mulberry32 — the engine's stream shape). Reseeded
|
|
3
|
+
* at the top of every sample, so a stochastic force (`jet`'s nozzle cone, `thermal`'s kick) reads the
|
|
4
|
+
* same at the same point however many samples came before it, and a seeded run a host is recording
|
|
5
|
+
* is never advanced by drawing a diagnostic. */
|
|
6
|
+
const PROBE_SEED = 0x9e3779b9;
|
|
7
|
+
let noise = PROBE_SEED;
|
|
8
|
+
function probeRng() {
|
|
9
|
+
noise = (noise + 0x6d2b79f5) | 0;
|
|
10
|
+
let t = Math.imul(noise ^ (noise >>> 15), 1 | noise);
|
|
11
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
12
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
13
|
+
}
|
|
14
|
+
/** The live env this sample mirrors — the source behind the read-through services below. */
|
|
15
|
+
let live = null;
|
|
16
|
+
/** A read-through, write-DROPPING view of a live scalar grid: `diffuse`/`memory` still read the real
|
|
17
|
+
* field (an honest diagnostic reading), but their deposits never wear it. Cached per grid name, so a
|
|
18
|
+
* whole frame's grid walk allocates nothing. */
|
|
19
|
+
const gridViews = new Map();
|
|
20
|
+
function probeGrid(name) {
|
|
21
|
+
let v = gridViews.get(name);
|
|
22
|
+
if (!v) {
|
|
23
|
+
v = {
|
|
24
|
+
sample: (x, y) => live?.grid(name).sample(x, y) ?? 0,
|
|
25
|
+
gradient: (x, y) => live?.grid(name).gradient(x, y) ?? { x: 0, y: 0 },
|
|
26
|
+
deposit: () => { },
|
|
27
|
+
decay: () => { },
|
|
28
|
+
clear: () => { },
|
|
29
|
+
};
|
|
30
|
+
gridViews.set(name, v);
|
|
31
|
+
}
|
|
32
|
+
return v;
|
|
33
|
+
}
|
|
34
|
+
/** Copied, never aliased, so no force can write through it back into the live env. */
|
|
35
|
+
const probeForm = { driftX: 0, wander: 0, orbit: 0, spread: 0, conv: 0 };
|
|
36
|
+
/**
|
|
37
|
+
* The one env every probe sample runs under. Its per-frame SCALARS mirror the caller's live env (so
|
|
38
|
+
* the reading is of the field as it is right now); every service that WRITES is inert —
|
|
39
|
+
* `spark`/`supernova`/`spawn` are no-ops, grids drop deposits, `rng` is the probe's own stream. The
|
|
40
|
+
* `probe` marker tells a force that writes engine state outside the probe particle (today only
|
|
41
|
+
* `sink`'s accretion) that this pass is a reading, not a capture.
|
|
42
|
+
*/
|
|
43
|
+
const probeEnv = {
|
|
44
|
+
dx: 0,
|
|
45
|
+
dy: 0,
|
|
46
|
+
dz: 0,
|
|
47
|
+
dist: 1,
|
|
48
|
+
form: probeForm,
|
|
49
|
+
W: 0,
|
|
50
|
+
H: 0,
|
|
51
|
+
t: 0,
|
|
52
|
+
frameN: 0,
|
|
53
|
+
dt: 1,
|
|
54
|
+
c: 12,
|
|
55
|
+
G: 1,
|
|
56
|
+
probe: true,
|
|
57
|
+
rng: probeRng,
|
|
58
|
+
spark: () => { },
|
|
59
|
+
supernova: () => { },
|
|
60
|
+
spawn: () => { },
|
|
61
|
+
neighbors: (p, r) => live?.neighbors(p, r) ?? [],
|
|
62
|
+
grid: probeGrid,
|
|
63
|
+
};
|
|
64
|
+
/** Point the probe env at this sample's live env: mirror the read-only per-frame state and reseed the
|
|
65
|
+
* probe's noise. The writing services are never re-pointed. */
|
|
66
|
+
function syncProbeEnv(env) {
|
|
67
|
+
live = env;
|
|
68
|
+
probeEnv.W = env.W;
|
|
69
|
+
probeEnv.H = env.H;
|
|
70
|
+
probeEnv.D = env.D;
|
|
71
|
+
probeEnv.t = env.t;
|
|
72
|
+
probeEnv.frameN = env.frameN;
|
|
73
|
+
probeEnv.dt = env.dt;
|
|
74
|
+
probeEnv.c = env.c;
|
|
75
|
+
probeEnv.G = env.G;
|
|
76
|
+
probeEnv.scrollV = env.scrollV;
|
|
77
|
+
probeEnv.integrator = env.integrator;
|
|
78
|
+
probeEnv.fieldAt = env.fieldAt; // a pure read (netField over the live bodies)
|
|
79
|
+
probeEnv.accum = undefined; // attribution belongs to the integrator's pass, not to a drawing
|
|
80
|
+
probeEnv.kinTouch = undefined;
|
|
81
|
+
// the probe sits on the body plane, so the z leg of every force vanishes — and is never the stale
|
|
82
|
+
// value the integrator happened to leave on the live env.
|
|
83
|
+
probeEnv.dz = 0;
|
|
84
|
+
Object.assign(probeForm, env.form);
|
|
85
|
+
noise = PROBE_SEED;
|
|
86
|
+
return probeEnv;
|
|
87
|
+
}
|
|
2
88
|
/** Net force a zero-velocity test particle would feel at (x, y) — the field vector.
|
|
3
89
|
* A force that defines a `field()` (its visual/structure field) contributes that instead
|
|
4
90
|
* of its `apply`, so velocity- and charge-dependent forces (magnetism, charge) appear here
|
|
5
|
-
* even though they no-op on a still, neutral probe.
|
|
91
|
+
* even though they no-op on a still, neutral probe.
|
|
92
|
+
*
|
|
93
|
+
* READ-ONLY: `env` supplies the per-frame reading only — the forces run against `probeEnv`, so this
|
|
94
|
+
* never writes to the simulation (#1155). */
|
|
6
95
|
export function forceAt(bodies, forces, env, x, y) {
|
|
7
96
|
probe.x = x;
|
|
8
97
|
probe.y = y;
|
|
9
98
|
probe.vx = 0;
|
|
10
99
|
probe.vy = 0;
|
|
11
100
|
probe.heat = 0;
|
|
101
|
+
probe.cap = null; // a fresh instrument every sample — safe ONLY because the path is inert (header)
|
|
102
|
+
const pe = syncProbeEnv(env);
|
|
12
103
|
let fxField = 0; // field() contributions, accumulated apart from the apply probe
|
|
13
104
|
let fyField = 0;
|
|
14
105
|
for (const b of bodies) {
|
|
@@ -36,9 +127,9 @@ export function forceAt(bodies, forces, env, x, y) {
|
|
|
36
127
|
if (b.range > 0 && d2 >= b.range * b.range * 2.56)
|
|
37
128
|
continue; // same cull as the integrator
|
|
38
129
|
const d = Math.sqrt(d2);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
130
|
+
pe.dx = dx;
|
|
131
|
+
pe.dy = dy;
|
|
132
|
+
pe.dist = d < 1 ? 1 : d;
|
|
42
133
|
for (const tok of b.tokens) {
|
|
43
134
|
const f = forces[tok];
|
|
44
135
|
if (!f || f.modify)
|
|
@@ -49,7 +140,7 @@ export function forceAt(bodies, forces, env, x, y) {
|
|
|
49
140
|
fyField += v.y;
|
|
50
141
|
}
|
|
51
142
|
else {
|
|
52
|
-
f.apply(b, probe,
|
|
143
|
+
f.apply(b, probe, pe);
|
|
53
144
|
}
|
|
54
145
|
}
|
|
55
146
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamlines.js","sourceRoot":"","sources":["../../src/engine/streamlines.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"streamlines.js","sourceRoot":"","sources":["../../src/engine/streamlines.ts"],"names":[],"mappings":"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"}
|