@forgeax/engine-ecs 0.1.21 → 0.1.24

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.
Files changed (104) hide show
  1. package/README.md +83 -17
  2. package/dist/__tests__/changed-block-summary.candidate.test.d.ts +2 -0
  3. package/dist/__tests__/changed-block-summary.candidate.test.d.ts.map +1 -0
  4. package/dist/__tests__/component-requirements.unit.test.d.ts +2 -0
  5. package/dist/__tests__/component-requirements.unit.test.d.ts.map +1 -0
  6. package/dist/__tests__/component-version-surface.test.d.ts +2 -0
  7. package/dist/__tests__/component-version-surface.test.d.ts.map +1 -0
  8. package/dist/__tests__/derived-range-writer.contract.test-d.d.ts +2 -0
  9. package/dist/__tests__/derived-range-writer.contract.test-d.d.ts.map +1 -0
  10. package/dist/__tests__/derived-range-writer.contract.test.d.ts +2 -0
  11. package/dist/__tests__/derived-range-writer.contract.test.d.ts.map +1 -0
  12. package/dist/__tests__/structural-evidence.contract.test-d.d.ts +2 -0
  13. package/dist/__tests__/structural-evidence.contract.test-d.d.ts.map +1 -0
  14. package/dist/__tests__/structural-evidence.contract.test.d.ts +2 -0
  15. package/dist/__tests__/structural-evidence.contract.test.d.ts.map +1 -0
  16. package/dist/component-schema.d.ts +17 -0
  17. package/dist/component-schema.d.ts.map +1 -1
  18. package/dist/component.d.ts +16 -7
  19. package/dist/component.d.ts.map +1 -1
  20. package/dist/errors/query-and-component-errors.d.ts +1 -1
  21. package/dist/errors/query-and-component-errors.d.ts.map +1 -1
  22. package/dist/errors/validation-errors.d.ts +24 -0
  23. package/dist/errors/validation-errors.d.ts.map +1 -1
  24. package/dist/errors.d.ts +14 -2
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/externalization/index.mjs.map +1 -1
  27. package/dist/index.mjs +977 -255
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/internal.d.ts +18 -0
  30. package/dist/internal.d.ts.map +1 -0
  31. package/dist/internal.mjs +20 -2
  32. package/dist/internal.mjs.map +1 -1
  33. package/dist/projection/index.d.ts +27 -52
  34. package/dist/projection/index.d.ts.map +1 -1
  35. package/dist/projection/index.mjs +66 -76
  36. package/dist/projection/index.mjs.map +1 -1
  37. package/dist/query/derived-range-writer.d.ts +62 -0
  38. package/dist/query/derived-range-writer.d.ts.map +1 -0
  39. package/dist/query/query.d.ts +1 -1
  40. package/dist/query/query.d.ts.map +1 -1
  41. package/dist/relationship-index.d.ts +8 -0
  42. package/dist/relationship-index.d.ts.map +1 -1
  43. package/dist/shared-ref-store.d.ts +5 -9
  44. package/dist/shared-ref-store.d.ts.map +1 -1
  45. package/dist/shared.mjs.map +1 -1
  46. package/dist/storage/change-detection.d.ts +1 -3
  47. package/dist/storage/change-detection.d.ts.map +1 -1
  48. package/dist/storage/structural-evidence.d.ts +30 -0
  49. package/dist/storage/structural-evidence.d.ts.map +1 -0
  50. package/dist/world-component-access.d.ts +65 -19
  51. package/dist/world-component-access.d.ts.map +1 -1
  52. package/dist/world-component-storage.d.ts +26 -10
  53. package/dist/world-component-storage.d.ts.map +1 -1
  54. package/dist/world-core.d.ts +2 -2
  55. package/dist/world-core.d.ts.map +1 -1
  56. package/dist/world-entity-lifecycle.d.ts.map +1 -1
  57. package/dist/world-internal.d.ts +1 -1
  58. package/dist/world-internal.d.ts.map +1 -1
  59. package/dist/world.d.ts +15 -14
  60. package/dist/world.d.ts.map +1 -1
  61. package/package.json +5 -5
  62. package/src/__tests__/changed-block-summary.candidate.test.ts +57 -0
  63. package/src/__tests__/component-requirements.unit.test.ts +76 -0
  64. package/src/__tests__/component-version-surface.test.ts +45 -0
  65. package/src/__tests__/derived-range-writer.contract.test-d.ts +35 -0
  66. package/src/__tests__/derived-range-writer.contract.test.ts +339 -0
  67. package/src/__tests__/errors.unit.test.ts +21 -5
  68. package/src/__tests__/externalization-render-read-lease.test-d.ts +1 -1
  69. package/src/__tests__/externalization-render-read-lease.unit.test.ts +15 -15
  70. package/src/__tests__/query-storage-trends.perf.test.ts +19 -0
  71. package/src/__tests__/query.unit.test.ts +10 -6
  72. package/src/__tests__/relationship-index.test.ts +147 -1
  73. package/src/__tests__/shared-ref-store.unit.test.ts +3 -8
  74. package/src/__tests__/structural-evidence.contract.test-d.ts +6 -0
  75. package/src/__tests__/structural-evidence.contract.test.ts +49 -0
  76. package/src/component-schema.ts +51 -0
  77. package/src/component.ts +21 -8
  78. package/src/errors/query-and-component-errors.ts +4 -1
  79. package/src/errors/validation-errors.ts +30 -0
  80. package/src/errors.ts +29 -5
  81. package/src/internal.ts +59 -0
  82. package/src/projection/index.ts +68 -149
  83. package/src/query/derived-range-writer.ts +443 -0
  84. package/src/query/query.ts +115 -16
  85. package/src/relationship-index.ts +13 -1
  86. package/src/shared-ref-store.ts +16 -24
  87. package/src/storage/change-detection.ts +0 -15
  88. package/src/storage/structural-evidence.ts +64 -0
  89. package/src/world-component-access.ts +479 -130
  90. package/src/world-component-storage.ts +104 -18
  91. package/src/world-core.ts +2 -2
  92. package/src/world-entity-lifecycle.ts +59 -10
  93. package/src/world-internal.ts +10 -5
  94. package/src/world.ts +97 -53
  95. package/dist/.tsbuildinfo +0 -1
  96. package/dist/__tests__/world-change-journal.unit.test.d.ts +0 -2
  97. package/dist/__tests__/world-change-journal.unit.test.d.ts.map +0 -1
  98. package/dist/__tests__/world-internal-identity.unit.test.d.ts +0 -2
  99. package/dist/__tests__/world-internal-identity.unit.test.d.ts.map +0 -1
  100. package/dist/world-change-journal.d.ts +0 -34
  101. package/dist/world-change-journal.d.ts.map +0 -1
  102. package/src/__tests__/world-change-journal.unit.test.ts +0 -97
  103. package/src/__tests__/world-internal-identity.unit.test.ts +0 -17
  104. package/src/world-change-journal.ts +0 -84
