@logixjs/devtools-react 0.0.2 → 1.0.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.
@@ -50,7 +50,10 @@ module.exports = __toCommonJS(DevtoolsLayer_exports);
50
50
  // src/internal/snapshot/index.ts
51
51
  var Logix = __toESM(require("@logixjs/core"), 1);
52
52
  var import_effect = require("effect");
53
- var clearDevtoolsEvents = Logix.Debug.clearDevtoolsEvents;
53
+ var clearDevtoolsEvents = () => {
54
+ Logix.Debug.clearDevtoolsEvents();
55
+ notify();
56
+ };
54
57
  var setInstanceLabel = Logix.Debug.setInstanceLabel;
55
58
  var getInstanceLabel = Logix.Debug.getInstanceLabel;
56
59
  var snapshotOverride;
@@ -95,7 +98,9 @@ var normalizeDevtoolsSnapshot = (snapshot) => {
95
98
  };
96
99
  var listeners = /* @__PURE__ */ new Set();
97
100
  var unsubscribeCore;
101
+ var snapshotPubSub = import_effect.Effect.runSync(import_effect.PubSub.unbounded());
98
102
  var notify = () => {
103
+ import_effect.PubSub.publishUnsafe(snapshotPubSub, getDevtoolsSnapshot());
99
104
  for (const listener of listeners) {
100
105
  listener();
101
106
  }
@@ -137,17 +142,13 @@ var subscribeDevtoolsSnapshot = (listener) => {
137
142
  };
138
143
  var subscribeDevtoolsSnapshotToken = subscribeDevtoolsSnapshot;
139
144
  var devtoolsLayer = Logix.Debug.devtoolsHubLayer();
140
- var DevtoolsSnapshotStore = class extends import_effect.Context.Tag("Logix/DevtoolsSnapshotStore")() {
145
+ var DevtoolsSnapshotStore = class extends import_effect.ServiceMap.Service()(
146
+ "Logix/DevtoolsSnapshotStore"
147
+ ) {
141
148
  };
142
149
  var devtoolsSnapshotService = {
143
150
  get: import_effect.Effect.sync(() => getDevtoolsSnapshot()),
144
- changes: import_effect.Stream.async((emit) => {
145
- const listener = () => {
146
- emit.single(getDevtoolsSnapshot());
147
- };
148
- const unsubscribe = subscribeDevtoolsSnapshot(listener);
149
- return import_effect.Effect.sync(unsubscribe);
150
- })
151
+ changes: import_effect.Stream.fromPubSub(snapshotPubSub)
151
152
  };
152
153
  var devtoolsSnapshotLayer = import_effect.Layer.succeed(
153
154
  DevtoolsSnapshotStore,
@@ -1,5 +1,5 @@
1
1
  import * as Logix from '@logixjs/core';
2
- import { Layer, Effect, Stream, Context } from 'effect';
2
+ import { Layer, Effect, Stream, ServiceMap } from 'effect';
3
3
 
4
4
  /**
5
5
  * Notes:
@@ -40,7 +40,7 @@ interface DevtoolsSnapshotService {
40
40
  readonly get: Effect.Effect<DevtoolsSnapshot>;
41
41
  readonly changes: Stream.Stream<DevtoolsSnapshot>;
42
42
  }
43
- declare const DevtoolsSnapshotStore_base: Context.TagClass<DevtoolsSnapshotStore, "Logix/DevtoolsSnapshotStore", DevtoolsSnapshotService>;
43
+ declare const DevtoolsSnapshotStore_base: ServiceMap.ServiceClass<DevtoolsSnapshotStore, "Logix/DevtoolsSnapshotStore", DevtoolsSnapshotService>;
44
44
  /**
45
45
  * DevtoolsSnapshotStore:
46
46
  * - Exposed as an Env Service for Devtools Runtime.
@@ -1,5 +1,5 @@
1
1
  import * as Logix from '@logixjs/core';
2
- import { Layer, Effect, Stream, Context } from 'effect';
2
+ import { Layer, Effect, Stream, ServiceMap } from 'effect';
3
3
 
4
4
  /**
5
5
  * Notes:
@@ -40,7 +40,7 @@ interface DevtoolsSnapshotService {
40
40
  readonly get: Effect.Effect<DevtoolsSnapshot>;
41
41
  readonly changes: Stream.Stream<DevtoolsSnapshot>;
42
42
  }
43
- declare const DevtoolsSnapshotStore_base: Context.TagClass<DevtoolsSnapshotStore, "Logix/DevtoolsSnapshotStore", DevtoolsSnapshotService>;
43
+ declare const DevtoolsSnapshotStore_base: ServiceMap.ServiceClass<DevtoolsSnapshotStore, "Logix/DevtoolsSnapshotStore", DevtoolsSnapshotService>;
44
44
  /**
45
45
  * DevtoolsSnapshotStore:
46
46
  * - Exposed as an Env Service for Devtools Runtime.
@@ -14,7 +14,7 @@ import {
14
14
  setInstanceLabel,
15
15
  subscribeDevtoolsSnapshot,
16
16
  subscribeDevtoolsSnapshotToken
17
- } from "./chunk-FNWHBEXD.js";
17
+ } from "./chunk-NH3EYAZ6.js";
18
18
  export {
19
19
  DevtoolsSnapshotStore,
20
20
  clearDevtoolsEvents,
@@ -64,15 +64,19 @@ var Logix8 = __toESM(require("@logixjs/core"), 1);
64
64
 
65
65
  // src/internal/ui/hooks/DevtoolsHooks.tsx
66
66
  var import_react = __toESM(require("react"), 1);
67
- var import_effect5 = require("effect");
67
+ var import_effect6 = require("effect");
68
68
 
69
69
  // src/internal/state/runtime.ts
70
70
  var Logix5 = __toESM(require("@logixjs/core"), 1);
71
+ var import_effect5 = require("effect");
71
72
 
72
73
  // src/internal/snapshot/index.ts
73
74
  var Logix = __toESM(require("@logixjs/core"), 1);
74
75
  var import_effect = require("effect");
75
- var clearDevtoolsEvents = Logix.Debug.clearDevtoolsEvents;
76
+ var clearDevtoolsEvents = () => {
77
+ Logix.Debug.clearDevtoolsEvents();
78
+ notify();
79
+ };
76
80
  var setInstanceLabel = Logix.Debug.setInstanceLabel;
77
81
  var getInstanceLabel = Logix.Debug.getInstanceLabel;
78
82
  var snapshotOverride;
@@ -116,19 +120,13 @@ var normalizeDevtoolsSnapshot = (snapshot) => {
116
120
  return { ...snapshot, events };
117
121
  };
118
122
  var listeners = /* @__PURE__ */ new Set();
119
- var unsubscribeCore;
123
+ var snapshotPubSub = import_effect.Effect.runSync(import_effect.PubSub.unbounded());
120
124
  var notify = () => {
125
+ import_effect.PubSub.publishUnsafe(snapshotPubSub, getDevtoolsSnapshot());
121
126
  for (const listener of listeners) {
122
127
  listener();
123
128
  }
124
129
  };
125
- var ensureCoreSubscribed = () => {
126
- if (unsubscribeCore) return;
127
- unsubscribeCore = Logix.Debug.subscribeDevtoolsSnapshot(() => {
128
- if (snapshotOverride) return;
129
- notify();
130
- });
131
- };
132
130
  var hasDevtoolsSnapshotOverride = () => snapshotOverride != null;
133
131
  var getDevtoolsSnapshotOverrideInfo = () => snapshotOverrideInfo;
134
132
  var setDevtoolsSnapshotOverride = (snapshot, info) => {
@@ -145,29 +143,14 @@ var clearDevtoolsSnapshotOverride = () => {
145
143
  notify();
146
144
  };
147
145
  var getDevtoolsSnapshot = () => snapshotOverride ?? Logix.Debug.getDevtoolsSnapshot();
148
- var subscribeDevtoolsSnapshot = (listener) => {
149
- listeners.add(listener);
150
- ensureCoreSubscribed();
151
- return () => {
152
- listeners.delete(listener);
153
- if (listeners.size === 0 && unsubscribeCore) {
154
- unsubscribeCore();
155
- unsubscribeCore = void 0;
156
- }
157
- };
158
- };
159
146
  var devtoolsLayer = Logix.Debug.devtoolsHubLayer();
160
- var DevtoolsSnapshotStore = class extends import_effect.Context.Tag("Logix/DevtoolsSnapshotStore")() {
147
+ var DevtoolsSnapshotStore = class extends import_effect.ServiceMap.Service()(
148
+ "Logix/DevtoolsSnapshotStore"
149
+ ) {
161
150
  };
162
151
  var devtoolsSnapshotService = {
163
152
  get: import_effect.Effect.sync(() => getDevtoolsSnapshot()),
164
- changes: import_effect.Stream.async((emit) => {
165
- const listener = () => {
166
- emit.single(getDevtoolsSnapshot());
167
- };
168
- const unsubscribe = subscribeDevtoolsSnapshot(listener);
169
- return import_effect.Effect.sync(unsubscribe);
170
- })
153
+ changes: import_effect.Stream.fromPubSub(snapshotPubSub)
171
154
  };
172
155
  var devtoolsSnapshotLayer = import_effect.Layer.succeed(
173
156
  DevtoolsSnapshotStore,
@@ -213,7 +196,7 @@ var OperationSummarySchema = import_effect2.Schema.Struct({
213
196
  top3: import_effect2.Schema.Array(
214
197
  import_effect2.Schema.Struct({
215
198
  stepId: import_effect2.Schema.String,
216
- kind: import_effect2.Schema.Literal("computed", "link"),
199
+ kind: import_effect2.Schema.Literals(["computed", "link"]),
217
200
  fieldPath: import_effect2.Schema.String,
218
201
  durationMs: import_effect2.Schema.Number,
219
202
  changed: import_effect2.Schema.Boolean,
@@ -229,7 +212,7 @@ var TriggerLayoutSchema = import_effect2.Schema.Struct({
229
212
  isDragging: import_effect2.Schema.Boolean
230
213
  });
231
214
  var DevtoolsSettingsSchema = import_effect2.Schema.Struct({
232
- mode: import_effect2.Schema.Literal("basic", "deep"),
215
+ mode: import_effect2.Schema.Literals(["basic", "deep"]),
233
216
  showTraitEvents: import_effect2.Schema.Boolean,
234
217
  showReactRenderEvents: import_effect2.Schema.Boolean,
235
218
  enableTimeTravelUI: import_effect2.Schema.Boolean,
@@ -270,7 +253,7 @@ var DevtoolsStateSchema = import_effect2.Schema.Struct({
270
253
  moduleId: import_effect2.Schema.String,
271
254
  instanceId: import_effect2.Schema.String,
272
255
  txnId: import_effect2.Schema.String,
273
- mode: import_effect2.Schema.Literal("before", "after")
256
+ mode: import_effect2.Schema.Literals(["before", "after"])
274
257
  })
275
258
  ),
276
259
  runtimes: import_effect2.Schema.Array(
@@ -299,7 +282,7 @@ var DevtoolsStateSchema = import_effect2.Schema.Struct({
299
282
  isDragging: import_effect2.Schema.Boolean,
300
283
  trigger: import_effect2.Schema.optional(TriggerLayoutSchema)
301
284
  }),
302
- theme: import_effect2.Schema.Literal("system", "light", "dark"),
285
+ theme: import_effect2.Schema.Literals(["system", "light", "dark"]),
303
286
  settings: DevtoolsSettingsSchema
304
287
  });
305
288
  var defaultSettings = {
@@ -369,13 +352,11 @@ var gateDirtyRootPathsByDigest = (meta) => {
369
352
  }
370
353
  const dirtySet = meta.dirtySet;
371
354
  if (!isRecord2(dirtySet)) return meta;
372
- if (!Array.isArray(dirtySet.rootPaths)) return meta;
355
+ if (!Object.prototype.hasOwnProperty.call(dirtySet, "rootPaths")) return meta;
356
+ const { rootPaths: _rootPaths, ...dirtySetWithoutRootPaths } = dirtySet;
373
357
  return {
374
358
  ...meta,
375
- dirtySet: {
376
- ...dirtySet,
377
- rootPaths: void 0
378
- }
359
+ dirtySet: dirtySetWithoutRootPaths
379
360
  };
380
361
  };
381
362
  var getEventTimestamp = (event) => event.timestamp;
@@ -906,23 +887,21 @@ var persistSettingsToStorage = (settings) => {
906
887
  var Logix3 = __toESM(require("@logixjs/core"), 1);
907
888
  var import_effect3 = require("effect");
908
889
  var ResizePayload = import_effect3.Schema.Struct({
909
- edge: import_effect3.Schema.Literal("top", "left", "right")
890
+ edge: import_effect3.Schema.Literals(["top", "left", "right"])
891
+ });
892
+ var UpdateLayoutPayload = import_effect3.Schema.Struct({
893
+ height: import_effect3.Schema.optional(import_effect3.Schema.Number),
894
+ marginLeft: import_effect3.Schema.optional(import_effect3.Schema.Number),
895
+ marginRight: import_effect3.Schema.optional(import_effect3.Schema.Number),
896
+ isDragging: import_effect3.Schema.optional(import_effect3.Schema.Boolean),
897
+ trigger: import_effect3.Schema.optional(
898
+ import_effect3.Schema.Struct({
899
+ x: import_effect3.Schema.Number,
900
+ y: import_effect3.Schema.Number,
901
+ isDragging: import_effect3.Schema.Boolean
902
+ })
903
+ )
910
904
  });
911
- var UpdateLayoutPayload = import_effect3.Schema.partial(
912
- import_effect3.Schema.Struct({
913
- height: import_effect3.Schema.Number,
914
- marginLeft: import_effect3.Schema.Number,
915
- marginRight: import_effect3.Schema.Number,
916
- isDragging: import_effect3.Schema.Boolean,
917
- trigger: import_effect3.Schema.optional(
918
- import_effect3.Schema.Struct({
919
- x: import_effect3.Schema.Number,
920
- y: import_effect3.Schema.Number,
921
- isDragging: import_effect3.Schema.Boolean
922
- })
923
- )
924
- })
925
- );
926
905
  var DevtoolsModule = Logix3.Module.make("LogixDevtoolsModule", {
927
906
  state: DevtoolsStateSchema,
928
907
  actions: {
@@ -956,8 +935,8 @@ var DevtoolsModule = Logix3.Module.make("LogixDevtoolsModule", {
956
935
  clearImportedEvidence: import_effect3.Schema.Void,
957
936
  resizeStart: ResizePayload,
958
937
  updateLayout: UpdateLayoutPayload,
959
- setTheme: import_effect3.Schema.Literal("system", "light", "dark"),
960
- setMode: import_effect3.Schema.Literal("basic", "deep"),
938
+ setTheme: import_effect3.Schema.Literals(["system", "light", "dark"]),
939
+ setMode: import_effect3.Schema.Literals(["basic", "deep"]),
961
940
  updateSettings: import_effect3.Schema.Any
962
941
  },
963
942
  reducers: {
@@ -1192,15 +1171,165 @@ var normalizeRuntimeDebugEventRef = (value) => {
1192
1171
  }
1193
1172
  return { ...value, instanceId };
1194
1173
  };
1195
- var fromDomEvent = (event) => import_effect4.Stream.async((emit) => {
1196
- const handler = (e) => emit.single(e);
1197
- window.addEventListener(event, handler);
1198
- return import_effect4.Effect.sync(() => window.removeEventListener(event, handler));
1199
- });
1174
+ var readConvergeFieldPathsByDigest = (summary) => {
1175
+ if (!isRecord3(summary)) return /* @__PURE__ */ new Map();
1176
+ const converge = isRecord3(summary.converge) ? summary.converge : void 0;
1177
+ const byDigest = converge && isRecord3(converge.staticIrByDigest) ? converge.staticIrByDigest : void 0;
1178
+ if (!byDigest) return /* @__PURE__ */ new Map();
1179
+ const out = /* @__PURE__ */ new Map();
1180
+ for (const [digest, ir] of Object.entries(byDigest)) {
1181
+ if (!isRecord3(ir)) continue;
1182
+ const fieldPathsRaw = ir.fieldPaths;
1183
+ if (!Array.isArray(fieldPathsRaw)) continue;
1184
+ const fieldPaths = [];
1185
+ for (const pathRaw of fieldPathsRaw) {
1186
+ if (!Array.isArray(pathRaw) || pathRaw.length === 0) {
1187
+ fieldPaths.length = 0;
1188
+ break;
1189
+ }
1190
+ if (!pathRaw.every((seg) => typeof seg === "string" && seg.length > 0)) {
1191
+ fieldPaths.length = 0;
1192
+ break;
1193
+ }
1194
+ fieldPaths.push(pathRaw);
1195
+ }
1196
+ if (fieldPaths.length > 0) {
1197
+ out.set(digest, fieldPaths);
1198
+ }
1199
+ }
1200
+ return out;
1201
+ };
1202
+ var isPrefixPath = (prefix, path) => {
1203
+ if (prefix.length > path.length) return false;
1204
+ for (let i = 0; i < prefix.length; i++) {
1205
+ if (prefix[i] !== path[i]) return false;
1206
+ }
1207
+ return true;
1208
+ };
1209
+ var minimizeRootPaths = (paths) => {
1210
+ const roots = [];
1211
+ for (const path of paths) {
1212
+ let redundant = false;
1213
+ for (const existing of roots) {
1214
+ if (isPrefixPath(existing, path)) {
1215
+ redundant = true;
1216
+ break;
1217
+ }
1218
+ }
1219
+ if (redundant) continue;
1220
+ let nextLen = 0;
1221
+ for (let i = 0; i < roots.length; i++) {
1222
+ const existing = roots[i];
1223
+ if (isPrefixPath(path, existing)) continue;
1224
+ roots[nextLen] = existing;
1225
+ nextLen += 1;
1226
+ }
1227
+ roots.length = nextLen;
1228
+ roots.push(path);
1229
+ }
1230
+ return roots;
1231
+ };
1232
+ var resolveRootPaths = (args) => {
1233
+ const ids = args.ids;
1234
+ if (!Array.isArray(ids) || ids.length === 0) return void 0;
1235
+ const candidates = [];
1236
+ for (const rawId of ids) {
1237
+ if (!Number.isInteger(rawId)) continue;
1238
+ const id = rawId;
1239
+ if (id < 0 || id >= args.fieldPaths.length) continue;
1240
+ candidates.push(args.fieldPaths[id]);
1241
+ }
1242
+ if (candidates.length === 0) return void 0;
1243
+ const minimized = minimizeRootPaths(candidates);
1244
+ return minimized.length > 0 ? minimized : void 0;
1245
+ };
1246
+ var stripRootPathsField = (value) => {
1247
+ const { rootPaths: _rootPaths, ...rest } = value;
1248
+ return rest;
1249
+ };
1250
+ var stripLegacyDirtyRootPathsFromEvent = (event) => {
1251
+ const meta = isRecord3(event.meta) ? event.meta : void 0;
1252
+ if (!meta) return event;
1253
+ if (event.kind === "state" && event.label === "state:update") {
1254
+ const dirtySet = isRecord3(meta.dirtySet) ? meta.dirtySet : void 0;
1255
+ if (!dirtySet || !Object.prototype.hasOwnProperty.call(dirtySet, "rootPaths")) return event;
1256
+ return {
1257
+ ...event,
1258
+ meta: {
1259
+ ...meta,
1260
+ dirtySet: stripRootPathsField(dirtySet)
1261
+ }
1262
+ };
1263
+ }
1264
+ if (event.kind === "trait:converge") {
1265
+ const dirty = isRecord3(meta.dirty) ? meta.dirty : void 0;
1266
+ if (!dirty || !Object.prototype.hasOwnProperty.call(dirty, "rootPaths")) return event;
1267
+ return {
1268
+ ...event,
1269
+ meta: {
1270
+ ...meta,
1271
+ dirty: stripRootPathsField(dirty)
1272
+ }
1273
+ };
1274
+ }
1275
+ return event;
1276
+ };
1277
+ var materializeDirtyRootPathsFromCanonical = (args) => {
1278
+ if (args.fieldPathsByDigest.size === 0) return args.event;
1279
+ const meta = isRecord3(args.event.meta) ? args.event.meta : void 0;
1280
+ if (!meta) return args.event;
1281
+ const staticIrDigest = asNonEmptyString2(meta.staticIrDigest);
1282
+ if (!staticIrDigest) return args.event;
1283
+ const fieldPaths = args.fieldPathsByDigest.get(staticIrDigest);
1284
+ if (!fieldPaths) return args.event;
1285
+ if (args.event.kind === "state" && args.event.label === "state:update") {
1286
+ const dirtySet = isRecord3(meta.dirtySet) ? meta.dirtySet : void 0;
1287
+ if (!dirtySet) return args.event;
1288
+ const ids = Object.prototype.hasOwnProperty.call(dirtySet, "pathIds") ? dirtySet.pathIds : dirtySet.rootIds;
1289
+ const rootPaths = resolveRootPaths({ ids, fieldPaths });
1290
+ if (!rootPaths) return args.event;
1291
+ return {
1292
+ ...args.event,
1293
+ meta: {
1294
+ ...meta,
1295
+ dirtySet: {
1296
+ ...dirtySet,
1297
+ rootPaths
1298
+ }
1299
+ }
1300
+ };
1301
+ }
1302
+ if (args.event.kind === "trait:converge") {
1303
+ const dirty = isRecord3(meta.dirty) ? meta.dirty : void 0;
1304
+ if (!dirty) return args.event;
1305
+ const rootPaths = resolveRootPaths({ ids: dirty.rootIds, fieldPaths });
1306
+ if (!rootPaths) return args.event;
1307
+ return {
1308
+ ...args.event,
1309
+ meta: {
1310
+ ...meta,
1311
+ dirty: {
1312
+ ...dirty,
1313
+ rootPaths
1314
+ }
1315
+ }
1316
+ };
1317
+ }
1318
+ return args.event;
1319
+ };
1320
+ var fromDomEvent = (event) => import_effect4.Stream.callback(
1321
+ (queue) => import_effect4.Effect.gen(function* () {
1322
+ const handler = (e) => {
1323
+ import_effect4.Queue.offerUnsafe(queue, e);
1324
+ };
1325
+ window.addEventListener(event, handler);
1326
+ yield* import_effect4.Effect.addFinalizer(() => import_effect4.Effect.sync(() => window.removeEventListener(event, handler)));
1327
+ })
1328
+ );
1200
1329
  var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1201
1330
  setup: $.lifecycle.onStart(
1202
1331
  import_effect4.Effect.gen(function* () {
1203
- const snapshotStore = yield* DevtoolsSnapshotStore;
1332
+ const snapshotStore = yield* $.use(DevtoolsSnapshotStore);
1204
1333
  const initialSnapshot = yield* snapshotStore.get;
1205
1334
  yield* $.state.update(
1206
1335
  (prev) => computeDevtoolsState(prev, initialSnapshot, {
@@ -1211,7 +1340,7 @@ var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1211
1340
  ),
1212
1341
  // run section: initialize snapshot subscription + register all onAction watchers and dragging logic.
1213
1342
  run: import_effect4.Effect.gen(function* () {
1214
- const snapshotStore = yield* DevtoolsSnapshotStore;
1343
+ const snapshotStore = yield* $.use(DevtoolsSnapshotStore);
1215
1344
  yield* $.on(snapshotStore.changes).runFork(
1216
1345
  (snapshot) => $.state.update(
1217
1346
  (prev) => computeDevtoolsState(prev, snapshot, {
@@ -1310,13 +1439,15 @@ var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1310
1439
  return;
1311
1440
  }
1312
1441
  const evidence = Logix4.Observability.importEvidencePackage(parsed);
1442
+ const fieldPathsByDigest = readConvergeFieldPathsByDigest(evidence.summary);
1313
1443
  const events = [];
1314
1444
  for (const envelope of evidence.events) {
1315
1445
  if (envelope.type !== "debug:event") continue;
1316
1446
  const payload = envelope.payload;
1317
1447
  const normalized = normalizeRuntimeDebugEventRef(payload);
1318
1448
  if (!normalized) continue;
1319
- events.push(normalized);
1449
+ const canonicalEvent = stripLegacyDirtyRootPathsFromEvent(normalized);
1450
+ events.push(materializeDirtyRootPathsFromCanonical({ event: canonicalEvent, fieldPathsByDigest }));
1320
1451
  }
1321
1452
  const snapshot = {
1322
1453
  snapshotToken: 0,
@@ -1408,18 +1539,18 @@ var devtoolsRuntime = Logix5.Runtime.make(DevtoolsImpl, {
1408
1539
  // so Logic can subscribe to Snapshot changes via Tag.
1409
1540
  layer: devtoolsSnapshotLayer
1410
1541
  });
1411
- var devtoolsModuleRuntime = devtoolsRuntime.runSync(DevtoolsModule.tag);
1542
+ var devtoolsModuleRuntime = devtoolsRuntime.runSync(import_effect5.Effect.service(DevtoolsModule.tag).pipe(import_effect5.Effect.orDie));
1412
1543
 
1413
1544
  // src/internal/ui/hooks/DevtoolsHooks.tsx
1414
1545
  var subscribe = (onStoreChange) => {
1415
1546
  const fiber = devtoolsRuntime.runFork(
1416
- import_effect5.Stream.runForEach(
1547
+ import_effect6.Stream.runForEach(
1417
1548
  devtoolsModuleRuntime.changes((state) => state),
1418
- () => import_effect5.Effect.sync(onStoreChange)
1549
+ () => import_effect6.Effect.sync(onStoreChange)
1419
1550
  )
1420
1551
  );
1421
1552
  return () => {
1422
- devtoolsRuntime.runFork(import_effect5.Fiber.interrupt(fiber));
1553
+ devtoolsRuntime.runFork(import_effect6.Fiber.interrupt(fiber));
1423
1554
  };
1424
1555
  };
1425
1556
  var getSnapshot = () => devtoolsRuntime.runSync(devtoolsModuleRuntime.getState);
@@ -1747,9 +1878,9 @@ var makeTraitConvergeOverrideSnippets = (params) => {
1747
1878
  [moduleId]: patch
1748
1879
  }
1749
1880
  })})`;
1750
- const moduleOverride = `Logix.Runtime.setTraitConvergeOverride(runtime, ${stableStringify(moduleId)}, ${stableStringify(
1881
+ const moduleOverride = `await Effect.runPromise(Logix.Runtime.setTraitConvergeOverride(runtime, ${stableStringify(moduleId)}, ${stableStringify(
1751
1882
  patch
1752
- )})`;
1883
+ )}))`;
1753
1884
  return [
1754
1885
  {
1755
1886
  kind: "provider_override",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  LogixDevtools
3
- } from "./chunk-WTZBDE4J.js";
4
- import "./chunk-FNWHBEXD.js";
3
+ } from "./chunk-H5JD2DNC.js";
4
+ import "./chunk-NH3EYAZ6.js";
5
5
  import "./chunk-CZWYV2AZ.js";
6
6
  export {
7
7
  LogixDevtools
@@ -8,7 +8,7 @@ import {
8
8
  getInstanceLabel,
9
9
  hasDevtoolsSnapshotOverride,
10
10
  setDevtoolsSnapshotOverride
11
- } from "./chunk-FNWHBEXD.js";
11
+ } from "./chunk-NH3EYAZ6.js";
12
12
  import {
13
13
  StateTraitGraphView,
14
14
  ensureDevtoolsStyles
@@ -24,14 +24,15 @@ import * as Logix7 from "@logixjs/core";
24
24
 
25
25
  // src/internal/ui/hooks/DevtoolsHooks.tsx
26
26
  import React, { useSyncExternalStore } from "react";
27
- import { Effect as Effect2, Fiber, Stream as Stream2 } from "effect";
27
+ import { Effect as Effect3, Fiber, Stream as Stream2 } from "effect";
28
28
 
29
29
  // src/internal/state/runtime.ts
30
30
  import * as Logix4 from "@logixjs/core";
31
+ import { Effect as Effect2 } from "effect";
31
32
 
32
33
  // src/internal/state/logic.ts
33
34
  import * as Logix3 from "@logixjs/core";
34
- import { Effect, Stream } from "effect";
35
+ import { Effect, Queue, Stream } from "effect";
35
36
 
36
37
  // src/internal/state/compute.ts
37
38
  import * as Logix from "@logixjs/core";
@@ -68,7 +69,7 @@ var OperationSummarySchema = Schema.Struct({
68
69
  top3: Schema.Array(
69
70
  Schema.Struct({
70
71
  stepId: Schema.String,
71
- kind: Schema.Literal("computed", "link"),
72
+ kind: Schema.Literals(["computed", "link"]),
72
73
  fieldPath: Schema.String,
73
74
  durationMs: Schema.Number,
74
75
  changed: Schema.Boolean,
@@ -84,7 +85,7 @@ var TriggerLayoutSchema = Schema.Struct({
84
85
  isDragging: Schema.Boolean
85
86
  });
86
87
  var DevtoolsSettingsSchema = Schema.Struct({
87
- mode: Schema.Literal("basic", "deep"),
88
+ mode: Schema.Literals(["basic", "deep"]),
88
89
  showTraitEvents: Schema.Boolean,
89
90
  showReactRenderEvents: Schema.Boolean,
90
91
  enableTimeTravelUI: Schema.Boolean,
@@ -125,7 +126,7 @@ var DevtoolsStateSchema = Schema.Struct({
125
126
  moduleId: Schema.String,
126
127
  instanceId: Schema.String,
127
128
  txnId: Schema.String,
128
- mode: Schema.Literal("before", "after")
129
+ mode: Schema.Literals(["before", "after"])
129
130
  })
130
131
  ),
131
132
  runtimes: Schema.Array(
@@ -154,7 +155,7 @@ var DevtoolsStateSchema = Schema.Struct({
154
155
  isDragging: Schema.Boolean,
155
156
  trigger: Schema.optional(TriggerLayoutSchema)
156
157
  }),
157
- theme: Schema.Literal("system", "light", "dark"),
158
+ theme: Schema.Literals(["system", "light", "dark"]),
158
159
  settings: DevtoolsSettingsSchema
159
160
  });
160
161
  var defaultSettings = {
@@ -224,13 +225,11 @@ var gateDirtyRootPathsByDigest = (meta) => {
224
225
  }
225
226
  const dirtySet = meta.dirtySet;
226
227
  if (!isRecord(dirtySet)) return meta;
227
- if (!Array.isArray(dirtySet.rootPaths)) return meta;
228
+ if (!Object.prototype.hasOwnProperty.call(dirtySet, "rootPaths")) return meta;
229
+ const { rootPaths: _rootPaths, ...dirtySetWithoutRootPaths } = dirtySet;
228
230
  return {
229
231
  ...meta,
230
- dirtySet: {
231
- ...dirtySet,
232
- rootPaths: void 0
233
- }
232
+ dirtySet: dirtySetWithoutRootPaths
234
233
  };
235
234
  };
236
235
  var getEventTimestamp = (event) => event.timestamp;
@@ -761,23 +760,21 @@ var persistSettingsToStorage = (settings) => {
761
760
  import * as Logix2 from "@logixjs/core";
762
761
  import { Schema as Schema2 } from "effect";
763
762
  var ResizePayload = Schema2.Struct({
764
- edge: Schema2.Literal("top", "left", "right")
763
+ edge: Schema2.Literals(["top", "left", "right"])
764
+ });
765
+ var UpdateLayoutPayload = Schema2.Struct({
766
+ height: Schema2.optional(Schema2.Number),
767
+ marginLeft: Schema2.optional(Schema2.Number),
768
+ marginRight: Schema2.optional(Schema2.Number),
769
+ isDragging: Schema2.optional(Schema2.Boolean),
770
+ trigger: Schema2.optional(
771
+ Schema2.Struct({
772
+ x: Schema2.Number,
773
+ y: Schema2.Number,
774
+ isDragging: Schema2.Boolean
775
+ })
776
+ )
765
777
  });
766
- var UpdateLayoutPayload = Schema2.partial(
767
- Schema2.Struct({
768
- height: Schema2.Number,
769
- marginLeft: Schema2.Number,
770
- marginRight: Schema2.Number,
771
- isDragging: Schema2.Boolean,
772
- trigger: Schema2.optional(
773
- Schema2.Struct({
774
- x: Schema2.Number,
775
- y: Schema2.Number,
776
- isDragging: Schema2.Boolean
777
- })
778
- )
779
- })
780
- );
781
778
  var DevtoolsModule = Logix2.Module.make("LogixDevtoolsModule", {
782
779
  state: DevtoolsStateSchema,
783
780
  actions: {
@@ -811,8 +808,8 @@ var DevtoolsModule = Logix2.Module.make("LogixDevtoolsModule", {
811
808
  clearImportedEvidence: Schema2.Void,
812
809
  resizeStart: ResizePayload,
813
810
  updateLayout: UpdateLayoutPayload,
814
- setTheme: Schema2.Literal("system", "light", "dark"),
815
- setMode: Schema2.Literal("basic", "deep"),
811
+ setTheme: Schema2.Literals(["system", "light", "dark"]),
812
+ setMode: Schema2.Literals(["basic", "deep"]),
816
813
  updateSettings: Schema2.Any
817
814
  },
818
815
  reducers: {
@@ -1047,15 +1044,165 @@ var normalizeRuntimeDebugEventRef = (value) => {
1047
1044
  }
1048
1045
  return { ...value, instanceId };
1049
1046
  };
1050
- var fromDomEvent = (event) => Stream.async((emit) => {
1051
- const handler = (e) => emit.single(e);
1052
- window.addEventListener(event, handler);
1053
- return Effect.sync(() => window.removeEventListener(event, handler));
1054
- });
1047
+ var readConvergeFieldPathsByDigest = (summary) => {
1048
+ if (!isRecord2(summary)) return /* @__PURE__ */ new Map();
1049
+ const converge = isRecord2(summary.converge) ? summary.converge : void 0;
1050
+ const byDigest = converge && isRecord2(converge.staticIrByDigest) ? converge.staticIrByDigest : void 0;
1051
+ if (!byDigest) return /* @__PURE__ */ new Map();
1052
+ const out = /* @__PURE__ */ new Map();
1053
+ for (const [digest, ir] of Object.entries(byDigest)) {
1054
+ if (!isRecord2(ir)) continue;
1055
+ const fieldPathsRaw = ir.fieldPaths;
1056
+ if (!Array.isArray(fieldPathsRaw)) continue;
1057
+ const fieldPaths = [];
1058
+ for (const pathRaw of fieldPathsRaw) {
1059
+ if (!Array.isArray(pathRaw) || pathRaw.length === 0) {
1060
+ fieldPaths.length = 0;
1061
+ break;
1062
+ }
1063
+ if (!pathRaw.every((seg) => typeof seg === "string" && seg.length > 0)) {
1064
+ fieldPaths.length = 0;
1065
+ break;
1066
+ }
1067
+ fieldPaths.push(pathRaw);
1068
+ }
1069
+ if (fieldPaths.length > 0) {
1070
+ out.set(digest, fieldPaths);
1071
+ }
1072
+ }
1073
+ return out;
1074
+ };
1075
+ var isPrefixPath = (prefix, path) => {
1076
+ if (prefix.length > path.length) return false;
1077
+ for (let i = 0; i < prefix.length; i++) {
1078
+ if (prefix[i] !== path[i]) return false;
1079
+ }
1080
+ return true;
1081
+ };
1082
+ var minimizeRootPaths = (paths) => {
1083
+ const roots = [];
1084
+ for (const path of paths) {
1085
+ let redundant = false;
1086
+ for (const existing of roots) {
1087
+ if (isPrefixPath(existing, path)) {
1088
+ redundant = true;
1089
+ break;
1090
+ }
1091
+ }
1092
+ if (redundant) continue;
1093
+ let nextLen = 0;
1094
+ for (let i = 0; i < roots.length; i++) {
1095
+ const existing = roots[i];
1096
+ if (isPrefixPath(path, existing)) continue;
1097
+ roots[nextLen] = existing;
1098
+ nextLen += 1;
1099
+ }
1100
+ roots.length = nextLen;
1101
+ roots.push(path);
1102
+ }
1103
+ return roots;
1104
+ };
1105
+ var resolveRootPaths = (args) => {
1106
+ const ids = args.ids;
1107
+ if (!Array.isArray(ids) || ids.length === 0) return void 0;
1108
+ const candidates = [];
1109
+ for (const rawId of ids) {
1110
+ if (!Number.isInteger(rawId)) continue;
1111
+ const id = rawId;
1112
+ if (id < 0 || id >= args.fieldPaths.length) continue;
1113
+ candidates.push(args.fieldPaths[id]);
1114
+ }
1115
+ if (candidates.length === 0) return void 0;
1116
+ const minimized = minimizeRootPaths(candidates);
1117
+ return minimized.length > 0 ? minimized : void 0;
1118
+ };
1119
+ var stripRootPathsField = (value) => {
1120
+ const { rootPaths: _rootPaths, ...rest } = value;
1121
+ return rest;
1122
+ };
1123
+ var stripLegacyDirtyRootPathsFromEvent = (event) => {
1124
+ const meta = isRecord2(event.meta) ? event.meta : void 0;
1125
+ if (!meta) return event;
1126
+ if (event.kind === "state" && event.label === "state:update") {
1127
+ const dirtySet = isRecord2(meta.dirtySet) ? meta.dirtySet : void 0;
1128
+ if (!dirtySet || !Object.prototype.hasOwnProperty.call(dirtySet, "rootPaths")) return event;
1129
+ return {
1130
+ ...event,
1131
+ meta: {
1132
+ ...meta,
1133
+ dirtySet: stripRootPathsField(dirtySet)
1134
+ }
1135
+ };
1136
+ }
1137
+ if (event.kind === "trait:converge") {
1138
+ const dirty = isRecord2(meta.dirty) ? meta.dirty : void 0;
1139
+ if (!dirty || !Object.prototype.hasOwnProperty.call(dirty, "rootPaths")) return event;
1140
+ return {
1141
+ ...event,
1142
+ meta: {
1143
+ ...meta,
1144
+ dirty: stripRootPathsField(dirty)
1145
+ }
1146
+ };
1147
+ }
1148
+ return event;
1149
+ };
1150
+ var materializeDirtyRootPathsFromCanonical = (args) => {
1151
+ if (args.fieldPathsByDigest.size === 0) return args.event;
1152
+ const meta = isRecord2(args.event.meta) ? args.event.meta : void 0;
1153
+ if (!meta) return args.event;
1154
+ const staticIrDigest = asNonEmptyString(meta.staticIrDigest);
1155
+ if (!staticIrDigest) return args.event;
1156
+ const fieldPaths = args.fieldPathsByDigest.get(staticIrDigest);
1157
+ if (!fieldPaths) return args.event;
1158
+ if (args.event.kind === "state" && args.event.label === "state:update") {
1159
+ const dirtySet = isRecord2(meta.dirtySet) ? meta.dirtySet : void 0;
1160
+ if (!dirtySet) return args.event;
1161
+ const ids = Object.prototype.hasOwnProperty.call(dirtySet, "pathIds") ? dirtySet.pathIds : dirtySet.rootIds;
1162
+ const rootPaths = resolveRootPaths({ ids, fieldPaths });
1163
+ if (!rootPaths) return args.event;
1164
+ return {
1165
+ ...args.event,
1166
+ meta: {
1167
+ ...meta,
1168
+ dirtySet: {
1169
+ ...dirtySet,
1170
+ rootPaths
1171
+ }
1172
+ }
1173
+ };
1174
+ }
1175
+ if (args.event.kind === "trait:converge") {
1176
+ const dirty = isRecord2(meta.dirty) ? meta.dirty : void 0;
1177
+ if (!dirty) return args.event;
1178
+ const rootPaths = resolveRootPaths({ ids: dirty.rootIds, fieldPaths });
1179
+ if (!rootPaths) return args.event;
1180
+ return {
1181
+ ...args.event,
1182
+ meta: {
1183
+ ...meta,
1184
+ dirty: {
1185
+ ...dirty,
1186
+ rootPaths
1187
+ }
1188
+ }
1189
+ };
1190
+ }
1191
+ return args.event;
1192
+ };
1193
+ var fromDomEvent = (event) => Stream.callback(
1194
+ (queue) => Effect.gen(function* () {
1195
+ const handler = (e) => {
1196
+ Queue.offerUnsafe(queue, e);
1197
+ };
1198
+ window.addEventListener(event, handler);
1199
+ yield* Effect.addFinalizer(() => Effect.sync(() => window.removeEventListener(event, handler)));
1200
+ })
1201
+ );
1055
1202
  var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1056
1203
  setup: $.lifecycle.onStart(
1057
1204
  Effect.gen(function* () {
1058
- const snapshotStore = yield* DevtoolsSnapshotStore;
1205
+ const snapshotStore = yield* $.use(DevtoolsSnapshotStore);
1059
1206
  const initialSnapshot = yield* snapshotStore.get;
1060
1207
  yield* $.state.update(
1061
1208
  (prev) => computeDevtoolsState(prev, initialSnapshot, {
@@ -1066,7 +1213,7 @@ var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1066
1213
  ),
1067
1214
  // run section: initialize snapshot subscription + register all onAction watchers and dragging logic.
1068
1215
  run: Effect.gen(function* () {
1069
- const snapshotStore = yield* DevtoolsSnapshotStore;
1216
+ const snapshotStore = yield* $.use(DevtoolsSnapshotStore);
1070
1217
  yield* $.on(snapshotStore.changes).runFork(
1071
1218
  (snapshot) => $.state.update(
1072
1219
  (prev) => computeDevtoolsState(prev, snapshot, {
@@ -1165,13 +1312,15 @@ var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1165
1312
  return;
1166
1313
  }
1167
1314
  const evidence = Logix3.Observability.importEvidencePackage(parsed);
1315
+ const fieldPathsByDigest = readConvergeFieldPathsByDigest(evidence.summary);
1168
1316
  const events = [];
1169
1317
  for (const envelope of evidence.events) {
1170
1318
  if (envelope.type !== "debug:event") continue;
1171
1319
  const payload = envelope.payload;
1172
1320
  const normalized = normalizeRuntimeDebugEventRef(payload);
1173
1321
  if (!normalized) continue;
1174
- events.push(normalized);
1322
+ const canonicalEvent = stripLegacyDirtyRootPathsFromEvent(normalized);
1323
+ events.push(materializeDirtyRootPathsFromCanonical({ event: canonicalEvent, fieldPathsByDigest }));
1175
1324
  }
1176
1325
  const snapshot = {
1177
1326
  snapshotToken: 0,
@@ -1263,14 +1412,14 @@ var devtoolsRuntime = Logix4.Runtime.make(DevtoolsImpl, {
1263
1412
  // so Logic can subscribe to Snapshot changes via Tag.
1264
1413
  layer: devtoolsSnapshotLayer
1265
1414
  });
1266
- var devtoolsModuleRuntime = devtoolsRuntime.runSync(DevtoolsModule.tag);
1415
+ var devtoolsModuleRuntime = devtoolsRuntime.runSync(Effect2.service(DevtoolsModule.tag).pipe(Effect2.orDie));
1267
1416
 
1268
1417
  // src/internal/ui/hooks/DevtoolsHooks.tsx
1269
1418
  var subscribe = (onStoreChange) => {
1270
1419
  const fiber = devtoolsRuntime.runFork(
1271
1420
  Stream2.runForEach(
1272
1421
  devtoolsModuleRuntime.changes((state) => state),
1273
- () => Effect2.sync(onStoreChange)
1422
+ () => Effect3.sync(onStoreChange)
1274
1423
  )
1275
1424
  );
1276
1425
  return () => {
@@ -1602,9 +1751,9 @@ var makeTraitConvergeOverrideSnippets = (params) => {
1602
1751
  [moduleId]: patch
1603
1752
  }
1604
1753
  })})`;
1605
- const moduleOverride = `Logix.Runtime.setTraitConvergeOverride(runtime, ${stableStringify(moduleId)}, ${stableStringify(
1754
+ const moduleOverride = `await Effect.runPromise(Logix.Runtime.setTraitConvergeOverride(runtime, ${stableStringify(moduleId)}, ${stableStringify(
1606
1755
  patch
1607
- )})`;
1756
+ )}))`;
1608
1757
  return [
1609
1758
  {
1610
1759
  kind: "provider_override",
@@ -1,7 +1,10 @@
1
1
  // src/internal/snapshot/index.ts
2
2
  import * as Logix from "@logixjs/core";
3
- import { Context, Effect, Layer, Stream } from "effect";
4
- var clearDevtoolsEvents = Logix.Debug.clearDevtoolsEvents;
3
+ import { Effect, Layer, PubSub, ServiceMap, Stream } from "effect";
4
+ var clearDevtoolsEvents = () => {
5
+ Logix.Debug.clearDevtoolsEvents();
6
+ notify();
7
+ };
5
8
  var setInstanceLabel = Logix.Debug.setInstanceLabel;
6
9
  var getInstanceLabel = Logix.Debug.getInstanceLabel;
7
10
  var snapshotOverride;
@@ -46,7 +49,9 @@ var normalizeDevtoolsSnapshot = (snapshot) => {
46
49
  };
47
50
  var listeners = /* @__PURE__ */ new Set();
48
51
  var unsubscribeCore;
52
+ var snapshotPubSub = Effect.runSync(PubSub.unbounded());
49
53
  var notify = () => {
54
+ PubSub.publishUnsafe(snapshotPubSub, getDevtoolsSnapshot());
50
55
  for (const listener of listeners) {
51
56
  listener();
52
57
  }
@@ -88,17 +93,13 @@ var subscribeDevtoolsSnapshot = (listener) => {
88
93
  };
89
94
  var subscribeDevtoolsSnapshotToken = subscribeDevtoolsSnapshot;
90
95
  var devtoolsLayer = Logix.Debug.devtoolsHubLayer();
91
- var DevtoolsSnapshotStore = class extends Context.Tag("Logix/DevtoolsSnapshotStore")() {
96
+ var DevtoolsSnapshotStore = class extends ServiceMap.Service()(
97
+ "Logix/DevtoolsSnapshotStore"
98
+ ) {
92
99
  };
93
100
  var devtoolsSnapshotService = {
94
101
  get: Effect.sync(() => getDevtoolsSnapshot()),
95
- changes: Stream.async((emit) => {
96
- const listener = () => {
97
- emit.single(getDevtoolsSnapshot());
98
- };
99
- const unsubscribe = subscribeDevtoolsSnapshot(listener);
100
- return Effect.sync(unsubscribe);
101
- })
102
+ changes: Stream.fromPubSub(snapshotPubSub)
102
103
  };
103
104
  var devtoolsSnapshotLayer = Layer.succeed(
104
105
  DevtoolsSnapshotStore,
package/dist/index.cjs CHANGED
@@ -79,15 +79,19 @@ var Logix8 = __toESM(require("@logixjs/core"), 1);
79
79
 
80
80
  // src/internal/ui/hooks/DevtoolsHooks.tsx
81
81
  var import_react = __toESM(require("react"), 1);
82
- var import_effect5 = require("effect");
82
+ var import_effect6 = require("effect");
83
83
 
84
84
  // src/internal/state/runtime.ts
85
85
  var Logix5 = __toESM(require("@logixjs/core"), 1);
86
+ var import_effect5 = require("effect");
86
87
 
87
88
  // src/internal/snapshot/index.ts
88
89
  var Logix = __toESM(require("@logixjs/core"), 1);
89
90
  var import_effect = require("effect");
90
- var clearDevtoolsEvents = Logix.Debug.clearDevtoolsEvents;
91
+ var clearDevtoolsEvents = () => {
92
+ Logix.Debug.clearDevtoolsEvents();
93
+ notify();
94
+ };
91
95
  var setInstanceLabel = Logix.Debug.setInstanceLabel;
92
96
  var getInstanceLabel = Logix.Debug.getInstanceLabel;
93
97
  var snapshotOverride;
@@ -132,7 +136,9 @@ var normalizeDevtoolsSnapshot = (snapshot) => {
132
136
  };
133
137
  var listeners = /* @__PURE__ */ new Set();
134
138
  var unsubscribeCore;
139
+ var snapshotPubSub = import_effect.Effect.runSync(import_effect.PubSub.unbounded());
135
140
  var notify = () => {
141
+ import_effect.PubSub.publishUnsafe(snapshotPubSub, getDevtoolsSnapshot());
136
142
  for (const listener of listeners) {
137
143
  listener();
138
144
  }
@@ -174,17 +180,13 @@ var subscribeDevtoolsSnapshot = (listener) => {
174
180
  };
175
181
  var subscribeDevtoolsSnapshotToken = subscribeDevtoolsSnapshot;
176
182
  var devtoolsLayer = Logix.Debug.devtoolsHubLayer();
177
- var DevtoolsSnapshotStore = class extends import_effect.Context.Tag("Logix/DevtoolsSnapshotStore")() {
183
+ var DevtoolsSnapshotStore = class extends import_effect.ServiceMap.Service()(
184
+ "Logix/DevtoolsSnapshotStore"
185
+ ) {
178
186
  };
179
187
  var devtoolsSnapshotService = {
180
188
  get: import_effect.Effect.sync(() => getDevtoolsSnapshot()),
181
- changes: import_effect.Stream.async((emit) => {
182
- const listener = () => {
183
- emit.single(getDevtoolsSnapshot());
184
- };
185
- const unsubscribe = subscribeDevtoolsSnapshot(listener);
186
- return import_effect.Effect.sync(unsubscribe);
187
- })
189
+ changes: import_effect.Stream.fromPubSub(snapshotPubSub)
188
190
  };
189
191
  var devtoolsSnapshotLayer = import_effect.Layer.succeed(
190
192
  DevtoolsSnapshotStore,
@@ -230,7 +232,7 @@ var OperationSummarySchema = import_effect2.Schema.Struct({
230
232
  top3: import_effect2.Schema.Array(
231
233
  import_effect2.Schema.Struct({
232
234
  stepId: import_effect2.Schema.String,
233
- kind: import_effect2.Schema.Literal("computed", "link"),
235
+ kind: import_effect2.Schema.Literals(["computed", "link"]),
234
236
  fieldPath: import_effect2.Schema.String,
235
237
  durationMs: import_effect2.Schema.Number,
236
238
  changed: import_effect2.Schema.Boolean,
@@ -246,7 +248,7 @@ var TriggerLayoutSchema = import_effect2.Schema.Struct({
246
248
  isDragging: import_effect2.Schema.Boolean
247
249
  });
248
250
  var DevtoolsSettingsSchema = import_effect2.Schema.Struct({
249
- mode: import_effect2.Schema.Literal("basic", "deep"),
251
+ mode: import_effect2.Schema.Literals(["basic", "deep"]),
250
252
  showTraitEvents: import_effect2.Schema.Boolean,
251
253
  showReactRenderEvents: import_effect2.Schema.Boolean,
252
254
  enableTimeTravelUI: import_effect2.Schema.Boolean,
@@ -287,7 +289,7 @@ var DevtoolsStateSchema = import_effect2.Schema.Struct({
287
289
  moduleId: import_effect2.Schema.String,
288
290
  instanceId: import_effect2.Schema.String,
289
291
  txnId: import_effect2.Schema.String,
290
- mode: import_effect2.Schema.Literal("before", "after")
292
+ mode: import_effect2.Schema.Literals(["before", "after"])
291
293
  })
292
294
  ),
293
295
  runtimes: import_effect2.Schema.Array(
@@ -316,7 +318,7 @@ var DevtoolsStateSchema = import_effect2.Schema.Struct({
316
318
  isDragging: import_effect2.Schema.Boolean,
317
319
  trigger: import_effect2.Schema.optional(TriggerLayoutSchema)
318
320
  }),
319
- theme: import_effect2.Schema.Literal("system", "light", "dark"),
321
+ theme: import_effect2.Schema.Literals(["system", "light", "dark"]),
320
322
  settings: DevtoolsSettingsSchema
321
323
  });
322
324
  var defaultSettings = {
@@ -386,13 +388,11 @@ var gateDirtyRootPathsByDigest = (meta) => {
386
388
  }
387
389
  const dirtySet = meta.dirtySet;
388
390
  if (!isRecord2(dirtySet)) return meta;
389
- if (!Array.isArray(dirtySet.rootPaths)) return meta;
391
+ if (!Object.prototype.hasOwnProperty.call(dirtySet, "rootPaths")) return meta;
392
+ const { rootPaths: _rootPaths, ...dirtySetWithoutRootPaths } = dirtySet;
390
393
  return {
391
394
  ...meta,
392
- dirtySet: {
393
- ...dirtySet,
394
- rootPaths: void 0
395
- }
395
+ dirtySet: dirtySetWithoutRootPaths
396
396
  };
397
397
  };
398
398
  var getEventTimestamp = (event) => event.timestamp;
@@ -923,23 +923,21 @@ var persistSettingsToStorage = (settings) => {
923
923
  var Logix3 = __toESM(require("@logixjs/core"), 1);
924
924
  var import_effect3 = require("effect");
925
925
  var ResizePayload = import_effect3.Schema.Struct({
926
- edge: import_effect3.Schema.Literal("top", "left", "right")
926
+ edge: import_effect3.Schema.Literals(["top", "left", "right"])
927
+ });
928
+ var UpdateLayoutPayload = import_effect3.Schema.Struct({
929
+ height: import_effect3.Schema.optional(import_effect3.Schema.Number),
930
+ marginLeft: import_effect3.Schema.optional(import_effect3.Schema.Number),
931
+ marginRight: import_effect3.Schema.optional(import_effect3.Schema.Number),
932
+ isDragging: import_effect3.Schema.optional(import_effect3.Schema.Boolean),
933
+ trigger: import_effect3.Schema.optional(
934
+ import_effect3.Schema.Struct({
935
+ x: import_effect3.Schema.Number,
936
+ y: import_effect3.Schema.Number,
937
+ isDragging: import_effect3.Schema.Boolean
938
+ })
939
+ )
927
940
  });
928
- var UpdateLayoutPayload = import_effect3.Schema.partial(
929
- import_effect3.Schema.Struct({
930
- height: import_effect3.Schema.Number,
931
- marginLeft: import_effect3.Schema.Number,
932
- marginRight: import_effect3.Schema.Number,
933
- isDragging: import_effect3.Schema.Boolean,
934
- trigger: import_effect3.Schema.optional(
935
- import_effect3.Schema.Struct({
936
- x: import_effect3.Schema.Number,
937
- y: import_effect3.Schema.Number,
938
- isDragging: import_effect3.Schema.Boolean
939
- })
940
- )
941
- })
942
- );
943
941
  var DevtoolsModule = Logix3.Module.make("LogixDevtoolsModule", {
944
942
  state: DevtoolsStateSchema,
945
943
  actions: {
@@ -973,8 +971,8 @@ var DevtoolsModule = Logix3.Module.make("LogixDevtoolsModule", {
973
971
  clearImportedEvidence: import_effect3.Schema.Void,
974
972
  resizeStart: ResizePayload,
975
973
  updateLayout: UpdateLayoutPayload,
976
- setTheme: import_effect3.Schema.Literal("system", "light", "dark"),
977
- setMode: import_effect3.Schema.Literal("basic", "deep"),
974
+ setTheme: import_effect3.Schema.Literals(["system", "light", "dark"]),
975
+ setMode: import_effect3.Schema.Literals(["basic", "deep"]),
978
976
  updateSettings: import_effect3.Schema.Any
979
977
  },
980
978
  reducers: {
@@ -1209,15 +1207,165 @@ var normalizeRuntimeDebugEventRef = (value) => {
1209
1207
  }
1210
1208
  return { ...value, instanceId };
1211
1209
  };
1212
- var fromDomEvent = (event) => import_effect4.Stream.async((emit) => {
1213
- const handler = (e) => emit.single(e);
1214
- window.addEventListener(event, handler);
1215
- return import_effect4.Effect.sync(() => window.removeEventListener(event, handler));
1216
- });
1210
+ var readConvergeFieldPathsByDigest = (summary) => {
1211
+ if (!isRecord3(summary)) return /* @__PURE__ */ new Map();
1212
+ const converge = isRecord3(summary.converge) ? summary.converge : void 0;
1213
+ const byDigest = converge && isRecord3(converge.staticIrByDigest) ? converge.staticIrByDigest : void 0;
1214
+ if (!byDigest) return /* @__PURE__ */ new Map();
1215
+ const out = /* @__PURE__ */ new Map();
1216
+ for (const [digest, ir] of Object.entries(byDigest)) {
1217
+ if (!isRecord3(ir)) continue;
1218
+ const fieldPathsRaw = ir.fieldPaths;
1219
+ if (!Array.isArray(fieldPathsRaw)) continue;
1220
+ const fieldPaths = [];
1221
+ for (const pathRaw of fieldPathsRaw) {
1222
+ if (!Array.isArray(pathRaw) || pathRaw.length === 0) {
1223
+ fieldPaths.length = 0;
1224
+ break;
1225
+ }
1226
+ if (!pathRaw.every((seg) => typeof seg === "string" && seg.length > 0)) {
1227
+ fieldPaths.length = 0;
1228
+ break;
1229
+ }
1230
+ fieldPaths.push(pathRaw);
1231
+ }
1232
+ if (fieldPaths.length > 0) {
1233
+ out.set(digest, fieldPaths);
1234
+ }
1235
+ }
1236
+ return out;
1237
+ };
1238
+ var isPrefixPath = (prefix, path) => {
1239
+ if (prefix.length > path.length) return false;
1240
+ for (let i = 0; i < prefix.length; i++) {
1241
+ if (prefix[i] !== path[i]) return false;
1242
+ }
1243
+ return true;
1244
+ };
1245
+ var minimizeRootPaths = (paths) => {
1246
+ const roots = [];
1247
+ for (const path of paths) {
1248
+ let redundant = false;
1249
+ for (const existing of roots) {
1250
+ if (isPrefixPath(existing, path)) {
1251
+ redundant = true;
1252
+ break;
1253
+ }
1254
+ }
1255
+ if (redundant) continue;
1256
+ let nextLen = 0;
1257
+ for (let i = 0; i < roots.length; i++) {
1258
+ const existing = roots[i];
1259
+ if (isPrefixPath(path, existing)) continue;
1260
+ roots[nextLen] = existing;
1261
+ nextLen += 1;
1262
+ }
1263
+ roots.length = nextLen;
1264
+ roots.push(path);
1265
+ }
1266
+ return roots;
1267
+ };
1268
+ var resolveRootPaths = (args) => {
1269
+ const ids = args.ids;
1270
+ if (!Array.isArray(ids) || ids.length === 0) return void 0;
1271
+ const candidates = [];
1272
+ for (const rawId of ids) {
1273
+ if (!Number.isInteger(rawId)) continue;
1274
+ const id = rawId;
1275
+ if (id < 0 || id >= args.fieldPaths.length) continue;
1276
+ candidates.push(args.fieldPaths[id]);
1277
+ }
1278
+ if (candidates.length === 0) return void 0;
1279
+ const minimized = minimizeRootPaths(candidates);
1280
+ return minimized.length > 0 ? minimized : void 0;
1281
+ };
1282
+ var stripRootPathsField = (value) => {
1283
+ const { rootPaths: _rootPaths, ...rest } = value;
1284
+ return rest;
1285
+ };
1286
+ var stripLegacyDirtyRootPathsFromEvent = (event) => {
1287
+ const meta = isRecord3(event.meta) ? event.meta : void 0;
1288
+ if (!meta) return event;
1289
+ if (event.kind === "state" && event.label === "state:update") {
1290
+ const dirtySet = isRecord3(meta.dirtySet) ? meta.dirtySet : void 0;
1291
+ if (!dirtySet || !Object.prototype.hasOwnProperty.call(dirtySet, "rootPaths")) return event;
1292
+ return {
1293
+ ...event,
1294
+ meta: {
1295
+ ...meta,
1296
+ dirtySet: stripRootPathsField(dirtySet)
1297
+ }
1298
+ };
1299
+ }
1300
+ if (event.kind === "trait:converge") {
1301
+ const dirty = isRecord3(meta.dirty) ? meta.dirty : void 0;
1302
+ if (!dirty || !Object.prototype.hasOwnProperty.call(dirty, "rootPaths")) return event;
1303
+ return {
1304
+ ...event,
1305
+ meta: {
1306
+ ...meta,
1307
+ dirty: stripRootPathsField(dirty)
1308
+ }
1309
+ };
1310
+ }
1311
+ return event;
1312
+ };
1313
+ var materializeDirtyRootPathsFromCanonical = (args) => {
1314
+ if (args.fieldPathsByDigest.size === 0) return args.event;
1315
+ const meta = isRecord3(args.event.meta) ? args.event.meta : void 0;
1316
+ if (!meta) return args.event;
1317
+ const staticIrDigest = asNonEmptyString2(meta.staticIrDigest);
1318
+ if (!staticIrDigest) return args.event;
1319
+ const fieldPaths = args.fieldPathsByDigest.get(staticIrDigest);
1320
+ if (!fieldPaths) return args.event;
1321
+ if (args.event.kind === "state" && args.event.label === "state:update") {
1322
+ const dirtySet = isRecord3(meta.dirtySet) ? meta.dirtySet : void 0;
1323
+ if (!dirtySet) return args.event;
1324
+ const ids = Object.prototype.hasOwnProperty.call(dirtySet, "pathIds") ? dirtySet.pathIds : dirtySet.rootIds;
1325
+ const rootPaths = resolveRootPaths({ ids, fieldPaths });
1326
+ if (!rootPaths) return args.event;
1327
+ return {
1328
+ ...args.event,
1329
+ meta: {
1330
+ ...meta,
1331
+ dirtySet: {
1332
+ ...dirtySet,
1333
+ rootPaths
1334
+ }
1335
+ }
1336
+ };
1337
+ }
1338
+ if (args.event.kind === "trait:converge") {
1339
+ const dirty = isRecord3(meta.dirty) ? meta.dirty : void 0;
1340
+ if (!dirty) return args.event;
1341
+ const rootPaths = resolveRootPaths({ ids: dirty.rootIds, fieldPaths });
1342
+ if (!rootPaths) return args.event;
1343
+ return {
1344
+ ...args.event,
1345
+ meta: {
1346
+ ...meta,
1347
+ dirty: {
1348
+ ...dirty,
1349
+ rootPaths
1350
+ }
1351
+ }
1352
+ };
1353
+ }
1354
+ return args.event;
1355
+ };
1356
+ var fromDomEvent = (event) => import_effect4.Stream.callback(
1357
+ (queue) => import_effect4.Effect.gen(function* () {
1358
+ const handler = (e) => {
1359
+ import_effect4.Queue.offerUnsafe(queue, e);
1360
+ };
1361
+ window.addEventListener(event, handler);
1362
+ yield* import_effect4.Effect.addFinalizer(() => import_effect4.Effect.sync(() => window.removeEventListener(event, handler)));
1363
+ })
1364
+ );
1217
1365
  var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1218
1366
  setup: $.lifecycle.onStart(
1219
1367
  import_effect4.Effect.gen(function* () {
1220
- const snapshotStore = yield* DevtoolsSnapshotStore;
1368
+ const snapshotStore = yield* $.use(DevtoolsSnapshotStore);
1221
1369
  const initialSnapshot = yield* snapshotStore.get;
1222
1370
  yield* $.state.update(
1223
1371
  (prev) => computeDevtoolsState(prev, initialSnapshot, {
@@ -1228,7 +1376,7 @@ var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1228
1376
  ),
1229
1377
  // run section: initialize snapshot subscription + register all onAction watchers and dragging logic.
1230
1378
  run: import_effect4.Effect.gen(function* () {
1231
- const snapshotStore = yield* DevtoolsSnapshotStore;
1379
+ const snapshotStore = yield* $.use(DevtoolsSnapshotStore);
1232
1380
  yield* $.on(snapshotStore.changes).runFork(
1233
1381
  (snapshot) => $.state.update(
1234
1382
  (prev) => computeDevtoolsState(prev, snapshot, {
@@ -1327,13 +1475,15 @@ var DevtoolsLogic = DevtoolsModule.logic(($) => ({
1327
1475
  return;
1328
1476
  }
1329
1477
  const evidence = Logix4.Observability.importEvidencePackage(parsed);
1478
+ const fieldPathsByDigest = readConvergeFieldPathsByDigest(evidence.summary);
1330
1479
  const events = [];
1331
1480
  for (const envelope of evidence.events) {
1332
1481
  if (envelope.type !== "debug:event") continue;
1333
1482
  const payload = envelope.payload;
1334
1483
  const normalized = normalizeRuntimeDebugEventRef(payload);
1335
1484
  if (!normalized) continue;
1336
- events.push(normalized);
1485
+ const canonicalEvent = stripLegacyDirtyRootPathsFromEvent(normalized);
1486
+ events.push(materializeDirtyRootPathsFromCanonical({ event: canonicalEvent, fieldPathsByDigest }));
1337
1487
  }
1338
1488
  const snapshot = {
1339
1489
  snapshotToken: 0,
@@ -1425,18 +1575,18 @@ var devtoolsRuntime = Logix5.Runtime.make(DevtoolsImpl, {
1425
1575
  // so Logic can subscribe to Snapshot changes via Tag.
1426
1576
  layer: devtoolsSnapshotLayer
1427
1577
  });
1428
- var devtoolsModuleRuntime = devtoolsRuntime.runSync(DevtoolsModule.tag);
1578
+ var devtoolsModuleRuntime = devtoolsRuntime.runSync(import_effect5.Effect.service(DevtoolsModule.tag).pipe(import_effect5.Effect.orDie));
1429
1579
 
1430
1580
  // src/internal/ui/hooks/DevtoolsHooks.tsx
1431
1581
  var subscribe = (onStoreChange) => {
1432
1582
  const fiber = devtoolsRuntime.runFork(
1433
- import_effect5.Stream.runForEach(
1583
+ import_effect6.Stream.runForEach(
1434
1584
  devtoolsModuleRuntime.changes((state) => state),
1435
- () => import_effect5.Effect.sync(onStoreChange)
1585
+ () => import_effect6.Effect.sync(onStoreChange)
1436
1586
  )
1437
1587
  );
1438
1588
  return () => {
1439
- devtoolsRuntime.runFork(import_effect5.Fiber.interrupt(fiber));
1589
+ devtoolsRuntime.runFork(import_effect6.Fiber.interrupt(fiber));
1440
1590
  };
1441
1591
  };
1442
1592
  var getSnapshot = () => devtoolsRuntime.runSync(devtoolsModuleRuntime.getState);
@@ -1764,9 +1914,9 @@ var makeTraitConvergeOverrideSnippets = (params) => {
1764
1914
  [moduleId]: patch
1765
1915
  }
1766
1916
  })})`;
1767
- const moduleOverride = `Logix.Runtime.setTraitConvergeOverride(runtime, ${stableStringify(moduleId)}, ${stableStringify(
1917
+ const moduleOverride = `await Effect.runPromise(Logix.Runtime.setTraitConvergeOverride(runtime, ${stableStringify(moduleId)}, ${stableStringify(
1768
1918
  patch
1769
- )})`;
1919
+ )}))`;
1770
1920
  return [
1771
1921
  {
1772
1922
  kind: "provider_override",
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import "./chunk-HFUIUVQI.js";
2
2
  import {
3
3
  LogixDevtools
4
- } from "./chunk-WTZBDE4J.js";
4
+ } from "./chunk-H5JD2DNC.js";
5
5
  import {
6
6
  DevtoolsSnapshotStore,
7
7
  clearDevtoolsEvents,
@@ -17,7 +17,7 @@ import {
17
17
  setInstanceLabel,
18
18
  subscribeDevtoolsSnapshot,
19
19
  subscribeDevtoolsSnapshotToken
20
- } from "./chunk-FNWHBEXD.js";
20
+ } from "./chunk-NH3EYAZ6.js";
21
21
  import "./chunk-AELNVFJN.js";
22
22
  import {
23
23
  StateTraitGraphView,
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@logixjs/devtools-react",
3
- "version": "0.0.2",
3
+ "version": "1.0.1",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/yoyooyooo/logix",
7
+ "directory": "packages/logix-devtools-react"
8
+ },
4
9
  "license": "Apache-2.0",
5
10
  "files": [
6
11
  "dist/**"
@@ -28,10 +33,10 @@
28
33
  },
29
34
  "dependencies": {
30
35
  "clsx": "^2.1.1",
31
- "effect": "^3.19.8",
36
+ "effect": "4.0.0-beta.28",
32
37
  "framer-motion": "^12.23.26",
33
38
  "tailwind-merge": "^3.4.0",
34
- "@logixjs/core": "0.0.2"
39
+ "@logixjs/core": "1.0.1"
35
40
  },
36
41
  "devDependencies": {
37
42
  "@tailwindcss/cli": "^4.1.17",
@@ -45,7 +50,7 @@
45
50
  "tsup": "^8.1.0",
46
51
  "typescript": "^5.4.5",
47
52
  "vitest": "^4.0.15",
48
- "@logixjs/react": "0.1.1"
53
+ "@logixjs/react": "1.0.1"
49
54
  },
50
55
  "peerDependencies": {
51
56
  "react": ">=18.0.0"