@almadar/runtime 6.8.1 → 6.9.1

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.
@@ -1,4 +1,4 @@
1
- export { InMemoryPersistence, OrbitalServerRuntime, collectDeclaredConfigDefaults, createOrbitalServerRuntime } from './chunk-L3FDWEQL.js';
1
+ export { InMemoryPersistence, OrbitalServerRuntime, collectDeclaredConfigDefaults, createOrbitalServerRuntime } from './chunk-6W74ZCFQ.js';
2
2
  import './chunk-PZ5AY32C.js';
3
3
  //# sourceMappingURL=OrbitalServerRuntime.js.map
4
4
  //# sourceMappingURL=OrbitalServerRuntime.js.map
@@ -1764,6 +1764,51 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1764
1764
  const count = seedCount ?? this.config.defaultSeedCount ?? 6;
1765
1765
  this.seed(schema.name, schema.fields, count);
1766
1766
  }
1767
+ this.linkRelationFields();
1768
+ }
1769
+ /**
1770
+ * Walk every row of every registered entity and fill in `type: "relation"`
1771
+ * fields with real IDs from the target entity's store. Without this pass,
1772
+ * relation fields stay as placeholder `[]` / `""` and `populateRelations`
1773
+ * in OrbitalServerRuntime has nothing to hydrate — catalog/preview demos
1774
+ * of nested-tree atoms (e.g. std-thread-comments-linear with ThreadPost.
1775
+ * replies → [ThreadPost]) render empty reply cards.
1776
+ *
1777
+ * For self-referential relations, each row gets 2–4 sibling IDs (excluding
1778
+ * self). For cross-entity relations, IDs are picked from the target store.
1779
+ * The runtime caps recursion at depth=2 in `populateRelations`, so
1780
+ * grandparent-of-self cycles render two levels deep then stop.
1781
+ */
1782
+ linkRelationFields() {
1783
+ for (const [normalizedName, schema] of this.schemas) {
1784
+ const store = this.stores.get(normalizedName);
1785
+ if (!store) continue;
1786
+ const relationFields = schema.fields.filter(
1787
+ (f) => f.type === "relation"
1788
+ );
1789
+ if (relationFields.length === 0) continue;
1790
+ for (const row of store.values()) {
1791
+ for (const field of relationFields) {
1792
+ const targetStore = this.stores.get(field.relation.entity.toLowerCase());
1793
+ if (!targetStore || targetStore.size === 0) continue;
1794
+ const selfId = row["id"];
1795
+ const sameStore = targetStore === store;
1796
+ const eligible = [];
1797
+ for (const id of targetStore.keys()) {
1798
+ if (sameStore && id === selfId) continue;
1799
+ eligible.push(id);
1800
+ }
1801
+ if (eligible.length === 0) continue;
1802
+ const cardinality = field.relation.cardinality ?? "many";
1803
+ if (cardinality === "one" || cardinality === "many-to-one") {
1804
+ row[field.name] = faker.helpers.arrayElement(eligible);
1805
+ } else {
1806
+ const pickCount = Math.min(eligible.length, faker.number.int({ min: 2, max: 4 }));
1807
+ row[field.name] = faker.helpers.shuffle(eligible.slice()).slice(0, pickCount);
1808
+ }
1809
+ }
1810
+ }
1811
+ }
1767
1812
  }
1768
1813
  /**
1769
1814
  * Seed an entity with pre-authored instance data.
@@ -1815,6 +1860,7 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1815
1860
  updatedAt: SEED_REFERENCE_TIMESTAMP
1816
1861
  };
1817
1862
  for (const field of fields) {
1863
+ if (!field.name) continue;
1818
1864
  if (field.name === "id" || field.name === "createdAt" || field.name === "updatedAt") {
1819
1865
  continue;
1820
1866
  }
@@ -1834,13 +1880,14 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1834
1880
  */
