@ai-matrx/content-ir-react 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/{directive-host-DJfF35FD.d.cts → directive-host-C4TcPpxX.d.cts} +19 -2
- package/dist/{directive-host-DJfF35FD.d.ts → directive-host-C4TcPpxX.d.ts} +19 -2
- package/dist/directives.cjs +150 -30
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +76 -41
- package/dist/directives.d.ts +76 -41
- package/dist/directives.js +150 -30
- package/dist/directives.js.map +1 -1
- package/dist/{host-types-9NfBeqrG.d.ts → host-types-CEc86R-v.d.ts} +1 -1
- package/dist/{host-types-DVIaaGR_.d.cts → host-types-a0XEr5b3.d.cts} +1 -1
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts +3 -3
- package/dist/host.d.ts +3 -3
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +156 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -42
- package/dist/index.d.ts +76 -42
- package/dist/index.js +153 -33
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +149 -35
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +146 -32
- package/dist/react.js.map +1 -1
- package/dist/{route-DDbgc-ID.d.ts → route-De9c5YgW.d.ts} +19 -2
- package/dist/{route-BCtPhF7W.d.cts → route-YcoyR3Fj.d.cts} +19 -2
- package/dist/route.d.cts +1 -1
- package/dist/route.d.ts +1 -1
- package/package.json +3 -3
package/dist/react.cjs
CHANGED
|
@@ -124,7 +124,7 @@ function useContentIrKindVersion(kind, sources) {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// react/KindInstanceRender.tsx
|
|
127
|
-
var
|
|
127
|
+
var import_react7 = require("react");
|
|
128
128
|
var import_content_ir8 = require("@ai-matrx/content-ir");
|
|
129
129
|
|
|
130
130
|
// directives/DirectiveRender.tsx
|
|
@@ -184,11 +184,26 @@ function safeJson(value) {
|
|
|
184
184
|
return String(value);
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
-
function
|
|
187
|
+
function sameValue(a, b) {
|
|
188
|
+
if (a === b) return true;
|
|
189
|
+
if (a === null || a === void 0 || b === null || b === void 0) {
|
|
190
|
+
const emptyA = a === null || a === void 0 || a === "";
|
|
191
|
+
const emptyB = b === null || b === void 0 || b === "";
|
|
192
|
+
return emptyA && emptyB;
|
|
193
|
+
}
|
|
194
|
+
if (typeof a === "object" || typeof b === "object") return safeJson(a) === safeJson(b);
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
function itemChanges(item, current) {
|
|
188
198
|
const out = [];
|
|
189
199
|
for (const [key, raw] of Object.entries(item)) {
|
|
190
200
|
if (NOT_A_CHANGE.has(key)) continue;
|
|
191
|
-
|
|
201
|
+
const change = { key, label: fieldLabel(key), ...describeValue(raw) };
|
|
202
|
+
if (current && Object.prototype.hasOwnProperty.call(current, key)) {
|
|
203
|
+
change.before = describeValue(current[key]);
|
|
204
|
+
change.same = sameValue(current[key], raw);
|
|
205
|
+
}
|
|
206
|
+
out.push(change);
|
|
192
207
|
}
|
|
193
208
|
return out;
|
|
194
209
|
}
|
|
@@ -301,11 +316,23 @@ function ApplyDirectiveButton({
|
|
|
301
316
|
const conversationId = scope.conversationId || void 0;
|
|
302
317
|
const items = directive.items;
|
|
303
318
|
const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
);
|
|
319
|
+
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
320
|
+
const [state, setState] = (0, import_react4.useState)(initial);
|
|
307
321
|
const [elapsed, setElapsed] = (0, import_react4.useState)(0);
|
|
322
|
+
const [askingAgain, setAskingAgain] = (0, import_react4.useState)(false);
|
|
308
323
|
const startedAt = (0, import_react4.useRef)(null);
|
|
324
|
+
const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
|
|
325
|
+
const [stateFor, setStateFor] = (0, import_react4.useState)(identity);
|
|
326
|
+
if (stateFor !== identity) {
|
|
327
|
+
setStateFor(identity);
|
|
328
|
+
setState(initial);
|
|
329
|
+
setAskingAgain(false);
|
|
330
|
+
setElapsed(0);
|
|
331
|
+
}
|
|
332
|
+
const currentIdentity = (0, import_react4.useRef)(identity);
|
|
333
|
+
(0, import_react4.useEffect)(() => {
|
|
334
|
+
currentIdentity.current = identity;
|
|
335
|
+
}, [identity]);
|
|
309
336
|
const nounText = (0, import_content_ir.nounLabel)(directive.noun, host.nouns);
|
|
310
337
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
311
338
|
const read = host.applyState;
|
|
@@ -328,7 +355,8 @@ function ApplyDirectiveButton({
|
|
|
328
355
|
applied: shellItems.length,
|
|
329
356
|
failed: 0,
|
|
330
357
|
message: answer.message?.trim() ? answer.message.trim() : null,
|
|
331
|
-
records: answer.records ?? []
|
|
358
|
+
records: answer.records ?? [],
|
|
359
|
+
copies: Math.max(1, answer.copies ?? 1)
|
|
332
360
|
} : prev
|
|
333
361
|
);
|
|
334
362
|
} else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
|
|
@@ -368,8 +396,12 @@ function ApplyDirectiveButton({
|
|
|
368
396
|
async function handleApply(again = false) {
|
|
369
397
|
if (!confirm) return;
|
|
370
398
|
const before = state;
|
|
399
|
+
const askedFor = identity;
|
|
400
|
+
const stillHere = () => currentIdentity.current === askedFor;
|
|
401
|
+
const priorCopies = state.status === "applied" ? state.copies : 0;
|
|
371
402
|
if (host.ask) {
|
|
372
|
-
|
|
403
|
+
if (again) setAskingAgain(true);
|
|
404
|
+
else setState({ status: "asking" });
|
|
373
405
|
let ok = false;
|
|
374
406
|
try {
|
|
375
407
|
ok = await host.ask({
|
|
@@ -379,12 +411,16 @@ function ApplyDirectiveButton({
|
|
|
379
411
|
...again ? { again: true } : {}
|
|
380
412
|
});
|
|
381
413
|
} catch (error) {
|
|
414
|
+
if (!stillHere()) return;
|
|
415
|
+
setAskingAgain(false);
|
|
382
416
|
setState({
|
|
383
417
|
status: "error",
|
|
384
418
|
message: error instanceof Error && error.message ? error.message : "We could not ask you to confirm this, so nothing was done."
|
|
385
419
|
});
|
|
386
420
|
return;
|
|
387
421
|
}
|
|
422
|
+
if (!stillHere()) return;
|
|
423
|
+
setAskingAgain(false);
|
|
388
424
|
if (!ok) {
|
|
389
425
|
setState(again ? before : { status: "idle" });
|
|
390
426
|
return;
|
|
@@ -397,15 +433,19 @@ function ApplyDirectiveButton({
|
|
|
397
433
|
if (conversationId) shell.conversationId = conversationId;
|
|
398
434
|
if (again) shell.force = true;
|
|
399
435
|
const result = await confirm(shell);
|
|
436
|
+
if (!stillHere()) return;
|
|
400
437
|
setState({
|
|
401
438
|
status: "applied",
|
|
402
439
|
applied: result.applied,
|
|
403
440
|
failed: result.failed,
|
|
404
441
|
message: result.message?.trim() ? result.message.trim() : null,
|
|
405
|
-
records: result.records ?? []
|
|
442
|
+
records: result.records ?? [],
|
|
443
|
+
// "Run again" made one more; a first apply (or a replay of one) is one.
|
|
444
|
+
copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies)
|
|
406
445
|
});
|
|
407
446
|
onApplied?.();
|
|
408
447
|
} catch (error) {
|
|
448
|
+
if (!stillHere()) return;
|
|
409
449
|
setState({
|
|
410
450
|
status: "error",
|
|
411
451
|
message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
|
|
@@ -430,6 +470,15 @@ function ApplyDirectiveButton({
|
|
|
430
470
|
bad && !state.message ? ` \xB7 ${state.failed} failed` : ""
|
|
431
471
|
] })
|
|
432
472
|
] }),
|
|
473
|
+
state.copies > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
474
|
+
"span",
|
|
475
|
+
{
|
|
476
|
+
className: "shrink-0 text-muted-foreground",
|
|
477
|
+
"data-apply-copies": state.copies,
|
|
478
|
+
title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
|
|
479
|
+
children: directive.directiveClass === "create" ? `${state.copies} copies` : `Ran ${state.copies} times`
|
|
480
|
+
}
|
|
481
|
+
) : null,
|
|
433
482
|
records.map((record) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
434
483
|
...record,
|
|
435
484
|
fallback: recordFallbackName(label2, record.id),
|
|
@@ -440,8 +489,9 @@ function ApplyDirectiveButton({
|
|
|
440
489
|
"button",
|
|
441
490
|
{
|
|
442
491
|
type: "button",
|
|
492
|
+
disabled: askingAgain,
|
|
443
493
|
onClick: () => void handleApply(!bad),
|
|
444
|
-
className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
|
494
|
+
className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-50",
|
|
445
495
|
"data-apply-action": bad ? "retry" : "run-again",
|
|
446
496
|
children: [
|
|
447
497
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RotateCcwIcon, { className: "h-3 w-3" }),
|
|
@@ -479,6 +529,7 @@ function ApplyDirectiveButton({
|
|
|
479
529
|
}
|
|
480
530
|
);
|
|
481
531
|
}
|
|
532
|
+
const destructive = directive.directiveClass === "delete";
|
|
482
533
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
|
|
483
534
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
484
535
|
"button",
|
|
@@ -486,7 +537,8 @@ function ApplyDirectiveButton({
|
|
|
486
537
|
type: "button",
|
|
487
538
|
onClick: () => void handleApply(),
|
|
488
539
|
disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
|
|
489
|
-
|
|
540
|
+
"data-apply-tone": destructive ? "destructive" : "default",
|
|
541
|
+
className: `inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-medium disabled:opacity-50 ${destructive ? "border-destructive/50 bg-background text-destructive hover:bg-destructive/10" : "border-border bg-background hover:bg-accent"}`,
|
|
490
542
|
children: [
|
|
491
543
|
state.status === "applying" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, { className: "h-3.5 w-3.5" }),
|
|
492
544
|
state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
@@ -579,8 +631,41 @@ function getDirectiveRenderer(directive) {
|
|
|
579
631
|
}
|
|
580
632
|
|
|
581
633
|
// directives/SideEffectDirectiveCard.tsx
|
|
582
|
-
var
|
|
634
|
+
var import_react6 = require("react");
|
|
583
635
|
var import_content_ir5 = require("@ai-matrx/content-ir");
|
|
636
|
+
|
|
637
|
+
// directives/record-values.ts
|
|
638
|
+
var import_react5 = require("react");
|
|
639
|
+
function useRecordValues(read, ref) {
|
|
640
|
+
const key = ref && read ? `${ref.noun}:${ref.id}` : "";
|
|
641
|
+
const [result, setResult] = (0, import_react5.useState)({
|
|
642
|
+
key: "",
|
|
643
|
+
values: null,
|
|
644
|
+
status: "idle"
|
|
645
|
+
});
|
|
646
|
+
(0, import_react5.useEffect)(() => {
|
|
647
|
+
if (!key || !read) return;
|
|
648
|
+
const split = key.indexOf(":");
|
|
649
|
+
const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
|
|
650
|
+
let live = true;
|
|
651
|
+
setResult({ key, values: null, status: "loading" });
|
|
652
|
+
read(target).then((values) => {
|
|
653
|
+
if (!live) return;
|
|
654
|
+
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
655
|
+
}).catch(() => {
|
|
656
|
+
if (!live) return;
|
|
657
|
+
setResult({ key, values: null, status: "unavailable" });
|
|
658
|
+
});
|
|
659
|
+
return () => {
|
|
660
|
+
live = false;
|
|
661
|
+
};
|
|
662
|
+
}, [key, read]);
|
|
663
|
+
if (!key) return { values: null, status: "idle" };
|
|
664
|
+
if (result.key !== key) return { values: null, status: "loading" };
|
|
665
|
+
return { values: result.values, status: result.status };
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// directives/SideEffectDirectiveCard.tsx
|
|
584
669
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
585
670
|
var ROWS_BEFORE_FOLD = 3;
|
|
586
671
|
function ItemRow({
|
|
@@ -634,44 +719,73 @@ function ItemRow({
|
|
|
634
719
|
host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
|
|
635
720
|
] });
|
|
636
721
|
}
|
|
637
|
-
function
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
recordId
|
|
722
|
+
function DirectiveChangeList({
|
|
723
|
+
changes,
|
|
724
|
+
className
|
|
641
725
|
}) {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
650
|
-
] }),
|
|
651
|
-
directive.directiveClass === "update" ? changes.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "px-1 text-[11px] text-muted-foreground", children: "Sets no fields \u2014 nothing would change." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: "mt-0.5 space-y-0.5 px-1", children: changes.map((change) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
726
|
+
if (changes.length === 0) {
|
|
727
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: `text-[11px] text-muted-foreground${className ? ` ${className}` : ""}`, children: "Sets no fields \u2014 nothing would change." });
|
|
728
|
+
}
|
|
729
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: `space-y-0.5${className ? ` ${className}` : ""}`, "data-directive-changes": "", children: changes.map((change) => {
|
|
730
|
+
const before = change.before && !change.same ? change.before : null;
|
|
731
|
+
const was = before ? before.clears ? "empty" : before.value : null;
|
|
732
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
652
733
|
"li",
|
|
653
734
|
{
|
|
654
735
|
className: "flex min-w-0 items-baseline gap-1.5 text-[11px]",
|
|
655
|
-
title: `${change.label} \u2192 ${change.full}`,
|
|
736
|
+
title: before ? `${change.label}: ${before.clears ? "empty" : before.full} \u2192 ${change.full}` : `${change.label} \u2192 ${change.full}`,
|
|
737
|
+
"data-change-key": change.key,
|
|
656
738
|
children: [
|
|
657
739
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "shrink-0 text-muted-foreground", children: change.label }),
|
|
740
|
+
was !== null ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
741
|
+
"span",
|
|
742
|
+
{
|
|
743
|
+
className: "min-w-0 max-w-[40%] shrink truncate text-muted-foreground line-through",
|
|
744
|
+
"data-change-before": "",
|
|
745
|
+
children: was
|
|
746
|
+
}
|
|
747
|
+
) : null,
|
|
658
748
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": true, className: "shrink-0 text-muted-foreground", children: "\u2192" }),
|
|
659
749
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
660
750
|
"span",
|
|
661
751
|
{
|
|
662
752
|
className: `min-w-0 truncate ${change.clears ? "italic text-muted-foreground" : "text-foreground"}`,
|
|
753
|
+
"data-change-after": "",
|
|
663
754
|
children: change.value
|
|
664
755
|
}
|
|
665
|
-
)
|
|
756
|
+
),
|
|
757
|
+
change.same ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "shrink-0 text-muted-foreground", children: "(no change)" }) : null
|
|
666
758
|
]
|
|
667
759
|
},
|
|
668
760
|
change.key
|
|
669
|
-
)
|
|
761
|
+
);
|
|
762
|
+
}) });
|
|
763
|
+
}
|
|
764
|
+
function TargetRow({
|
|
765
|
+
directive,
|
|
766
|
+
item,
|
|
767
|
+
recordId
|
|
768
|
+
}) {
|
|
769
|
+
const host = useDirectiveHost();
|
|
770
|
+
const fallback = recordFallbackName((0, import_content_ir5.nounLabel)(directive.noun, host.nouns), recordId);
|
|
771
|
+
const isUpdate = directive.directiveClass === "update";
|
|
772
|
+
const current = useRecordValues(
|
|
773
|
+
isUpdate ? host.readRecord : void 0,
|
|
774
|
+
isUpdate ? { noun: directive.noun, id: recordId } : null
|
|
775
|
+
);
|
|
776
|
+
const changes = isUpdate ? itemChanges(item, current.values) : [];
|
|
777
|
+
const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "truncate font-medium text-foreground", children: fallback });
|
|
778
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
780
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
|
|
781
|
+
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
782
|
+
] }),
|
|
783
|
+
isUpdate ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DirectiveChangeList, { changes, className: "mt-0.5 px-1" }) : null
|
|
670
784
|
] });
|
|
671
785
|
}
|
|
672
786
|
function SideEffectDirectiveCard({ directive }) {
|
|
673
787
|
const host = useDirectiveHost();
|
|
674
|
-
const [expanded, setExpanded] = (0,
|
|
788
|
+
const [expanded, setExpanded] = (0, import_react6.useState)(false);
|
|
675
789
|
const items = directive.items;
|
|
676
790
|
const total = items.length;
|
|
677
791
|
const display = (0, import_content_ir5.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
|
|
@@ -804,10 +918,10 @@ function KindInstanceRenderInner({
|
|
|
804
918
|
className
|
|
805
919
|
}) {
|
|
806
920
|
const host = useContentIrHost();
|
|
807
|
-
const [routingStatus, setRoutingStatus] = (0,
|
|
921
|
+
const [routingStatus, setRoutingStatus] = (0, import_react7.useState)(
|
|
808
922
|
() => kindIsRoutable(kind, host) ? "routable" : "checking"
|
|
809
923
|
);
|
|
810
|
-
(0,
|
|
924
|
+
(0, import_react7.useEffect)(() => {
|
|
811
925
|
let cancelled = false;
|
|
812
926
|
let warmed = false;
|
|
813
927
|
const syncRoutingStatus = () => {
|
|
@@ -855,7 +969,7 @@ function KindInstanceRenderInner({
|
|
|
855
969
|
}
|
|
856
970
|
|
|
857
971
|
// react/ProvisionalKindBoundary.tsx
|
|
858
|
-
var
|
|
972
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
859
973
|
|
|
860
974
|
// route/partial-kind-route.ts
|
|
861
975
|
var import_content_ir9 = require("@ai-matrx/content-ir");
|
|
@@ -869,7 +983,7 @@ function markKindPartialUnsafe(kind) {
|
|
|
869
983
|
|
|
870
984
|
// react/ProvisionalKindBoundary.tsx
|
|
871
985
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
872
|
-
var ProvisionalKindBoundaryInner = class extends
|
|
986
|
+
var ProvisionalKindBoundaryInner = class extends import_react8.default.Component {
|
|
873
987
|
state = { failed: false };
|
|
874
988
|
static getDerivedStateFromError() {
|
|
875
989
|
return { failed: true };
|
|
@@ -905,7 +1019,7 @@ function ProvisionalKindFrame({ children }) {
|
|
|
905
1019
|
}
|
|
906
1020
|
|
|
907
1021
|
// react/GenericStructuredView.tsx
|
|
908
|
-
var
|
|
1022
|
+
var import_react9 = require("react");
|
|
909
1023
|
var import_content_ir10 = require("@ai-matrx/content-ir");
|
|
910
1024
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
911
1025
|
function readStructuredValue(content, metadata) {
|