@yagejs/core 0.4.0 → 0.6.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/index.cjs CHANGED
@@ -110,6 +110,8 @@ __export(index_exports, {
110
110
  Sequence: () => Sequence,
111
111
  SerializableRegistry: () => SerializableRegistry,
112
112
  ServiceKey: () => ServiceKey,
113
+ StoreMigrationMissingError: () => StoreMigrationMissingError,
114
+ StoreVersionTooNewError: () => StoreVersionTooNewError,
113
115
  System: () => System,
114
116
  SystemScheduler: () => SystemScheduler,
115
117
  SystemSchedulerKey: () => SystemSchedulerKey,
@@ -119,16 +121,25 @@ __export(index_exports, {
119
121
  Tween: () => Tween,
120
122
  VERSION: () => VERSION,
121
123
  Vec2: () => Vec2,
124
+ _clearStoreRegistryForTesting: () => _clearStoreRegistryForTesting,
125
+ _resetAllStoresForTesting: () => _resetAllStoresForTesting,
122
126
  _resetEntityIdCounter: () => _resetEntityIdCounter,
123
127
  advanceFrames: () => advanceFrames,
128
+ createAtom: () => createAtom,
124
129
  createDefaultRandomSeed: () => createDefaultRandomSeed,
125
130
  createKeyframeTrack: () => createKeyframeTrack,
126
131
  createMockEntity: () => createMockEntity,
127
132
  createMockScene: () => createMockScene,
128
133
  createRandomService: () => createRandomService,
134
+ createStore: () => createStore,
129
135
  createTestEngine: () => createTestEngine,
136
+ dateCodec: () => dateCodec,
130
137
  defineBlueprint: () => defineBlueprint,
138
+ defineCounter: () => defineCounter,
131
139
  defineEvent: () => defineEvent,
140
+ defineMap: () => defineMap,
141
+ defineSet: () => defineSet,
142
+ defineStore: () => defineStore,
132
143
  defineTrait: () => defineTrait,
133
144
  easeInOutQuad: () => easeInOutQuad,
134
145
  easeInQuad: () => easeInQuad,
@@ -139,14 +150,20 @@ __export(index_exports, {
139
150
  getSerializableType: () => getSerializableType,
140
151
  globalRandom: () => globalRandom,
141
152
  interpolate: () => interpolate,
153
+ isPointerConsumeContainer: () => isPointerConsumeContainer,
142
154
  isSerializable: () => isSerializable,
155
+ jsonCodec: () => jsonCodec,
143
156
  makeEntityScopedQueue: () => makeEntityScopedQueue,
144
157
  makeGlobalScopedQueue: () => makeGlobalScopedQueue,
145
158
  makeSceneScopedQueue: () => makeSceneScopedQueue,
159
+ mapCodec: () => mapCodec,
160
+ markPointerConsumeContainer: () => markPointerConsumeContainer,
146
161
  normalizeSeed: () => normalizeSeed,
147
162
  resolveTransition: () => resolveTransition,
148
163
  serializable: () => serializable,
149
- trait: () => trait
164
+ setCodec: () => setCodec,
165
+ trait: () => trait,
166
+ unmarkPointerConsumeContainer: () => unmarkPointerConsumeContainer
150
167
  });
151
168
  module.exports = __toCommonJS(index_exports);
152
169
 
@@ -1240,6 +1257,13 @@ var Entity = class {
1240
1257
  name;
1241
1258
  /** Tags for group queries. */
1242
1259
  tags;
1260
+ /**
1261
+ * Stable identity key, scene-scoped. Set at spawn-time when
1262
+ * `options.key` is passed to `scene.spawn` / `entity.spawnChild`;
1263
+ * `undefined` otherwise. Used with `scene.findByKey` and as a stable
1264
+ * id in persistent stores (e.g. `defineSet<string>("world.opened")`).
1265
+ */
1266
+ key;
1243
1267
  components = /* @__PURE__ */ new Map();
1244
1268
  _destroyed = false;
1245
1269
  _scene = null;
@@ -1310,17 +1334,21 @@ var Entity = class {
1310
1334
  this._scene._addExistingEntity(child);
1311
1335
  }
1312
1336
  }
1313
- spawnChild(name, classOrBlueprint, params) {
1337
+ spawnChild(name, classOrBlueprintOrOptions, paramsOrOptions, maybeOptions) {
1314
1338
  const scene = this.scene;
1315
1339
  if (this._children?.has(name)) {
1316
1340
  throw new Error(
1317
1341
  `Entity "${this.name}" already has a child named "${name}".`
1318
1342
  );
1319
1343
  }
1320
- const child = classOrBlueprint === void 0 ? scene.spawn(name) : scene.spawn(
1321
- classOrBlueprint,
1322
- params
1323
- );
1344
+ let child;
1345
+ if (classOrBlueprintOrOptions === void 0) {
1346
+ child = scene.spawn(name);
1347
+ } else if (typeof classOrBlueprintOrOptions === "object" && !("build" in classOrBlueprintOrOptions)) {
1348
+ child = scene.spawn(name, classOrBlueprintOrOptions);
1349
+ } else {
1350
+ child = scene.spawn(classOrBlueprintOrOptions, paramsOrOptions, maybeOptions);
1351
+ }
1324
1352
  this.addChild(name, child);
1325
1353
  return child;
1326
1354
  }
@@ -1463,6 +1491,19 @@ var Entity = class {
1463
1491
  }
1464
1492
  return false;
1465
1493
  }
1494
+ /**
1495
+ * Return the stable key, or throw if this entity was spawned without one.
1496
+ * Use inside component `setup()` when the component depends on identity
1497
+ * (e.g. reading from a `defineSet` keyed by entity id).
1498
+ */
1499
+ requireKey() {
1500
+ if (this.key === void 0) {
1501
+ throw new Error(
1502
+ `Entity "${this.name}" (id=${this.id}) has no stable key. Pass { key: "..." } to scene.spawn(...) or entity.spawnChild(...).`
1503
+ );
1504
+ }
1505
+ return this.key;
1506
+ }
1466
1507
  /**
1467
1508
  * Internal: set the scene and callbacks. Called by Scene.spawn().
1468
1509
  * @internal
@@ -1471,6 +1512,20 @@ var Entity = class {
1471
1512
  this._scene = scene;
1472
1513
  this.callbacks = callbacks;
1473
1514
  }
1515
+ /**
1516
+ * Internal: assign the stable identity key. Called by `Scene._registerKey`
1517
+ * during spawn. Throws if the entity already has a key — keys are
1518
+ * immutable for an entity's lifetime.
1519
+ * @internal
1520
+ */
1521
+ _setKey(key) {
1522
+ if (this.key !== void 0) {
1523
+ throw new Error(
1524
+ `Entity "${this.name}" already has key "${this.key}".`
1525
+ );
1526
+ }
1527
+ this.key = key;
1528
+ }
1474
1529
  };
1475
1530
 
1476
1531
  // src/QueryCache.ts
@@ -1907,11 +1962,30 @@ var Inspector = class {
1907
1962
  mouseUp: /* @__PURE__ */ __name((button = 0) => {
1908
1963
  this.requireInputManager().firePointerUp(button);
1909
1964
  }, "mouseUp"),
1910
- gamepadButton: /* @__PURE__ */ __name((idx, pressed) => {
1911
- this.requireInputManager().fireGamepadButton(idx, pressed);
1965
+ /**
1966
+ * Inject a synthetic pointer-move with full pointer addressing. Pass `opts`
1967
+ * with `id` / `type: "touch"` to drive a specific finger; defaults match
1968
+ * the primary mouse pointer (same as `mouseMove`).
1969
+ */
1970
+ pointerMove: /* @__PURE__ */ __name((x, y, opts) => {
1971
+ this.requireInputManager().firePointerMove(x, y, opts);
1972
+ }, "pointerMove"),
1973
+ /**
1974
+ * Inject a synthetic pointer-down. With `opts.id` and `opts.type: "touch"`
1975
+ * this drives a multi-touch contact, exercising `getPointers()`,
1976
+ * per-pointer event hooks, and the any-pointer aggregate for `MouseLeft`.
1977
+ */
1978
+ pointerDown: /* @__PURE__ */ __name((button = 0, opts) => {
1979
+ this.requireInputManager().firePointerDown(button, opts);
1980
+ }, "pointerDown"),
1981
+ pointerUp: /* @__PURE__ */ __name((button = 0, opts) => {
1982
+ this.requireInputManager().firePointerUp(button, opts);
1983
+ }, "pointerUp"),
1984
+ gamepadButton: /* @__PURE__ */ __name((code, pressed) => {
1985
+ this.requireInputManager().fireGamepadButton(code, pressed);
1912
1986
  }, "gamepadButton"),
1913
- gamepadAxis: /* @__PURE__ */ __name((idx, value) => {
1914
- this.requireInputManager().fireGamepadAxis(idx, value);
1987
+ gamepadAxis: /* @__PURE__ */ __name((side, value) => {
1988
+ this.requireInputManager().fireGamepadAxis(side, value);
1915
1989
  }, "gamepadAxis"),
1916
1990
  tap: /* @__PURE__ */ __name((code, frames = 1) => {
1917
1991
  this.assertNonNegativeInteger(frames, "Inspector.input.tap(frames)");
@@ -2470,6 +2544,7 @@ var Inspector = class {
2470
2544
  keys: [],
2471
2545
  actions: [],
2472
2546
  mouse: { x: 0, y: 0, buttons: [], down: false },
2547
+ pointers: [],
2473
2548
  gamepad: { buttons: [], axes: [] }
2474
2549
  };
2475
2550
  }
@@ -2633,6 +2708,17 @@ function decodeBase64(base64) {
2633
2708
  __name(decodeBase64, "decodeBase64");
2634
2709
 
2635
2710
  // src/Scene.ts
2711
+ var _SPAWN_OPTION_KEYS = /* @__PURE__ */ new Set(["key"]);
2712
+ function _looksLikeSpawnOptions(v) {
2713
+ if (typeof v !== "object" || v === null || Array.isArray(v)) return false;
2714
+ const keys = Object.keys(v);
2715
+ if (keys.length === 0) return false;
2716
+ for (const k of keys) {
2717
+ if (!_SPAWN_OPTION_KEYS.has(k)) return false;
2718
+ }
2719
+ return true;
2720
+ }
2721
+ __name(_looksLikeSpawnOptions, "_looksLikeSpawnOptions");
2636
2722
  var Scene = class {
2637
2723
  static {
2638
2724
  __name(this, "Scene");
@@ -2658,6 +2744,7 @@ var Scene = class {
2658
2744
  _entityEventHandlers;
2659
2745
  _entityEventObserver;
2660
2746
  _scopedServices;
2747
+ _identityIndex;
2661
2748
  /** Access the EngineContext. */
2662
2749
  get context() {
2663
2750
  return this._context;
@@ -2706,10 +2793,26 @@ var Scene = class {
2706
2793
  }, "set")
2707
2794
  });
2708
2795
  }
2709
- spawn(nameOrBlueprintOrClass, params) {
2796
+ spawn(nameOrBlueprintOrClass, paramsOrOptions, maybeOptions) {
2710
2797
  if (typeof nameOrBlueprintOrClass === "function") {
2711
- const entity2 = new nameOrBlueprintOrClass();
2798
+ const Ctor = nameOrBlueprintOrClass;
2799
+ const hasSetup = typeof Ctor.prototype.setup === "function";
2800
+ let params;
2801
+ let options2;
2802
+ if (maybeOptions !== void 0) {
2803
+ params = paramsOrOptions;
2804
+ options2 = maybeOptions;
2805
+ } else if (paramsOrOptions === void 0) {
2806
+ } else if (!hasSetup) {
2807
+ options2 = paramsOrOptions;
2808
+ } else if (_looksLikeSpawnOptions(paramsOrOptions)) {
2809
+ options2 = paramsOrOptions;
2810
+ } else {
2811
+ params = paramsOrOptions;
2812
+ }
2813
+ const entity2 = new Ctor();
2712
2814
  entity2._setScene(this, this.entityCallbacks);
2815
+ if (options2?.key !== void 0) this._registerKey(entity2, options2.key);
2713
2816
  this.entities.add(entity2);
2714
2817
  this.bus?.emit("entity:created", { entity: entity2 });
2715
2818
  entity2.setup?.(params);
@@ -2717,15 +2820,59 @@ var Scene = class {
2717
2820
  }
2718
2821
  const isBlueprint = typeof nameOrBlueprintOrClass === "object" && nameOrBlueprintOrClass !== null && "build" in nameOrBlueprintOrClass;
2719
2822
  const name = isBlueprint ? nameOrBlueprintOrClass.name : nameOrBlueprintOrClass;
2823
+ let blueprintParams;
2824
+ let options;
2825
+ if (isBlueprint) {
2826
+ if (maybeOptions !== void 0) {
2827
+ blueprintParams = paramsOrOptions;
2828
+ options = maybeOptions;
2829
+ } else if (paramsOrOptions !== void 0 && _looksLikeSpawnOptions(paramsOrOptions)) {
2830
+ options = paramsOrOptions;
2831
+ } else {
2832
+ blueprintParams = paramsOrOptions;
2833
+ }
2834
+ } else {
2835
+ options = paramsOrOptions;
2836
+ }
2720
2837
  const entity = new Entity(name);
2721
2838
  entity._setScene(this, this.entityCallbacks);
2839
+ if (options?.key !== void 0) this._registerKey(entity, options.key);
2722
2840
  this.entities.add(entity);
2723
2841
  this.bus?.emit("entity:created", { entity });
2724
2842
  if (isBlueprint) {
2725
- nameOrBlueprintOrClass.build(entity, params);
2843
+ nameOrBlueprintOrClass.build(
2844
+ entity,
2845
+ blueprintParams
2846
+ );
2726
2847
  }
2727
2848
  return entity;
2728
2849
  }
2850
+ /**
2851
+ * Look up an entity by its stable identity key, scoped to this scene.
2852
+ * Returns `undefined` for unknown or already-destroyed entities.
2853
+ */
2854
+ findByKey(key) {
2855
+ const entity = this._identityIndex?.get(key);
2856
+ if (!entity || entity.isDestroyed) return void 0;
2857
+ return entity;
2858
+ }
2859
+ /**
2860
+ * Internal: register a key on a freshly spawned entity. Throws on
2861
+ * duplicate so callers (Scene.spawn) can abort before adding to
2862
+ * `this.entities` or emitting `entity:created`.
2863
+ * @internal
2864
+ */
2865
+ _registerKey(entity, key) {
2866
+ this._identityIndex ??= /* @__PURE__ */ new Map();
2867
+ const existing = this._identityIndex.get(key);
2868
+ if (existing && !existing.isDestroyed) {
2869
+ throw new Error(
2870
+ `Scene "${this.name}" already has an entity with key "${key}". Destroy it before spawning a duplicate.`
2871
+ );
2872
+ }
2873
+ entity._setKey(key);
2874
+ this._identityIndex.set(key, entity);
2875
+ }
2729
2876
  /**
2730
2877
  * Add an existing entity to this scene (used by Entity.addChild for auto-scene-membership).
2731
2878
  * @internal
@@ -2876,12 +3023,17 @@ var Scene = class {
2876
3023
  entity._performDestroy();
2877
3024
  this.queryCache?.onEntityDestroyed(entity);
2878
3025
  this.entities.delete(entity);
3026
+ if (entity.key !== void 0 && this._identityIndex?.get(entity.key) === entity) {
3027
+ this._identityIndex.delete(entity.key);
3028
+ }
2879
3029
  this.bus?.emit("entity:destroyed", { entity });
2880
3030
  }
2881
3031
  this.destroyQueue.length = 0;
2882
3032
  }
2883
3033
  /**
2884
- * Destroy all entities — used during scene exit.
3034
+ * Destroy all entities — used during scene exit. Clears the identity
3035
+ * index in bulk; per-entity key removal in `_flushDestroyQueue` is the
3036
+ * in-game path.
2885
3037
  * @internal
2886
3038
  */
2887
3039
  _destroyAllEntities() {
@@ -2892,6 +3044,7 @@ var Scene = class {
2892
3044
  this.entities.clear();
2893
3045
  this.destroyQueue.length = 0;
2894
3046
  this._entityEventHandlers?.clear();
3047
+ this._identityIndex?.clear();
2895
3048
  }
2896
3049
  };
2897
3050
 
@@ -4493,6 +4646,21 @@ var RendererAdapterKey = new ServiceKey(
4493
4646
  "rendererAdapter"
4494
4647
  );
4495
4648
 
4649
+ // src/ui-consume-registry.ts
4650
+ var registry2 = /* @__PURE__ */ new WeakSet();
4651
+ function markPointerConsumeContainer(container) {
4652
+ registry2.add(container);
4653
+ }
4654
+ __name(markPointerConsumeContainer, "markPointerConsumeContainer");
4655
+ function unmarkPointerConsumeContainer(container) {
4656
+ registry2.delete(container);
4657
+ }
4658
+ __name(unmarkPointerConsumeContainer, "unmarkPointerConsumeContainer");
4659
+ function isPointerConsumeContainer(container) {
4660
+ return registry2.has(container);
4661
+ }
4662
+ __name(isPointerConsumeContainer, "isPointerConsumeContainer");
4663
+
4496
4664
  // src/test-utils.ts
4497
4665
  var _TestScene = class extends Scene {
4498
4666
  static {
@@ -4540,6 +4708,387 @@ function advanceFrames(engine, n, dtMs = 1e3 / 60) {
4540
4708
  }
4541
4709
  __name(advanceFrames, "advanceFrames");
4542
4710
 
4711
+ // src/state/Atom.ts
4712
+ function createAtom(initial) {
4713
+ let value = initial;
4714
+ const listeners = /* @__PURE__ */ new Set();
4715
+ return {
4716
+ get() {
4717
+ return value;
4718
+ },
4719
+ set(next) {
4720
+ if (Object.is(value, next)) return;
4721
+ value = next;
4722
+ for (const fn of listeners) fn(value);
4723
+ },
4724
+ subscribe(listener) {
4725
+ listeners.add(listener);
4726
+ return () => {
4727
+ listeners.delete(listener);
4728
+ };
4729
+ }
4730
+ };
4731
+ }
4732
+ __name(createAtom, "createAtom");
4733
+
4734
+ // src/state/Store.ts
4735
+ function createStore(initial) {
4736
+ let snapshot = { ...initial };
4737
+ const listeners = /* @__PURE__ */ new Set();
4738
+ return {
4739
+ get() {
4740
+ return snapshot;
4741
+ },
4742
+ set(partial) {
4743
+ let changed = false;
4744
+ for (const key of Object.keys(partial)) {
4745
+ if (!Object.is(snapshot[key], partial[key])) {
4746
+ changed = true;
4747
+ break;
4748
+ }
4749
+ }
4750
+ if (!changed) return;
4751
+ snapshot = { ...snapshot, ...partial };
4752
+ for (const fn of listeners) fn();
4753
+ },
4754
+ subscribe(listener) {
4755
+ listeners.add(listener);
4756
+ return () => {
4757
+ listeners.delete(listener);
4758
+ };
4759
+ }
4760
+ };
4761
+ }
4762
+ __name(createStore, "createStore");
4763
+
4764
+ // src/state/codecs.ts
4765
+ function jsonCodec() {
4766
+ return {
4767
+ encode: /* @__PURE__ */ __name((value) => value, "encode"),
4768
+ decode: /* @__PURE__ */ __name((raw) => raw, "decode")
4769
+ };
4770
+ }
4771
+ __name(jsonCodec, "jsonCodec");
4772
+ function setCodec() {
4773
+ return {
4774
+ encode: /* @__PURE__ */ __name((value) => Array.from(value), "encode"),
4775
+ decode: /* @__PURE__ */ __name((raw) => {
4776
+ if (!Array.isArray(raw)) {
4777
+ throw new Error("setCodec.decode: expected an array");
4778
+ }
4779
+ return new Set(raw);
4780
+ }, "decode")
4781
+ };
4782
+ }
4783
+ __name(setCodec, "setCodec");
4784
+ function mapCodec() {
4785
+ return {
4786
+ encode: /* @__PURE__ */ __name((value) => Array.from(value.entries()), "encode"),
4787
+ decode: /* @__PURE__ */ __name((raw) => {
4788
+ if (!Array.isArray(raw)) {
4789
+ throw new Error("mapCodec.decode: expected an array of entries");
4790
+ }
4791
+ return new Map(raw);
4792
+ }, "decode")
4793
+ };
4794
+ }
4795
+ __name(mapCodec, "mapCodec");
4796
+ function dateCodec() {
4797
+ return {
4798
+ encode: /* @__PURE__ */ __name((value) => value.toISOString(), "encode"),
4799
+ decode: /* @__PURE__ */ __name((raw) => {
4800
+ if (typeof raw !== "string") {
4801
+ throw new Error("dateCodec.decode: expected an ISO string");
4802
+ }
4803
+ const d = new Date(raw);
4804
+ if (Number.isNaN(d.getTime())) {
4805
+ throw new Error(`dateCodec.decode: invalid ISO string ${JSON.stringify(raw)}`);
4806
+ }
4807
+ return d;
4808
+ }, "decode")
4809
+ };
4810
+ }
4811
+ __name(dateCodec, "dateCodec");
4812
+
4813
+ // src/state/persistent.ts
4814
+ var registry3 = /* @__PURE__ */ new Map();
4815
+ function register(entry) {
4816
+ registry3.set(entry.id, entry);
4817
+ }
4818
+ __name(register, "register");
4819
+ function _resetAllStoresForTesting() {
4820
+ for (const entry of registry3.values()) entry.reset();
4821
+ }
4822
+ __name(_resetAllStoresForTesting, "_resetAllStoresForTesting");
4823
+ function _clearStoreRegistryForTesting() {
4824
+ registry3.clear();
4825
+ }
4826
+ __name(_clearStoreRegistryForTesting, "_clearStoreRegistryForTesting");
4827
+ var StoreVersionTooNewError = class extends Error {
4828
+ static {
4829
+ __name(this, "StoreVersionTooNewError");
4830
+ }
4831
+ storeId;
4832
+ storedVersion;
4833
+ currentVersion;
4834
+ constructor(storeId, storedVersion, currentVersion) {
4835
+ super(
4836
+ `Store "${storeId}" was saved at version ${storedVersion}, but this build is at version ${currentVersion}. Cannot downgrade.`
4837
+ );
4838
+ this.name = "StoreVersionTooNewError";
4839
+ this.storeId = storeId;
4840
+ this.storedVersion = storedVersion;
4841
+ this.currentVersion = currentVersion;
4842
+ }
4843
+ };
4844
+ var StoreMigrationMissingError = class extends Error {
4845
+ static {
4846
+ __name(this, "StoreMigrationMissingError");
4847
+ }
4848
+ storeId;
4849
+ storedVersion;
4850
+ currentVersion;
4851
+ constructor(storeId, storedVersion, currentVersion) {
4852
+ super(
4853
+ `Store "${storeId}" needs migration from version ${storedVersion} to ${currentVersion}, but no migrate() was provided.`
4854
+ );
4855
+ this.name = "StoreMigrationMissingError";
4856
+ this.storeId = storeId;
4857
+ this.storedVersion = storedVersion;
4858
+ this.currentVersion = currentVersion;
4859
+ }
4860
+ };
4861
+ function defineStore(id, opts) {
4862
+ const version = opts.version ?? 1;
4863
+ const codec = opts.codec ?? jsonCodec();
4864
+ const defaults = opts.defaults;
4865
+ const inner = createStore(defaults());
4866
+ const replaceAll = /* @__PURE__ */ __name((next) => {
4867
+ inner.set({ ...next });
4868
+ }, "replaceAll");
4869
+ const store = {
4870
+ id,
4871
+ version,
4872
+ get: inner.get,
4873
+ set: inner.set,
4874
+ subscribe: inner.subscribe,
4875
+ reset() {
4876
+ replaceAll(defaults());
4877
+ },
4878
+ serialize() {
4879
+ return { version, data: codec.encode(inner.get()) };
4880
+ },
4881
+ hydrate(payload) {
4882
+ if (payload.version > version) {
4883
+ throw new StoreVersionTooNewError(id, payload.version, version);
4884
+ }
4885
+ let next;
4886
+ if (payload.version < version) {
4887
+ if (!opts.migrate) {
4888
+ throw new StoreMigrationMissingError(id, payload.version, version);
4889
+ }
4890
+ next = opts.migrate(payload.data, payload.version);
4891
+ } else {
4892
+ next = codec.decode(payload.data);
4893
+ }
4894
+ replaceAll(next);
4895
+ }
4896
+ };
4897
+ register({ id, reset: /* @__PURE__ */ __name(() => store.reset(), "reset") });
4898
+ return store;
4899
+ }
4900
+ __name(defineStore, "defineStore");
4901
+ function defineSet(id, opts) {
4902
+ const version = opts?.version ?? 1;
4903
+ const defaults = /* @__PURE__ */ __name(() => new Set(opts?.defaults?.() ?? []), "defaults");
4904
+ const codec = setCodec();
4905
+ const atom = createAtom(defaults());
4906
+ const replace = /* @__PURE__ */ __name((next) => {
4907
+ atom.set(next);
4908
+ }, "replace");
4909
+ const store = {
4910
+ id,
4911
+ version,
4912
+ has(key) {
4913
+ return atom.get().has(key);
4914
+ },
4915
+ add(key) {
4916
+ const current = atom.get();
4917
+ if (current.has(key)) return;
4918
+ const next = new Set(current);
4919
+ next.add(key);
4920
+ replace(next);
4921
+ },
4922
+ remove(key) {
4923
+ const current = atom.get();
4924
+ if (!current.has(key)) return;
4925
+ const next = new Set(current);
4926
+ next.delete(key);
4927
+ replace(next);
4928
+ },
4929
+ clear() {
4930
+ if (atom.get().size === 0) return;
4931
+ replace(/* @__PURE__ */ new Set());
4932
+ },
4933
+ size() {
4934
+ return atom.get().size;
4935
+ },
4936
+ values() {
4937
+ return atom.get().values();
4938
+ },
4939
+ subscribe(listener) {
4940
+ return atom.subscribe(() => listener());
4941
+ },
4942
+ reset() {
4943
+ replace(defaults());
4944
+ },
4945
+ serialize() {
4946
+ return { version, data: codec.encode(atom.get()) };
4947
+ },
4948
+ hydrate(payload) {
4949
+ if (payload.version > version) {
4950
+ throw new StoreVersionTooNewError(id, payload.version, version);
4951
+ }
4952
+ if (payload.version < version) {
4953
+ if (!opts?.migrate) {
4954
+ throw new StoreMigrationMissingError(id, payload.version, version);
4955
+ }
4956
+ replace(opts.migrate(payload.data, payload.version));
4957
+ return;
4958
+ }
4959
+ replace(codec.decode(payload.data));
4960
+ }
4961
+ };
4962
+ register({ id, reset: /* @__PURE__ */ __name(() => store.reset(), "reset") });
4963
+ return store;
4964
+ }
4965
+ __name(defineSet, "defineSet");
4966
+ function defineMap(id, opts) {
4967
+ const version = opts?.version ?? 1;
4968
+ const defaults = /* @__PURE__ */ __name(() => new Map(opts?.defaults?.() ?? []), "defaults");
4969
+ const codec = mapCodec();
4970
+ const atom = createAtom(defaults());
4971
+ const replace = /* @__PURE__ */ __name((next) => {
4972
+ atom.set(next);
4973
+ }, "replace");
4974
+ const store = {
4975
+ id,
4976
+ version,
4977
+ has(key) {
4978
+ return atom.get().has(key);
4979
+ },
4980
+ get(key) {
4981
+ return atom.get().get(key);
4982
+ },
4983
+ set(key, value) {
4984
+ const current = atom.get();
4985
+ if (current.has(key) && Object.is(current.get(key), value)) return;
4986
+ const next = new Map(current);
4987
+ next.set(key, value);
4988
+ replace(next);
4989
+ },
4990
+ remove(key) {
4991
+ const current = atom.get();
4992
+ if (!current.has(key)) return;
4993
+ const next = new Map(current);
4994
+ next.delete(key);
4995
+ replace(next);
4996
+ },
4997
+ clear() {
4998
+ if (atom.get().size === 0) return;
4999
+ replace(/* @__PURE__ */ new Map());
5000
+ },
5001
+ size() {
5002
+ return atom.get().size;
5003
+ },
5004
+ entries() {
5005
+ return atom.get().entries();
5006
+ },
5007
+ subscribe(listener) {
5008
+ return atom.subscribe(() => listener());
5009
+ },
5010
+ reset() {
5011
+ replace(defaults());
5012
+ },
5013
+ serialize() {
5014
+ return { version, data: codec.encode(atom.get()) };
5015
+ },
5016
+ hydrate(payload) {
5017
+ if (payload.version > version) {
5018
+ throw new StoreVersionTooNewError(id, payload.version, version);
5019
+ }
5020
+ if (payload.version < version) {
5021
+ if (!opts?.migrate) {
5022
+ throw new StoreMigrationMissingError(id, payload.version, version);
5023
+ }
5024
+ replace(opts.migrate(payload.data, payload.version));
5025
+ return;
5026
+ }
5027
+ replace(codec.decode(payload.data));
5028
+ }
5029
+ };
5030
+ register({ id, reset: /* @__PURE__ */ __name(() => store.reset(), "reset") });
5031
+ return store;
5032
+ }
5033
+ __name(defineMap, "defineMap");
5034
+ function defineCounter(id, opts) {
5035
+ const version = opts?.version ?? 1;
5036
+ const defaults = /* @__PURE__ */ __name(() => opts?.defaults?.() ?? 0, "defaults");
5037
+ const atom = createAtom(defaults());
5038
+ const store = {
5039
+ id,
5040
+ version,
5041
+ value() {
5042
+ return atom.get();
5043
+ },
5044
+ set(n) {
5045
+ atom.set(n);
5046
+ },
5047
+ increment(by = 1) {
5048
+ atom.set(atom.get() + by);
5049
+ },
5050
+ decrement(by = 1) {
5051
+ atom.set(atom.get() - by);
5052
+ },
5053
+ subscribe(listener) {
5054
+ return atom.subscribe(() => listener());
5055
+ },
5056
+ reset() {
5057
+ atom.set(defaults());
5058
+ },
5059
+ serialize() {
5060
+ return { version, data: atom.get() };
5061
+ },
5062
+ hydrate(payload) {
5063
+ if (payload.version > version) {
5064
+ throw new StoreVersionTooNewError(id, payload.version, version);
5065
+ }
5066
+ if (payload.version < version) {
5067
+ if (!opts?.migrate) {
5068
+ throw new StoreMigrationMissingError(id, payload.version, version);
5069
+ }
5070
+ const migrated = opts.migrate(payload.data, payload.version);
5071
+ if (typeof migrated !== "number") {
5072
+ throw new Error(
5073
+ `defineCounter "${id}".hydrate: migrate returned non-number ${typeof migrated}`
5074
+ );
5075
+ }
5076
+ atom.set(migrated);
5077
+ return;
5078
+ }
5079
+ if (typeof payload.data !== "number") {
5080
+ throw new Error(
5081
+ `defineCounter "${id}".hydrate: expected number, got ${typeof payload.data}`
5082
+ );
5083
+ }
5084
+ atom.set(payload.data);
5085
+ }
5086
+ };
5087
+ register({ id, reset: /* @__PURE__ */ __name(() => store.reset(), "reset") });
5088
+ return store;
5089
+ }
5090
+ __name(defineCounter, "defineCounter");
5091
+
4543
5092
  // src/index.ts
4544
5093
  var VERSION = "0.0.0";
4545
5094
  // Annotate the CommonJS export names for ESM import in node:
@@ -4589,6 +5138,8 @@ var VERSION = "0.0.0";
4589
5138
  Sequence,
4590
5139
  SerializableRegistry,
4591
5140
  ServiceKey,
5141
+ StoreMigrationMissingError,
5142
+ StoreVersionTooNewError,
4592
5143
  System,
4593
5144
  SystemScheduler,
4594
5145
  SystemSchedulerKey,
@@ -4598,16 +5149,25 @@ var VERSION = "0.0.0";
4598
5149
  Tween,
4599
5150
  VERSION,
4600
5151
  Vec2,
5152
+ _clearStoreRegistryForTesting,
5153
+ _resetAllStoresForTesting,
4601
5154
  _resetEntityIdCounter,
4602
5155
  advanceFrames,
5156
+ createAtom,
4603
5157
  createDefaultRandomSeed,
4604
5158
  createKeyframeTrack,
4605
5159
  createMockEntity,
4606
5160
  createMockScene,
4607
5161
  createRandomService,
5162
+ createStore,
4608
5163
  createTestEngine,
5164
+ dateCodec,
4609
5165
  defineBlueprint,
5166
+ defineCounter,
4610
5167
  defineEvent,
5168
+ defineMap,
5169
+ defineSet,
5170
+ defineStore,
4611
5171
  defineTrait,
4612
5172
  easeInOutQuad,
4613
5173
  easeInQuad,
@@ -4618,13 +5178,19 @@ var VERSION = "0.0.0";
4618
5178
  getSerializableType,
4619
5179
  globalRandom,
4620
5180
  interpolate,
5181
+ isPointerConsumeContainer,
4621
5182
  isSerializable,
5183
+ jsonCodec,
4622
5184
  makeEntityScopedQueue,
4623
5185
  makeGlobalScopedQueue,
4624
5186
  makeSceneScopedQueue,
5187
+ mapCodec,
5188
+ markPointerConsumeContainer,
4625
5189
  normalizeSeed,
4626
5190
  resolveTransition,
4627
5191
  serializable,
4628
- trait
5192
+ setCodec,
5193
+ trait,
5194
+ unmarkPointerConsumeContainer
4629
5195
  });
4630
5196
  //# sourceMappingURL=index.cjs.map