@almadar/ui 4.15.4 → 4.15.6

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.
@@ -3,6 +3,56 @@
3
3
  var react = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
 
6
+ // lib/logger.ts
7
+ var LEVEL_PRIORITY = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
8
+ var ENV = typeof process !== "undefined" && process.env ? process.env : {};
9
+ function envGet(key) {
10
+ return ENV[key] ?? ENV[`VITE_${key}`];
11
+ }
12
+ var NODE_ENV = envGet("NODE_ENV") ?? "development";
13
+ var CONFIGURED_LEVEL = (envGet("LOG_LEVEL") ?? (NODE_ENV === "production" ? "info" : "debug")).toUpperCase();
14
+ var MIN_PRIORITY = LEVEL_PRIORITY[CONFIGURED_LEVEL] ?? 0;
15
+ var DEBUG_FILTER = (envGet("ALMADAR_DEBUG") ?? "").split(",").map((s) => s.trim()).filter(Boolean);
16
+ function matchesNamespace(namespace) {
17
+ if (DEBUG_FILTER.length === 0) return true;
18
+ return DEBUG_FILTER.some((pattern) => {
19
+ if (pattern === "*" || pattern === "almadar:*") return true;
20
+ if (pattern.endsWith(":*")) return namespace.startsWith(pattern.slice(0, -1));
21
+ return namespace === pattern;
22
+ });
23
+ }
24
+ function createLogger(namespace) {
25
+ const nsAllowed = matchesNamespace(namespace);
26
+ const log = (level, message, data, correlationId) => {
27
+ if (LEVEL_PRIORITY[level] < MIN_PRIORITY) return;
28
+ if (level === "DEBUG" && !nsAllowed) return;
29
+ const prefix = `[${namespace}]`;
30
+ const logData = correlationId ? { ...data, cid: correlationId } : data;
31
+ switch (level) {
32
+ case "DEBUG":
33
+ console.debug(prefix, message, logData ?? "");
34
+ break;
35
+ case "INFO":
36
+ console.info(prefix, message, logData ?? "");
37
+ break;
38
+ case "WARN":
39
+ console.warn(prefix, message, logData ?? "");
40
+ break;
41
+ case "ERROR":
42
+ console.error(prefix, message, logData ?? "");
43
+ break;
44
+ }
45
+ };
46
+ return {
47
+ debug: (msg, data, cid) => log("DEBUG", msg, data, cid),
48
+ info: (msg, data, cid) => log("INFO", msg, data, cid),
49
+ warn: (msg, data, cid) => log("WARN", msg, data, cid),
50
+ error: (msg, data, cid) => log("ERROR", msg, data, cid)
51
+ };
52
+ }
53
+
54
+ // hooks/useUISlots.ts
55
+ var slotLog = createLogger("almadar:ui:useUISlots");
6
56
  var DEFAULT_SOURCE_KEY = "__default__";
7
57
  var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
8
58
  var ALL_SLOTS = [
@@ -161,6 +211,13 @@ function useUISlotManager() {
161
211
  indexTraitRender(content.sourceTrait, content);
162
212
  notifyTraitSubscribers(content.sourceTrait, content);
163
213
  }
214
+ slotLog.info("slot:written", {
215
+ slot: config.target,
216
+ sourceKey,
217
+ sourceTrait: content.sourceTrait,
218
+ patternType: content.pattern,
219
+ priority: content.priority
220
+ });
164
221
  notifySubscribers(config.target, aggregateSlot(nextSources));
165
222
  return nextAll;
166
223
  });
