@vibecook/ice 0.8.0 → 0.9.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-CBCSIEXW.js → chunk-E33I7R2Z.js} +2 -2
- package/dist/{chunk-3SUDKHUF.js → chunk-HM25ULBP.js} +3 -3
- package/dist/{chunk-BE4F4X3Q.js → chunk-LBRHND4G.js} +68 -8
- package/dist/chunk-LBRHND4G.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 +1 -1
- package/dist/r3f.js +3 -3
- package/dist/react.js +3 -3
- package/dist/types/packages/core/src/behavior/define-behavior.d.ts +11 -0
- package/dist/types/packages/core/src/behavior/types.d.ts +21 -0
- package/dist/types/packages/core/src/index.d.ts +1 -1
- package/package.json +2 -2
- package/dist/chunk-BE4F4X3Q.js.map +0 -1
- /package/dist/{chunk-CBCSIEXW.js.map → chunk-E33I7R2Z.js.map} +0 -0
- /package/dist/{chunk-3SUDKHUF.js.map → chunk-HM25ULBP.js.map} +0 -0
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
createSiblingOrderIndex,
|
|
17
17
|
defineQuery,
|
|
18
18
|
widgets
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-LBRHND4G.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-E33I7R2Z.js.map
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
keyboardClaimOf,
|
|
13
13
|
startRafLoop,
|
|
14
14
|
wireMeasurement
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-E33I7R2Z.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-LBRHND4G.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-HM25ULBP.js.map
|
|
@@ -1623,6 +1623,10 @@ function defaultsOf(schema) {
|
|
|
1623
1623
|
for (const [name, spec] of Object.entries(schema)) out[name] = defaultValueOf(spec);
|
|
1624
1624
|
return out;
|
|
1625
1625
|
}
|
|
1626
|
+
var utf8 = new TextEncoder();
|
|
1627
|
+
function facetBytesOf(cell) {
|
|
1628
|
+
return utf8.encode(JSON.stringify(cell)).length;
|
|
1629
|
+
}
|
|
1626
1630
|
function signatureOf(spec, phase2) {
|
|
1627
1631
|
const schema = spec.schema ?? {};
|
|
1628
1632
|
return JSON.stringify({
|
|
@@ -1632,6 +1636,11 @@ function signatureOf(spec, phase2) {
|
|
|
1632
1636
|
version: spec.version ?? 1,
|
|
1633
1637
|
phase: phase2,
|
|
1634
1638
|
tickWhile: spec.tick?.while ?? "all",
|
|
1639
|
+
// The I19 byte claim is IDENTITY-BEARING: a redefinition that changes only
|
|
1640
|
+
// the claim is a different declaration (hosts compare descriptors; the
|
|
1641
|
+
// ensure-cache must agree). `?? null` because JSON.stringify drops
|
|
1642
|
+
// undefined-valued keys, which would alias "no claim" with "absent field".
|
|
1643
|
+
maxFacetBytes: spec.maxFacetBytes ?? null,
|
|
1635
1644
|
// Field ORDER is part of the shape: it is the generated component's column
|
|
1636
1645
|
// order, which the durable cell layout depends on.
|
|
1637
1646
|
schema: Object.entries(schema).map(([k, s]) => [k, s.kind, defaultValueOf(s)]),
|
|
@@ -1679,6 +1688,17 @@ function validate(name, spec, phase2) {
|
|
|
1679
1688
|
if (spec.budgetMs !== void 0 && (!Number.isFinite(spec.budgetMs) || spec.budgetMs <= 0)) {
|
|
1680
1689
|
fail2(name, `budgetMs must be a positive number (got ${String(spec.budgetMs)}).`);
|
|
1681
1690
|
}
|
|
1691
|
+
if (spec.maxFacetBytes !== void 0) {
|
|
1692
|
+
if (spec.store !== "ephemeral") {
|
|
1693
|
+
fail2(
|
|
1694
|
+
name,
|
|
1695
|
+
`"maxFacetBytes" is ephemeral-only \u2014 it bounds the published presence facet, and only ephemeral behaviors publish one (petition I19).`
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
if (!Number.isSafeInteger(spec.maxFacetBytes) || spec.maxFacetBytes <= 0) {
|
|
1699
|
+
fail2(name, `maxFacetBytes must be a positive integer byte count (got ${String(spec.maxFacetBytes)}).`);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1682
1702
|
for (const [fieldName, s] of Object.entries(spec.schema ?? {})) {
|
|
1683
1703
|
if (fieldName.length === 0) fail2(name, "schema field names must be non-empty.");
|
|
1684
1704
|
if (typeof s !== "object" || s === null || typeof s.kind !== "string") {
|
|
@@ -1817,6 +1837,7 @@ function describeBehavior(behavior) {
|
|
|
1817
1837
|
version: behavior.version,
|
|
1818
1838
|
phase: behavior.phase,
|
|
1819
1839
|
...behavior.budgetMs === void 0 ? {} : { budgetMs: behavior.budgetMs },
|
|
1840
|
+
...behavior.maxFacetBytes === void 0 ? {} : { maxFacetBytes: behavior.maxFacetBytes },
|
|
1820
1841
|
tickWhile: behavior.tickWhile,
|
|
1821
1842
|
schema: Object.entries(behavior.schema).map(([name, spec]) => ({
|
|
1822
1843
|
name,
|
|
@@ -1845,6 +1866,15 @@ function defineBehavior(name, spec) {
|
|
|
1845
1866
|
return existing;
|
|
1846
1867
|
}
|
|
1847
1868
|
const schema = spec.schema ?? {};
|
|
1869
|
+
const defaults = defaultsOf(schema);
|
|
1870
|
+
if (spec.maxFacetBytes !== void 0 && spec.store === "ephemeral") {
|
|
1871
|
+
const bytes = facetBytesOf(defaults);
|
|
1872
|
+
if (bytes > spec.maxFacetBytes) {
|
|
1873
|
+
throw new Error(
|
|
1874
|
+
`ice: defineBehavior("${name}") \u2014 the default facet is ${bytes} bytes, over the behavior's own maxFacetBytes=${spec.maxFacetBytes} claim. Nothing was registered.`
|
|
1875
|
+
);
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1848
1878
|
const raw = {};
|
|
1849
1879
|
for (const [fieldName, s] of Object.entries(schema)) raw[fieldName] = strataFieldOf(name, fieldName, s);
|
|
1850
1880
|
const component = ensureComponent(behaviorComponentName(name), raw);
|
|
@@ -1857,9 +1887,10 @@ function defineBehavior(name, spec) {
|
|
|
1857
1887
|
version: spec.version ?? 1,
|
|
1858
1888
|
phase: phase2,
|
|
1859
1889
|
budgetMs: spec.budgetMs,
|
|
1890
|
+
maxFacetBytes: spec.maxFacetBytes,
|
|
1860
1891
|
schema,
|
|
1861
1892
|
component,
|
|
1862
|
-
defaults
|
|
1893
|
+
defaults,
|
|
1863
1894
|
reads: spec.reads ?? [],
|
|
1864
1895
|
writes: spec.writes ?? [],
|
|
1865
1896
|
migrate: spec.migrate ?? {},
|
|
@@ -7920,7 +7951,7 @@ function createBehaviorRuntime(opts) {
|
|
|
7920
7951
|
if (presence === void 0) return;
|
|
7921
7952
|
const peer = presence.localPeer;
|
|
7922
7953
|
if (!(world.isAlive(peer) && world.has(peer, this.own))) return;
|
|
7923
|
-
const midTick = world.inImmediateProjectionUnsafeContext
|
|
7954
|
+
const midTick = world.inImmediateProjectionUnsafeContext;
|
|
7924
7955
|
if (midTick) {
|
|
7925
7956
|
const behaviorName = this.b.name;
|
|
7926
7957
|
const own = this.own;
|
|
@@ -8486,6 +8517,15 @@ function createBehaviorRuntime(opts) {
|
|
|
8486
8517
|
if (!world.isAlive(peer)) return;
|
|
8487
8518
|
if (this.hookEntity !== void 0 && this.hookEntity !== peer) return;
|
|
8488
8519
|
const cell = cellForBehavior(world, this.b, peer, patch);
|
|
8520
|
+
const bound = this.b.maxFacetBytes;
|
|
8521
|
+
if (bound !== void 0) {
|
|
8522
|
+
const bytes = facetBytesOf(cell);
|
|
8523
|
+
if (bytes > bound) {
|
|
8524
|
+
throw new Error(
|
|
8525
|
+
`ice: behavior "${this.b.name}" ctx.write produced a ${bytes}-byte facet, over its declared maxFacetBytes=${bound} \u2014 the write was refused and the prior facet left intact.`
|
|
8526
|
+
);
|
|
8527
|
+
}
|
|
8528
|
+
}
|
|
8489
8529
|
if (world.has(peer, this.own)) presence.eph.edit(peer).set(this.own, cell);
|
|
8490
8530
|
else presence.eph.addComponent(peer, this.own, cell);
|
|
8491
8531
|
}
|
|
@@ -8627,6 +8667,11 @@ function createBehaviorRuntime(opts) {
|
|
|
8627
8667
|
},
|
|
8628
8668
|
attach(e, behavior, data) {
|
|
8629
8669
|
const other = behavior;
|
|
8670
|
+
if (other.store === "ephemeral") {
|
|
8671
|
+
throw new Error(
|
|
8672
|
+
`ice: behavior "${node.b.name}" called tx.attach("${other.name}") \u2014 an ephemeral behavior's facet is presence data and cannot be attached into the document.`
|
|
8673
|
+
);
|
|
8674
|
+
}
|
|
8630
8675
|
const cell = cellForBehavior(world, other, e, data ?? {});
|
|
8631
8676
|
if (world.has(e, other.component)) {
|
|
8632
8677
|
tx.edit(e).set(other.component, cell);
|
|
@@ -8635,6 +8680,11 @@ function createBehaviorRuntime(opts) {
|
|
|
8635
8680
|
}
|
|
8636
8681
|
},
|
|
8637
8682
|
detach(e, behavior) {
|
|
8683
|
+
if (behavior.store === "ephemeral") {
|
|
8684
|
+
throw new Error(
|
|
8685
|
+
`ice: behavior "${node.b.name}" called tx.detach("${behavior.name}") \u2014 ephemeral facets are withdrawn by the runtime (I17) or the presence layer's tombstones, never through the document.`
|
|
8686
|
+
);
|
|
8687
|
+
}
|
|
8638
8688
|
tx.removeComponent(e, behavior.component);
|
|
8639
8689
|
}
|
|
8640
8690
|
};
|
|
@@ -8710,6 +8760,11 @@ function createBehaviorRuntime(opts) {
|
|
|
8710
8760
|
`ice: engine.behaviors.attach("${b.name}") \u2014 durable attachment is a DOCUMENT op: use tx.attach inside a transaction so it syncs and undoes.`
|
|
8711
8761
|
);
|
|
8712
8762
|
}
|
|
8763
|
+
if (b.store === "ephemeral") {
|
|
8764
|
+
throw new Error(
|
|
8765
|
+
`ice: engine.behaviors.attach("${b.name}") \u2014 an ephemeral behavior's facet is minted by the runtime on the local peer; it cannot be attached to an entity.`
|
|
8766
|
+
);
|
|
8767
|
+
}
|
|
8713
8768
|
const cell = cellForBehavior(world, b, e, data ?? {});
|
|
8714
8769
|
if (world.has(e, b.component)) world.edit(e).set(b.component, cell);
|
|
8715
8770
|
else world.addComponent(e, b.component, cell);
|
|
@@ -8720,6 +8775,11 @@ function createBehaviorRuntime(opts) {
|
|
|
8720
8775
|
`ice: engine.behaviors.detach("${b.name}") \u2014 durable detachment is a DOCUMENT op: use tx.detach inside a transaction.`
|
|
8721
8776
|
);
|
|
8722
8777
|
}
|
|
8778
|
+
if (b.store === "ephemeral") {
|
|
8779
|
+
throw new Error(
|
|
8780
|
+
`ice: engine.behaviors.detach("${b.name}") \u2014 ephemeral facets are withdrawn by the runtime (I17) or the presence layer's tombstones, never detached through the world.`
|
|
8781
|
+
);
|
|
8782
|
+
}
|
|
8723
8783
|
if (world.has(e, b.component)) world.removeComponent(e, b.component);
|
|
8724
8784
|
},
|
|
8725
8785
|
has: (e, b) => world.isAlive(e) && world.has(e, b.component),
|
|
@@ -9986,7 +10046,7 @@ var K_SNAPSHOT_OFFER = 2;
|
|
|
9986
10046
|
var K_SNAPSHOT = 3;
|
|
9987
10047
|
var K_UPDATE = 4;
|
|
9988
10048
|
var K_PRESENCE = 5;
|
|
9989
|
-
var
|
|
10049
|
+
var utf82 = new TextEncoder();
|
|
9990
10050
|
var fromUtf8 = new TextDecoder();
|
|
9991
10051
|
var defaultClock = {
|
|
9992
10052
|
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
@@ -10000,7 +10060,7 @@ function frame(kind, payload) {
|
|
|
10000
10060
|
return out;
|
|
10001
10061
|
}
|
|
10002
10062
|
function frameSnapshot(targetId, snapshot) {
|
|
10003
|
-
const id =
|
|
10063
|
+
const id = utf82.encode(targetId);
|
|
10004
10064
|
const out = new Uint8Array(1 + 2 + id.length + snapshot.length);
|
|
10005
10065
|
out[0] = K_SNAPSHOT;
|
|
10006
10066
|
out[1] = id.length & 255;
|
|
@@ -10174,7 +10234,7 @@ function joinDoc(world, channel, opts = {}) {
|
|
|
10174
10234
|
active = false;
|
|
10175
10235
|
buffered.length = 0;
|
|
10176
10236
|
opts.onSession?.(void 0);
|
|
10177
|
-
send(frame(K_HELLO,
|
|
10237
|
+
send(frame(K_HELLO, utf82.encode(joinerId)));
|
|
10178
10238
|
armTimeout();
|
|
10179
10239
|
};
|
|
10180
10240
|
const onFrame = (bytes) => {
|
|
@@ -10222,7 +10282,7 @@ function joinDoc(world, channel, opts = {}) {
|
|
|
10222
10282
|
if (unsubPresence !== void 0) roomSubs.push(unsubPresence);
|
|
10223
10283
|
const begin = () => {
|
|
10224
10284
|
if (left) return;
|
|
10225
|
-
send(frame(K_HELLO,
|
|
10285
|
+
send(frame(K_HELLO, utf82.encode(joinerId)));
|
|
10226
10286
|
if (left) return;
|
|
10227
10287
|
armTimeout();
|
|
10228
10288
|
};
|
|
@@ -10844,7 +10904,7 @@ import {
|
|
|
10844
10904
|
Local as Local3
|
|
10845
10905
|
} from "@vibecook/strata-ecs";
|
|
10846
10906
|
import { DurableUndoStatus } from "@vibecook/strata-ecs/durable";
|
|
10847
|
-
var CORE_VERSION = "0.
|
|
10907
|
+
var CORE_VERSION = "0.9.0";
|
|
10848
10908
|
|
|
10849
10909
|
export {
|
|
10850
10910
|
defineSchemaOnce,
|
|
@@ -11129,4 +11189,4 @@ export {
|
|
|
11129
11189
|
Local3 as Local,
|
|
11130
11190
|
DurableUndoStatus
|
|
11131
11191
|
};
|
|
11132
|
-
//# sourceMappingURL=chunk-
|
|
11192
|
+
//# sourceMappingURL=chunk-LBRHND4G.js.map
|