@ai-matrx/content-ir-react 0.18.1 → 0.19.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.
@@ -44,7 +44,7 @@ function resetDirectiveRenderers() {
44
44
  }
45
45
 
46
46
  // directives/ApplyDirectiveButton.tsx
47
- import { useEffect, useRef, useState, useSyncExternalStore } from "react";
47
+ import { useEffect as useEffect2, useRef, useState as useState2, useSyncExternalStore as useSyncExternalStore2 } from "react";
48
48
  import { nounLabel } from "@ai-matrx/content-ir";
49
49
 
50
50
  // directives/item-changes.ts
@@ -123,6 +123,73 @@ function itemChanges(item, current, options = {}) {
123
123
  return out;
124
124
  }
125
125
 
126
+ // directives/record-values.ts
127
+ import { useEffect, useState, useSyncExternalStore } from "react";
128
+ var STORE_SLOT = /* @__PURE__ */ Symbol.for("@ai-matrx/content-ir-react/record-revisions");
129
+ function revisionStore() {
130
+ const slots = globalThis;
131
+ let store = slots[STORE_SLOT];
132
+ if (!store) {
133
+ store = { revisions: /* @__PURE__ */ new Map(), listeners: /* @__PURE__ */ new Set() };
134
+ slots[STORE_SLOT] = store;
135
+ }
136
+ return store;
137
+ }
138
+ var { revisions, listeners } = revisionStore();
139
+ function recordRevision(id) {
140
+ return revisions.get(id) ?? 0;
141
+ }
142
+ function noteRecordChanged(id) {
143
+ if (!id) return;
144
+ revisions.set(id, recordRevision(id) + 1);
145
+ for (const listener of listeners) listener();
146
+ }
147
+ function subscribeRevisions(listener) {
148
+ listeners.add(listener);
149
+ return () => {
150
+ listeners.delete(listener);
151
+ };
152
+ }
153
+ function useRecordRevision(id) {
154
+ return useSyncExternalStore(
155
+ subscribeRevisions,
156
+ () => recordRevision(id),
157
+ () => 0
158
+ );
159
+ }
160
+ function useRecordValues(read, ref) {
161
+ const revision = useRecordRevision(ref?.id ?? "");
162
+ const key = ref && read ? `${ref.noun}:${ref.id}#${revision}` : "";
163
+ const [result, setResult] = useState({
164
+ key: "",
165
+ values: null,
166
+ status: "idle"
167
+ });
168
+ useEffect(() => {
169
+ if (!key || !read) return;
170
+ const split = key.indexOf(":");
171
+ const target = {
172
+ noun: key.slice(0, split),
173
+ id: key.slice(split + 1, key.lastIndexOf("#"))
174
+ };
175
+ let live = true;
176
+ setResult({ key, values: null, status: "loading" });
177
+ read(target).then((values) => {
178
+ if (!live) return;
179
+ setResult({ key, values, status: values ? "ready" : "unavailable" });
180
+ }).catch(() => {
181
+ if (!live) return;
182
+ setResult({ key, values: null, status: "unavailable" });
183
+ });
184
+ return () => {
185
+ live = false;
186
+ };
187
+ }, [key, read]);
188
+ if (!key) return { values: null, status: "idle" };
189
+ if (result.key !== key) return { values: null, status: "loading" };
190
+ return { values: result.values, status: result.status };
191
+ }
192
+
126
193
  // directives/failure-words.ts
