@almadar/runtime 6.32.0 → 6.34.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.
@@ -1,12 +1,37 @@
1
- import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, createContextFromBindings, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, collectDeclaredEntityDefaults, EffectExecutor } from './chunk-YFH577FH.js';
2
- export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-YFH577FH.js';
1
+ import { createTickScheduler, EventBus, createUnifiedLoader, MockPersistenceAdapter, InMemoryPersistence, preprocessSchema, normalizeCallSiteConfigToValues, StateMachineManager, parseDurationString, createContextFromBindings, validateEventPayload, formatPayloadValidationError, collectDeclaredConfigDefaults, resolveCallSitePayloadCaptures, collectDeclaredEntityDefaults, EffectExecutor } from './chunk-TRA44DDY.js';
2
+ export { InMemoryPersistence, collectDeclaredConfigDefaults } from './chunk-TRA44DDY.js';
3
3
  import { isValidCronExpression } from './chunk-OU3ITB5S.js';
4
+ import './chunk-OQJIK6PZ.js';
5
+ import './chunk-SCRAHWOC.js';
4
6
  import './chunk-MLKGABMK.js';
5
7
  import { createLogger } from '@almadar/logger';
6
8
  import * as nodeModule from 'module';
7
9
  import { evaluateGuard, evaluate } from '@almadar/evaluator';
8
- import { isInlineTrait, isEntityCall } from '@almadar/core';
10
+ import { buildResolvedTraitConfigs, isInlineTrait, isEntityCall } from '@almadar/core';
9
11
 
12
+ // src/identity/routing.ts
13
+ function eventRouteKey(eventName, eventId) {
14
+ return eventId ? `@evt:${eventId}` : eventName;
15
+ }
16
+ function buildSourceMatcher(src, listenerOrbital) {
17
+ if (src.kind === "any") return () => true;
18
+ if (src.kind === "trait") {
19
+ if (src.traitId !== void 0) {
20
+ const wantedTraitId = src.traitId;
21
+ return (source) => !!source && source.traitId === wantedTraitId;
22
+ }
23
+ const wantedTrait2 = src.trait;
24
+ return (source) => !!source && source.orbital === listenerOrbital && source.trait === wantedTrait2;
25
+ }
26
+ if (src.orbitalId !== void 0 && src.traitId !== void 0) {
27
+ const wantedOrbitalId = src.orbitalId;
28
+ const wantedTraitId = src.traitId;
29
+ return (source) => !!source && source.orbitalId === wantedOrbitalId && source.traitId === wantedTraitId;
30
+ }
31
+ const wantedOrbital = src.orbital;
32
+ const wantedTrait = src.trait;
33
+ return (source) => !!source && source.orbital === wantedOrbital && source.trait === wantedTrait;
34
+ }
10
35
  var _resolvedNodeRequire = null;
