@vibecook/ice 0.6.0 → 0.7.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/dist/{chunk-ELCBCTKY.js → chunk-55QCOE74.js} +2 -2
- package/dist/{chunk-BFT7YWS2.js → chunk-5OU3OWDH.js} +3 -3
- package/dist/{chunk-JLXETATP.js → chunk-LATXYFMO.js} +339 -42
- package/dist/chunk-LATXYFMO.js.map +1 -0
- package/dist/devtools.js +1 -1
- package/dist/dom.js +2 -2
- package/dist/ground.js +1 -1
- package/dist/index.js +3 -1
- package/dist/r3f.js +3 -3
- package/dist/react.js +3 -3
- package/dist/types/packages/core/src/behavior/define-behavior.d.ts +2 -1
- package/dist/types/packages/core/src/behavior/runtime.d.ts +16 -2
- package/dist/types/packages/core/src/behavior/types.d.ts +47 -1
- package/dist/types/packages/core/src/engine/guests.d.ts +5 -2
- package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +10 -0
- package/dist/types/packages/core/src/index.d.ts +4 -3
- package/package.json +1 -1
- package/dist/chunk-JLXETATP.js.map +0 -1
- /package/dist/{chunk-ELCBCTKY.js.map → chunk-55QCOE74.js.map} +0 -0
- /package/dist/{chunk-BFT7YWS2.js.map → chunk-5OU3OWDH.js.map} +0 -0
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
createSiblingOrderIndex,
|
|
17
17
|
defineQuery,
|
|
18
18
|
widgets
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-LATXYFMO.js";
|
|
20
20
|
import {
|
|
21
21
|
planeCssTransform,
|
|
22
22
|
worldToScreen
|
|
@@ -1160,4 +1160,4 @@ export {
|
|
|
1160
1160
|
wireMeasurement,
|
|
1161
1161
|
DOM_VERSION
|
|
1162
1162
|
};
|
|
1163
|
-
//# sourceMappingURL=chunk-
|
|
1163
|
+
//# sourceMappingURL=chunk-55QCOE74.js.map
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
keyboardClaimOf,
|
|
13
13
|
startRafLoop,
|
|
14
14
|
wireMeasurement
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-55QCOE74.js";
|
|
16
16
|
import {
|
|
17
17
|
ActiveTool,
|
|
18
18
|
DurableUndoStatus,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
tools,
|
|
34
34
|
widgets,
|
|
35
35
|
writeRuntimeResource
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-LATXYFMO.js";
|
|
37
37
|
|
|
38
38
|
// ../react/src/hooks.ts
|
|
39
39
|
import { createContext, useCallback, useContext, useMemo, useRef, useSyncExternalStore } from "react";
|
|
@@ -673,4 +673,4 @@ export {
|
|
|
673
673
|
InfiniteCanvas,
|
|
674
674
|
REACT_VERSION
|
|
675
675
|
};
|
|
676
|
-
//# sourceMappingURL=chunk-
|
|
676
|
+
//# sourceMappingURL=chunk-5OU3OWDH.js.map
|
|
@@ -843,6 +843,7 @@ function createGuestRegistry(world, opts) {
|
|
|
843
843
|
},
|
|
844
844
|
fault(err) {
|
|
845
845
|
if (!entry.alive || disposed) return;
|
|
846
|
+
if (entry.suspended) return;
|
|
846
847
|
entry.faultedThisFrame = true;
|
|
847
848
|
entry.accrued = true;
|
|
848
849
|
entry.consecutiveThrows++;
|
|
@@ -1733,6 +1734,102 @@ function validate(name, spec, phase2) {
|
|
|
1733
1734
|
}
|
|
1734
1735
|
}
|
|
1735
1736
|
}
|
|
1737
|
+
function cloneJsonShape(shape) {
|
|
1738
|
+
switch (shape.kind) {
|
|
1739
|
+
case "string":
|
|
1740
|
+
case "number":
|
|
1741
|
+
case "boolean":
|
|
1742
|
+
return { kind: shape.kind };
|
|
1743
|
+
case "enum":
|
|
1744
|
+
return { kind: "enum", options: [...shape.options] };
|
|
1745
|
+
case "array":
|
|
1746
|
+
return { kind: "array", item: cloneJsonShape(shape.item) };
|
|
1747
|
+
case "object":
|
|
1748
|
+
return {
|
|
1749
|
+
kind: "object",
|
|
1750
|
+
fields: Object.fromEntries(
|
|
1751
|
+
Object.entries(shape.fields).map(([name, field15]) => [name, cloneJsonShape(field15)])
|
|
1752
|
+
)
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
function describeProp(spec) {
|
|
1757
|
+
switch (spec.kind) {
|
|
1758
|
+
case "string":
|
|
1759
|
+
return {
|
|
1760
|
+
kind: "string",
|
|
1761
|
+
...spec.default === void 0 ? {} : { default: spec.default }
|
|
1762
|
+
};
|
|
1763
|
+
case "number":
|
|
1764
|
+
return {
|
|
1765
|
+
kind: "number",
|
|
1766
|
+
...spec.default === void 0 ? {} : { default: spec.default },
|
|
1767
|
+
...spec.min === void 0 ? {} : { min: spec.min },
|
|
1768
|
+
...spec.max === void 0 ? {} : { max: spec.max }
|
|
1769
|
+
};
|
|
1770
|
+
case "boolean":
|
|
1771
|
+
return {
|
|
1772
|
+
kind: "boolean",
|
|
1773
|
+
...spec.default === void 0 ? {} : { default: spec.default }
|
|
1774
|
+
};
|
|
1775
|
+
case "enum":
|
|
1776
|
+
return {
|
|
1777
|
+
kind: "enum",
|
|
1778
|
+
options: [...spec.options],
|
|
1779
|
+
...spec.default === void 0 ? {} : { default: spec.default }
|
|
1780
|
+
};
|
|
1781
|
+
case "json":
|
|
1782
|
+
return {
|
|
1783
|
+
kind: "json",
|
|
1784
|
+
inner: cloneJsonShape(spec.inner),
|
|
1785
|
+
...spec.default === void 0 ? {} : { default: spec.default }
|
|
1786
|
+
};
|
|
1787
|
+
case "entityKey":
|
|
1788
|
+
return {
|
|
1789
|
+
kind: "entityKey",
|
|
1790
|
+
...spec.default === void 0 ? {} : { default: spec.default }
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
var DESCRIPTION_HOOK_ORDER = [
|
|
1795
|
+
"init",
|
|
1796
|
+
"update",
|
|
1797
|
+
"changed",
|
|
1798
|
+
"tick",
|
|
1799
|
+
"dispose"
|
|
1800
|
+
];
|
|
1801
|
+
function describeBehavior(behavior) {
|
|
1802
|
+
const reads = [];
|
|
1803
|
+
for (const read of behavior.reads) {
|
|
1804
|
+
const description = classifyRead(read);
|
|
1805
|
+
if (description !== void 0) reads.push(description);
|
|
1806
|
+
}
|
|
1807
|
+
const writes = [];
|
|
1808
|
+
for (const component of behavior.writes) {
|
|
1809
|
+
const meta = schemaMeta.component(component);
|
|
1810
|
+
if (meta !== void 0) writes.push(meta.name);
|
|
1811
|
+
}
|
|
1812
|
+
return {
|
|
1813
|
+
id: behavior.name,
|
|
1814
|
+
store: behavior.store,
|
|
1815
|
+
derived: behavior.derived,
|
|
1816
|
+
deriveDuringGesture: behavior.deriveDuringGesture,
|
|
1817
|
+
version: behavior.version,
|
|
1818
|
+
phase: behavior.phase,
|
|
1819
|
+
...behavior.budgetMs === void 0 ? {} : { budgetMs: behavior.budgetMs },
|
|
1820
|
+
tickWhile: behavior.tickWhile,
|
|
1821
|
+
schema: Object.entries(behavior.schema).map(([name, spec]) => ({
|
|
1822
|
+
name,
|
|
1823
|
+
spec: describeProp(spec)
|
|
1824
|
+
})),
|
|
1825
|
+
reads,
|
|
1826
|
+
writes,
|
|
1827
|
+
migrationFrom: Object.keys(behavior.migrate).map(Number).sort((left, right) => left - right),
|
|
1828
|
+
hooks: DESCRIPTION_HOOK_ORDER.filter(
|
|
1829
|
+
(hook) => typeof behavior.on[hook] === "function"
|
|
1830
|
+
)
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1736
1833
|
function defineBehavior(name, spec) {
|
|
1737
1834
|
const phase2 = spec.phase ?? BEHAVIOR_DEFAULT_PHASE[spec.store];
|
|
1738
1835
|
if (devGuardsEnabled()) validate(name, spec, phase2);
|
|
@@ -7399,6 +7496,19 @@ function allowedQueryTerms(behavior, readComponents, readTags) {
|
|
|
7399
7496
|
// ../core/src/behavior/runtime.ts
|
|
7400
7497
|
var INSTANCE_THROW_LIMIT = 3;
|
|
7401
7498
|
var SUPPRESSION_WARN_FRAMES = 600;
|
|
7499
|
+
function isThenable(value) {
|
|
7500
|
+
return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
|
|
7501
|
+
}
|
|
7502
|
+
var BehaviorHookThenableError = class extends TypeError {
|
|
7503
|
+
};
|
|
7504
|
+
function invokeHook(behavior, hook, body) {
|
|
7505
|
+
const result = body();
|
|
7506
|
+
if (!isThenable(result)) return;
|
|
7507
|
+
void Promise.resolve(result).catch(() => void 0);
|
|
7508
|
+
throw new BehaviorHookThenableError(
|
|
7509
|
+
`ice: behavior "${behavior}" ${hook} returned a thenable; behavior hooks are synchronous`
|
|
7510
|
+
);
|
|
7511
|
+
}
|
|
7402
7512
|
function isClaimed(world, e) {
|
|
7403
7513
|
if (!world.isAlive(e)) return false;
|
|
7404
7514
|
for (const claimant of world.getReverse(e, Captures)) {
|
|
@@ -7426,6 +7536,7 @@ function cellForBehavior(world, b, e, patch) {
|
|
|
7426
7536
|
function createBehaviorRuntime(opts) {
|
|
7427
7537
|
const { world } = opts;
|
|
7428
7538
|
const nodes = /* @__PURE__ */ new Map();
|
|
7539
|
+
let nextRegistrationSequence = 0;
|
|
7429
7540
|
const onFault = opts.onFault ?? ((behavior, hook, entity, err) => {
|
|
7430
7541
|
console.error(`[ice] behavior "${behavior}" ${hook}${entity === void 0 ? "" : ` on entity ${entity}`} threw`, err);
|
|
7431
7542
|
});
|
|
@@ -7437,8 +7548,42 @@ function createBehaviorRuntime(opts) {
|
|
|
7437
7548
|
for (const n of nodes.values()) n.markGeneration();
|
|
7438
7549
|
}
|
|
7439
7550
|
});
|
|
7551
|
+
const publishOrder = [];
|
|
7552
|
+
const pendingWithdrawals = [];
|
|
7553
|
+
let publishHookRemover;
|
|
7554
|
+
function ensurePublishHook() {
|
|
7555
|
+
if (publishHookRemover !== void 0) return;
|
|
7556
|
+
publishHookRemover = opts.engine.onPublish(() => {
|
|
7557
|
+
if (pendingWithdrawals.length > 0) {
|
|
7558
|
+
const jobs = pendingWithdrawals.splice(0, pendingWithdrawals.length);
|
|
7559
|
+
for (const job of jobs) job();
|
|
7560
|
+
}
|
|
7561
|
+
if (publishOrder.length > 0) {
|
|
7562
|
+
const pass = publishOrder.slice();
|
|
7563
|
+
for (const node of pass) if (!node.isStopped()) node.runPublish();
|
|
7564
|
+
}
|
|
7565
|
+
if (publishOrder.length === 0 && pendingWithdrawals.length === 0) {
|
|
7566
|
+
publishHookRemover?.();
|
|
7567
|
+
publishHookRemover = void 0;
|
|
7568
|
+
}
|
|
7569
|
+
});
|
|
7570
|
+
}
|
|
7571
|
+
function installPublishNode(node) {
|
|
7572
|
+
publishOrder.push(node);
|
|
7573
|
+
ensurePublishHook();
|
|
7574
|
+
return () => {
|
|
7575
|
+
const i = publishOrder.indexOf(node);
|
|
7576
|
+
if (i !== -1) publishOrder.splice(i, 1);
|
|
7577
|
+
};
|
|
7578
|
+
}
|
|
7579
|
+
function deferWithdrawal(job) {
|
|
7580
|
+
pendingWithdrawals.push(job);
|
|
7581
|
+
ensurePublishHook();
|
|
7582
|
+
}
|
|
7440
7583
|
class Node {
|
|
7441
7584
|
b;
|
|
7585
|
+
orderKey;
|
|
7586
|
+
registrationSequence;
|
|
7442
7587
|
compiled;
|
|
7443
7588
|
own;
|
|
7444
7589
|
/** The same handle, typed for `readField`'s keyof-based field parameter. */
|
|
@@ -7449,6 +7594,19 @@ function createBehaviorRuntime(opts) {
|
|
|
7449
7594
|
peersQuery;
|
|
7450
7595
|
/** Ephemeral only: the local peer this node last published a facet on. */
|
|
7451
7596
|
facetPeer;
|
|
7597
|
+
/** The ephemeral singleton was quarantined THIS generation (I17). */
|
|
7598
|
+
singletonQuarantined = false;
|
|
7599
|
+
/** Uninstalled — a captured ctx.write closure must go inert (I17). */
|
|
7600
|
+
stopped = false;
|
|
7601
|
+
/** Per-FRAME strike dedupe (review finding 4): the ladder counts FRAMES,
|
|
7602
|
+
* not calls — 500 async instances must cost ONE strike, not write 500
|
|
7603
|
+
* into a ledger hosts persist across engine generations. Keyed by
|
|
7604
|
+
* FrameInfo.tick because no single pass entry point runs every frame
|
|
7605
|
+
* (the delivery system is runIf-gated off on no-churn frames while the
|
|
7606
|
+
* tick system keeps running). */
|
|
7607
|
+
strikeFrame = -1;
|
|
7608
|
+
thenableStruckPass = false;
|
|
7609
|
+
spanStruckPass = false;
|
|
7452
7610
|
/** The session whose version state has already been checked (§5.6). */
|
|
7453
7611
|
checkedSession;
|
|
7454
7612
|
/**
|
|
@@ -7519,8 +7677,10 @@ function createBehaviorRuntime(opts) {
|
|
|
7519
7677
|
/** Set for the duration of a delivery/tick pass; see BehaviorWalker. */
|
|
7520
7678
|
walker;
|
|
7521
7679
|
ctx;
|
|
7522
|
-
constructor(b) {
|
|
7680
|
+
constructor(b, registration, registrationSequence) {
|
|
7523
7681
|
this.b = b;
|
|
7682
|
+
this.orderKey = registration.orderKey;
|
|
7683
|
+
this.registrationSequence = registrationSequence;
|
|
7524
7684
|
this.own = b.component;
|
|
7525
7685
|
this.ownFields = b.component;
|
|
7526
7686
|
this.schema = b.schema;
|
|
@@ -7543,6 +7703,7 @@ function createBehaviorRuntime(opts) {
|
|
|
7543
7703
|
this.guest = opts.engine.guests.addDriven({
|
|
7544
7704
|
id: `behavior:${b.name}`,
|
|
7545
7705
|
...b.budgetMs !== void 0 ? { budgetMs: b.budgetMs } : {},
|
|
7706
|
+
...registration.ledger === void 0 ? {} : { ledger: registration.ledger },
|
|
7546
7707
|
busy: () => this.owed()
|
|
7547
7708
|
});
|
|
7548
7709
|
this.ctx = this.buildCtx();
|
|
@@ -7576,6 +7737,7 @@ function createBehaviorRuntime(opts) {
|
|
|
7576
7737
|
this.readsCollector?.dispose();
|
|
7577
7738
|
this.ownCollector = void 0;
|
|
7578
7739
|
this.readsCollector = void 0;
|
|
7740
|
+
this.withdrawFacet();
|
|
7579
7741
|
}
|
|
7580
7742
|
/**
|
|
7581
7743
|
* Resumed. Fresh collectors journal from NOW, so everything that happened
|
|
@@ -7597,18 +7759,10 @@ function createBehaviorRuntime(opts) {
|
|
|
7597
7759
|
if (this.compiled.readRelations.length > 0) {
|
|
7598
7760
|
world.orderStamp(0, this.compiled.readRelations[0]);
|
|
7599
7761
|
}
|
|
7762
|
+
}
|
|
7763
|
+
installExecution() {
|
|
7600
7764
|
if (this.b.phase === "publish") {
|
|
7601
|
-
this.removeSystems =
|
|
7602
|
-
if (this.guest.suspended()) {
|
|
7603
|
-
this.goCold();
|
|
7604
|
-
return;
|
|
7605
|
-
}
|
|
7606
|
-
this.guest.run(() => {
|
|
7607
|
-
if (this.b.store === "ephemeral") this.ensureFacet();
|
|
7608
|
-
if (this.shouldDeliver()) this.runDeliver(publishWalker(world));
|
|
7609
|
-
this.publishTick();
|
|
7610
|
-
});
|
|
7611
|
-
});
|
|
7765
|
+
this.removeSystems = installPublishNode(this);
|
|
7612
7766
|
} else {
|
|
7613
7767
|
this.removeSystems = opts.engine.addSystems(
|
|
7614
7768
|
this.b.phase,
|
|
@@ -7616,6 +7770,25 @@ function createBehaviorRuntime(opts) {
|
|
|
7616
7770
|
);
|
|
7617
7771
|
}
|
|
7618
7772
|
}
|
|
7773
|
+
/** The publish-slot body — driven by the runtime's one stable hook. */
|
|
7774
|
+
runPublish() {
|
|
7775
|
+
if (this.guest.suspended()) {
|
|
7776
|
+
this.goCold();
|
|
7777
|
+
return;
|
|
7778
|
+
}
|
|
7779
|
+
this.guest.run(() => {
|
|
7780
|
+
if (this.b.store === "ephemeral") this.ensureFacet();
|
|
7781
|
+
if (this.shouldDeliver()) this.runDeliver(publishWalker(world));
|
|
7782
|
+
this.publishTick();
|
|
7783
|
+
});
|
|
7784
|
+
}
|
|
7785
|
+
isStopped() {
|
|
7786
|
+
return this.stopped;
|
|
7787
|
+
}
|
|
7788
|
+
uninstallExecution() {
|
|
7789
|
+
this.removeSystems?.();
|
|
7790
|
+
this.removeSystems = void 0;
|
|
7791
|
+
}
|
|
7619
7792
|
/** The version-marker surface for the current session, if it has one. */
|
|
7620
7793
|
metaOf(session) {
|
|
7621
7794
|
const snapshot = session?.store.snapshot;
|
|
@@ -7701,6 +7874,10 @@ function createBehaviorRuntime(opts) {
|
|
|
7701
7874
|
this.facetPeer = void 0;
|
|
7702
7875
|
return;
|
|
7703
7876
|
}
|
|
7877
|
+
if (this.singletonQuarantined) {
|
|
7878
|
+
this.facetPeer = void 0;
|
|
7879
|
+
return;
|
|
7880
|
+
}
|
|
7704
7881
|
if (peer === this.facetPeer && world.has(peer, this.own)) return;
|
|
7705
7882
|
this.facetPeer = peer;
|
|
7706
7883
|
if (!world.has(peer, this.own)) {
|
|
@@ -7711,6 +7888,48 @@ function createBehaviorRuntime(opts) {
|
|
|
7711
7888
|
);
|
|
7712
7889
|
}
|
|
7713
7890
|
}
|
|
7891
|
+
/**
|
|
7892
|
+
* Withdraw the published facet (petition I17). An ephemeral facet is LIVE
|
|
7893
|
+
* PUBLICATION — the local peer telling every remote peer "this value is
|
|
7894
|
+
* current" — so every edge where the producer stops executing must reverse
|
|
7895
|
+
* the publication too, or a disabled, suspended, or quarantined behavior
|
|
7896
|
+
* keeps asserting its last value forever (remote peers have no TTL for a
|
|
7897
|
+
* peer that is still connected). Idempotent by construction: presence
|
|
7898
|
+
* absent, a dead peer (mid re-mint window), and an already-gone facet are
|
|
7899
|
+
* all quiet no-ops. The removal goes through the PRESENCE writer, never
|
|
7900
|
+
* `world.removeComponent`, because only the presence path encodes a
|
|
7901
|
+
* tombstone remote projections honor.
|
|
7902
|
+
*/
|
|
7903
|
+
withdrawFacet() {
|
|
7904
|
+
if (this.b.store !== "ephemeral") return;
|
|
7905
|
+
this.facetPeer = void 0;
|
|
7906
|
+
const presence = opts.presence?.();
|
|
7907
|
+
if (presence === void 0) return;
|
|
7908
|
+
const peer = presence.localPeer;
|
|
7909
|
+
if (!(world.isAlive(peer) && world.has(peer, this.own))) return;
|
|
7910
|
+
const midTick = world.inImmediateProjectionUnsafeContext ?? false;
|
|
7911
|
+
if (midTick) {
|
|
7912
|
+
const behaviorName = this.b.name;
|
|
7913
|
+
const own = this.own;
|
|
7914
|
+
deferWithdrawal(() => {
|
|
7915
|
+
const p2 = opts.presence?.();
|
|
7916
|
+
if (p2 === void 0) return;
|
|
7917
|
+
if (p2.localPeer !== peer) return;
|
|
7918
|
+
if (!(world.isAlive(peer) && world.has(peer, own))) return;
|
|
7919
|
+
try {
|
|
7920
|
+
p2.eph.removeComponent(peer, own);
|
|
7921
|
+
} catch (err) {
|
|
7922
|
+
onFault(behaviorName, "withdraw", peer, err);
|
|
7923
|
+
}
|
|
7924
|
+
});
|
|
7925
|
+
return;
|
|
7926
|
+
}
|
|
7927
|
+
try {
|
|
7928
|
+
presence.eph.removeComponent(peer, this.own);
|
|
7929
|
+
} catch (err) {
|
|
7930
|
+
onFault(this.b.name, "withdraw", peer, err);
|
|
7931
|
+
}
|
|
7932
|
+
}
|
|
7714
7933
|
/** The publish-slot twin of the tick SYSTEM (no query, no chunks). */
|
|
7715
7934
|
publishTick() {
|
|
7716
7935
|
const on = this.b.on;
|
|
@@ -7723,16 +7942,19 @@ function createBehaviorRuntime(opts) {
|
|
|
7723
7942
|
const inst = this.instances.get(e);
|
|
7724
7943
|
if (inst === void 0 || inst.failed || !inst.inited) continue;
|
|
7725
7944
|
const data = this.dataOf(e);
|
|
7726
|
-
this.callHook(
|
|
7727
|
-
|
|
7728
|
-
|
|
7945
|
+
this.callHook(
|
|
7946
|
+
"tick",
|
|
7947
|
+
inst,
|
|
7948
|
+
faulted,
|
|
7949
|
+
() => on.tick?.(e, data, frame2, this.ctx)
|
|
7950
|
+
);
|
|
7729
7951
|
}
|
|
7730
7952
|
this.walker = void 0;
|
|
7731
7953
|
}
|
|
7732
7954
|
uninstall() {
|
|
7955
|
+
this.stopped = true;
|
|
7733
7956
|
this.endGeneration();
|
|
7734
|
-
this.
|
|
7735
|
-
this.removeSystems = void 0;
|
|
7957
|
+
this.uninstallExecution();
|
|
7736
7958
|
this.ownCollector?.dispose();
|
|
7737
7959
|
this.readsCollector?.dispose();
|
|
7738
7960
|
this.ownCollector = void 0;
|
|
@@ -7995,9 +8217,12 @@ function createBehaviorRuntime(opts) {
|
|
|
7995
8217
|
for (const e of appeared) {
|
|
7996
8218
|
const inst = this.instances.get(e);
|
|
7997
8219
|
if (inst === void 0 || inst.failed) continue;
|
|
7998
|
-
if (this.callHook(
|
|
7999
|
-
|
|
8000
|
-
|
|
8220
|
+
if (this.callHook(
|
|
8221
|
+
"init",
|
|
8222
|
+
inst,
|
|
8223
|
+
faultedEntities,
|
|
8224
|
+
() => on.init?.(e, this.dataOf(e), this.ctx)
|
|
8225
|
+
)) {
|
|
8001
8226
|
inst.inited = true;
|
|
8002
8227
|
}
|
|
8003
8228
|
}
|
|
@@ -8019,16 +8244,19 @@ function createBehaviorRuntime(opts) {
|
|
|
8019
8244
|
if (valueEquals2(this.own, this.scratchCell, inst.prevCell)) continue;
|
|
8020
8245
|
const data = this.viewOf(this.scratchCell, this.scratchData);
|
|
8021
8246
|
const prev = this.viewOf(inst.prevCell, this.scratchPrevData);
|
|
8022
|
-
this.callHook(
|
|
8023
|
-
|
|
8024
|
-
|
|
8247
|
+
this.callHook(
|
|
8248
|
+
"update",
|
|
8249
|
+
inst,
|
|
8250
|
+
faultedEntities,
|
|
8251
|
+
() => on.update?.(e, data, prev, this.ctx)
|
|
8252
|
+
);
|
|
8025
8253
|
this.copyInto(this.scratchCell, inst.prevCell);
|
|
8026
8254
|
}
|
|
8027
8255
|
}
|
|
8028
8256
|
const anyVisible = this.visible.length > 0;
|
|
8029
8257
|
if (on.changed !== void 0 && (full || (work?.readsFired ?? false) || lifted) && anyVisible) {
|
|
8030
8258
|
try {
|
|
8031
|
-
on.changed(this.ctx);
|
|
8259
|
+
invokeHook(this.b.name, "changed", () => on.changed?.(this.ctx));
|
|
8032
8260
|
} catch (err) {
|
|
8033
8261
|
onFault(this.b.name, "changed", void 0, err);
|
|
8034
8262
|
this.guest.fault(err);
|
|
@@ -8037,7 +8265,11 @@ function createBehaviorRuntime(opts) {
|
|
|
8037
8265
|
if (on.dispose !== void 0) {
|
|
8038
8266
|
for (const inst of departed) {
|
|
8039
8267
|
try {
|
|
8040
|
-
|
|
8268
|
+
invokeHook(
|
|
8269
|
+
this.b.name,
|
|
8270
|
+
"dispose",
|
|
8271
|
+
() => on.dispose?.(inst.e, this.ctx)
|
|
8272
|
+
);
|
|
8041
8273
|
} catch (err) {
|
|
8042
8274
|
onFault(this.b.name, "dispose", inst.e, err);
|
|
8043
8275
|
}
|
|
@@ -8062,9 +8294,12 @@ function createBehaviorRuntime(opts) {
|
|
|
8062
8294
|
const inst = this.instances.get(e);
|
|
8063
8295
|
if (inst === void 0 || inst.failed || !inst.inited) continue;
|
|
8064
8296
|
const data = this.dataOf(e);
|
|
8065
|
-
this.callHook(
|
|
8066
|
-
|
|
8067
|
-
|
|
8297
|
+
this.callHook(
|
|
8298
|
+
"tick",
|
|
8299
|
+
inst,
|
|
8300
|
+
faulted,
|
|
8301
|
+
() => on.tick?.(e, data, frame2, this.ctx)
|
|
8302
|
+
);
|
|
8068
8303
|
}
|
|
8069
8304
|
this.walker = void 0;
|
|
8070
8305
|
}
|
|
@@ -8076,15 +8311,33 @@ function createBehaviorRuntime(opts) {
|
|
|
8076
8311
|
*/
|
|
8077
8312
|
callHook(hook, inst, faulted, body) {
|
|
8078
8313
|
try {
|
|
8079
|
-
body
|
|
8314
|
+
invokeHook(this.b.name, hook, body);
|
|
8080
8315
|
inst.consecutiveThrows = 0;
|
|
8081
8316
|
return true;
|
|
8082
8317
|
} catch (err) {
|
|
8083
8318
|
inst.consecutiveThrows++;
|
|
8084
8319
|
onFault(this.b.name, hook, inst.e, err);
|
|
8085
|
-
if (inst.consecutiveThrows >= INSTANCE_THROW_LIMIT)
|
|
8320
|
+
if (inst.consecutiveThrows >= INSTANCE_THROW_LIMIT) {
|
|
8321
|
+
inst.failed = true;
|
|
8322
|
+
if (this.b.store === "ephemeral") this.singletonQuarantined = true;
|
|
8323
|
+
this.withdrawFacet();
|
|
8324
|
+
}
|
|
8086
8325
|
faulted.add(inst.e);
|
|
8087
|
-
|
|
8326
|
+
const frameTick = world.getResource(FrameInfo)?.tick ?? -1;
|
|
8327
|
+
if (frameTick !== this.strikeFrame) {
|
|
8328
|
+
this.strikeFrame = frameTick;
|
|
8329
|
+
this.thenableStruckPass = false;
|
|
8330
|
+
this.spanStruckPass = false;
|
|
8331
|
+
}
|
|
8332
|
+
if (err instanceof BehaviorHookThenableError) {
|
|
8333
|
+
if (!this.thenableStruckPass) {
|
|
8334
|
+
this.thenableStruckPass = true;
|
|
8335
|
+
this.guest.fault(err);
|
|
8336
|
+
}
|
|
8337
|
+
} else if (faulted.size > 1 && !this.spanStruckPass) {
|
|
8338
|
+
this.spanStruckPass = true;
|
|
8339
|
+
this.guest.fault(err);
|
|
8340
|
+
}
|
|
8088
8341
|
return false;
|
|
8089
8342
|
}
|
|
8090
8343
|
}
|
|
@@ -8094,14 +8347,19 @@ function createBehaviorRuntime(opts) {
|
|
|
8094
8347
|
if (on.dispose !== void 0) {
|
|
8095
8348
|
for (const inst of this.instances.values()) {
|
|
8096
8349
|
try {
|
|
8097
|
-
|
|
8350
|
+
invokeHook(
|
|
8351
|
+
this.b.name,
|
|
8352
|
+
"dispose",
|
|
8353
|
+
() => on.dispose?.(inst.e, this.ctx)
|
|
8354
|
+
);
|
|
8098
8355
|
} catch (err) {
|
|
8099
8356
|
onFault(this.b.name, "dispose", inst.e, err);
|
|
8100
8357
|
}
|
|
8101
8358
|
}
|
|
8102
8359
|
}
|
|
8103
8360
|
this.instances.clear();
|
|
8104
|
-
this.
|
|
8361
|
+
this.withdrawFacet();
|
|
8362
|
+
this.singletonQuarantined = false;
|
|
8105
8363
|
this.suppressed.clear();
|
|
8106
8364
|
this.suppressedFrames.clear();
|
|
8107
8365
|
this.carry.clear();
|
|
@@ -8199,6 +8457,7 @@ function createBehaviorRuntime(opts) {
|
|
|
8199
8457
|
}
|
|
8200
8458
|
/** `ctx.write(patch)` for the ephemeral class — publish THIS peer's facet. */
|
|
8201
8459
|
writeFacet(patch) {
|
|
8460
|
+
if (this.stopped || this.cold || this.singletonQuarantined) return;
|
|
8202
8461
|
const presence = opts.presence?.();
|
|
8203
8462
|
if (presence === void 0) return;
|
|
8204
8463
|
const peer = presence.localPeer;
|
|
@@ -8368,10 +8627,32 @@ function createBehaviorRuntime(opts) {
|
|
|
8368
8627
|
instances: this.instances.size,
|
|
8369
8628
|
failed,
|
|
8370
8629
|
ticking: this.b.on.tick === void 0 ? 0 : this.instances.size - failed,
|
|
8371
|
-
suspended: this.guest.suspended()
|
|
8630
|
+
suspended: this.guest.suspended(),
|
|
8631
|
+
quarantined: this.singletonQuarantined
|
|
8372
8632
|
};
|
|
8373
8633
|
}
|
|
8374
8634
|
}
|
|
8635
|
+
function orderedNodes() {
|
|
8636
|
+
return [...nodes.values()].sort((left, right) => {
|
|
8637
|
+
if (left.orderKey !== void 0 || right.orderKey !== void 0) {
|
|
8638
|
+
if (left.orderKey === void 0) return 1;
|
|
8639
|
+
if (right.orderKey === void 0) return -1;
|
|
8640
|
+
if (left.orderKey < right.orderKey) return -1;
|
|
8641
|
+
if (left.orderKey > right.orderKey) return 1;
|
|
8642
|
+
}
|
|
8643
|
+
return left.registrationSequence - right.registrationSequence;
|
|
8644
|
+
});
|
|
8645
|
+
}
|
|
8646
|
+
function reorderExecution(inserted) {
|
|
8647
|
+
const order = orderedNodes();
|
|
8648
|
+
const at = order.indexOf(inserted);
|
|
8649
|
+
if (at === order.length - 1) {
|
|
8650
|
+
inserted.installExecution();
|
|
8651
|
+
return;
|
|
8652
|
+
}
|
|
8653
|
+
for (let i = order.length - 1; i > at; i--) order[i]?.uninstallExecution();
|
|
8654
|
+
for (let i = at; i < order.length; i++) order[i]?.installExecution();
|
|
8655
|
+
}
|
|
8375
8656
|
function safeParse(raw) {
|
|
8376
8657
|
try {
|
|
8377
8658
|
return JSON.parse(raw);
|
|
@@ -8380,13 +8661,17 @@ function createBehaviorRuntime(opts) {
|
|
|
8380
8661
|
}
|
|
8381
8662
|
}
|
|
8382
8663
|
return {
|
|
8383
|
-
register(b) {
|
|
8664
|
+
register(b, options = {}) {
|
|
8665
|
+
if (options.orderKey !== void 0 && (typeof options.orderKey !== "string" || options.orderKey.length === 0)) {
|
|
8666
|
+
throw new TypeError("ice: behavior registration orderKey must be a non-empty string");
|
|
8667
|
+
}
|
|
8384
8668
|
if (nodes.has(b.name)) {
|
|
8385
8669
|
throw new Error(`ice: behavior "${b.name}" is already registered with this engine.`);
|
|
8386
8670
|
}
|
|
8387
|
-
const node = new Node(b);
|
|
8671
|
+
const node = new Node(b, options, nextRegistrationSequence++);
|
|
8388
8672
|
nodes.set(b.name, node);
|
|
8389
8673
|
node.install();
|
|
8674
|
+
reorderExecution(node);
|
|
8390
8675
|
return () => {
|
|
8391
8676
|
if (nodes.get(b.name) !== node) return;
|
|
8392
8677
|
nodes.delete(b.name);
|
|
@@ -8394,7 +8679,7 @@ function createBehaviorRuntime(opts) {
|
|
|
8394
8679
|
};
|
|
8395
8680
|
},
|
|
8396
8681
|
registered() {
|
|
8397
|
-
return
|
|
8682
|
+
return orderedNodes().map((n) => n.b);
|
|
8398
8683
|
},
|
|
8399
8684
|
attach(e, b, data) {
|
|
8400
8685
|
if (b.store === "durable") {
|
|
@@ -8427,12 +8712,18 @@ function createBehaviorRuntime(opts) {
|
|
|
8427
8712
|
return cell;
|
|
8428
8713
|
},
|
|
8429
8714
|
list() {
|
|
8430
|
-
return
|
|
8715
|
+
return orderedNodes().map((n) => n.status());
|
|
8431
8716
|
},
|
|
8432
8717
|
dispose() {
|
|
8433
8718
|
stopResetWatch();
|
|
8434
8719
|
for (const n of nodes.values()) n.uninstall();
|
|
8435
8720
|
nodes.clear();
|
|
8721
|
+
if (pendingWithdrawals.length > 0) {
|
|
8722
|
+
const jobs = pendingWithdrawals.splice(0, pendingWithdrawals.length);
|
|
8723
|
+
for (const job of jobs) job();
|
|
8724
|
+
}
|
|
8725
|
+
publishHookRemover?.();
|
|
8726
|
+
publishHookRemover = void 0;
|
|
8436
8727
|
}
|
|
8437
8728
|
};
|
|
8438
8729
|
}
|
|
@@ -10030,7 +10321,10 @@ function createCanvasEngine(opts = {}) {
|
|
|
10030
10321
|
}
|
|
10031
10322
|
}
|
|
10032
10323
|
const world = createWorld2();
|
|
10033
|
-
const engine = createEngine(world
|
|
10324
|
+
const engine = createEngine(world, {
|
|
10325
|
+
...opts.onGuestFault === void 0 ? {} : { onGuestFault: opts.onGuestFault },
|
|
10326
|
+
...opts.onGuestNotice === void 0 ? {} : { onGuestNotice: opts.onGuestNotice }
|
|
10327
|
+
});
|
|
10034
10328
|
const sink = createForwardingSink();
|
|
10035
10329
|
const stack = installInteractionStack(engine, { sink });
|
|
10036
10330
|
const budgets = {
|
|
@@ -10205,7 +10499,9 @@ function createCanvasEngine(opts = {}) {
|
|
|
10205
10499
|
// document, so this reads through per publish: an ephemeral behavior
|
|
10206
10500
|
// installed before anyone joins simply lies dormant until there is a peer
|
|
10207
10501
|
// for it to be.
|
|
10208
|
-
presence: () => presence
|
|
10502
|
+
presence: () => presence,
|
|
10503
|
+
...opts.onBehaviorFault === void 0 ? {} : { onFault: opts.onBehaviorFault },
|
|
10504
|
+
...opts.onBehaviorLog === void 0 ? {} : { onLog: opts.onBehaviorLog }
|
|
10209
10505
|
});
|
|
10210
10506
|
for (const b of opts.behaviors ?? []) behaviors2.register(b);
|
|
10211
10507
|
const widgetQuery = () => {
|
|
@@ -10437,7 +10733,7 @@ import {
|
|
|
10437
10733
|
Local as Local3
|
|
10438
10734
|
} from "@vibecook/strata-ecs";
|
|
10439
10735
|
import { DurableUndoStatus } from "@vibecook/strata-ecs/durable";
|
|
10440
|
-
var CORE_VERSION = "0.
|
|
10736
|
+
var CORE_VERSION = "0.7.0";
|
|
10441
10737
|
|
|
10442
10738
|
export {
|
|
10443
10739
|
defineSchemaOnce,
|
|
@@ -10579,6 +10875,7 @@ export {
|
|
|
10579
10875
|
BEHAVIOR_PHASES,
|
|
10580
10876
|
BEHAVIOR_DEFAULT_PHASE,
|
|
10581
10877
|
behaviors,
|
|
10878
|
+
describeBehavior,
|
|
10582
10879
|
defineBehavior,
|
|
10583
10880
|
isDurableEligible,
|
|
10584
10881
|
compileBehavior,
|
|
@@ -10721,4 +11018,4 @@ export {
|
|
|
10721
11018
|
Local3 as Local,
|
|
10722
11019
|
DurableUndoStatus
|
|
10723
11020
|
};
|
|
10724
|
-
//# sourceMappingURL=chunk-
|
|
11021
|
+
//# sourceMappingURL=chunk-LATXYFMO.js.map
|