127
194
  var PAST = {
128
195
  create: "created",
@@ -242,6 +309,13 @@ function classIcon(directiveClass, noun) {
242
309
 
243
310
  // directives/ApplyDirectiveButton.tsx
244
311
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
312
+ function announceChangedRecords(directive, items) {
313
+ if (!TARGETING_CLASSES.has(directive.directiveClass)) return;
314
+ for (const item of items) {
315
+ const id = itemRecordId(item);
316
+ if (id) noteRecordChanged(id);
317
+ }
318
+ }
245
319
  var applyOutcomes = /* @__PURE__ */ new WeakMap();
246
320
  var EMPTY_AUTHORITY = {};
247
321
  var outcomeListeners = /* @__PURE__ */ new Set();
@@ -264,7 +338,7 @@ function subscribeOutcomes(listener) {
264
338
  };
265
339
  }
266
340
  function useApplyOutcome(host, identity) {
267
- return useSyncExternalStore(
341
+ return useSyncExternalStore2(
268
342
  subscribeOutcomes,
269
343
  () => applyOutcomes.get(host)?.get(identity) ?? null,
270
344
  () => null
@@ -289,12 +363,12 @@ function ApplyDirectiveButton({
289
363
  const items = directive.items;
290
364
  const readsLedger = readsApplyLedger(host, directive);
291
365
  const initial = readsLedger ? { status: "checking" } : { status: "idle" };
292
- const [state, setState] = useState(initial);
293
- const [elapsed, setElapsed] = useState(0);
294
- const [askingAgain, setAskingAgain] = useState(false);
366
+ const [state, setState] = useState2(initial);
367
+ const [elapsed, setElapsed] = useState2(0);
368
+ const [askingAgain, setAskingAgain] = useState2(false);
295
369
  const startedAt = useRef(null);
296
370
  const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
297
- const [stateFor, setStateFor] = useState(identity);
371
+ const [stateFor, setStateFor] = useState2(identity);
298
372
  if (stateFor !== identity) {
299
373
  setStateFor(identity);
300
374
  setState(initial);
@@ -304,14 +378,14 @@ function ApplyDirectiveButton({
304
378
  const shared = useApplyOutcome(host.confirm ?? EMPTY_AUTHORITY, identity);
305
379
  const view = state.status === "asking" || !shared ? state : shared;
306
380
  const currentIdentity = useRef(identity);
307
- useEffect(() => {
381
+ useEffect2(() => {
308
382
  currentIdentity.current = identity;
309
383
  }, [identity]);
310
384
  const nounText = nounLabel(directive.noun, host.nouns);
311
385
  const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
312
386
  const read = host.applyState;
313
387
  const report = host.reportError;
314
- useEffect(() => {
388
+ useEffect2(() => {
315
389
  if (!shellKey || !read) return;
316
390
  const [slug, shellItems, inConversation] = JSON.parse(shellKey);
317
391
  const shell = { __kind: slug, items: shellItems };
@@ -359,14 +433,14 @@ function ApplyDirectiveButton({
359
433
  const appliedClean = view.status === "applied" && view.failed === 0 ? view : null;
360
434
  const appliedBefore = appliedClean ? appliedClean.before : null;
361
435
  const phaseKey = view.status === "checking" || view.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
362
- useEffect(() => {
436
+ useEffect2(() => {
363
437
  if (!onPhase) return;
364
438
  if (phaseKey === "pending") onPhase({ phase: "pending" });
365
439
  else if (phaseKey === "open") onPhase({ phase: "open" });
366
440
  else onPhase({ phase: "applied", before: appliedBefore });
367
441
  }, [phaseKey, onPhase, appliedBefore]);
368
442
  const applyingSince = view.status === "applying" ? view.startedAt : null;
369
- useEffect(() => {
443
+ useEffect2(() => {
370
444
  if (applyingSince === null) return;
371
445
  startedAt.current = applyingSince;
372
446
  const id = setInterval(
@@ -418,7 +492,13 @@ function ApplyDirectiveButton({
418
492
  const shell = { __kind: directive.slug, items };
419
493
  if (conversationId) shell.conversationId = conversationId;
420
494
  if (again) shell.force = true;
421
- const result = await confirm(shell);
495
+ let result;
496
+ try {
497
+ result = await confirm(shell);
498
+ } finally {
499
+ announceChangedRecords(directive, items);
500
+ }
501
+ for (const record of result.records ?? []) noteRecordChanged(record.id);
422
502
  publishOutcome(confirm, askedFor, {
423
503
  status: "applied",
424
504
  applied: result.applied,
@@ -579,7 +659,7 @@ function FailureNotice({
579
659
  words,
580
660
  raw
581
661
  }) {
582
- const [open, setOpen] = useState(false);
662
+ const [open, setOpen] = useState2(false);
583
663
  const detail = raw?.trim() ?? "";
584
664
  return /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 flex-col gap-0.5", "data-apply-failure": true, children: [
585
665
  /* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
@@ -620,39 +700,6 @@ import {
620
700
  nounLabel as nounLabel2,
621
701
  nounTitleColumn
622
702
  } from "@ai-matrx/content-ir";
623
-
624
- // directives/record-values.ts
625
- import { useEffect as useEffect2, useState as useState2 } from "react";
626
- function useRecordValues(read, ref) {
627
- const key = ref && read ? `${ref.noun}:${ref.id}` : "";
628
- const [result, setResult] = useState2({
629
- key: "",
630
- values: null,
631
- status: "idle"
632
- });
633
- useEffect2(() => {
634
- if (!key || !read) return;
635
- const split = key.indexOf(":");
636
- const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
637
- let live = true;
638
- setResult({ key, values: null, status: "loading" });
639
- read(target).then((values) => {
640
- if (!live) return;
641
- setResult({ key, values, status: values ? "ready" : "unavailable" });
642
- }).catch(() => {
643
- if (!live) return;
644
- setResult({ key, values: null, status: "unavailable" });
645
- });
646
- return () => {
647
- live = false;
648
- };
649
- }, [key, read]);
650
- if (!key) return { values: null, status: "idle" };
651
- if (result.key !== key) return { values: null, status: "loading" };
652
- return { values: result.values, status: result.status };
653
- }
654
-
655
- // directives/SideEffectDirectiveCard.tsx
656
703
  import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
657
704
  var ROWS_BEFORE_FOLD = 3;
658
705
  function ItemRow({
@@ -956,13 +1003,16 @@ export {
956
1003
  getDirectiveRenderer,
957
1004
  itemChanges,
958
1005
  itemRecordId,
1006
+ noteRecordChanged,
959
1007
  provisionalDirectiveSlug,
960
1008
  readsApplyLedger,
961
1009
  recordFallbackName,
1010
+ recordRevision,
962
1011
  registerDirectiveRenderer,
963
1012
  resetDirectiveRenderers,
964
1013
  useDirectiveHost,
965
1014
  useDirectiveScope,
1015
+ useRecordRevision,
966
1016
  useRecordValues
967
1017
  };
968
1018
  //# sourceMappingURL=directives.js.map