11
36
  function nodeRequire(modulePath) {
12
37
  if (!_resolvedNodeRequire) {
@@ -72,6 +97,16 @@ var OrbitalServerRuntime = class {
72
97
  substrateHandlers = null;
73
98
  substrateHandlersPromise = null;
74
99
  resolvedSchema = null;
100
+ /**
101
+ * Trait name -> resolved `TraitConfig`, computed once per `register()` via
102
+ * `buildResolvedTraitConfigs` (`@almadar/core`). An embedded sub-trait's
103
+ * OWN declared config schema (`registered.traits` / `collectDeclaredConfigDefaults`)
104
+ * carries `@config.X` forwards verbatim — this map chains those through to
105
+ * the trait that actually embeds it (see `embedded-trait-config.ts` for the
106
+ * full rationale). Used as a fallback layer in `buildBindingContext` behind
107
+ * `declaredDefaults` and ahead of `callSiteOverride`.
108
+ */
109
+ resolvedTraitConfigs = {};
75
110
  constructor(config = {}) {
76
111
  this.config = {
77
112
  mode: "mock",
@@ -257,6 +292,7 @@ var OrbitalServerRuntime = class {
257
292
  this.setupEventListeners();
258
293
  this.setupTicks();
259
294
  this.resolvedSchema = schema;
295
+ this.resolvedTraitConfigs = buildResolvedTraitConfigs(schema);
260
296
  }
261
297
  /**
262
298
  * Register an OrbitalSchema synchronously (for backward compatibility).
@@ -273,6 +309,7 @@ var OrbitalServerRuntime = class {
273
309
  this.setupEventListeners();
274
310
  this.setupTicks();
275
311
  this.resolvedSchema = schema;
312
+ this.resolvedTraitConfigs = buildResolvedTraitConfigs(schema);
276
313
  }
277
314
  /**
278
315
  * Returns the schema that this runtime is currently executing, post-
@@ -440,6 +477,9 @@ var OrbitalServerRuntime = class {
440
477
  const states = sm?.states || [];
441
478
  const transitions = sm?.transitions || [];
442
479
  return {
480
+ // V4 dual-carry: thread the trait id so the manager's id index is
481
+ // populated for ledger-backed schemas (undefined → name-keyed only).
482
+ ...t.id !== void 0 ? { id: t.id } : {},
443
483
  name: t.name,
444
484
  states,
445
485
  transitions,
@@ -507,7 +547,7 @@ var OrbitalServerRuntime = class {
507
547
  const fields = entity.fields.filter(
508
548
  (f) => typeof f.name === "string" && f.name.length > 0
509
549
  );
510
- this.persistence.registerEntity({ name: entity.name, fields });
550
+ this.persistence.registerEntity({ name: entity.name, id: entity.id, fields });
511
551
  if (this.config.debug) {
512
552
  persistLog.debug("mock:seeded", { entity: entity.name, count: this.persistence.count(entity.name) });
513
553
  }
@@ -522,7 +562,7 @@ var OrbitalServerRuntime = class {
522
562
  const auxFields = auxEntity.fields.filter(
523
563
  (f) => typeof f.name === "string" && f.name.length > 0
524
564
  );
525
- this.persistence.registerEntity({ name: auxEntity.name, fields: auxFields });
565
+ this.persistence.registerEntity({ name: auxEntity.name, id: auxEntity.id, fields: auxFields });
526
566
  if (this.config.debug) {
527
567
  persistLog.debug("mock:seeded-auxiliary", {
528
568
  entity: auxEntity.name,
@@ -562,7 +602,8 @@ var OrbitalServerRuntime = class {
562
602
  if (!trait.listens) continue;
563
603
  for (const listener of trait.listens) {
564
604
  const { bareEvent, matcher } = parseListenSource(listener, orbitalName);
565
- const cleanup = this.eventBus.on(bareEvent, async (event) => {
605
+ const routeKey = eventRouteKey(bareEvent, listener.eventId);
606
+ const cleanup = this.eventBus.on(routeKey, async (event) => {
566
607
  if (!matcher(event.source)) return;
567
608
  if (this.config.debug) {
568
609
  xOrbitalLog.debug("listen:received", () => ({
@@ -593,6 +634,7 @@ var OrbitalServerRuntime = class {
593
634
  const forwardedEntityId = pickId("entityId") ?? pickId("orbitalName");
594
635
  await this.processOrbitalEvent(orbitalName, {
595
636
  event: listener.triggers,
637
+ eventId: listener.triggersId,
596
638
  payload: mappedPayload,
597
639
  entityId: forwardedEntityId
598
640
  });
@@ -798,7 +840,7 @@ var OrbitalServerRuntime = class {
798
840
  const fields = entity.fields.filter(
799
841
  (f) => typeof f.name === "string" && f.name.length > 0
800
842
  );
801
- this.persistence.registerEntity({ name: entity.name, fields });
843
+ this.persistence.registerEntity({ name: entity.name, id: entity.id, fields });
802
844
  }
803
845
  }
804
846
  }
@@ -814,146 +856,164 @@ var OrbitalServerRuntime = class {
814
856
  * response as they arrive rather than buffering and flushing at the end.
815
857
  */
816
858
  async processOrbitalEvent(orbitalName, request, onPush) {
817
- await this.ensureOsHandlers();
818
- await this.ensureAgentSubstrateHandlers();
819
- const registered = this.orbitals.get(orbitalName);
820
- if (!registered) {
821
- return {
822
- success: false,
823
- transitioned: false,
824
- states: {},
825
- emittedEvents: [],
826
- error: `Orbital not found: ${orbitalName}`
827
- };
828
- }
829
- const payloadRow = request.payload?.["row"];
830
- const payloadRowAsPayload = payloadRow !== null && typeof payloadRow === "object" && !Array.isArray(payloadRow) ? payloadRow : void 0;
831
- const payloadRowId = payloadRowAsPayload?.["id"];
832
- renderLog.debug("processOrbitalEvent:enter", {
833
- orbital: orbitalName,
834
- event: request.event,
835
- hasPayloadRow: payloadRowAsPayload !== void 0,
836
- payloadRowId: typeof payloadRowId === "string" || typeof payloadRowId === "number" ? payloadRowId : void 0,
837
- entityId: request.entityId
838
- });
839
- busLog.debug("bus:incoming", () => ({
840
- orbital: orbitalName,
841
- event: request.event,
842
- payload: JSON.stringify(request.payload ?? null),
843
- entityId: request.entityId,
844
- traitStates: JSON.stringify(
845
- Array.from(registered.manager.getAllStates().entries()).map(([traitName, state]) => ({
846
- traitName,
847
- currentState: state.currentState
848
- }))
849
- )
850
- }));
851
- xOrbitalLog.info("processOrbitalEvent:enter", () => ({
852
- orbital: orbitalName,
853
- event: request.event,
854
- traitsInOrbital: registered.traits.map((t) => t.name).join(","),
855
- payloadActiveTraits: JSON.stringify(
856
- request.payload?.["_activeTraits"] ?? null
857
- )
858
- }));
859
- const { event, payload, entityId, user } = request;
860
- const validationFailures = [];
861
- for (const trait of registered.traits) {
862
- const eventSchema = trait.stateMachine?.events?.find((e) => e.key === event);
863
- if (eventSchema?.payloadSchema && eventSchema.payloadSchema.length > 0) {
864
- validationFailures.push(
865
- ...validateEventPayload(event, payload, eventSchema.payloadSchema)
859
+ try {
860
+ await this.ensureOsHandlers();
861
+ await this.ensureAgentSubstrateHandlers();
862
+ const registered = this.orbitals.get(orbitalName);
863
+ if (!registered) {
864
+ return {
865
+ success: false,
866
+ transitioned: false,
867
+ states: {},
868
+ emittedEvents: [],
869
+ error: `Orbital not found: ${orbitalName}`
870
+ };
871
+ }
872
+ const payloadRow = request.payload?.["row"];
873
+ const payloadRowAsPayload = payloadRow !== null && typeof payloadRow === "object" && !Array.isArray(payloadRow) ? payloadRow : void 0;
874
+ const payloadRowId = payloadRowAsPayload?.["id"];
875
+ renderLog.debug("processOrbitalEvent:enter", {
876
+ orbital: orbitalName,
877
+ event: request.event,
878
+ hasPayloadRow: payloadRowAsPayload !== void 0,
879
+ payloadRowId: typeof payloadRowId === "string" || typeof payloadRowId === "number" ? payloadRowId : void 0,
880
+ entityId: request.entityId
881
+ });
882
+ busLog.debug("bus:incoming", () => ({
883
+ orbital: orbitalName,
884
+ event: request.event,
885
+ payload: JSON.stringify(request.payload ?? null),
886
+ entityId: request.entityId,
887
+ traitStates: JSON.stringify(
888
+ Array.from(registered.manager.getAllStates().entries()).map(([traitName, state]) => ({
889
+ traitName,
890
+ currentState: state.currentState
891
+ }))
892
+ )
893
+ }));
894
+ xOrbitalLog.info("processOrbitalEvent:enter", () => ({
895
+ orbital: orbitalName,
896
+ event: request.event,
897
+ traitsInOrbital: registered.traits.map((t) => t.name).join(","),
898
+ payloadActiveTraits: JSON.stringify(
899
+ request.payload?.["_activeTraits"] ?? null
900
+ )
901
+ }));
902
+ const { event, eventId, payload, entityId, user } = request;
903
+ const validationFailures = [];
904
+ for (const trait of registered.traits) {
905
+ const eventSchema = trait.stateMachine?.events?.find((e) => e.key === event);
906
+ if (eventSchema?.payloadSchema && eventSchema.payloadSchema.length > 0) {
907
+ validationFailures.push(
908
+ ...validateEventPayload(event, payload, eventSchema.payloadSchema)
909
+ );
910
+ }
911
+ }
912
+ if (validationFailures.length > 0) {
913
+ return {
914
+ success: false,
915
+ transitioned: false,
916
+ states: {},
917
+ emittedEvents: [],
918
+ error: formatPayloadValidationError(validationFailures)
919
+ };
920
+ }
921
+ const emittedEvents = [];
922
+ const fetchedData = {};
923
+ const clientEffects = [];
924
+ const clientEffectsByTrait = [];
925
+ const effectResults = [];
926
+ const activeTraits = payload?._activeTraits;
927
+ const cleanPayload = payload ? { ...payload } : void 0;
928
+ if (cleanPayload) {
929
+ delete cleanPayload._activeTraits;
930
+ }
931
+ let entityData = {};
932
+ if (entityId) {
933
+ const stored = await this.persistence.getById(
934
+ registered.entity.name,
935
+ entityId
866
936
  );
937
+ if (stored) {
938
+ entityData = stored;
939
+ }
867
940
  }
868
- }
869
- if (validationFailures.length > 0) {
941
+ const entityByTrait = {};
942
+ for (const [name, fields] of registered.traitFieldStates) {
943
+ if (fields && Object.keys(fields).length > 0) {
944
+ entityByTrait[name] = fields;
945
+ }
946
+ }
947
+ const results = registered.manager.sendEvent(
948
+ event,
949
+ cleanPayload,
950
+ entityData,
951
+ entityByTrait,
952
+ eventId
953
+ );
954
+ const filteredResults = activeTraits && activeTraits.length > 0 ? results.filter(({ traitName }) => activeTraits.includes(traitName)) : results;
955
+ if (this.config.debug && activeTraits) {
956
+ busLog.debug("dispatch:filter-traits", () => ({
957
+ total: results.length,
958
+ active: filteredResults.length,
959
+ activeTraits: activeTraits.join(",")
960
+ }));
961
+ }
962
+ for (const { traitName, result } of filteredResults) {
963
+ if (result.effects.length > 0) {
964
+ await this.executeEffects(
965
+ registered,
966
+ traitName,
967
+ result.effects,
968
+ cleanPayload,
969
+ entityData,
970
+ entityId,
971
+ emittedEvents,
972
+ fetchedData,
973
+ clientEffects,
974
+ effectResults,
975
+ user,
976
+ clientEffectsByTrait,
977
+ onPush
978
+ );
979
+ }
980
+ }
981
+ const states = {};
982
+ for (const [name, state] of registered.manager.getAllStates()) {
983
+ states[name] = state.currentState;
984
+ }
985
+ const response = {
986
+ success: true,
987
+ transitioned: results.length > 0,
988
+ states,
989
+ emittedEvents
990
+ };
991
+ if (clientEffects.length > 0) {
992
+ response.clientEffects = clientEffects;
993
+ }
994
+ if (clientEffectsByTrait.length > 0) {
995
+ response.clientEffectsByTrait = clientEffectsByTrait;
996
+ }
997
+ if (effectResults.length > 0) {
998
+ response.effectResults = effectResults;
999
+ }
1000
+ return response;
1001
+ } catch (error) {
1002
+ const message = error instanceof Error ? error.message : String(error);
1003
+ xOrbitalLog.error("processOrbitalEvent:error", {
1004
+ orbital: orbitalName,
1005
+ event: request.event,
1006
+ entityId: request.entityId,
1007
+ error: message
1008
+ });
870
1009
  return {
871
1010
  success: false,
872
1011
  transitioned: false,
873
1012
  states: {},
874
1013
  emittedEvents: [],
875
- error: formatPayloadValidationError(validationFailures)
1014
+ error: message
876
1015
  };
877
1016
  }
878
- const emittedEvents = [];
879
- const fetchedData = {};
880
- const clientEffects = [];
881
- const clientEffectsByTrait = [];
882
- const effectResults = [];
883
- const activeTraits = payload?._activeTraits;
884
- const cleanPayload = payload ? { ...payload } : void 0;
885
- if (cleanPayload) {
886
- delete cleanPayload._activeTraits;
887
- }
888
- let entityData = {};
889
- if (entityId) {
890
- const stored = await this.persistence.getById(
891
- registered.entity.name,
892
- entityId
893
- );
894
- if (stored) {
895
- entityData = stored;
896
- }
897
- }
898
- const entityByTrait = {};
899
- for (const [name, fields] of registered.traitFieldStates) {
900
- if (fields && Object.keys(fields).length > 0) {
901
- entityByTrait[name] = fields;
902
- }
903
- }
904
- const results = registered.manager.sendEvent(
905
- event,
906
- cleanPayload,
907
- entityData,
908
- entityByTrait
909
- );
910
- const filteredResults = activeTraits && activeTraits.length > 0 ? results.filter(({ traitName }) => activeTraits.includes(traitName)) : results;
911
- if (this.config.debug && activeTraits) {
912
- busLog.debug("dispatch:filter-traits", () => ({
913
- total: results.length,
914
- active: filteredResults.length,
915
- activeTraits: activeTraits.join(",")
916
- }));
917
- }
918
- for (const { traitName, result } of filteredResults) {
919
- if (result.effects.length > 0) {
920
- await this.executeEffects(
921
- registered,
922
- traitName,
923
- result.effects,
924
- cleanPayload,
925
- entityData,
926
- entityId,
927
- emittedEvents,
928
- fetchedData,
929
- clientEffects,
930
- effectResults,
931
- user,
932
- clientEffectsByTrait,
933
- onPush
934
- );
935
- }
936
- }
937
- const states = {};
938
- for (const [name, state] of registered.manager.getAllStates()) {
939
- states[name] = state.currentState;
940
- }
941
- const response = {
942
- success: true,
943
- transitioned: results.length > 0,
944
- states,
945
- emittedEvents
946
- };
947
- if (clientEffects.length > 0) {
948
- response.clientEffects = clientEffects;
949
- }
950
- if (clientEffectsByTrait.length > 0) {
951
- response.clientEffectsByTrait = clientEffectsByTrait;
952
- }
953
- if (effectResults.length > 0) {
954
- response.effectResults = effectResults;
955
- }
956
- return response;
957
1017
  }
958
1018
  /**
959
1019
  * Execute effects from a transition
@@ -977,11 +1037,22 @@ var OrbitalServerRuntime = class {
977
1037
  sourceTrait: source?.trait
978
1038
  }));
979
1039
  }
1040
+ const emittingTrait = registered.traits.find((t) => t.name === traitName);
1041
+ const emitContract = emittingTrait?.emits?.find((e) => e.event === event);
980
1042
  const stamp = source ?? {
981
1043
  orbital: registered.schema.name,
982
1044
  trait: traitName
983
1045
  };
984
- this.eventBus.emit(event, eventPayload, stamp);
1046
+ if (stamp.orbitalId === void 0 && registered.schema.id !== void 0) {
1047
+ stamp.orbitalId = registered.schema.id;
1048
+ }
1049
+ if (stamp.traitId === void 0 && emittingTrait?.id !== void 0) {
1050
+ stamp.traitId = emittingTrait.id;
1051
+ }
1052
+ if (stamp.eventId === void 0 && emitContract?.eventId !== void 0) {
1053
+ stamp.eventId = emitContract.eventId;
1054
+ }
1055
+ this.eventBus.emit(event, eventPayload, stamp, eventRouteKey(event, stamp.eventId));
985
1056
  const emittedItem = { event, payload: eventPayload, source: stamp };
986
1057
  emittedEvents.push(emittedItem);
987
1058
  onPush?.({ type: "event", data: emittedItem });
@@ -1446,9 +1517,22 @@ var OrbitalServerRuntime = class {
1446
1517
  };
1447
1518
  const traitDef = registered.traits.find((t) => t.name === traitName);
1448
1519
  const declaredDefaults = collectDeclaredConfigDefaults(traitDef);
1449
- const callSiteOverride = registered.configByTrait.get(traitName);
1450
- if (declaredDefaults || callSiteOverride) {
1451
- bindings.config = { ...declaredDefaults ?? {}, ...callSiteOverride ?? {} };
1520
+ const resolvedDefaults = this.resolvedTraitConfigs[traitName];
1521
+ const callSiteOverrideRaw = registered.configByTrait.get(traitName);
1522
+ const callSiteOverride = callSiteOverrideRaw ? resolveCallSitePayloadCaptures(
1523
+ Object.fromEntries(
1524
+ Object.entries(callSiteOverrideRaw).filter(
1525
+ ([, v]) => !(typeof v === "string" && v.startsWith("@config."))
1526
+ )
1527
+ ),
1528
+ payload
1529
+ ) : void 0;
1530
+ if (declaredDefaults || resolvedDefaults || callSiteOverride) {
1531
+ bindings.config = {
1532
+ ...declaredDefaults ?? {},
1533
+ ...resolvedDefaults ?? {},
1534
+ ...callSiteOverride ?? {}
1535
+ };
1452
1536
  }
1453
1537
  const entityFieldDefaults = collectDeclaredEntityDefaults(registered.entity);
1454
1538
  const traitFieldState = registered.traitFieldStates.get(traitName);
@@ -1639,7 +1723,15 @@ var OrbitalServerRuntime = class {
1639
1723
  continue;
1640
1724
  }
1641
1725
  const foreignKeyField = relationField.name;
1642
- const relatedEntityType = relationField.relation.entity;
1726
+ let relatedEntityType = relationField.relation.entity;
1727
+ if (relationField.relation.entityId) {
1728
+ for (const registered of this.orbitals.values()) {
1729
+ if (registered.entity.id === relationField.relation.entityId) {
1730
+ relatedEntityType = registered.entity.name;
1731
+ break;
1732
+ }
1733
+ }
1734
+ }
1643
1735
  const cardinality = relationField.relation.cardinality || "one";
1644
1736
  const foreignKeyIds = /* @__PURE__ */ new Set();
1645
1737
  for (const entity of entities) {
@@ -1877,7 +1969,7 @@ function parseListenSource(listener, listenerOrbital) {
1877
1969
  if (explicit && typeof explicit === "object") {
1878
1970
  return {
1879
1971
  bareEvent: listener.event,
1880
- matcher: buildMatcher(explicit, listenerOrbital)
1972
+ matcher: buildSourceMatcher(explicit, listenerOrbital)
1881
1973
  };
1882
1974
  }
1883
1975
  const key = listener.event;
@@ -1892,7 +1984,7 @@ function parseListenSource(listener, listenerOrbital) {
1892
1984
  }
1893
1985
  return {
1894
1986
  bareEvent: eventName,
1895
- matcher: buildMatcher(
1987
+ matcher: buildSourceMatcher(
1896
1988
  { kind: "trait", trait: sourceOrStar },
1897
1989
  listenerOrbital
1898
1990
  )
@@ -1904,20 +1996,10 @@ function parseListenSource(listener, listenerOrbital) {
1904
1996
  const orbital = parts.slice(0, parts.length - 2).join(".");
1905
1997
  return {
1906
1998
  bareEvent: eventName,
1907
- matcher: buildMatcher({ kind: "orbital", orbital, trait }, listenerOrbital)
1999
+ matcher: buildSourceMatcher({ kind: "orbital", orbital, trait }, listenerOrbital)
1908
2000
  };
1909
2001
  }
1910
2002
  return { bareEvent: key, matcher: () => true };
1911
2003
  }
1912
- function buildMatcher(src, listenerOrbital) {
1913
- if (src.kind === "any") return () => true;
1914
- if (src.kind === "trait") {
1915
- const wantedTrait2 = src.trait;
1916
- return (source) => !!source && source.orbital === listenerOrbital && source.trait === wantedTrait2;
1917
- }
1918
- const wantedOrbital = src.orbital;
1919
- const wantedTrait = src.trait;
1920
- return (source) => !!source && source.orbital === wantedOrbital && source.trait === wantedTrait;
1921
- }
1922
2004
 
1923
2005
  export { OrbitalServerRuntime, createOrbitalServerRuntime };
@@ -1,4 +1,4 @@
1
- import { I as IEventBus } from './types-D-9feVsj.js';
1
+ import { I as IEventBus } from './types-C8RsO0xa.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**