@@ -2,35 +2,12 @@ import type { Result } from '@forgeax/engine-types';
2
2
  import type { Component } from '../component';
3
3
  import type { EntityHandle } from '../entity-handle';
4
4
  import type { SharedRefMutationRead } from '../shared-ref-store';
5
- import type { WorldChangeRead } from '../storage/change-detection';
5
+ import type { StructuralEvidenceRead } from '../storage/structural-evidence';
6
6
  import type { EcsError, World } from '../world';
7
7
  export { fillComponentDefaults } from '../component-default-fallback';
8
8
  export { ComponentNotDefinedError, InstanceTransformsStrideMismatchError, ManagedBufferOutOfBoundsError, ResourceInvalidValueError, SpawnLightInvalidBoundsError, SpriteAnimationInvalidError, SpriteInstancesCountMismatchError, SpriteInstancesMutuallyExclusiveWithInstancesError, SpriteInstancesRequiresSpriteShaderError, StaleEntityError, } from '../errors';
9
- export type ProjectionChangeKind = 'component-added' | 'component-changed' | 'component-removed' | 'derived-component-changed' | 'entity-removed';
10
- export interface ProjectionChange {
11
- readonly entity: EntityHandle;
12
- readonly kind: ProjectionChangeKind;
13
- /** Token identity is the owner-facing component discriminator. */
14
- readonly component?: Component;
15
- /** Numeric id remains journal evidence for ECS-internal consumers. */
16
- readonly componentId?: number;
17
- }
18
- export type ProjectionRead = {
19
- readonly status: 'delta';
20
- readonly cursor: number;
21
- readonly changes: readonly ProjectionChange[];
22
- } | {
23
- readonly status: 'rebuild';
24
- readonly cursor: number;
25
- readonly reason: 'journal-overflow';
26
- };
27
- export interface WorldProjection {
28
- readonly cursor: number;
29
- poll(): ProjectionRead;
30
- }
31
- export interface WorldProjectionOptions {
32
- readonly components?: readonly Component[];
33
- }
9
+ /** Read producer-owned typed structural facts without inferring from a World scan. */
10
+ export declare function readStructuralEvidence(world: World, cursor: number): StructuralEvidenceRead;
34
11
  export interface RenderProjectionComponentRequest {
35
12
  readonly component: Component;
36
13
  readonly fields: readonly string[];
@@ -49,29 +26,30 @@ export interface RenderProjectionSpans {
49
26
  }
50
27
  export interface RenderChangeBatchOk {
51
28
  readonly status: 'ok';
52
- readonly cursor: number;
53
- readonly world: Extract<WorldChangeRead, {
54
- readonly status: 'ok';
55
- }>;
56
- readonly sharedRefs: Extract<SharedRefMutationRead, {
57
- readonly status: 'ok';
58
- }>;
29
+ readonly version: RenderReadVersion;
30
+ readonly world: RenderWorldChanges;
31
+ readonly sharedRefs: SharedRefMutationRead;
59
32
  }
60
- export interface RenderChangeBatchOverflow {
61
- readonly status: 'overflow';
62
- readonly cursor: number;
33
+ export interface RenderChangeBatchRebuild {
34
+ readonly status: 'rebuild';
35
+ readonly version: RenderReadVersion;
63
36
  readonly resync: true;
64
- readonly oldestAvailable: number;
65
- readonly world: WorldChangeRead;
37
+ readonly reason: 'structure-changed';
38
+ readonly world: RenderWorldChanges;
66
39
  readonly sharedRefs: SharedRefMutationRead;
67
40
  }
68
- export type RenderChangeBatch = RenderChangeBatchOk | RenderChangeBatchOverflow;
41
+ export interface RenderWorldChanges {
42
+ readonly fromEpoch: number;
43
+ readonly toEpoch: number;
44
+ readonly changedComponentIds: readonly number[];
45
+ }
46
+ export type RenderChangeBatch = RenderChangeBatchOk | RenderChangeBatchRebuild;
69
47
  export interface RenderReadLease {
70
48
  readonly worldIdentity: string;
71
49
  readonly generation: number;
72
- readChanges(cursor: number): RenderChangeBatch;
50
+ readChanges(version: RenderReadVersion): RenderChangeBatch;
73
51
  querySpans(request: RenderProjectionRequest): RenderProjectionSpans;
74
- inspectCursor(): number;
52
+ captureVersion(): RenderReadVersion;
75
53
  dispose(): void;
76
54
  }
77
55
  /**
@@ -80,24 +58,21 @@ export interface RenderReadLease {
80
58
  * transform/instance columns; the World internals remain owned by ECS.
81
59
  */
82
60
  export declare function readRenderArrayView(world: World, entity: EntityHandle, component: Component, fieldName: string): ArrayLike<number> | undefined;
61
+ export interface RenderReadVersion {
62
+ readonly mutationEpoch: number;
63
+ readonly structureEpoch: number;
64
+ readonly sharedRefEpoch: number;
65
+ }
83
66
  /** Create the render-owned lease from the ECS projection boundary. */
84
67
  export declare function createRenderReadLease(world: World, token?: object): RenderReadLease;
85
68
  /**
86
- * Publish one owner-derived component value without confusing it with an
87
- * authored mutation. Owner packages use this narrow seam for fields such as
88
- * `Transform.world`: the write still passes through ECS validation and managed
89
- * storage, while the journal records a `derived-component-changed` fact for
90
- * incremental projections.
69
+ * Publish one owner-derived component value through the component's ordinary
70
+ * version. Numeric consumers observe the same row epoch regardless of which
71
+ * owner computed the value; there is no parallel derived-change vocabulary.
91
72
  */
92
73
  export declare function setDerivedComponent(world: World, entity: EntityHandle, component: Component, value: Record<string, unknown>): Result<void, EcsError>;
93
74
  /** Route an owner-domain error through the World without exposing raw internals. */
94
75
  export declare function routeWorldError(world: World, error: unknown, context?: {
95
76
  readonly systemName: string;
96
77
  }): void;
97
- /**
98
- * Create the narrow incremental evidence surface for an owner projection.
99
- * Rebuilds intentionally return a reason; complete data always comes from
100
- * the owner's regular Query/QuerySpan path.
101
- */
102
- export declare function createWorldProjection(world: World, options?: WorldProjectionOptions): WorldProjection;
103
78
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":"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"}
@@ -122,6 +122,30 @@ var SpriteInstancesMutuallyExclusiveWithInstancesError = class extends Error {
122
122
 
123
123
  // src/errors/validation-errors.ts
124
124
  var SPAWN_LIGHT_INVALID_BOUNDS_POLICY = {
125
+ intensity: {
126
+ expected: "intensity is finite and >= 0",
127
+ hint: (componentName, got) => `${componentName}.intensity must be a finite non-negative number (got ${got})`
128
+ },
129
+ color: {
130
+ expected: "color is a finite non-negative [r, g, b] vector",
131
+ hint: (componentName, got) => `${componentName}.color must contain three finite non-negative channels (got ${JSON.stringify(got)})`
132
+ },
133
+ width: {
134
+ expected: "width is finite and > 0",
135
+ hint: (componentName, got) => `${componentName}.width must be a finite positive meter value (got ${got})`
136
+ },
137
+ height: {
138
+ expected: "height is finite and > 0",
139
+ hint: (componentName, got) => `${componentName}.height must be a finite positive meter value (got ${got})`
140
+ },
141
+ irradiance: {
142
+ expected: "irradiance is a finite 27-value SH vector",
143
+ hint: (componentName, got) => `${componentName}.irradiance must contain 27 finite SH values (got ${JSON.stringify(got)})`
144
+ },
145
+ radius: {
146
+ expected: "radius is finite and >= R_MIN",
147
+ hint: (componentName, got) => `${componentName}.radius must be a finite value >= R_MIN (got ${got})`
148
+ },
125
149
  range: {
126
150
  expected: "range >= 0 or Number.POSITIVE_INFINITY",
127
151
  hint: (componentName, got) => `${componentName}.range = ${got} is invalid; use Number.POSITIVE_INFINITY for unlimited range, or a non-negative meter value`
@@ -467,6 +491,9 @@ function fillComponentDefaults(token, raw) {
467
491
  }
468
492
 
469
493
  // src/projection/index.ts
494
+ function readStructuralEvidence(world, cursor) {
495
+ return world[worldInternal].getStructuralEvidence().readAfter(cursor);
496
+ }
470
497
  function readRenderArrayView(world, entity, component, fieldName) {
471
498
  return world[worldInternal].getArrayView(entity, component, fieldName);
472
499
  }
@@ -501,115 +528,78 @@ function readProjectionSpans(world, generation, request) {
501
528
  }
502
529
  function createRenderReadLease(world, token = {}) {
503
530
  const sharedRefs = world[worldInternal].getSharedRefs();
504
- const generation = Math.max(1, world[worldInternal].getStructureEpoch());
505
531
  let disposed = false;
506
- let nextCursor = 1;
507
- const cursors = /* @__PURE__ */ new Map([
508
- [
509
- 0,
510
- { world: world[worldInternal].getChangeCursor(), sharedRefs: sharedRefs.getMutationEpoch() }
511
- ]
512
- ]);
513
532
  const assertLive = () => {
514
533
  if (disposed) throw new Error("RenderReadLease is disposed.");
515
534
  };
516
- const captureCursor = () => {
517
- const cursor = nextCursor++;
518
- cursors.set(cursor, {
519
- world: world[worldInternal].getChangeCursor(),
520
- sharedRefs: sharedRefs.getMutationEpoch()
521
- });
522
- if (cursors.size > 8) {
523
- const oldest = cursors.keys().next().value;
524
- if (typeof oldest === "number" && oldest !== cursor) cursors.delete(oldest);
525
- }
526
- return cursor;
535
+ const captureVersion = () => {
536
+ return {
537
+ mutationEpoch: world[worldInternal].getMutationEpoch(),
538
+ structureEpoch: world[worldInternal].getStructureEpoch(),
539
+ sharedRefEpoch: sharedRefs.getMutationEpoch()
540
+ };
527
541
  };
528
542
  return {
529
543
  worldIdentity: world.identity,
530
- generation,
531
- inspectCursor() {
544
+ get generation() {
545
+ return Math.max(1, world[worldInternal].getStructureEpoch());
546
+ },
547
+ captureVersion() {
532
548
  assertLive();
533
- return captureCursor();
549
+ return captureVersion();
534
550
  },
535
- readChanges(cursor) {
551
+ readChanges(start) {
536
552
  assertLive();
537
- const start = cursors.get(cursor);
538
- if (start === void 0) throw new RangeError(`Unknown RenderReadLease cursor ${cursor}.`);
539
- const worldRead = world[worldInternal].readChangesSince(start.world);
540
- const sharedRead = sharedRefs.readChangesSince(start.sharedRefs);
541
- const next = captureCursor();
542
- if (worldRead.status === "overflow" || sharedRead.status === "overflow") {
543
- const oldestAvailable = Math.min(
544
- worldRead.status === "overflow" ? worldRead.oldestAvailable : Number.MAX_SAFE_INTEGER,
545
- sharedRead.status === "overflow" ? sharedRead.oldestAvailable : Number.MAX_SAFE_INTEGER
546
- );
553
+ const toEpoch = world[worldInternal].getMutationEpoch();
554
+ const componentEpochs = world[worldInternal].getComponentMutationEpochs();
555
+ const changedComponentIds = [];
556
+ for (let componentId2 = 0; componentId2 < componentEpochs.length; componentId2 += 1) {
557
+ const epoch = componentEpochs[componentId2] ?? 0;
558
+ if (epoch > start.mutationEpoch && epoch <= toEpoch) changedComponentIds.push(componentId2);
559
+ }
560
+ const worldRead = {
561
+ fromEpoch: start.mutationEpoch,
562
+ toEpoch,
563
+ changedComponentIds
564
+ };
565
+ const sharedRead = sharedRefs.readChangesSince(start.sharedRefEpoch);
566
+ const version = captureVersion();
567
+ const structureChanged = start.structureEpoch !== world[worldInternal].getStructureEpoch();
568
+ if (structureChanged) {
547
569
  return {
548
- status: "overflow",
549
- cursor: next,
570
+ status: "rebuild",
571
+ version,
550
572
  resync: true,
551
- oldestAvailable,
573
+ reason: "structure-changed",
552
574
  world: worldRead,
553
575
  sharedRefs: sharedRead
554
576
  };
555
577
  }
556
- return { status: "ok", cursor: next, world: worldRead, sharedRefs: sharedRead };
578
+ return { status: "ok", version, world: worldRead, sharedRefs: sharedRead };
557
579
  },
558
580
  querySpans(request) {
559
581
  assertLive();
560
- return readProjectionSpans(world, generation, request);
582
+ return readProjectionSpans(
583
+ world,
584
+ Math.max(1, world[worldInternal].getStructureEpoch()),
585
+ request
586
+ );
561
587
  },
562
588
  dispose() {
563
589
  disposed = true;
564
- cursors.clear();
565
590
  }
566
591
  };
567
592
  }
568
593
  function setDerivedComponent(world, entity, component, value) {
569
594
  const result = world[worldInternal].setQueryRow(entity, component, value);
570
595
  if (!result.ok) return result;
571
- world[worldInternal].markDerivedComponentChanges(componentId(component), [entity]);
596
+ world[worldInternal].markComponentChanged(entity, componentId(component));
572
597
  return result;
573
598
  }
574
599
  function routeWorldError(world, error, context) {
575
600
  world[worldInternal].routeError(error, context);
576
601
  }
577
- function createWorldProjection(world, options = {}) {
578
- const componentById = options.components === void 0 ? void 0 : new Map(options.components.map((component) => [componentId(component), component]));
579
- const componentIds = componentById === void 0 ? void 0 : new Set(componentById.keys());
580
- let cursor = world[worldInternal].getChangeCursor();
581
- const pollSince = (requestedCursor) => {
582
- const result = world[worldInternal].readChangesSince(requestedCursor);
583
- if (result.status === "overflow") {
584
- cursor = result.cursor;
585
- return { status: "rebuild", cursor, reason: "journal-overflow" };
586
- }
587
- cursor = result.cursor;
588
- const changes = [];
589
- for (const record of result.records) {
590
- if (componentIds !== void 0 && record.kind !== "entity-removed" && (record.componentId === void 0 || !componentIds.has(record.componentId))) {
591
- continue;
592
- }
593
- const component = record.componentId === void 0 ? void 0 : componentById?.get(record.componentId);
594
- changes.push({
595
- entity: record.entity,
596
- kind: record.kind,
597
- ...component === void 0 ? {} : { component },
598
- ...record.componentId === void 0 ? {} : { componentId: record.componentId }
599
- });
600
- }
601
- return { status: "delta", cursor, changes };
602
- };
603
- return {
604
- get cursor() {
605
- return cursor;
606
- },
607
- poll() {
608
- return pollSince(cursor);
609
- }
610
- };
611
- }
612
602
 
613
- export { ComponentNotDefinedError, InstanceTransformsStrideMismatchError, ManagedBufferOutOfBoundsError, ResourceInvalidValueError, SpawnLightInvalidBoundsError, SpriteAnimationInvalidError, SpriteInstancesCountMismatchError, SpriteInstancesMutuallyExclusiveWithInstancesError, SpriteInstancesRequiresSpriteShaderError, StaleEntityError, createRenderReadLease, createWorldProjection, fillComponentDefaults, readRenderArrayView, routeWorldError, setDerivedComponent };
603
+ export { ComponentNotDefinedError, InstanceTransformsStrideMismatchError, ManagedBufferOutOfBoundsError, ResourceInvalidValueError, SpawnLightInvalidBoundsError, SpriteAnimationInvalidError, SpriteInstancesCountMismatchError, SpriteInstancesMutuallyExclusiveWithInstancesError, SpriteInstancesRequiresSpriteShaderError, StaleEntityError, createRenderReadLease, fillComponentDefaults, readRenderArrayView, readStructuralEvidence, routeWorldError, setDerivedComponent };
614
604
  //# sourceMappingURL=index.mjs.map
615
605
  //# sourceMappingURL=index.mjs.map