@almadar/runtime 5.1.0 → 5.2.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/{OrbitalServerRuntime-D-b_dg8I.d.ts → OrbitalServerRuntime-BrJ7m0hz.d.ts} +28 -1
- package/dist/OrbitalServerRuntime.d.ts +2 -2
- package/dist/OrbitalServerRuntime.js +45 -2
- package/dist/OrbitalServerRuntime.js.map +1 -1
- package/dist/ServerBridge.d.ts +1 -1
- package/dist/{chunk-T343XTYB.js → chunk-OG2NHXES.js} +165 -8
- package/dist/chunk-OG2NHXES.js.map +1 -0
- package/dist/index.d.ts +45 -6
- package/dist/index.js +3 -80
- package/dist/index.js.map +1 -1
- package/dist/{types-DwDhc9Jt.d.ts → types-SmmabGZk.d.ts} +1 -2
- package/package.json +1 -1
- package/dist/chunk-T343XTYB.js.map +0 -1
package/dist/ServerBridge.d.ts
CHANGED
|
@@ -176,6 +176,7 @@ function createLogger(namespace) {
|
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
178
|
var bindLog = createLogger("almadar:runtime:bindings");
|
|
179
|
+
var renderLog = createLogger("almadar:runtime:render-ui");
|
|
179
180
|
var CLIENT_ONLY_BINDING_ROOTS = /* @__PURE__ */ new Set(["trait"]);
|
|
180
181
|
function isClientOnlyBinding(value) {
|
|
181
182
|
if (!value.startsWith("@")) return false;
|
|
@@ -186,10 +187,27 @@ function isClientOnlyBinding(value) {
|
|
|
186
187
|
}
|
|
187
188
|
function interpolateProps(props, ctx) {
|
|
188
189
|
const result = {};
|
|
190
|
+
let anyChanged = false;
|
|
189
191
|
for (const [key, value] of Object.entries(props)) {
|
|
190
|
-
|
|
192
|
+
const interpolated = interpolateValue(value, ctx);
|
|
193
|
+
result[key] = interpolated;
|
|
194
|
+
if (interpolated !== value) anyChanged = true;
|
|
195
|
+
}
|
|
196
|
+
const entityBindingRaw = props["entity"];
|
|
197
|
+
const typeBindingRaw = props["type"];
|
|
198
|
+
if (typeof entityBindingRaw === "string") {
|
|
199
|
+
const resolvedEntity = result["entity"];
|
|
200
|
+
const resolvedRow = resolvedEntity !== null && typeof resolvedEntity === "object" && !Array.isArray(resolvedEntity) ? resolvedEntity : null;
|
|
201
|
+
const ctxRow = ctx.payload["row"];
|
|
202
|
+
renderLog.debug("interpolateProps:entity", {
|
|
203
|
+
patternType: typeof typeBindingRaw === "string" ? typeBindingRaw : void 0,
|
|
204
|
+
entityBinding: entityBindingRaw,
|
|
205
|
+
resolvedIsObject: resolvedRow !== null,
|
|
206
|
+
resolvedEqualsCtxRow: ctxRow !== void 0 && resolvedRow !== null && resolvedRow === ctxRow,
|
|
207
|
+
resolvedRowId: resolvedRow?.id
|
|
208
|
+
});
|
|
191
209
|
}
|
|
192
|
-
return result;
|
|
210
|
+
return anyChanged ? result : props;
|
|
193
211
|
}
|
|
194
212
|
function interpolateValue(value, ctx) {
|
|
195
213
|
if (value === null || value === void 0) {
|
|
@@ -235,12 +253,20 @@ function interpolateEmbeddedBindings(value, ctx) {
|
|
|
235
253
|
}
|
|
236
254
|
function interpolateArray(value, ctx) {
|
|
237
255
|
if (value.length === 0) {
|
|
238
|
-
return
|
|
256
|
+
return value;
|
|
239
257
|
}
|
|
240
258
|
if (isSExpression(value)) {
|
|
241
259
|
return evaluate(value, ctx);
|
|
242
260
|
}
|
|
243
|
-
|
|
261
|
+
const mapped = [];
|
|
262
|
+
let anyChanged = false;
|
|
263
|
+
for (let i = 0; i < value.length; i++) {
|
|
264
|
+
const item = value[i];
|
|
265
|
+
const interpolated = interpolateValue(item, ctx);
|
|
266
|
+
mapped.push(interpolated);
|
|
267
|
+
if (interpolated !== item) anyChanged = true;
|
|
268
|
+
}
|
|
269
|
+
return anyChanged ? mapped : value;
|
|
244
270
|
}
|
|
245
271
|
function isSExpression(value) {
|
|
246
272
|
if (value.length === 0) return false;
|
|
@@ -341,6 +367,7 @@ function processEvent(options) {
|
|
|
341
367
|
eventKey,
|
|
342
368
|
payload,
|
|
343
369
|
entityData,
|
|
370
|
+
config,
|
|
344
371
|
guardMode = "permissive",
|
|
345
372
|
strictBindings = false,
|
|
346
373
|
contextExtensions
|
|
@@ -375,7 +402,13 @@ function processEvent(options) {
|
|
|
375
402
|
const ctx = createContextFromBindings({
|
|
376
403
|
entity: entityData,
|
|
377
404
|
payload,
|
|
378
|
-
state: traitState.currentState
|
|
405
|
+
state: traitState.currentState,
|
|
406
|
+
// Surface call-site config so `@config.X` resolves inside
|
|
407
|
+
// guard expressions (matches the validator's allowed sigil
|
|
408
|
+
// list as of v3.12.0). createContextFromBindings already
|
|
409
|
+
// propagates `bindings.config` to ctx.config when present —
|
|
410
|
+
// we just need to pass it through here.
|
|
411
|
+
config
|
|
379
412
|
}, strictBindings, contextExtensions);
|
|
380
413
|
try {
|
|
381
414
|
const guardPasses = evaluateGuard(
|
|
@@ -455,6 +488,15 @@ function compositeKey(traitName, scope) {
|
|
|
455
488
|
}
|
|
456
489
|
var StateMachineManager = class {
|
|
457
490
|
traits = /* @__PURE__ */ new Map();
|
|
491
|
+
/**
|
|
492
|
+
* Per-trait call-site config, surfaced to guard expressions so
|
|
493
|
+
* `@config.X` resolves at runtime. Populated by the orbital's
|
|
494
|
+
* registration step (see `OrbitalServerRuntime.registerOrbital`'s
|
|
495
|
+
* `configByTrait` projection). Empty for atom-scope traits whose
|
|
496
|
+
* call-site config wasn't supplied — guards that read `@config.X`
|
|
497
|
+
* in that case will see `undefined` and short-circuit accordingly.
|
|
498
|
+
*/
|
|
499
|
+
traitConfigs = /* @__PURE__ */ new Map();
|
|
458
500
|
/**
|
|
459
501
|
* State map keyed by `${traitName}::${entityId | __singleton__}`.
|
|
460
502
|
*
|
|
@@ -497,6 +539,19 @@ var StateMachineManager = class {
|
|
|
497
539
|
addTrait(trait) {
|
|
498
540
|
this.traits.set(trait.name, trait);
|
|
499
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* Bind the call-site config for a trait so guard `@config.X`
|
|
544
|
+
* resolves at runtime. Typically called by the orbital
|
|
545
|
+
* registration step right after `addTrait`. Idempotent; passing
|
|
546
|
+
* `undefined` clears the binding.
|
|
547
|
+
*/
|
|
548
|
+
setTraitConfig(traitName, config) {
|
|
549
|
+
if (config === void 0) {
|
|
550
|
+
this.traitConfigs.delete(traitName);
|
|
551
|
+
} else {
|
|
552
|
+
this.traitConfigs.set(traitName, config);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
500
555
|
/**
|
|
501
556
|
* Remove a trait from the manager.
|
|
502
557
|
*/
|
|
@@ -612,6 +667,7 @@ var StateMachineManager = class {
|
|
|
612
667
|
eventKey,
|
|
613
668
|
payload,
|
|
614
669
|
entityData,
|
|
670
|
+
config: this.traitConfigs.get(traitName),
|
|
615
671
|
guardMode: this.config.guardMode,
|
|
616
672
|
strictBindings: this.config.strictBindings,
|
|
617
673
|
contextExtensions: this.config.contextExtensions
|
|
@@ -681,6 +737,7 @@ var StateMachineManager = class {
|
|
|
681
737
|
eventKey: entry.eventKey,
|
|
682
738
|
payload: entry.payload,
|
|
683
739
|
entityData: entry.entityData,
|
|
740
|
+
config: this.traitConfigs.get(traitName),
|
|
684
741
|
guardMode: this.config.guardMode,
|
|
685
742
|
strictBindings: this.config.strictBindings,
|
|
686
743
|
contextExtensions: this.config.contextExtensions
|
|
@@ -1513,6 +1570,106 @@ function createTestExecutor(overrides = {}) {
|
|
|
1513
1570
|
debug: true
|
|
1514
1571
|
});
|
|
1515
1572
|
}
|
|
1573
|
+
|
|
1574
|
+
// src/PayloadValidator.ts
|
|
1575
|
+
function validateEventPayload(eventKey, payload, schema) {
|
|
1576
|
+
if (!schema || schema.length === 0) return [];
|
|
1577
|
+
const failures = [];
|
|
1578
|
+
for (const field of schema) {
|
|
1579
|
+
if (!field.required) continue;
|
|
1580
|
+
const value = payload?.[field.name];
|
|
1581
|
+
if (value === void 0) {
|
|
1582
|
+
failures.push({ event: eventKey, field: field.name, reason: "missing", expectedType: field.type });
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
if (value === null) {
|
|
1586
|
+
failures.push({ event: eventKey, field: field.name, reason: "null", expectedType: field.type });
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return failures;
|
|
1590
|
+
}
|
|
1591
|
+
function formatPayloadValidationError(failures) {
|
|
1592
|
+
if (failures.length === 0) return "";
|
|
1593
|
+
const parts = failures.map(
|
|
1594
|
+
(f) => `${f.field} (${f.reason}${f.expectedType ? `, expected ${f.expectedType}` : ""})`
|
|
1595
|
+
);
|
|
1596
|
+
return `Payload validation failed for event '${failures[0].event}': ${parts.join("; ")}`;
|
|
1597
|
+
}
|
|
1598
|
+
function validatePayloadShapes(traits, emits) {
|
|
1599
|
+
const mismatches = [];
|
|
1600
|
+
const emitIndex = /* @__PURE__ */ new Map();
|
|
1601
|
+
for (const [traitName, declarations] of emits) {
|
|
1602
|
+
for (const decl of declarations) {
|
|
1603
|
+
const fields = decl.payloadSchema?.map((p) => p.name) ?? [];
|
|
1604
|
+
emitIndex.set(decl.event, { traitName, fields });
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
for (const trait of traits) {
|
|
1608
|
+
if (!trait.listens) continue;
|
|
1609
|
+
for (const listener of trait.listens) {
|
|
1610
|
+
const emitter = emitIndex.get(listener.event);
|
|
1611
|
+
if (!emitter) continue;
|
|
1612
|
+
if (!listener.payloadMapping) continue;
|
|
1613
|
+
const payloadRefs = extractPayloadReferences(listener.payloadMapping);
|
|
1614
|
+
for (const ref of payloadRefs) {
|
|
1615
|
+
if (!emitter.fields.includes(ref)) {
|
|
1616
|
+
mismatches.push({
|
|
1617
|
+
listenerTrait: trait.name,
|
|
1618
|
+
emitterTrait: emitter.traitName,
|
|
1619
|
+
event: listener.event,
|
|
1620
|
+
referencedField: ref,
|
|
1621
|
+
availableFields: emitter.fields
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
return mismatches;
|
|
1628
|
+
}
|
|
1629
|
+
function extractPayloadReferences(mapping) {
|
|
1630
|
+
const refs = [];
|
|
1631
|
+
function collect(value) {
|
|
1632
|
+
if (typeof value === "string") {
|
|
1633
|
+
const match = value.match(/^@payload\.(\w+)$/);
|
|
1634
|
+
if (match) {
|
|
1635
|
+
refs.push(match[1]);
|
|
1636
|
+
}
|
|
1637
|
+
} else if (typeof value === "object" && value !== null) {
|
|
1638
|
+
if (Array.isArray(value)) {
|
|
1639
|
+
value.forEach(collect);
|
|
1640
|
+
} else {
|
|
1641
|
+
Object.values(value).forEach(collect);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
Object.values(mapping).forEach(collect);
|
|
1646
|
+
return [...new Set(refs)];
|
|
1647
|
+
}
|
|
1648
|
+
function buildEmitsFromTraits(traits, explicitEmits) {
|
|
1649
|
+
const result = new Map(explicitEmits ?? []);
|
|
1650
|
+
for (const trait of traits) {
|
|
1651
|
+
if (result.has(trait.name)) continue;
|
|
1652
|
+
const emitDecls = [];
|
|
1653
|
+
for (const transition of trait.transitions) {
|
|
1654
|
+
if (!transition.effects) continue;
|
|
1655
|
+
for (const effect of transition.effects) {
|
|
1656
|
+
if (!Array.isArray(effect)) continue;
|
|
1657
|
+
if (effect[0] === "emit" && typeof effect[1] === "string") {
|
|
1658
|
+
const event = effect[1];
|
|
1659
|
+
const payloadObj = effect[2];
|
|
1660
|
+
const payloadSchema = payloadObj ? Object.keys(payloadObj).map((name) => ({ name })) : void 0;
|
|
1661
|
+
if (!emitDecls.some((d) => d.event === event)) {
|
|
1662
|
+
emitDecls.push({ event, payloadSchema });
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
if (emitDecls.length > 0) {
|
|
1668
|
+
result.set(trait.name, emitDecls);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
return result;
|
|
1672
|
+
}
|
|
1516
1673
|
var MockPersistenceAdapter = class {
|
|
1517
1674
|
stores = /* @__PURE__ */ new Map();
|
|
1518
1675
|
schemas = /* @__PURE__ */ new Map();
|
|
@@ -3224,6 +3381,6 @@ var InMemoryPersistence = class {
|
|
|
3224
3381
|
}
|
|
3225
3382
|
};
|
|
3226
3383
|
|
|
3227
|
-
export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, containsBindings, createContextFromBindings, createInitialTraitState, createLogger, createMockPersistence, createTestExecutor, createUnifiedLoader, extractBindings, findInitialState, findTransition, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isBrowser, isElectron, isNamespacedEvent, isNode, normalizeEventKey, parseNamespacedEvent, preprocessSchema, processEvent };
|
|
3228
|
-
//# sourceMappingURL=chunk-
|
|
3229
|
-
//# sourceMappingURL=chunk-
|
|
3384
|
+
export { EffectExecutor, EventBus, HANDLER_MANIFEST, InMemoryPersistence, MockPersistenceAdapter, StateMachineManager, buildEmitsFromTraits, containsBindings, createContextFromBindings, createInitialTraitState, createLogger, createMockPersistence, createTestExecutor, createUnifiedLoader, extractBindings, findInitialState, findTransition, formatPayloadValidationError, getIsolatedCollectionName, getNamespacedEvent, interpolateProps, interpolateValue, isBrowser, isElectron, isNamespacedEvent, isNode, normalizeEventKey, parseNamespacedEvent, preprocessSchema, processEvent, validateEventPayload, validatePayloadShapes };
|
|
3385
|
+
//# sourceMappingURL=chunk-OG2NHXES.js.map
|
|
3386
|
+
//# sourceMappingURL=chunk-OG2NHXES.js.map
|