1835
1881
  generateFieldValue(entityName, field, index, depth = 0) {
1836
1882
  const fieldTypeLc = field.type.toLowerCase();
1883
+ const values = "values" in field ? field.values : void 0;
1837
1884
  mockLog.debug("field:generate", {
1838
1885
  entityName,
1839
1886
  fieldName: field.name,
1840
1887
  fieldType: fieldTypeLc,
1841
- hasValues: !!field.values?.length,
1842
- valuesCount: field.values?.length ?? 0,
1843
- values: field.values?.length ? field.values.join(",") : null,
1888
+ hasValues: !!values?.length,
1889
+ valuesCount: values?.length ?? 0,
1890
+ values: values?.length ? values.join(",") : null,
1844
1891
  format: field.format ?? null,
1845
1892
  hasDefault: field.default !== void 0
1846
1893
  });
@@ -1848,7 +1895,7 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1848
1895
  if (isNumeric && field.default !== void 0) {
1849
1896
  return field.default;
1850
1897
  }
1851
- switch (fieldTypeLc) {
1898
+ switch (field.type) {
1852
1899
  case "string":
1853
1900
  return this.generateStringValue(entityName, field, index);
1854
1901
  case "number":
@@ -1865,8 +1912,7 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1865
1912
  }
1866
1913
  return null;
1867
1914
  case "relation":
1868
- return null;
1869
- // Relations need special handling
1915
+ return field.relation?.cardinality === "one" ? "" : [];
1870
1916
  case "array":
1871
1917
  return this.generateArrayValue(entityName, field, index, depth);
1872
1918
  case "object":
@@ -1885,14 +1931,15 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1885
1931
  * behavior.
1886
1932
  */
1887
1933
  generateArrayValue(entityName, field, index, depth = 0) {
1888
- if (!field.items) return [];
1934
+ if (field.type !== "array" || !field.items) return [];
1889
1935
  if (depth >= _MockPersistenceAdapter.MAX_NESTED_DEPTH) return [];
1890
1936
  const count = faker.number.int({ min: 3, max: 5 });
1891
1937
  const out = [];
1938
+ const elementName = field.name ?? "item";
1892
1939
  for (let i = 0; i < count; i++) {
1893
1940
  const elementField = {
1894
1941
  ...field.items,
1895
- name: `${field.name}[${i}]`
1942
+ name: `${elementName}[${i}]`
1896
1943
  };
1897
1944
  out.push(this.generateFieldValue(entityName, elementField, index * 10 + i, depth + 1));
1898
1945
  }
@@ -1922,9 +1969,11 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1922
1969
  * declare `format: "email"`; if they need an enum, they declare `values: [...]`.
1923
1970
  */
1924
1971
  generateStringValue(entityName, field, _index) {
1925
- if (field.values && field.values.length > 0) {
1926
- return faker.helpers.arrayElement(field.values);
1972
+ const values = "values" in field ? field.values : void 0;
1973
+ if (values && values.length > 0) {
1974
+ return faker.helpers.arrayElement(values);
1927
1975
  }
1976
+ const fieldName = field.name ?? "field";
1928
1977
  switch (field.format) {
1929
1978
  case "email":
1930
1979
  return faker.internet.email();
@@ -1941,11 +1990,11 @@ var MockPersistenceAdapter = class _MockPersistenceAdapter {
1941
1990
  case "image":
1942
1991
  case "avatar":
1943
1992
  case "thumbnail":
1944
- return picsumUrl(entityName, field.name);
1993
+ return picsumUrl(entityName, fieldName);
1945
1994
  }
1946
- const lname = field.name.toLowerCase();
1995
+ const lname = fieldName.toLowerCase();
1947
1996
  if (lname === "image" || lname === "imageurl" || lname === "image_url" || lname === "photo" || lname === "photourl" || lname === "photo_url" || lname === "avatar" || lname === "avatarurl" || lname === "avatar_url" || lname === "thumbnail" || lname === "thumbnailurl" || lname === "thumbnail_url" || lname === "picture" || lname === "pictureurl" || lname === "cover" || lname === "coverurl" || lname === "banner" || lname === "bannerurl") {
1948
- return picsumUrl(entityName, field.name);
1997
+ return picsumUrl(entityName, fieldName);
1949
1998
  }
1950
1999
  const value = faker.lorem.words(2);
1951
2000
  mockLog.debug("field:fallback-lorem", () => ({
@@ -3635,32 +3684,6 @@ function needsPreprocessing(schema) {
3635
3684
  }
3636
3685
  return false;
3637
3686
  }
3638
- function mapFieldForMock(f) {
3639
- const rec = f;
3640
- const out = {
3641
- name: f.name,
3642
- type: rec["type"]
3643
- };
3644
- if (typeof rec["required"] === "boolean") out.required = rec["required"];
3645
- if (Array.isArray(rec["values"])) out.values = rec["values"];
3646
- if (rec["default"] !== void 0) out.default = rec["default"];
3647
- if (typeof rec["format"] === "string") out.format = rec["format"];
3648
- const items = rec["items"];
3649
- if (items && typeof items === "object" && "type" in items) {
3650
- out.items = mapFieldForMock({ name: "", ...items });
3651
- }
3652
- const properties = rec["properties"];
3653
- if (properties && typeof properties === "object" && !Array.isArray(properties)) {
3654
- const propsOut = {};
3655
- for (const [k, v] of Object.entries(properties)) {
3656
- if (v && typeof v === "object" && "type" in v) {
3657
- propsOut[k] = mapFieldForMock({ name: k, ...v });
3658
- }
3659
- }
3660
- if (Object.keys(propsOut).length > 0) out.properties = propsOut;
3661
- }
3662
- return out;
3663
- }
3664
3687
  var OrbitalServerRuntime = class {
3665
3688
  orbitals = /* @__PURE__ */ new Map();
3666
3689
  eventBus;
@@ -4077,7 +4100,7 @@ var OrbitalServerRuntime = class {
4077
4100
  if (entity?.name && entity.fields) {
4078
4101
  const fields = entity.fields.filter(
4079
4102
  (f) => typeof f.name === "string" && f.name.length > 0
4080
- ).map((f) => mapFieldForMock(f));
4103
+ );
4081
4104
  this.persistence.registerEntity({ name: entity.name, fields });
4082
4105
  if (this.config.debug) {
4083
4106
  persistLog.debug("mock:seeded", { entity: entity.name, count: this.persistence.count(entity.name) });
@@ -4092,7 +4115,7 @@ var OrbitalServerRuntime = class {
4092
4115
  if (!auxEntity.name || !auxEntity.fields) continue;
4093
4116
  const auxFields = auxEntity.fields.filter(
4094
4117
  (f) => typeof f.name === "string" && f.name.length > 0
4095
- ).map((f) => mapFieldForMock(f));
4118
+ );
4096
4119
  this.persistence.registerEntity({ name: auxEntity.name, fields: auxFields });
4097
4120
  if (this.config.debug) {
4098
4121
  persistLog.debug("mock:seeded-auxiliary", {
@@ -4374,7 +4397,7 @@ var OrbitalServerRuntime = class {
4374
4397
  if (entity?.name && entity.fields) {
4375
4398
  const fields = entity.fields.filter(
4376
4399
  (f) => typeof f.name === "string" && f.name.length > 0
4377
- ).map((f) => mapFieldForMock(f));
4400
+ );
4378
4401
  this.persistence.registerEntity({ name: entity.name, fields });
4379
4402
  }
4380
4403
  }
@@ -5233,12 +5256,20 @@ var OrbitalServerRuntime = class {
5233
5256
  }
5234
5257
  }
5235
5258
  const populatedFieldName = includeField.endsWith("Id") ? includeField.slice(0, -2) : includeField;
5259
+ const isSelfRef = relatedEntityType === entityType;
5260
+ const hydrateClone = (id) => {
5261
+ const related = relatedEntities.get(id);
5262
+ if (!related) return void 0;
5263
+ const copy = { ...related };
5264
+ if (isSelfRef) copy[foreignKeyField] = [];
5265
+ return copy;
5266
+ };
5236
5267
  for (const entity of entities) {
5237
5268
  const fkValue = entity[foreignKeyField];
5238
5269
  if (cardinality === "one" || cardinality === "many-to-one") {
5239
5270
  if (typeof fkValue === "string" && relatedEntities.has(fkValue)) {
5240
5271
  Object.defineProperty(entity, populatedFieldName, {
5241
- value: relatedEntities.get(fkValue),
5272
+ value: hydrateClone(fkValue),
5242
5273
  writable: true,
5243
5274
  enumerable: true,
5244
5275
  configurable: true
@@ -5248,14 +5279,14 @@ var OrbitalServerRuntime = class {
5248
5279
  if (Array.isArray(fkValue)) {
5249
5280
  const fkIds = fkValue.filter((id) => typeof id === "string");
5250
5281
  Object.defineProperty(entity, populatedFieldName, {
5251
- value: fkIds.map((id) => relatedEntities.get(id)).filter(Boolean),
5282
+ value: fkIds.map(hydrateClone).filter(Boolean),
5252
5283
  writable: true,
5253
5284
  enumerable: true,
5254
5285
  configurable: true
5255
5286
  });
5256
5287
  } else if (typeof fkValue === "string" && relatedEntities.has(fkValue)) {
5257
5288
  Object.defineProperty(entity, populatedFieldName, {
5258
- value: [relatedEntities.get(fkValue)],
5289
+ value: [hydrateClone(fkValue)],
5259
5290
  writable: true,
5260
5291
  enumerable: true,
5261
5292
  configurable: true
@@ -5452,5 +5483,5 @@ function buildMatcher(src, listenerOrbital) {
5452
5483
  }
5453
5484
 
5454
5485
  export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, OrbitalServerRuntime, StateMachineManager, buildEmitsFromTraits, collectDeclaredConfigDefaults, containsBindings, createContextFromBindings, createInitialTraitState, createMockPersistence, createOrbitalServerRuntime, createTestExecutor, createUnifiedLoader, extractBindings, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isBrowser, isElectron, isNamespacedEvent, isNode, normalizeEventKey, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes };
5455
- //# sourceMappingURL=chunk-L3FDWEQL.js.map
5456
- //# sourceMappingURL=chunk-L3FDWEQL.js.map
5486
+ //# sourceMappingURL=chunk-6W74ZCFQ.js.map
5487
+ //# sourceMappingURL=chunk-6W74ZCFQ.js.map