@almadar/runtime 6.31.0 → 6.33.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.
@@ -0,0 +1,435 @@
1
+ import { isEntityCall } from '@almadar/core';
2
+ import { createLogger, isLogLevelEnabled } from '@almadar/logger';
3
+
4
+ // src/ui/contract-errors.ts
5
+ var RendererContractViolationError = class extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = "RendererContractViolationError";
9
+ }
10
+ };
11
+
12
+ // src/ui/slots.ts
13
+ function aggregateSlotContent(slot, sources) {
14
+ const entries = Array.from(sources.values());
15
+ if (entries.length === 0) return void 0;
16
+ if (entries.length === 1) return entries[0];
17
+ Array.from(sources.keys());
18
+ const children = entries.map((entry) => ({
19
+ type: entry.pattern?.type ?? "box",
20
+ ...entry.props
21
+ }));
22
+ return {
23
+ slot,
24
+ pattern: { type: "stack", direction: "vertical", gap: "lg", children },
25
+ props: { direction: "vertical", gap: "lg", children },
26
+ source: entries[0].source
27
+ };
28
+ }
29
+ function isNonNullObject(value) {
30
+ return typeof value === "object" && value !== null;
31
+ }
32
+ function assertHasFunctionMethods(label, value, methods) {
33
+ for (const method of methods) {
34
+ if (typeof value[method] !== "function") {
35
+ throw new RendererContractViolationError(`${label}.${method} must be a function`);
36
+ }
37
+ }
38
+ }
39
+ function assertIsSlotManager(value) {
40
+ if (!isNonNullObject(value)) {
41
+ throw new RendererContractViolationError("SlotManager must be a non-null object");
42
+ }
43
+ assertHasFunctionMethods("SlotManager", value, [
44
+ "getContent",
45
+ "setContent",
46
+ "clearSlot",
47
+ "getAllSlots",
48
+ "subscribe"
49
+ ]);
50
+ }
51
+ function assertIsMultiSourceSlotManager(value) {
52
+ if (!isNonNullObject(value)) {
53
+ throw new RendererContractViolationError("MultiSourceSlotManager must be a non-null object");
54
+ }
55
+ assertHasFunctionMethods("SlotManager", value, [
56
+ "getContent",
57
+ "setContent",
58
+ "clearSlot",
59
+ "getAllSlots",
60
+ "subscribe"
61
+ ]);
62
+ assertHasFunctionMethods("MultiSourceSlotManager", value, [
63
+ "getTraitContent",
64
+ "subscribeTrait",
65
+ "updateTraitContent"
66
+ ]);
67
+ }
68
+ function validateSlotContent(content) {
69
+ const errors = [];
70
+ if (content.slot === void 0 || content.slot === null) {
71
+ errors.push({ message: "SlotContent.slot is required", path: "slot" });
72
+ }
73
+ if (!("pattern" in content)) {
74
+ errors.push({ message: "SlotContent.pattern is required", path: "pattern" });
75
+ }
76
+ return errors;
77
+ }
78
+ function createSlotSetter(manager) {
79
+ return {
80
+ addPattern: (slot, pattern, props) => {
81
+ manager.setContent({
82
+ slot,
83
+ pattern,
84
+ props
85
+ });
86
+ },
87
+ clearSlot: (slot) => {
88
+ manager.clearSlot(slot);
89
+ }
90
+ };
91
+ }
92
+
93
+ // src/ui/wrapCallbackForEvent.ts
94
+ function wrapCallbackForEvent(qualifiedEvent, callbackArgs, emit) {
95
+ const argNames = (callbackArgs ?? []).map((a) => a.name);
96
+ if (argNames.length === 0) {
97
+ return () => emit(qualifiedEvent);
98
+ }
99
+ return (...args) => {
100
+ const payload = {};
101
+ for (let i = 0; i < argNames.length; i += 1) {
102
+ payload[argNames[i]] = args[i];
103
+ }
104
+ emit(qualifiedEvent, payload);
105
+ };
106
+ }
107
+ var PERF_NAMESPACE = "almadar:perf:canvas";
108
+ var log = createLogger(PERF_NAMESPACE);
109
+ var RING_SIZE = 50;
110
+ var ring = [];
111
+ var writeIdx = 0;
112
+ var subscribers = /* @__PURE__ */ new Set();
113
+ var notifyScheduled = false;
114
+ var revision = 0;
115
+ var cachedSnapshot = [];
116
+ var cachedRevision = -1;
117
+ function scheduleNotify() {
118
+ if (notifyScheduled) return;
119
+ notifyScheduled = true;
120
+ queueMicrotask(() => {
121
+ notifyScheduled = false;
122
+ revision++;
123
+ for (const fn of subscribers) fn();
124
+ });
125
+ }
126
+ function push(entry) {
127
+ if (ring.length < RING_SIZE) {
128
+ ring.push(entry);
129
+ } else {
130
+ ring[writeIdx] = entry;
131
+ }
132
+ writeIdx = (writeIdx + 1) % RING_SIZE;
133
+ scheduleNotify();
134
+ }
135
+ function isEnabled() {
136
+ return isLogLevelEnabled("DEBUG", PERF_NAMESPACE);
137
+ }
138
+ function now() {
139
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
140
+ }
141
+ function perfStart(name) {
142
+ if (!isEnabled()) return -1;
143
+ if (typeof performance !== "undefined" && typeof performance.mark === "function") {
144
+ try {
145
+ performance.mark(`${name}-start`);
146
+ } catch {
147
+ }
148
+ }
149
+ return now();
150
+ }
151
+ function perfEnd(name, startToken, detail) {
152
+ if (startToken < 0 || !isEnabled()) return;
153
+ const endTs = now();
154
+ const durationMs = endTs - startToken;
155
+ if (typeof performance !== "undefined" && typeof performance.measure === "function") {
156
+ try {
157
+ performance.mark(`${name}-end`);
158
+ performance.measure(name, `${name}-start`, `${name}-end`);
159
+ } catch {
160
+ }
161
+ }
162
+ push({ name, durationMs, ts: endTs, detail });
163
+ log.debug(name, () => ({ durationMs, ...detail ?? {} }));
164
+ }
165
+ function perfTime(name, fn, detail) {
166
+ const t = perfStart(name);
167
+ try {
168
+ return fn();
169
+ } finally {
170
+ perfEnd(name, t, detail);
171
+ }
172
+ }
173
+ function getPerfSnapshot() {
174
+ if (ring.length < RING_SIZE) return ring.slice();
175
+ return [...ring.slice(writeIdx), ...ring.slice(0, writeIdx)];
176
+ }
177
+ function getSnapshot() {
178
+ if (cachedRevision !== revision) {
179
+ cachedSnapshot = getPerfSnapshot();
180
+ cachedRevision = revision;
181
+ }
182
+ return cachedSnapshot;
183
+ }
184
+ function subscribe(fn) {
185
+ subscribers.add(fn);
186
+ return () => {
187
+ subscribers.delete(fn);
188
+ };
189
+ }
190
+ function pushPerfEntry(entry) {
191
+ if (!isEnabled()) return;
192
+ push(entry);
193
+ }
194
+ function clearPerf() {
195
+ ring.length = 0;
196
+ writeIdx = 0;
197
+ scheduleNotify();
198
+ }
199
+ var perfStore = {
200
+ subscribe,
201
+ getSnapshot
202
+ };
203
+
204
+ // src/ui/prepareSchemaForPreview.ts
205
+ function generateEntityRow(entity, idx) {
206
+ const row = { id: String(idx) };
207
+ for (const f of entity.fields) {
208
+ if (f.name === void 0 || f.name === "id") continue;
209
+ row[f.name] = generateFieldValue(entity.name, f, idx);
210
+ }
211
+ return row;
212
+ }
213
+ function generateFieldValue(entityName, field, idx) {
214
+ if ("values" in field && field.values && field.values.length > 0) {
215
+ return field.values[(idx - 1) % field.values.length];
216
+ }
217
+ const fieldName = field.name ?? "";
218
+ switch (field.type) {
219
+ case "string":
220
+ return `${entityName} ${fieldName.charAt(0).toUpperCase() + fieldName.slice(1)} ${idx}`;
221
+ case "number":
222
+ return idx * 10;
223
+ case "boolean":
224
+ return idx % 2 === 0;
225
+ default:
226
+ return field.default ?? null;
227
+ }
228
+ }
229
+ function buildMockData(schema) {
230
+ const t = perfStart("build-mock-data");
231
+ const result = {};
232
+ for (const orbital of schema.orbitals) {
233
+ const entity = orbital.entity;
234
+ if (!entity || typeof entity === "string") continue;
235
+ if (isEntityCall(entity)) continue;
236
+ const entityName = entity.name;
237
+ if (!entityName) continue;
238
+ if (entity.instances && entity.instances.length > 0) {
239
+ result[entityName] = entity.instances;
240
+ continue;
241
+ }
242
+ const rows = Array.from(
243
+ { length: 10 },
244
+ (_, i) => generateEntityRow(entity, i + 1)
245
+ );
246
+ result[entityName] = rows;
247
+ }
248
+ for (const orbital of schema.orbitals) {
249
+ for (const traitRef of orbital.traits ?? []) {
250
+ if (!isInlineTrait(traitRef)) continue;
251
+ const trait = traitRef;
252
+ const sourceEntity = trait.sourceEntityDefinition;
253
+ if (!sourceEntity || isEntityCall(sourceEntity)) continue;
254
+ const sourceName = sourceEntity.name;
255
+ if (!sourceName) continue;
256
+ if (!result[sourceName]) {
257
+ result[sourceName] = sourceEntity.instances && sourceEntity.instances.length > 0 ? sourceEntity.instances : Array.from(
258
+ { length: 10 },
259
+ (_, i) => generateEntityRow(sourceEntity, i + 1)
260
+ );
261
+ }
262
+ const reboundName = trait.linkedEntity;
263
+ if (!reboundName || reboundName === sourceName) continue;
264
+ const reboundRows = result[reboundName];
265
+ if (!reboundRows || reboundRows.length === 0) continue;
266
+ reboundRows.forEach((row, i) => {
267
+ for (const f of sourceEntity.fields) {
268
+ if (f.name === void 0 || f.name === "id") continue;
269
+ if (row[f.name] !== void 0) continue;
270
+ row[f.name] = generateFieldValue(sourceName, f, i + 1);
271
+ }
272
+ });
273
+ }
274
+ }
275
+ perfEnd("build-mock-data", t, { orbitalCount: schema.orbitals.length, entityCount: Object.keys(result).length });
276
+ return result;
277
+ }
278
+ function isInlineTrait(traitRef) {
279
+ return typeof traitRef === "object" && traitRef !== null && "stateMachine" in traitRef;
280
+ }
281
+ function findDataState(sm, initialStateName) {
282
+ return sm.states.find((s) => {
283
+ if (s.name === initialStateName) return false;
284
+ return sm.transitions.some(
285
+ (t) => t.event === "INIT" && (t.from === s.name || Array.isArray(t.from) && t.from.includes(s.name))
286
+ );
287
+ });
288
+ }
289
+ function rewriteTraitInitialState(trait, mockData) {
290
+ const sm = trait.stateMachine;
291
+ if (!sm) return trait;
292
+ const linkedEntity = trait.linkedEntity;
293
+ if (!linkedEntity || !mockData[linkedEntity]?.length) return trait;
294
+ const initialStateName = sm.states.find((s) => s.isInitial)?.name ?? sm.states[0]?.name;
295
+ if (!initialStateName) return trait;
296
+ const dataState = findDataState(sm, initialStateName);
297
+ if (!dataState) return trait;
298
+ const updatedStates = sm.states.map((s) => {
299
+ if (s.name === initialStateName) return { ...s, isInitial: false };
300
+ if (s.name === dataState.name) return { ...s, isInitial: true };
301
+ return s;
302
+ });
303
+ return { ...trait, stateMachine: { ...sm, states: updatedStates } };
304
+ }
305
+ function adjustSchemaForMockData(schema, mockData) {
306
+ let changed = false;
307
+ const updatedOrbitals = schema.orbitals.map((orbital) => {
308
+ const traits = orbital.traits ?? [];
309
+ const updatedTraits = traits.map((traitRef) => {
310
+ if (!isInlineTrait(traitRef)) return traitRef;
311
+ const updated = rewriteTraitInitialState(traitRef, mockData);
312
+ if (updated !== traitRef) changed = true;
313
+ return updated;
314
+ });
315
+ return changed ? { ...orbital, traits: updatedTraits } : orbital;
316
+ });
317
+ return changed ? { ...schema, orbitals: updatedOrbitals } : schema;
318
+ }
319
+ function prepareSchemaForPreview(input) {
320
+ const parsed = typeof input === "string" ? JSON.parse(input) : input;
321
+ const mockData = buildMockData(parsed);
322
+ const schema = adjustSchemaForMockData(parsed, mockData);
323
+ return { schema, mockData };
324
+ }
325
+
326
+ // src/ui/orbitalsByTrait.ts
327
+ function buildOrbitalsByTrait(schema, resolvedPages = []) {
328
+ const map = {};
329
+ if (!schema?.orbitals) return map;
330
+ const pagePathToOrbital = {};
331
+ for (const orb of schema.orbitals) {
332
+ for (const traitRef of orb.traits ?? []) {
333
+ let traitName;
334
+ if (typeof traitRef === "string") {
335
+ const parts = traitRef.split(".");
336
+ traitName = parts[parts.length - 1];
337
+ } else if ("ref" in traitRef && typeof traitRef.ref === "string") {
338
+ const parts = traitRef.ref.split(".");
339
+ traitName = traitRef.name ?? parts[parts.length - 1];
340
+ } else if ("name" in traitRef && typeof traitRef.name === "string") {
341
+ traitName = traitRef.name;
342
+ }
343
+ if (traitName) map[traitName] = orb.name;
344
+ }
345
+ for (const pg of orb.pages ?? []) {
346
+ const path = typeof pg === "string" ? pg : pg?.path;
347
+ if (path) pagePathToOrbital[path] = orb.name;
348
+ }
349
+ }
350
+ for (const page of resolvedPages) {
351
+ const orbital = page.path ? pagePathToOrbital[page.path] : void 0;
352
+ if (!orbital) continue;
353
+ for (const traitName of page.traitNames) {
354
+ if (traitName && !(traitName in map)) map[traitName] = orbital;
355
+ }
356
+ }
357
+ return map;
358
+ }
359
+ var log2 = createLogger("almadar:runtime:verify");
360
+ var MAX_EVENT_LOG = 200;
361
+ var EMPTY_SUMMARY = {
362
+ totalChecks: 0,
363
+ passed: 0,
364
+ failed: 0,
365
+ warnings: 0,
366
+ pending: 0
367
+ };
368
+ function emptySnapshot() {
369
+ return {
370
+ checks: [],
371
+ transitions: [],
372
+ bridge: null,
373
+ summary: EMPTY_SUMMARY,
374
+ traits: []
375
+ };
376
+ }
377
+ function ensureVerificationApi() {
378
+ if (typeof window === "undefined") return void 0;
379
+ if (!window.__orbitalVerification) {
380
+ window.__orbitalVerification = {
381
+ getSnapshot: emptySnapshot,
382
+ getChecks: () => [],
383
+ getTransitions: () => [],
384
+ getBridge: () => null,
385
+ getSummary: () => EMPTY_SUMMARY,
386
+ waitForTransition: () => Promise.resolve(null),
387
+ getTraitSnapshots: () => []
388
+ };
389
+ }
390
+ return window.__orbitalVerification;
391
+ }
392
+ function getOrbitalVerification() {
393
+ if (typeof window === "undefined") return void 0;
394
+ return window.__orbitalVerification;
395
+ }
396
+ function bindEventBus(eventBus) {
397
+ const api = ensureVerificationApi();
398
+ if (!api) return;
399
+ api.sendEvent = (event, payload, traitScope) => {
400
+ const prefixed = event.startsWith("UI:") ? event : traitScope ? `UI:${traitScope}.${event}` : `UI:${event}`;
401
+ log2.debug("sendEvent", {
402
+ event: prefixed,
403
+ traitScope,
404
+ payloadKeys: payload ? Object.keys(payload) : []
405
+ });
406
+ eventBus.emit(prefixed, payload);
407
+ };
408
+ const eventLog = [];
409
+ api.eventLog = eventLog;
410
+ api.clearEventLog = () => {
411
+ eventLog.length = 0;
412
+ };
413
+ if (eventBus.onAny) {
414
+ const verificationEventLogger = (event) => {
415
+ if (eventLog.length < MAX_EVENT_LOG) {
416
+ eventLog.push({
417
+ type: event.type,
418
+ payload: event.payload,
419
+ timestamp: Date.now()
420
+ });
421
+ }
422
+ };
423
+ Object.defineProperty(verificationEventLogger, "name", {
424
+ value: "runtime-verify:eventLog"
425
+ });
426
+ eventBus.onAny(verificationEventLogger);
427
+ }
428
+ }
429
+ function bindTraitStateGetter(getter) {
430
+ const api = ensureVerificationApi();
431
+ if (!api) return;
432
+ api.getTraitState = getter;
433
+ }
434
+
435
+ export { PERF_NAMESPACE, RendererContractViolationError, adjustSchemaForMockData, aggregateSlotContent, assertIsMultiSourceSlotManager, assertIsSlotManager, bindEventBus, bindTraitStateGetter, buildMockData, buildOrbitalsByTrait, clearPerf, createSlotSetter, ensureVerificationApi, getOrbitalVerification, perfEnd, perfStart, perfStore, perfTime, prepareSchemaForPreview, pushPerfEntry, validateSlotContent, wrapCallbackForEvent };
@@ -0,0 +1,163 @@
1
+ // src/mockRandom.ts
2
+ var seedState = 42;
3
+ function seedRandom(value) {
4
+ seedState = (value ?? 42) >>> 0;
5
+ }
6
+ function nextFloat() {
7
+ seedState = seedState * 1664525 + 1013904223 >>> 0;
8
+ return seedState / 4294967296;
9
+ }
10
+ function randomInt({ min, max }) {
11
+ return Math.floor(nextFloat() * (max - min + 1)) + min;
12
+ }
13
+ function randomFloat({
14
+ min,
15
+ max,
16
+ fractionDigits = 2
17
+ }) {
18
+ const value = nextFloat() * (max - min) + min;
19
+ const factor = 10 ** fractionDigits;
20
+ return Math.round(value * factor) / factor;
21
+ }
22
+ function randomBoolean() {
23
+ return nextFloat() < 0.5;
24
+ }
25
+ function randomArrayElement(array) {
26
+ return array[randomInt({ min: 0, max: array.length - 1 })];
27
+ }
28
+ function shuffleArray(array) {
29
+ const copy = array.slice();
30
+ for (let i = copy.length - 1; i > 0; i--) {
31
+ const j = randomInt({ min: 0, max: i });
32
+ const tmp = copy[i];
33
+ copy[i] = copy[j];
34
+ copy[j] = tmp;
35
+ }
36
+ return copy;
37
+ }
38
+ function randomPastDate({ years = 1 } = {}) {
39
+ const now = Date.now();
40
+ const maxAge = years * 365 * 24 * 60 * 60 * 1e3;
41
+ const age = Math.floor(nextFloat() * maxAge);
42
+ return new Date(now - age);
43
+ }
44
+ function randomRecentDate({ days = 30 } = {}) {
45
+ const now = Date.now();
46
+ const maxAge = days * 24 * 60 * 60 * 1e3;
47
+ const age = Math.floor(nextFloat() * maxAge);
48
+ return new Date(now - age);
49
+ }
50
+ function randomAnytimeDate() {
51
+ const now = Date.now();
52
+ const maxAge = 100 * 365 * 24 * 60 * 60 * 1e3;
53
+ const age = Math.floor(nextFloat() * maxAge);
54
+ return new Date(now - age);
55
+ }
56
+ var LOREM_WORDS = [
57
+ "lorem",
58
+ "ipsum",
59
+ "dolor",
60
+ "sit",
61
+ "amet",
62
+ "consectetur",
63
+ "adipiscing",
64
+ "elit",
65
+ "sed",
66
+ "do",
67
+ "eiusmod",
68
+ "tempor",
69
+ "incididunt",
70
+ "ut",
71
+ "labore",
72
+ "et",
73
+ "dolore",
74
+ "magna",
75
+ "aliqua",
76
+ "enim",
77
+ "ad",
78
+ "minim",
79
+ "veniam",
80
+ "quis",
81
+ "nostrud",
82
+ "exercitation",
83
+ "ullamco",
84
+ "laboris",
85
+ "nisi",
86
+ "aliquip",
87
+ "ex",
88
+ "ea",
89
+ "commodo",
90
+ "consequat",
91
+ "duis",
92
+ "aute",
93
+ "irure",
94
+ "in",
95
+ "reprehenderit",
96
+ "voluptate",
97
+ "velit",
98
+ "esse",
99
+ "cillum",
100
+ "fugiat",
101
+ "nulla",
102
+ "pariatur",
103
+ "excepteur",
104
+ "sint",
105
+ "occaecat",
106
+ "cupidatat",
107
+ "non",
108
+ "proident",
109
+ "sunt",
110
+ "culpa",
111
+ "qui",
112
+ "officia",
113
+ "deserunt",
114
+ "mollit",
115
+ "anim",
116
+ "id",
117
+ "est",
118
+ "laborum"
119
+ ];
120
+ function randomWords(count) {
121
+ const words = [];
122
+ for (let i = 0; i < count; i++) {
123
+ words.push(randomArrayElement(LOREM_WORDS));
124
+ }
125
+ return words.join(" ");
126
+ }
127
+ function randomSentence() {
128
+ const words = randomWords(randomInt({ min: 4, max: 8 }));
129
+ return words.charAt(0).toUpperCase() + words.slice(1) + ".";
130
+ }
131
+ function randomUuid() {
132
+ const hex = () => randomInt({ min: 0, max: 15 }).toString(16);
133
+ return `${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}-${hex()}${hex()}${hex()}${hex()}-4${hex()}${hex()}${hex()}-${hex()}${hex()}${hex()}${hex()}-${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}${hex()}`;
134
+ }
135
+ function randomColor() {
136
+ const channel = () => randomInt({ min: 0, max: 255 }).toString(16).padStart(2, "0");
137
+ return `#${channel()}${channel()}${channel()}`;
138
+ }
139
+ var PASSWORD_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
140
+ function randomPassword(length = 12) {
141
+ let password = "";
142
+ for (let i = 0; i < length; i++) {
143
+ password += randomArrayElement(PASSWORD_CHARS.split(""));
144
+ }
145
+ return password;
146
+ }
147
+ function randomEmail() {
148
+ const user = randomWords(1).toLowerCase().replace(/\s+/g, ".");
149
+ const domain = randomWords(1).toLowerCase().replace(/\s+/g, "");
150
+ return `${user}@${domain}.com`;
151
+ }
152
+ function randomUrl() {
153
+ const slug = randomWords(2).toLowerCase().replace(/\s+/g, "-");
154
+ return `https://example.com/${slug}`;
155
+ }
156
+ function randomPhone() {
157
+ const area = randomInt({ min: 200, max: 999 });
158
+ const prefix = randomInt({ min: 200, max: 999 });
159
+ const line = randomInt({ min: 0, max: 9999 }).toString().padStart(4, "0");
160
+ return `+1 (${area}) ${prefix}-${line}`;
161
+ }
162
+
163
+ export { randomAnytimeDate, randomArrayElement, randomBoolean, randomColor, randomEmail, randomFloat, randomInt, randomPassword, randomPastDate, randomPhone, randomRecentDate, randomSentence, randomUrl, randomUuid, randomWords, seedRandom, shuffleArray };
@@ -0,0 +1,82 @@
1
+ // src/ui/embedded-traits.ts
2
+ var TRAIT_BINDING_PREFIX = "@trait.";
3
+ function collectTraitRefsFromValue(value, into) {
4
+ if (value === null || value === void 0) return;
5
+ if (typeof value === "string") {
6
+ if (value.startsWith(TRAIT_BINDING_PREFIX)) {
7
+ const rest = value.slice(TRAIT_BINDING_PREFIX.length);
8
+ const dot = rest.indexOf(".");
9
+ const traitName = dot === -1 ? rest : rest.slice(0, dot);
10
+ if (traitName.length > 0) into.add(traitName);
11
+ }
12
+ return;
13
+ }
14
+ if (Array.isArray(value)) {
15
+ for (const item of value) collectTraitRefsFromValue(item, into);
16
+ return;
17
+ }
18
+ if (typeof value === "object") {
19
+ for (const v of Object.values(value)) {
20
+ collectTraitRefsFromValue(v, into);
21
+ }
22
+ }
23
+ }
24
+ function collectTraitRefsFromEffects(effects, into) {
25
+ if (!effects) return;
26
+ for (const effect of effects) {
27
+ if (!Array.isArray(effect)) continue;
28
+ if (effect[0] === "render-ui" && effect.length >= 3) {
29
+ collectTraitRefsFromValue(effect[2], into);
30
+ continue;
31
+ }
32
+ for (let i = 1; i < effect.length; i++) {
33
+ const arg = effect[i];
34
+ if (Array.isArray(arg)) collectTraitRefsFromEffects([arg], into);
35
+ else collectTraitRefsFromValue(arg, into);
36
+ }
37
+ }
38
+ }
39
+ function collectTraitRefsFromResolvedTrait(trait) {
40
+ const out = /* @__PURE__ */ new Set();
41
+ for (const transition of trait.transitions ?? []) {
42
+ collectTraitRefsFromEffects(transition.effects, out);
43
+ }
44
+ for (const tick of trait.ticks ?? []) {
45
+ collectTraitRefsFromEffects(tick.effects, out);
46
+ }
47
+ return out;
48
+ }
49
+ function collectEmbeddedTraits(schema) {
50
+ const out = /* @__PURE__ */ new Set();
51
+ if (!schema?.orbitals) return out;
52
+ for (const orbital of schema.orbitals) {
53
+ const traits = orbital.traits;
54
+ if (!Array.isArray(traits)) continue;
55
+ for (const traitRef of traits) {
56
+ if (!traitRef || typeof traitRef !== "object") continue;
57
+ const resolved = traitRef._resolved;
58
+ const target = resolved && typeof resolved === "object" ? resolved : traitRef;
59
+ if (typeof traitRef !== "string" && "config" in traitRef && traitRef.config) {
60
+ collectTraitRefsFromValue(traitRef.config, out);
61
+ }
62
+ if (target.config) {
63
+ collectTraitRefsFromValue(target.config, out);
64
+ }
65
+ const transitions = target.stateMachine?.transitions;
66
+ if (!Array.isArray(transitions)) continue;
67
+ for (const t of transitions) {
68
+ collectTraitRefsFromEffects(t.effects, out);
69
+ }
70
+ collectTraitRefsFromEffects(target.initialEffects, out);
71
+ const ticks = target.ticks;
72
+ if (Array.isArray(ticks)) {
73
+ for (const tick of ticks) {
74
+ collectTraitRefsFromEffects(tick.effects, out);
75
+ }
76
+ }
77
+ }
78
+ }
79
+ return out;
80
+ }
81
+
82
+ export { collectEmbeddedTraits, collectTraitRefsFromEffects, collectTraitRefsFromResolvedTrait, collectTraitRefsFromValue };
@@ -1,4 +1,4 @@
1
- import { a as EffectHandlers } from './types-D-9feVsj.js';
1
+ import { E as EffectHandlers } from './types-ConZnrpe.js';
2
2
  import { EventPayload } from '@almadar/core';
3
3
 
4
4
  /**