@@ -198,7 +255,10 @@ function useUISlotManager() {
198
255
  const sourceKey = sourceTrait;
199
256
  setSources((prev) => {
200
257
  const slotSources = prev[slot];
201
- if (!slotSources || !(sourceKey in slotSources)) return prev;
258
+ if (!slotSources || !(sourceKey in slotSources)) {
259
+ slotLog.debug("slot:clear-noop", { slot, sourceTrait, reason: !slotSources ? "no-slot" : "no-source" });
260
+ return prev;
261
+ }
202
262
  const content = slotSources[sourceKey];
203
263
  const timer = timersRef.current.get(content.id);
204
264
  if (timer) {
@@ -212,6 +272,7 @@ function useUISlotManager() {
212
272
  }
213
273
  const nextSources = { ...slotSources };
214
274
  delete nextSources[sourceKey];
275
+ slotLog.info("slot:cleared", { slot, sourceTrait, lastPatternType: content.pattern });
215
276
  notifySubscribers(slot, aggregateSlot(nextSources));
216
277
  return { ...prev, [slot]: nextSources };
217
278
  });
@@ -1,6 +1,56 @@
1
1
  import { createContext, useMemo, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
 
4
+ // lib/logger.ts
5
+ var LEVEL_PRIORITY = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
6
+ var ENV = typeof process !== "undefined" && process.env ? process.env : {};
7
+ function envGet(key) {
8
+ return ENV[key] ?? ENV[`VITE_${key}`];
9
+ }
10
+ var NODE_ENV = envGet("NODE_ENV") ?? "development";
11
+ var CONFIGURED_LEVEL = (envGet("LOG_LEVEL") ?? (NODE_ENV === "production" ? "info" : "debug")).toUpperCase();
12
+ var MIN_PRIORITY = LEVEL_PRIORITY[CONFIGURED_LEVEL] ?? 0;
13
+ var DEBUG_FILTER = (envGet("ALMADAR_DEBUG") ?? "").split(",").map((s) => s.trim()).filter(Boolean);
14
+ function matchesNamespace(namespace) {
15
+ if (DEBUG_FILTER.length === 0) return true;
16
+ return DEBUG_FILTER.some((pattern) => {
17
+ if (pattern === "*" || pattern === "almadar:*") return true;
18
+ if (pattern.endsWith(":*")) return namespace.startsWith(pattern.slice(0, -1));
19
+ return namespace === pattern;
20
+ });
21
+ }
22
+ function createLogger(namespace) {
23
+ const nsAllowed = matchesNamespace(namespace);
24
+ const log = (level, message, data, correlationId) => {
25
+ if (LEVEL_PRIORITY[level] < MIN_PRIORITY) return;
26
+ if (level === "DEBUG" && !nsAllowed) return;
27
+ const prefix = `[${namespace}]`;
28
+ const logData = correlationId ? { ...data, cid: correlationId } : data;
29
+ switch (level) {
30
+ case "DEBUG":
31
+ console.debug(prefix, message, logData ?? "");
32
+ break;
33
+ case "INFO":
34
+ console.info(prefix, message, logData ?? "");
35
+ break;
36
+ case "WARN":
37
+ console.warn(prefix, message, logData ?? "");
38
+ break;
39
+ case "ERROR":
40
+ console.error(prefix, message, logData ?? "");
41
+ break;
42
+ }
43
+ };
44
+ return {
45
+ debug: (msg, data, cid) => log("DEBUG", msg, data, cid),
46
+ info: (msg, data, cid) => log("INFO", msg, data, cid),
47
+ warn: (msg, data, cid) => log("WARN", msg, data, cid),
48
+ error: (msg, data, cid) => log("ERROR", msg, data, cid)
49
+ };
50
+ }
51
+
52
+ // hooks/useUISlots.ts
53
+ var slotLog = createLogger("almadar:ui:useUISlots");
4
54
  var DEFAULT_SOURCE_KEY = "__default__";
5
55
  var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
6
56
  var ALL_SLOTS = [
@@ -159,6 +209,13 @@ function useUISlotManager() {
159
209
  indexTraitRender(content.sourceTrait, content);
160
210
  notifyTraitSubscribers(content.sourceTrait, content);
161
211
  }
212
+ slotLog.info("slot:written", {
213
+ slot: config.target,
214
+ sourceKey,
215
+ sourceTrait: content.sourceTrait,
216
+ patternType: content.pattern,
217
+ priority: content.priority
218
+ });
162
219
  notifySubscribers(config.target, aggregateSlot(nextSources));
163
220
  return nextAll;
164
221
  });
@@ -196,7 +253,10 @@ function useUISlotManager() {
196
253
  const sourceKey = sourceTrait;
197
254
  setSources((prev) => {
198
255
  const slotSources = prev[slot];
199
- if (!slotSources || !(sourceKey in slotSources)) return prev;
256
+ if (!slotSources || !(sourceKey in slotSources)) {
257
+ slotLog.debug("slot:clear-noop", { slot, sourceTrait, reason: !slotSources ? "no-slot" : "no-source" });
258
+ return prev;
259
+ }
200
260
  const content = slotSources[sourceKey];
201
261
  const timer = timersRef.current.get(content.id);
202
262
  if (timer) {
@@ -210,6 +270,7 @@ function useUISlotManager() {
210
270
  }
211
271
  const nextSources = { ...slotSources };
212
272
  delete nextSources[sourceKey];
273
+ slotLog.info("slot:cleared", { slot, sourceTrait, lastPatternType: content.pattern });
213
274
  notifySubscribers(slot, aggregateSlot(nextSources));
214
275
  return { ...prev, [slot]: nextSources };
215
276
  });
@@ -1046,6 +1046,7 @@ function useEmitEvent() {
1046
1046
  [eventBus]
1047
1047
  );
1048
1048
  }
1049
+ var slotLog = createLogger("almadar:ui:useUISlots");
1049
1050
  var DEFAULT_SOURCE_KEY = "__default__";
1050
1051
  var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
1051
1052
  var ALL_SLOTS = [
@@ -1204,6 +1205,13 @@ function useUISlotManager() {
1204
1205
  indexTraitRender(content.sourceTrait, content);
1205
1206
  notifyTraitSubscribers(content.sourceTrait, content);
1206
1207
  }
1208
+ slotLog.info("slot:written", {
1209
+ slot: config.target,
1210
+ sourceKey,
1211
+ sourceTrait: content.sourceTrait,
1212
+ patternType: content.pattern,
1213
+ priority: content.priority
1214
+ });
1207
1215
  notifySubscribers(config.target, aggregateSlot(nextSources));
1208
1216
  return nextAll;
1209
1217
  });
@@ -1241,7 +1249,10 @@ function useUISlotManager() {
1241
1249
  const sourceKey = sourceTrait;
1242
1250
  setSources((prev) => {
1243
1251
  const slotSources = prev[slot];
1244
- if (!slotSources || !(sourceKey in slotSources)) return prev;
1252
+ if (!slotSources || !(sourceKey in slotSources)) {
1253
+ slotLog.debug("slot:clear-noop", { slot, sourceTrait, reason: !slotSources ? "no-slot" : "no-source" });
1254
+ return prev;
1255
+ }
1245
1256
  const content = slotSources[sourceKey];
1246
1257
  const timer = timersRef.current.get(content.id);
1247
1258
  if (timer) {
@@ -1255,6 +1266,7 @@ function useUISlotManager() {
1255
1266
  }
1256
1267
  const nextSources = { ...slotSources };
1257
1268
  delete nextSources[sourceKey];
1269
+ slotLog.info("slot:cleared", { slot, sourceTrait, lastPatternType: content.pattern });
1258
1270
  notifySubscribers(slot, aggregateSlot(nextSources));
1259
1271
  return { ...prev, [slot]: nextSources };
1260
1272
  });
@@ -1044,6 +1044,7 @@ function useEmitEvent() {
1044
1044
  [eventBus]
1045
1045
  );
1046
1046
  }
1047
+ var slotLog = createLogger("almadar:ui:useUISlots");
1047
1048
  var DEFAULT_SOURCE_KEY = "__default__";
1048
1049
  var MULTI_SOURCE_STACK_TRAIT = "__multi_source_stack__";
1049
1050
  var ALL_SLOTS = [
@@ -1202,6 +1203,13 @@ function useUISlotManager() {
1202
1203
  indexTraitRender(content.sourceTrait, content);
1203
1204
  notifyTraitSubscribers(content.sourceTrait, content);
1204
1205
  }
1206
+ slotLog.info("slot:written", {
1207
+ slot: config.target,
1208
+ sourceKey,
1209
+ sourceTrait: content.sourceTrait,
1210
+ patternType: content.pattern,
1211
+ priority: content.priority
1212
+ });
1205
1213
  notifySubscribers(config.target, aggregateSlot(nextSources));
1206
1214
  return nextAll;
1207
1215
  });
@@ -1239,7 +1247,10 @@ function useUISlotManager() {
1239
1247
  const sourceKey = sourceTrait;
1240
1248
  setSources((prev) => {
1241
1249
  const slotSources = prev[slot];
1242
- if (!slotSources || !(sourceKey in slotSources)) return prev;
1250
+ if (!slotSources || !(sourceKey in slotSources)) {
1251
+ slotLog.debug("slot:clear-noop", { slot, sourceTrait, reason: !slotSources ? "no-slot" : "no-source" });
1252
+ return prev;
1253
+ }
1243
1254
  const content = slotSources[sourceKey];
1244
1255
  const timer = timersRef.current.get(content.id);
1245
1256
  if (timer) {
@@ -1253,6 +1264,7 @@ function useUISlotManager() {
1253
1264
  }
1254
1265
  const nextSources = { ...slotSources };
1255
1266
  delete nextSources[sourceKey];
1267
+ slotLog.info("slot:cleared", { slot, sourceTrait, lastPatternType: content.pattern });
1256
1268
  notifySubscribers(slot, aggregateSlot(nextSources));
1257
1269
  return { ...prev, [slot]: nextSources };
1258
1270
  });
@@ -18749,6 +18749,17 @@ function DataGrid({
18749
18749
  };
18750
18750
  eventBus.emit(`UI:${action.event}`, payload);
18751
18751
  };
18752
+ const hasRenderProp = typeof children === "function";
18753
+ React115.useEffect(() => {
18754
+ if (data.length > 0 && !hasRenderProp && (!fields || fields.length === 0)) {
18755
+ const renderItemRaw = schemaRenderItem;
18756
+ const isFnLambda = Array.isArray(renderItemRaw) && renderItemRaw.length >= 3 && (renderItemRaw[0] === "fn" || renderItemRaw[0] === "lambda");
18757
+ dataGridLog.warn("renderItem-unresolved", {
18758
+ rowCount: data.length,
18759
+ renderItemIsFnLambda: isFnLambda
18760
+ });
18761
+ }
18762
+ }, [data, hasRenderProp, schemaRenderItem, fields]);
18752
18763
  const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
18753
18764
  const colsClass = cols ? {
18754
18765
  1: "grid-cols-1",
@@ -18767,17 +18778,6 @@ function DataGrid({
18767
18778
  if (data.length === 0) {
18768
18779
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
18769
18780
  }
18770
- const hasRenderProp = typeof children === "function";
18771
- React115.useEffect(() => {
18772
- if (data.length > 0 && !hasRenderProp && (!fields || fields.length === 0)) {
18773
- const renderItemRaw = schemaRenderItem;
18774
- const isFnLambda = Array.isArray(renderItemRaw) && renderItemRaw.length >= 3 && (renderItemRaw[0] === "fn" || renderItemRaw[0] === "lambda");
18775
- dataGridLog.warn("renderItem-unresolved", {
18776
- rowCount: data.length,
18777
- renderItemIsFnLambda: isFnLambda
18778
- });
18779
- }
18780
- }, [data, hasRenderProp, schemaRenderItem, fields]);
18781
18781
  const allIds = data.map((item, i) => item.id || String(i));
18782
18782
  const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
18783
18783
  const someSelected = selectedIds.size > 0;
@@ -19677,7 +19677,7 @@ var init_FilterGroup = __esm({
19677
19677
  eventBus.emit("UI:FILTER", {
19678
19678
  entity,
19679
19679
  field,
19680
- value: value === "all" ? null : value,
19680
+ value: value === "all" || value === null ? "" : value,
19681
19681
  query
19682
19682
  });
19683
19683
  },
@@ -20489,7 +20489,7 @@ var init_SearchInput = __esm({
20489
20489
  /* @__PURE__ */ jsxRuntime.jsx(
20490
20490
  Input,
20491
20491
  {
20492
- type: "search",
20492
+ type: "text",
20493
20493
  value: searchValue,
20494
20494
  onChange: handleChange,
20495
20495
  placeholder: resolvedPlaceholder,
@@ -18704,6 +18704,17 @@ function DataGrid({
18704
18704
  };
18705
18705
  eventBus.emit(`UI:${action.event}`, payload);
18706
18706
  };
18707
+ const hasRenderProp = typeof children === "function";
18708
+ useEffect(() => {
18709
+ if (data.length > 0 && !hasRenderProp && (!fields || fields.length === 0)) {
18710
+ const renderItemRaw = schemaRenderItem;
18711
+ const isFnLambda = Array.isArray(renderItemRaw) && renderItemRaw.length >= 3 && (renderItemRaw[0] === "fn" || renderItemRaw[0] === "lambda");
18712
+ dataGridLog.warn("renderItem-unresolved", {
18713
+ rowCount: data.length,
18714
+ renderItemIsFnLambda: isFnLambda
18715
+ });
18716
+ }
18717
+ }, [data, hasRenderProp, schemaRenderItem, fields]);
18707
18718
  const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
18708
18719
  const colsClass = cols ? {
18709
18720
  1: "grid-cols-1",
@@ -18722,17 +18733,6 @@ function DataGrid({
18722
18733
  if (data.length === 0) {
18723
18734
  return /* @__PURE__ */ jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
18724
18735
  }
18725
- const hasRenderProp = typeof children === "function";
18726
- useEffect(() => {
18727
- if (data.length > 0 && !hasRenderProp && (!fields || fields.length === 0)) {
18728
- const renderItemRaw = schemaRenderItem;
18729
- const isFnLambda = Array.isArray(renderItemRaw) && renderItemRaw.length >= 3 && (renderItemRaw[0] === "fn" || renderItemRaw[0] === "lambda");
18730
- dataGridLog.warn("renderItem-unresolved", {
18731
- rowCount: data.length,
18732
- renderItemIsFnLambda: isFnLambda
18733
- });
18734
- }
18735
- }, [data, hasRenderProp, schemaRenderItem, fields]);
18736
18736
  const allIds = data.map((item, i) => item.id || String(i));
18737
18737
  const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
18738
18738
  const someSelected = selectedIds.size > 0;
@@ -19632,7 +19632,7 @@ var init_FilterGroup = __esm({
19632
19632
  eventBus.emit("UI:FILTER", {
19633
19633
  entity,
19634
19634
  field,
19635
- value: value === "all" ? null : value,
19635
+ value: value === "all" || value === null ? "" : value,
19636
19636
  query
19637
19637
  });
19638
19638
  },
@@ -20444,7 +20444,7 @@ var init_SearchInput = __esm({
20444
20444
  /* @__PURE__ */ jsx(
20445
20445
  Input,
20446
20446
  {
20447
- type: "search",
20447
+ type: "text",
20448
20448
  value: searchValue,
20449
20449
  onChange: handleChange,
20450
20450
  placeholder: resolvedPlaceholder,
@@ -2086,11 +2086,11 @@ function refId(obj) {
2086
2086
  refIds.set(obj, id);
2087
2087
  return id;
2088
2088
  }
2089
- var slotLog, refIds, nextRefId;
2089
+ var slotLog2, refIds, nextRefId;
2090
2090
  var init_slot_types = __esm({
2091
2091
  "runtime/ui/slot-types.ts"() {
2092
2092
  init_logger();
2093
- slotLog = createLogger("almadar:ui:slot-render");
2093
+ slotLog2 = createLogger("almadar:ui:slot-render");
2094
2094
  refIds = /* @__PURE__ */ new WeakMap();
2095
2095
  nextRefId = 1;
2096
2096
  }
@@ -18525,6 +18525,17 @@ function DataGrid({
18525
18525
  };
18526
18526
  eventBus.emit(`UI:${action.event}`, payload);
18527
18527
  };
18528
+ const hasRenderProp = typeof children === "function";
18529
+ React113.useEffect(() => {
18530
+ if (data.length > 0 && !hasRenderProp && (!fields || fields.length === 0)) {
18531
+ const renderItemRaw = schemaRenderItem;
18532
+ const isFnLambda = Array.isArray(renderItemRaw) && renderItemRaw.length >= 3 && (renderItemRaw[0] === "fn" || renderItemRaw[0] === "lambda");
18533
+ dataGridLog.warn("renderItem-unresolved", {
18534
+ rowCount: data.length,
18535
+ renderItemIsFnLambda: isFnLambda
18536
+ });
18537
+ }
18538
+ }, [data, hasRenderProp, schemaRenderItem, fields]);
18528
18539
  const gridTemplateColumns = cols ? void 0 : `repeat(auto-fit, minmax(min(${minCardWidth}px, 100%), 1fr))`;
18529
18540
  const colsClass = cols ? {
18530
18541
  1: "grid-cols-1",
@@ -18543,17 +18554,6 @@ function DataGrid({
18543
18554
  if (data.length === 0) {
18544
18555
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "secondary", children: t("empty.noItems") || "No items found" }) });
18545
18556
  }
18546
- const hasRenderProp = typeof children === "function";
18547
- React113.useEffect(() => {
18548
- if (data.length > 0 && !hasRenderProp && (!fields || fields.length === 0)) {
18549
- const renderItemRaw = schemaRenderItem;
18550
- const isFnLambda = Array.isArray(renderItemRaw) && renderItemRaw.length >= 3 && (renderItemRaw[0] === "fn" || renderItemRaw[0] === "lambda");
18551
- dataGridLog.warn("renderItem-unresolved", {
18552
- rowCount: data.length,
18553
- renderItemIsFnLambda: isFnLambda
18554
- });
18555
- }
18556
- }, [data, hasRenderProp, schemaRenderItem, fields]);
18557
18557
  const allIds = data.map((item, i) => item.id || String(i));
18558
18558
  const allSelected = allIds.length > 0 && allIds.every((id) => selectedIds.has(id));
18559
18559
  const someSelected = selectedIds.size > 0;
@@ -19389,7 +19389,7 @@ var init_FilterGroup = __esm({
19389
19389
  eventBus.emit("UI:FILTER", {
19390
19390
  entity,
19391
19391
  field,
19392
- value: value === "all" ? null : value,
19392
+ value: value === "all" || value === null ? "" : value,
19393
19393
  query
19394
19394
  });
19395
19395
  },
@@ -20201,7 +20201,7 @@ var init_SearchInput = __esm({
20201
20201
  /* @__PURE__ */ jsxRuntime.jsx(
20202
20202
  Input,
20203
20203
  {
20204
- type: "search",
20204
+ type: "text",
20205
20205
  value: searchValue,
20206
20206
  onChange: handleChange,
20207
20207
  placeholder: resolvedPlaceholder,
@@ -37880,7 +37880,7 @@ function SlotContentRenderer({
37880
37880
  }) {
37881
37881
  const entityProp = content.props.entity;
37882
37882
  if (content.pattern === "form-section") {
37883
- slotLog.debug("SlotContentRenderer:form-section-render", {
37883
+ slotLog2.debug("SlotContentRenderer:form-section-render", {
37884
37884
  contentId: content.id,
37885
37885
  sourceTrait: content.sourceTrait,
37886
37886
  entityRefId: refId(entityProp),
@@ -38091,6 +38091,10 @@ var init_UISlotRenderer = __esm({
38091
38091
 
38092
38092
  // hooks/index.ts
38093
38093
  init_useEventBus();
38094
+
38095
+ // hooks/useUISlots.ts
38096
+ init_logger();
38097
+ createLogger("almadar:ui:useUISlots");
38094
38098
  var ALL_SLOTS = [
38095
38099
  "main",
38096
38100
  "sidebar",
@@ -38293,6 +38297,7 @@ init_traitRegistry();
38293
38297
  init_verificationRegistry();
38294
38298
  var crossTraitLog = createLogger("almadar:ui:cross-trait");
38295
38299
  var flushLog = createLogger("almadar:ui:slot-flush");
38300
+ var stateLog = createLogger("almadar:ui:state-transitions");
38296
38301
  function toTraitDefinition(binding) {
38297
38302
  return {
38298
38303
  name: binding.trait.name,
@@ -38725,21 +38730,29 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
38725
38730
  const executor = new runtime.EffectExecutor({ handlers: trackingHandlers, bindings: bindingCtx, context: effectContext });
38726
38731
  try {
38727
38732
  await executor.executeAll(result.effects);
38728
- console.log(
38729
- "[TraitStateMachine] After executeAll, pendingSlots:",
38730
- Object.fromEntries(pendingSlots.entries())
38731
- );
38733
+ stateLog.info("transition:render-ui-dispatched", {
38734
+ traitName,
38735
+ fromState: result.previousState,
38736
+ toState: result.newState,
38737
+ event: eventKey,
38738
+ slotsTouched: Array.from(pendingSlots.keys()).join(","),
38739
+ patternTypes: Array.from(pendingSlots.entries()).map(
38740
+ ([slot, patterns]) => `${slot}:[${patterns.map((p2) => p2.pattern?.type ?? "null").join(",")}]`
38741
+ ).join(";")
38742
+ });
38732
38743
  void slotSource;
38733
38744
  for (const [slot, patterns] of pendingSlots) {
38734
38745
  flushSlot(traitName, slot, patterns);
38735
38746
  }
38736
38747
  } catch (error) {
38737
- console.error(
38738
- "[TraitStateMachine] Effect execution error:",
38739
- error,
38740
- "| effects:",
38741
- JSON.stringify(result.effects)
38742
- );
38748
+ stateLog.error("transition:effect-error", {
38749
+ traitName,
38750
+ fromState: result.previousState,
38751
+ toState: result.newState,
38752
+ event: eventKey,
38753
+ error: error instanceof Error ? error.message : String(error),
38754
+ effectCount: result.effects.length
38755
+ });
38743
38756
  }
38744
38757
  } else if (!result.executed) {
38745
38758
  if (result.guardResult === false) {
@@ -38885,13 +38898,20 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
38885
38898
  if (eventKey === "INIT" || eventKey === "LOAD" || eventKey === "$MOUNT") {
38886
38899
  continue;
38887
38900
  }
38888
- const unsub = eventBus.on(`UI:${orbitalName}.${traitName}.${eventKey}`, (event) => {
38901
+ const selfBusKey = `UI:${orbitalName}.${traitName}.${eventKey}`;
38902
+ crossTraitLog.debug("self:subscribe", { traitName, busKey: selfBusKey, eventKey });
38903
+ const unsub = eventBus.on(selfBusKey, (event) => {
38889
38904
  if (event.source && event.source.fromBridge) {
38905
+ crossTraitLog.debug("self:fire-skipped-bridge-echo", { traitName, busKey: selfBusKey, eventKey });
38890
38906
  return;
38891
38907
  }
38908
+ crossTraitLog.info("self:fire", { traitName, busKey: selfBusKey, eventKey });
38892
38909
  enqueueAndDrain(eventKey, event.payload);
38893
38910
  });
38894
- unsubscribes.push(unsub);
38911
+ unsubscribes.push(() => {
38912
+ crossTraitLog.debug("self:unsubscribe", { traitName, busKey: selfBusKey, eventKey });
38913
+ unsub();
38914
+ });
38895
38915
  }
38896
38916
  }
38897
38917
  for (const binding of traitBindings) {
@@ -38909,18 +38929,23 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
38909
38929
  const sourceOrbital = listen.source?.orbital ?? ownOrbital;
38910
38930
  if (!sourceOrbital) continue;
38911
38931
  const busKey = `UI:${sourceOrbital}.${sourceTrait}.${listen.event}`;
38912
- crossTraitLog.debug("listen:subscribed", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
38932
+ crossTraitLog.debug("listen:subscribed", { busKey, targetTrait: binding.trait.name, sourceOrbital, sourceTrait, listenEvent: listen.event, triggers: listen.triggers });
38913
38933
  const unsub = eventBus.on(busKey, (event) => {
38914
38934
  crossTraitLog.info("listen:fired", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
38915
38935
  enqueueAndDrain(listen.triggers, event.payload);
38916
38936
  });
38917
- unsubscribes.push(unsub);
38937
+ unsubscribes.push(() => {
38938
+ crossTraitLog.debug("listen:unsubscribe", { busKey, targetTrait: binding.trait.name, triggers: listen.triggers });
38939
+ unsub();
38940
+ });
38918
38941
  }
38919
38942
  }
38920
38943
  return () => {
38944
+ crossTraitLog.debug("cleanup:start", { unsubscribeCount: unsubscribes.length });
38921
38945
  for (const unsub of unsubscribes) {
38922
38946
  unsub();
38923
38947
  }
38948
+ crossTraitLog.debug("cleanup:done", {});
38924
38949
  };
38925
38950
  }, [traitBindings, eventBus, enqueueAndDrain]);
38926
38951
  return {