@joewinke/jatui 0.37.0 → 0.38.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/dist/artifact-blocks/AttachmentChip.svelte +66 -0
- package/dist/artifact-blocks/AttachmentChip.svelte.d.ts +7 -0
- package/dist/artifact-blocks/BlockComments.svelte +309 -0
- package/dist/artifact-blocks/BlockComments.svelte.d.ts +33 -0
- package/dist/artifact-blocks/BlockRenderer.svelte +674 -0
- package/dist/artifact-blocks/BlockRenderer.svelte.d.ts +55 -0
- package/dist/artifact-blocks/BlockVerdict.svelte +151 -0
- package/dist/artifact-blocks/BlockVerdict.svelte.d.ts +13 -0
- package/dist/artifact-blocks/BlocksArtifactView.svelte +1616 -0
- package/dist/artifact-blocks/BlocksArtifactView.svelte.d.ts +113 -0
- package/dist/artifact-blocks/CONTRACT.md +225 -0
- package/dist/artifact-blocks/CommentPill.svelte +49 -0
- package/dist/artifact-blocks/CommentPill.svelte.d.ts +16 -0
- package/dist/artifact-blocks/FoldedRounds.svelte +95 -0
- package/dist/artifact-blocks/FoldedRounds.svelte.d.ts +9 -0
- package/dist/artifact-blocks/Glyph.svelte +54 -0
- package/dist/artifact-blocks/Glyph.svelte.d.ts +10 -0
- package/dist/artifact-blocks/HistoryScrubber.svelte +500 -0
- package/dist/artifact-blocks/HistoryScrubber.svelte.d.ts +15 -0
- package/dist/artifact-blocks/Markdown.svelte +186 -0
- package/dist/artifact-blocks/Markdown.svelte.d.ts +30 -0
- package/dist/artifact-blocks/NoteComposer.svelte +31 -0
- package/dist/artifact-blocks/NoteComposer.svelte.d.ts +8 -0
- package/dist/artifact-blocks/PlainComposer.svelte +200 -0
- package/dist/artifact-blocks/PlainComposer.svelte.d.ts +15 -0
- package/dist/artifact-blocks/SectionTools.svelte +102 -0
- package/dist/artifact-blocks/SectionTools.svelte.d.ts +19 -0
- package/dist/artifact-blocks/adapter.d.ts +13 -0
- package/dist/artifact-blocks/adapter.js +31 -0
- package/dist/artifact-blocks/autoSend.d.ts +49 -0
- package/dist/artifact-blocks/autoSend.js +103 -0
- package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte +557 -0
- package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte.d.ts +48 -0
- package/dist/artifact-blocks/blocks/actions/block.d.ts +8 -0
- package/dist/artifact-blocks/blocks/actions/block.js +74 -0
- package/dist/artifact-blocks/blocks/actions/requests.d.ts +62 -0
- package/dist/artifact-blocks/blocks/actions/requests.js +26 -0
- package/dist/artifact-blocks/blocks/actions/schema.d.ts +168 -0
- package/dist/artifact-blocks/blocks/actions/schema.js +253 -0
- package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte +779 -0
- package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte.d.ts +40 -0
- package/dist/artifact-blocks/blocks/callout/block.d.ts +7 -0
- package/dist/artifact-blocks/blocks/callout/block.js +39 -0
- package/dist/artifact-blocks/blocks/callout/schema.d.ts +72 -0
- package/dist/artifact-blocks/blocks/callout/schema.js +115 -0
- package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte +875 -0
- package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte.d.ts +59 -0
- package/dist/artifact-blocks/blocks/chart/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/chart/block.js +70 -0
- package/dist/artifact-blocks/blocks/chart/schema.d.ts +171 -0
- package/dist/artifact-blocks/blocks/chart/schema.js +498 -0
- package/dist/artifact-blocks/blocks/chart/thumb.d.ts +2 -0
- package/dist/artifact-blocks/blocks/chart/thumb.js +201 -0
- package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte +1048 -0
- package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte.d.ts +16 -0
- package/dist/artifact-blocks/blocks/checklist/Icon.svelte +105 -0
- package/dist/artifact-blocks/blocks/checklist/Icon.svelte.d.ts +17 -0
- package/dist/artifact-blocks/blocks/checklist/block.d.ts +10 -0
- package/dist/artifact-blocks/blocks/checklist/block.js +63 -0
- package/dist/artifact-blocks/blocks/checklist/itemReview.d.ts +16 -0
- package/dist/artifact-blocks/blocks/checklist/itemReview.js +63 -0
- package/dist/artifact-blocks/blocks/checklist/labels.d.ts +62 -0
- package/dist/artifact-blocks/blocks/checklist/labels.js +96 -0
- package/dist/artifact-blocks/blocks/checklist/retest.d.ts +43 -0
- package/dist/artifact-blocks/blocks/checklist/retest.js +68 -0
- package/dist/artifact-blocks/blocks/checklist/schema.d.ts +84 -0
- package/dist/artifact-blocks/blocks/checklist/schema.js +91 -0
- package/dist/artifact-blocks/blocks/code/CodeBlock.svelte +128 -0
- package/dist/artifact-blocks/blocks/code/CodeBlock.svelte.d.ts +12 -0
- package/dist/artifact-blocks/blocks/code/block.d.ts +8 -0
- package/dist/artifact-blocks/blocks/code/block.js +31 -0
- package/dist/artifact-blocks/blocks/code/highlight.d.ts +34 -0
- package/dist/artifact-blocks/blocks/code/highlight.js +280 -0
- package/dist/artifact-blocks/blocks/code/schema.d.ts +32 -0
- package/dist/artifact-blocks/blocks/code/schema.js +39 -0
- package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte +290 -0
- package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte.d.ts +29 -0
- package/dist/artifact-blocks/blocks/collage/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/collage/block.js +29 -0
- package/dist/artifact-blocks/blocks/collage/schema.d.ts +52 -0
- package/dist/artifact-blocks/blocks/collage/schema.js +86 -0
- package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte +484 -0
- package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte.d.ts +25 -0
- package/dist/artifact-blocks/blocks/compare/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/compare/block.js +32 -0
- package/dist/artifact-blocks/blocks/compare/schema.d.ts +74 -0
- package/dist/artifact-blocks/blocks/compare/schema.js +148 -0
- package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte +392 -0
- package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte.d.ts +30 -0
- package/dist/artifact-blocks/blocks/diagram/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/diagram/block.js +50 -0
- package/dist/artifact-blocks/blocks/diagram/constants.d.ts +48 -0
- package/dist/artifact-blocks/blocks/diagram/constants.js +53 -0
- package/dist/artifact-blocks/blocks/diagram/schema.d.ts +161 -0
- package/dist/artifact-blocks/blocks/diagram/schema.js +621 -0
- package/dist/artifact-blocks/blocks/diagram/thumb.d.ts +2 -0
- package/dist/artifact-blocks/blocks/diagram/thumb.js +157 -0
- package/dist/artifact-blocks/blocks/diagram/types.d.ts +74 -0
- package/dist/artifact-blocks/blocks/diagram/types.js +1 -0
- package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte +81 -0
- package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte.d.ts +10 -0
- package/dist/artifact-blocks/blocks/diff/block.d.ts +7 -0
- package/dist/artifact-blocks/blocks/diff/block.js +36 -0
- package/dist/artifact-blocks/blocks/diff/schema.d.ts +18 -0
- package/dist/artifact-blocks/blocks/diff/schema.js +35 -0
- package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte +1055 -0
- package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte.d.ts +5 -0
- package/dist/artifact-blocks/blocks/diff-review/block.d.ts +15 -0
- package/dist/artifact-blocks/blocks/diff-review/block.js +64 -0
- package/dist/artifact-blocks/blocks/diff-review/decisions.d.ts +57 -0
- package/dist/artifact-blocks/blocks/diff-review/decisions.js +80 -0
- package/dist/artifact-blocks/blocks/diff-review/schema.d.ts +13 -0
- package/dist/artifact-blocks/blocks/diff-review/schema.js +84 -0
- package/dist/artifact-blocks/blocks/diff-review/types.d.ts +35 -0
- package/dist/artifact-blocks/blocks/diff-review/types.js +1 -0
- package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte +145 -0
- package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte.d.ts +5 -0
- package/dist/artifact-blocks/blocks/explainer/block.d.ts +8 -0
- package/dist/artifact-blocks/blocks/explainer/block.js +21 -0
- package/dist/artifact-blocks/blocks/explainer/schema.d.ts +26 -0
- package/dist/artifact-blocks/blocks/explainer/schema.js +69 -0
- package/dist/artifact-blocks/blocks/group-content.d.ts +10 -0
- package/dist/artifact-blocks/blocks/group-content.js +16 -0
- package/dist/artifact-blocks/blocks/group-data.d.ts +10 -0
- package/dist/artifact-blocks/blocks/group-data.js +7 -0
- package/dist/artifact-blocks/blocks/group-review.d.ts +10 -0
- package/dist/artifact-blocks/blocks/group-review.js +12 -0
- package/dist/artifact-blocks/blocks/group-visual.d.ts +17 -0
- package/dist/artifact-blocks/blocks/group-visual.js +14 -0
- package/dist/artifact-blocks/blocks/map/MapBlock.svelte +413 -0
- package/dist/artifact-blocks/blocks/map/MapBlock.svelte.d.ts +53 -0
- package/dist/artifact-blocks/blocks/map/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/map/block.js +62 -0
- package/dist/artifact-blocks/blocks/map/schema.d.ts +123 -0
- package/dist/artifact-blocks/blocks/map/schema.js +113 -0
- package/dist/artifact-blocks/blocks/map/thumb.d.ts +2 -0
- package/dist/artifact-blocks/blocks/map/thumb.js +69 -0
- package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte +33 -0
- package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte.d.ts +15 -0
- package/dist/artifact-blocks/blocks/markdown/block.d.ts +7 -0
- package/dist/artifact-blocks/blocks/markdown/block.js +28 -0
- package/dist/artifact-blocks/blocks/markdown/render.d.ts +17 -0
- package/dist/artifact-blocks/blocks/markdown/render.js +115 -0
- package/dist/artifact-blocks/blocks/markdown/schema.d.ts +10 -0
- package/dist/artifact-blocks/blocks/markdown/schema.js +23 -0
- package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte +2112 -0
- package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte.d.ts +5 -0
- package/dist/artifact-blocks/blocks/media-picker/block.d.ts +24 -0
- package/dist/artifact-blocks/blocks/media-picker/block.js +137 -0
- package/dist/artifact-blocks/blocks/media-picker/choices.d.ts +28 -0
- package/dist/artifact-blocks/blocks/media-picker/choices.js +35 -0
- package/dist/artifact-blocks/blocks/media-picker/decisions.d.ts +51 -0
- package/dist/artifact-blocks/blocks/media-picker/decisions.js +75 -0
- package/dist/artifact-blocks/blocks/media-picker/schema.d.ts +7 -0
- package/dist/artifact-blocks/blocks/media-picker/schema.js +199 -0
- package/dist/artifact-blocks/blocks/media-picker/types.d.ts +92 -0
- package/dist/artifact-blocks/blocks/media-picker/types.js +1 -0
- package/dist/artifact-blocks/blocks/media-picker/versions.d.ts +51 -0
- package/dist/artifact-blocks/blocks/media-picker/versions.js +118 -0
- package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte +213 -0
- package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte.d.ts +5 -0
- package/dist/artifact-blocks/blocks/mockup/block.d.ts +26 -0
- package/dist/artifact-blocks/blocks/mockup/block.js +52 -0
- package/dist/artifact-blocks/blocks/mockup/doc.d.ts +24 -0
- package/dist/artifact-blocks/blocks/mockup/doc.js +44 -0
- package/dist/artifact-blocks/blocks/mockup/sandbox.d.ts +21 -0
- package/dist/artifact-blocks/blocks/mockup/sandbox.js +27 -0
- package/dist/artifact-blocks/blocks/mockup/schema.d.ts +7 -0
- package/dist/artifact-blocks/blocks/mockup/schema.js +90 -0
- package/dist/artifact-blocks/blocks/mockup/types.d.ts +36 -0
- package/dist/artifact-blocks/blocks/mockup/types.js +17 -0
- package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte +359 -0
- package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte.d.ts +32 -0
- package/dist/artifact-blocks/blocks/program/block.d.ts +35 -0
- package/dist/artifact-blocks/blocks/program/block.js +68 -0
- package/dist/artifact-blocks/blocks/program/schema.d.ts +132 -0
- package/dist/artifact-blocks/blocks/program/schema.js +268 -0
- package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte +315 -0
- package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte.d.ts +24 -0
- package/dist/artifact-blocks/blocks/stats/block.d.ts +7 -0
- package/dist/artifact-blocks/blocks/stats/block.js +49 -0
- package/dist/artifact-blocks/blocks/stats/schema.d.ts +82 -0
- package/dist/artifact-blocks/blocks/stats/schema.js +43 -0
- package/dist/artifact-blocks/blocks/stats/thumb.d.ts +2 -0
- package/dist/artifact-blocks/blocks/stats/thumb.js +102 -0
- package/dist/artifact-blocks/blocks/table/TableBlock.svelte +490 -0
- package/dist/artifact-blocks/blocks/table/TableBlock.svelte.d.ts +28 -0
- package/dist/artifact-blocks/blocks/table/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/table/block.js +100 -0
- package/dist/artifact-blocks/blocks/table/schema.d.ts +143 -0
- package/dist/artifact-blocks/blocks/table/schema.js +278 -0
- package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte +347 -0
- package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte.d.ts +42 -0
- package/dist/artifact-blocks/blocks/timeline/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/timeline/block.js +96 -0
- package/dist/artifact-blocks/blocks/timeline/constants.d.ts +26 -0
- package/dist/artifact-blocks/blocks/timeline/constants.js +27 -0
- package/dist/artifact-blocks/blocks/timeline/schema.d.ts +102 -0
- package/dist/artifact-blocks/blocks/timeline/schema.js +405 -0
- package/dist/artifact-blocks/blocks/timeline/thumb.d.ts +2 -0
- package/dist/artifact-blocks/blocks/timeline/thumb.js +117 -0
- package/dist/artifact-blocks/blocks/timeline/types.d.ts +66 -0
- package/dist/artifact-blocks/blocks/timeline/types.js +1 -0
- package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte +169 -0
- package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte.d.ts +26 -0
- package/dist/artifact-blocks/blocks/transcript/block.d.ts +9 -0
- package/dist/artifact-blocks/blocks/transcript/block.js +86 -0
- package/dist/artifact-blocks/blocks/transcript/schema.d.ts +114 -0
- package/dist/artifact-blocks/blocks/transcript/schema.js +126 -0
- package/dist/artifact-blocks/builtins.d.ts +40 -0
- package/dist/artifact-blocks/builtins.js +22 -0
- package/dist/artifact-blocks/contractBlocks.d.ts +92 -0
- package/dist/artifact-blocks/contractBlocks.js +279 -0
- package/dist/artifact-blocks/history.d.ts +140 -0
- package/dist/artifact-blocks/history.js +363 -0
- package/dist/artifact-blocks/index.d.ts +40 -0
- package/dist/artifact-blocks/index.js +46 -0
- package/dist/artifact-blocks/listen/context.d.ts +30 -0
- package/dist/artifact-blocks/listen/context.js +30 -0
- package/dist/artifact-blocks/liveData.d.ts +78 -0
- package/dist/artifact-blocks/liveData.js +137 -0
- package/dist/artifact-blocks/liveDataPoller.d.ts +41 -0
- package/dist/artifact-blocks/liveDataPoller.js +140 -0
- package/dist/artifact-blocks/openNav.d.ts +46 -0
- package/dist/artifact-blocks/openNav.js +106 -0
- package/dist/artifact-blocks/pageReviewKeys.d.ts +17 -0
- package/dist/artifact-blocks/pageReviewKeys.js +115 -0
- package/dist/artifact-blocks/params.d.ts +98 -0
- package/dist/artifact-blocks/params.js +159 -0
- package/dist/artifact-blocks/registry.d.ts +27 -0
- package/dist/artifact-blocks/registry.js +83 -0
- package/dist/artifact-blocks/review/BlockIcon.svelte +99 -0
- package/dist/artifact-blocks/review/BlockIcon.svelte.d.ts +17 -0
- package/dist/artifact-blocks/review/BulkRejectForm.svelte +94 -0
- package/dist/artifact-blocks/review/BulkRejectForm.svelte.d.ts +11 -0
- package/dist/artifact-blocks/review/BulkUndoBar.svelte +40 -0
- package/dist/artifact-blocks/review/BulkUndoBar.svelte.d.ts +9 -0
- package/dist/artifact-blocks/review/ItemNote.svelte +193 -0
- package/dist/artifact-blocks/review/ItemNote.svelte.d.ts +33 -0
- package/dist/artifact-blocks/review/NoteToggle.svelte +52 -0
- package/dist/artifact-blocks/review/NoteToggle.svelte.d.ts +12 -0
- package/dist/artifact-blocks/review/TeamChip.svelte +71 -0
- package/dist/artifact-blocks/review/TeamChip.svelte.d.ts +8 -0
- package/dist/artifact-blocks/review/attachments.d.ts +10 -0
- package/dist/artifact-blocks/review/attachments.js +37 -0
- package/dist/artifact-blocks/review/bulk.d.ts +52 -0
- package/dist/artifact-blocks/review/bulk.js +61 -0
- package/dist/artifact-blocks/review/itemReview.d.ts +33 -0
- package/dist/artifact-blocks/review/itemReview.js +112 -0
- package/dist/artifact-blocks/review/roundLines.d.ts +14 -0
- package/dist/artifact-blocks/review/roundLines.js +20 -0
- package/dist/artifact-blocks/review/rounds.d.ts +86 -0
- package/dist/artifact-blocks/review/rounds.js +302 -0
- package/dist/artifact-blocks/review/saver.d.ts +23 -0
- package/dist/artifact-blocks/review/saver.js +48 -0
- package/dist/artifact-blocks/review/team.d.ts +31 -0
- package/dist/artifact-blocks/review/team.js +42 -0
- package/dist/artifact-blocks/review/visualOrder.d.ts +29 -0
- package/dist/artifact-blocks/review/visualOrder.js +66 -0
- package/dist/artifact-blocks/review.d.ts +180 -0
- package/dist/artifact-blocks/review.js +716 -0
- package/dist/artifact-blocks/thumb-kit.d.ts +80 -0
- package/dist/artifact-blocks/thumb-kit.js +149 -0
- package/dist/artifact-blocks/types.d.ts +513 -0
- package/dist/artifact-blocks/types.js +1 -0
- package/package.json +11 -2
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The jat provider contract's block-level surface (jat
|
|
3
|
+
* docs/artifacts/provider-contract.md), read into the renderer's own blocks.
|
|
4
|
+
*
|
|
5
|
+
* - P10 `decision` block: the contract's decision card
|
|
6
|
+
* `{ question, options: [string | { letter?, label, detail? }],
|
|
7
|
+
* recommended?, context? }`. The renderer stores it as its NATIVE decision
|
|
8
|
+
* callout (variant `decision`, one option per letter, the context as the
|
|
9
|
+
* body), so every surface that already reads decision callouts — the
|
|
10
|
+
* page, the desk, the dock, the census, the Finish review panel — serves
|
|
11
|
+
* a contract card with no second renderer. The translation runs at
|
|
12
|
+
* publish; the stored spec is the callout.
|
|
13
|
+
* - P11 per-block task links (mos-4tgfj): a block may carry its OWN jat
|
|
14
|
+
* `taskId`, and a decision block that also carries one may name the
|
|
15
|
+
* jat-decision it mirrors (`decisionId`). A finished review answers each
|
|
16
|
+
* linked block on that block's task (feedbackReview.ts → F13).
|
|
17
|
+
*
|
|
18
|
+
* Pure and isomorphic: the service and the MCP publish tool both call it.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
import type { BlockInstance, BlocksSpec, BlockValidationError } from "./types";
|
|
22
|
+
/**
|
|
23
|
+
* P11: a block `taskId` matches the P6 shape, and a `decisionId` only rides
|
|
24
|
+
* a decision block that also carries a `taskId`. Anything else is an error
|
|
25
|
+
* (the publish answers 422 and stores nothing).
|
|
26
|
+
*/
|
|
27
|
+
export declare function blockLinkErrors(b: BlockInstance): BlockValidationError[];
|
|
28
|
+
/** A linked block's task (and mirrored decision), keyed by block id. */
|
|
29
|
+
interface BlockTaskLink {
|
|
30
|
+
taskId: string;
|
|
31
|
+
decisionId: string | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* F13: block id → its own linked task, for the blocks of a STORED spec that
|
|
35
|
+
* carry a valid one (untrusted jsonb: anything malformed is skipped, never
|
|
36
|
+
* answered).
|
|
37
|
+
*/
|
|
38
|
+
export declare function blockTasksOf(spec: unknown): Map<string, BlockTaskLink>;
|
|
39
|
+
export declare const decisionMetaSchema: z.ZodArray<z.ZodObject<{
|
|
40
|
+
label: z.ZodString;
|
|
41
|
+
value: z.ZodString;
|
|
42
|
+
href: z.ZodOptional<z.ZodString>;
|
|
43
|
+
title: z.ZodOptional<z.ZodString>;
|
|
44
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
45
|
+
error: "error";
|
|
46
|
+
warning: "warning";
|
|
47
|
+
info: "info";
|
|
48
|
+
success: "success";
|
|
49
|
+
neutral: "neutral";
|
|
50
|
+
}>>;
|
|
51
|
+
}, z.core.$strip>>;
|
|
52
|
+
/** Sections' markdown shares the callout body's 20,000-character budget. */
|
|
53
|
+
export declare const DECISION_BODY_BUDGET = 20000;
|
|
54
|
+
export declare const decisionSectionsSchema: z.ZodArray<z.ZodObject<{
|
|
55
|
+
heading: z.ZodString;
|
|
56
|
+
markdown: z.ZodString;
|
|
57
|
+
open: z.ZodOptional<z.ZodBoolean>;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
export declare const decisionPrimaryActionSchema: z.ZodObject<{
|
|
60
|
+
label: z.ZodString;
|
|
61
|
+
url: z.ZodString;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
export declare const blockGroupSchema: z.ZodObject<{
|
|
64
|
+
key: z.ZodString;
|
|
65
|
+
label: z.ZodString;
|
|
66
|
+
quiet: z.ZodOptional<z.ZodBoolean>;
|
|
67
|
+
}, z.core.$strip>;
|
|
68
|
+
export declare const decisionTitleSchema: z.ZodString;
|
|
69
|
+
/**
|
|
70
|
+
* The optional NEEDS YOU fields of one card, each validated alone: a
|
|
71
|
+
* well-formed field passes through (parsed, so trims apply), a malformed
|
|
72
|
+
* one is DROPPED and named in `warnings` — never a refused publish
|
|
73
|
+
* (PARAMS-SPEC §1 "drop (not refuse)").
|
|
74
|
+
*/
|
|
75
|
+
export declare function decisionExtras(params: Record<string, unknown>): {
|
|
76
|
+
extras: Record<string, unknown>;
|
|
77
|
+
warnings: Array<[string, string]>;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Read a publish's spec through the contract: every `decision` block becomes
|
|
81
|
+
* a decision callout (its id, owner, taskId and decisionId kept), and the
|
|
82
|
+
* malformed ones come back as errors. A malformed OPTIONAL card field
|
|
83
|
+
* (title, meta, sections, primaryAction, group) is dropped and comes back
|
|
84
|
+
* as a warning — the publish still succeeds. Blocks of every other type
|
|
85
|
+
* pass through untouched, so this is idempotent on an already-native spec.
|
|
86
|
+
*/
|
|
87
|
+
export declare function normalizeContractBlocks(spec: BlocksSpec): {
|
|
88
|
+
spec: BlocksSpec;
|
|
89
|
+
errors: BlockValidationError[];
|
|
90
|
+
warnings: BlockValidationError[];
|
|
91
|
+
};
|
|
92
|
+
export {};
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The jat provider contract's block-level surface (jat
|
|
3
|
+
* docs/artifacts/provider-contract.md), read into the renderer's own blocks.
|
|
4
|
+
*
|
|
5
|
+
* - P10 `decision` block: the contract's decision card
|
|
6
|
+
* `{ question, options: [string | { letter?, label, detail? }],
|
|
7
|
+
* recommended?, context? }`. The renderer stores it as its NATIVE decision
|
|
8
|
+
* callout (variant `decision`, one option per letter, the context as the
|
|
9
|
+
* body), so every surface that already reads decision callouts — the
|
|
10
|
+
* page, the desk, the dock, the census, the Finish review panel — serves
|
|
11
|
+
* a contract card with no second renderer. The translation runs at
|
|
12
|
+
* publish; the stored spec is the callout.
|
|
13
|
+
* - P11 per-block task links (mos-4tgfj): a block may carry its OWN jat
|
|
14
|
+
* `taskId`, and a decision block that also carries one may name the
|
|
15
|
+
* jat-decision it mirrors (`decisionId`). A finished review answers each
|
|
16
|
+
* linked block on that block's task (feedbackReview.ts → F13).
|
|
17
|
+
*
|
|
18
|
+
* Pure and isomorphic: the service and the MCP publish tool both call it.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
import { linkUrlSchema } from "./params";
|
|
22
|
+
/** Contract P6 shape: project key, dash, base-36 id, optional `.N` children. */
|
|
23
|
+
const BLOCK_TASK_ID_RE = /^[a-z0-9][a-z0-9_-]*-[a-z0-9]+(\.[0-9]+)*$/;
|
|
24
|
+
const MAX_BLOCK_TASK_ID = 64;
|
|
25
|
+
/** Contract P11: a jat-decision id. */
|
|
26
|
+
const DECISION_ID_RE = /^dec-[A-Za-z0-9_-]{1,64}$/;
|
|
27
|
+
const LETTER_RE = /^[A-Z]$/;
|
|
28
|
+
const MAX_OPTIONS = 26;
|
|
29
|
+
const MAX_LABEL = 120;
|
|
30
|
+
const MAX_DETAIL = 300;
|
|
31
|
+
const MAX_QUESTION = 500;
|
|
32
|
+
const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
33
|
+
/** Is this block a decision card (the contract type, or the native callout)? */
|
|
34
|
+
function isDecisionInstance(b) {
|
|
35
|
+
return (b.type === "decision" ||
|
|
36
|
+
(b.type === "callout" && isObj(b.params) && b.params.variant === "decision"));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* P11: a block `taskId` matches the P6 shape, and a `decisionId` only rides
|
|
40
|
+
* a decision block that also carries a `taskId`. Anything else is an error
|
|
41
|
+
* (the publish answers 422 and stores nothing).
|
|
42
|
+
*/
|
|
43
|
+
export function blockLinkErrors(b) {
|
|
44
|
+
const errors = [];
|
|
45
|
+
const at = (path, message) => errors.push({ blockId: String(b.id), type: b.type, path, message });
|
|
46
|
+
if (b.taskId !== undefined) {
|
|
47
|
+
if (typeof b.taskId !== "string" ||
|
|
48
|
+
b.taskId.length > MAX_BLOCK_TASK_ID ||
|
|
49
|
+
!BLOCK_TASK_ID_RE.test(b.taskId))
|
|
50
|
+
at("taskId", "taskId must be a jat task id (e.g. mos-9unv1, jat-abc.3)");
|
|
51
|
+
}
|
|
52
|
+
if (b.decisionId !== undefined) {
|
|
53
|
+
if (!isDecisionInstance(b))
|
|
54
|
+
at("decisionId", "decisionId belongs on a decision block");
|
|
55
|
+
else if (typeof b.taskId !== "string")
|
|
56
|
+
at("decisionId", "decisionId needs the block's own taskId");
|
|
57
|
+
else if (typeof b.decisionId !== "string" ||
|
|
58
|
+
!DECISION_ID_RE.test(b.decisionId))
|
|
59
|
+
at("decisionId", "decisionId must look like dec-<id>");
|
|
60
|
+
}
|
|
61
|
+
return errors;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* F13: block id → its own linked task, for the blocks of a STORED spec that
|
|
65
|
+
* carry a valid one (untrusted jsonb: anything malformed is skipped, never
|
|
66
|
+
* answered).
|
|
67
|
+
*/
|
|
68
|
+
export function blockTasksOf(spec) {
|
|
69
|
+
const out = new Map();
|
|
70
|
+
const blocks = isObj(spec) && Array.isArray(spec.blocks) ? spec.blocks : [];
|
|
71
|
+
for (const b of blocks) {
|
|
72
|
+
if (!isObj(b) || typeof b.id !== "string")
|
|
73
|
+
continue;
|
|
74
|
+
if (typeof b.taskId !== "string" ||
|
|
75
|
+
b.taskId.length > MAX_BLOCK_TASK_ID ||
|
|
76
|
+
!BLOCK_TASK_ID_RE.test(b.taskId))
|
|
77
|
+
continue;
|
|
78
|
+
const decisionId = typeof b.decisionId === "string" &&
|
|
79
|
+
DECISION_ID_RE.test(b.decisionId) &&
|
|
80
|
+
isDecisionInstance({ type: String(b.type), params: b.params })
|
|
81
|
+
? b.decisionId
|
|
82
|
+
: null;
|
|
83
|
+
out.set(b.id, { taskId: b.taskId, decisionId });
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// The NEEDS YOU card fields (PARAMS-SPEC §1, jat-j49id → jatui-vsuzi)
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
//
|
|
91
|
+
// Additive and optional: a decision card may carry a topic `title`, a
|
|
92
|
+
// compact `meta` row, collapsed markdown `sections`, a `primaryAction`
|
|
93
|
+
// link button and the `group` it belongs to. None of them is answerable —
|
|
94
|
+
// links navigate, they never post a verdict. Exported so the callout block
|
|
95
|
+
// validates its params with the SAME limits the normalizer enforces.
|
|
96
|
+
const META_TONES = ["neutral", "info", "success", "warning", "error"];
|
|
97
|
+
export const decisionMetaSchema = z
|
|
98
|
+
.array(z.object({
|
|
99
|
+
label: z.string().trim().min(1).max(24),
|
|
100
|
+
value: z.string().trim().min(1).max(80),
|
|
101
|
+
href: linkUrlSchema.optional(),
|
|
102
|
+
title: z.string().max(120).optional(),
|
|
103
|
+
tone: z.enum(META_TONES).optional(),
|
|
104
|
+
}))
|
|
105
|
+
.max(8);
|
|
106
|
+
/** Sections' markdown shares the callout body's 20,000-character budget. */
|
|
107
|
+
export const DECISION_BODY_BUDGET = 20_000;
|
|
108
|
+
export const decisionSectionsSchema = z
|
|
109
|
+
.array(z.object({
|
|
110
|
+
heading: z.string().trim().min(1).max(60),
|
|
111
|
+
markdown: z.string().max(DECISION_BODY_BUDGET),
|
|
112
|
+
open: z.boolean().optional(),
|
|
113
|
+
}))
|
|
114
|
+
.max(8)
|
|
115
|
+
.refine((list) => list.reduce((n, s) => n + s.markdown.length, 0) <= DECISION_BODY_BUDGET, `sections share a ${DECISION_BODY_BUDGET}-character budget`);
|
|
116
|
+
export const decisionPrimaryActionSchema = z.object({
|
|
117
|
+
label: z.string().trim().min(1).max(60),
|
|
118
|
+
url: linkUrlSchema,
|
|
119
|
+
});
|
|
120
|
+
export const blockGroupSchema = z.object({
|
|
121
|
+
key: z.string().regex(/^[a-z0-9-]{1,32}$/, "group key must be [a-z0-9-]{1,32}"),
|
|
122
|
+
label: z.string().trim().min(1).max(60),
|
|
123
|
+
quiet: z.boolean().optional(),
|
|
124
|
+
});
|
|
125
|
+
export const decisionTitleSchema = z.string().trim().min(1).max(120);
|
|
126
|
+
const DECISION_EXTRAS = {
|
|
127
|
+
title: decisionTitleSchema,
|
|
128
|
+
meta: decisionMetaSchema,
|
|
129
|
+
sections: decisionSectionsSchema,
|
|
130
|
+
primaryAction: decisionPrimaryActionSchema,
|
|
131
|
+
group: blockGroupSchema,
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* The optional NEEDS YOU fields of one card, each validated alone: a
|
|
135
|
+
* well-formed field passes through (parsed, so trims apply), a malformed
|
|
136
|
+
* one is DROPPED and named in `warnings` — never a refused publish
|
|
137
|
+
* (PARAMS-SPEC §1 "drop (not refuse)").
|
|
138
|
+
*/
|
|
139
|
+
export function decisionExtras(params) {
|
|
140
|
+
const extras = {};
|
|
141
|
+
const warnings = [];
|
|
142
|
+
for (const [key, schema] of Object.entries(DECISION_EXTRAS)) {
|
|
143
|
+
if (params[key] === undefined)
|
|
144
|
+
continue;
|
|
145
|
+
const r = schema.safeParse(params[key]);
|
|
146
|
+
if (r.success)
|
|
147
|
+
extras[key] = r.data;
|
|
148
|
+
else {
|
|
149
|
+
const issue = r.error.issues[0];
|
|
150
|
+
const at = issue?.path.length ? `.${issue.path.join(".")}` : "";
|
|
151
|
+
warnings.push([
|
|
152
|
+
`${key}${at}`,
|
|
153
|
+
`dropped: ${issue?.message ?? "malformed"}`,
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return { extras, warnings };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* One contract decision card → the decision callout params, or the list of
|
|
161
|
+
* reasons it is not a card (P10). Letters default to A, B, C… by position;
|
|
162
|
+
* each becomes the callout option id (lower-cased), so a saved pick maps back
|
|
163
|
+
* to its letter.
|
|
164
|
+
*/
|
|
165
|
+
function decisionToCallout(params) {
|
|
166
|
+
const errors = [];
|
|
167
|
+
if (!isObj(params))
|
|
168
|
+
return { ok: false, errors: [["", "params must be an object"]] };
|
|
169
|
+
const q = typeof params.question === "string"
|
|
170
|
+
? params.question.trim()
|
|
171
|
+
: typeof params.title === "string"
|
|
172
|
+
? params.title.trim()
|
|
173
|
+
: "";
|
|
174
|
+
if (!q)
|
|
175
|
+
errors.push(["question", "a decision needs a question"]);
|
|
176
|
+
else if (q.length > MAX_QUESTION)
|
|
177
|
+
errors.push([
|
|
178
|
+
"question",
|
|
179
|
+
`question must be ${MAX_QUESTION} characters or fewer`,
|
|
180
|
+
]);
|
|
181
|
+
const raw = Array.isArray(params.options) ? params.options : null;
|
|
182
|
+
if (!raw || raw.length < 2 || raw.length > MAX_OPTIONS)
|
|
183
|
+
errors.push(["options", `a decision needs 2-${MAX_OPTIONS} options`]);
|
|
184
|
+
const options = [];
|
|
185
|
+
const seen = new Set();
|
|
186
|
+
for (const [i, o] of (raw ?? []).entries()) {
|
|
187
|
+
const label = typeof o === "string"
|
|
188
|
+
? o.trim()
|
|
189
|
+
: isObj(o) && typeof o.label === "string"
|
|
190
|
+
? o.label.trim()
|
|
191
|
+
: "";
|
|
192
|
+
const letter = isObj(o) && o.letter !== undefined
|
|
193
|
+
? o.letter
|
|
194
|
+
: String.fromCharCode(65 + i);
|
|
195
|
+
const detail = isObj(o) && typeof o.detail === "string" ? o.detail.trim() : "";
|
|
196
|
+
if (!label)
|
|
197
|
+
errors.push([`options.${i}`, "an option needs a label"]);
|
|
198
|
+
else if (label.length > MAX_LABEL)
|
|
199
|
+
errors.push([
|
|
200
|
+
`options.${i}.label`,
|
|
201
|
+
`label must be ${MAX_LABEL} characters or fewer`,
|
|
202
|
+
]);
|
|
203
|
+
if (typeof letter !== "string" || !LETTER_RE.test(letter))
|
|
204
|
+
errors.push([`options.${i}.letter`, "letter must be one capital A-Z"]);
|
|
205
|
+
else if (seen.has(letter))
|
|
206
|
+
errors.push([`options.${i}.letter`, `letter ${letter} is used twice`]);
|
|
207
|
+
else
|
|
208
|
+
seen.add(letter);
|
|
209
|
+
if (detail.length > MAX_DETAIL)
|
|
210
|
+
errors.push([
|
|
211
|
+
`options.${i}.detail`,
|
|
212
|
+
`detail must be ${MAX_DETAIL} characters or fewer`,
|
|
213
|
+
]);
|
|
214
|
+
if (typeof letter === "string" && LETTER_RE.test(letter))
|
|
215
|
+
options.push({
|
|
216
|
+
id: letter.toLowerCase(),
|
|
217
|
+
letter,
|
|
218
|
+
label,
|
|
219
|
+
...(detail ? { detail } : {}),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (params.recommended !== undefined && !seen.has(String(params.recommended)))
|
|
223
|
+
errors.push([
|
|
224
|
+
"recommended",
|
|
225
|
+
"recommended must be one of the card's letters",
|
|
226
|
+
]);
|
|
227
|
+
if (params.context !== undefined && typeof params.context !== "string")
|
|
228
|
+
errors.push(["context", "context must be markdown text"]);
|
|
229
|
+
if (errors.length)
|
|
230
|
+
return { ok: false, errors };
|
|
231
|
+
const { extras, warnings } = decisionExtras(params);
|
|
232
|
+
return {
|
|
233
|
+
ok: true,
|
|
234
|
+
warnings,
|
|
235
|
+
params: {
|
|
236
|
+
// The topic `title` (the card's `question` stays the ask itself).
|
|
237
|
+
...extras,
|
|
238
|
+
variant: "decision",
|
|
239
|
+
question: q,
|
|
240
|
+
options,
|
|
241
|
+
...(typeof params.recommended === "string"
|
|
242
|
+
? { recommended: params.recommended }
|
|
243
|
+
: {}),
|
|
244
|
+
...(typeof params.context === "string" && params.context.trim()
|
|
245
|
+
? { body: params.context }
|
|
246
|
+
: {}),
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Read a publish's spec through the contract: every `decision` block becomes
|
|
252
|
+
* a decision callout (its id, owner, taskId and decisionId kept), and the
|
|
253
|
+
* malformed ones come back as errors. A malformed OPTIONAL card field
|
|
254
|
+
* (title, meta, sections, primaryAction, group) is dropped and comes back
|
|
255
|
+
* as a warning — the publish still succeeds. Blocks of every other type
|
|
256
|
+
* pass through untouched, so this is idempotent on an already-native spec.
|
|
257
|
+
*/
|
|
258
|
+
export function normalizeContractBlocks(spec) {
|
|
259
|
+
const errors = [];
|
|
260
|
+
const warnings = [];
|
|
261
|
+
if (!Array.isArray(spec?.blocks))
|
|
262
|
+
return { spec, errors, warnings };
|
|
263
|
+
let changed = false;
|
|
264
|
+
const blocks = spec.blocks.map((b) => {
|
|
265
|
+
if (!isObj(b) || b.type !== "decision")
|
|
266
|
+
return b;
|
|
267
|
+
const r = decisionToCallout(b.params);
|
|
268
|
+
if (!r.ok) {
|
|
269
|
+
for (const [path, message] of r.errors)
|
|
270
|
+
errors.push({ blockId: String(b.id), type: "decision", path, message });
|
|
271
|
+
return b;
|
|
272
|
+
}
|
|
273
|
+
for (const [path, message] of r.warnings)
|
|
274
|
+
warnings.push({ blockId: String(b.id), type: "decision", path, message });
|
|
275
|
+
changed = true;
|
|
276
|
+
return { ...b, type: "callout", params: r.params };
|
|
277
|
+
});
|
|
278
|
+
return { spec: changed ? { ...spec, blocks } : spec, errors, warnings };
|
|
279
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History scrubber model (mos-p9m3g, living artifacts phase 4).
|
|
3
|
+
*
|
|
4
|
+
* "What did this page look like yesterday at 9am?" A blocks page has two
|
|
5
|
+
* clocks, and the state at any instant is one reading of each:
|
|
6
|
+
*
|
|
7
|
+
* LAYOUT the artifact_versions row live at that instant (the highest
|
|
8
|
+
* version created at or before it);
|
|
9
|
+
* DATA the artifact_data_history snapshot live at that instant (the
|
|
10
|
+
* newest recorded at or before it — migration 20272490000210
|
|
11
|
+
* captures every change of artifacts.data by trigger).
|
|
12
|
+
*
|
|
13
|
+
* This module is PURE (no db, no fetch): the history route resolves an
|
|
14
|
+
* instant with it on the server, and HistoryScrubber builds its timeline and
|
|
15
|
+
* diffs with it in the browser.
|
|
16
|
+
*
|
|
17
|
+
* Diffs are SHAPE-AWARE but never shape-dependent: a stats-shaped value
|
|
18
|
+
* (`cards[]` with label + numeric value) diffs as KPI deltas, a table-shaped
|
|
19
|
+
* value (`rows[]`) diffs as added / removed / changed rows, and anything
|
|
20
|
+
* else diffs as its changed numeric and text leaves. Data is untrusted: every
|
|
21
|
+
* reader here tolerates any JSON and caps what it reports.
|
|
22
|
+
*/
|
|
23
|
+
/** Mirrors the trigger's prune rule in drizzle/20272490000210 — keep both in
|
|
24
|
+
* step. The scrubber names where the trail ends with these. */
|
|
25
|
+
export declare const HISTORY_RETENTION: {
|
|
26
|
+
readonly maxSnapshots: 500;
|
|
27
|
+
readonly maxAgeDays: 30;
|
|
28
|
+
readonly maxBytes: number;
|
|
29
|
+
};
|
|
30
|
+
/** A layout version, as the history route lists it. */
|
|
31
|
+
export interface HistoryVersion {
|
|
32
|
+
version: number;
|
|
33
|
+
/** ISO timestamp. */
|
|
34
|
+
createdAt: string;
|
|
35
|
+
kind: "html" | "blocks";
|
|
36
|
+
changeNote: string | null;
|
|
37
|
+
}
|
|
38
|
+
/** A data snapshot, as the history route lists it (no payload). */
|
|
39
|
+
export interface HistorySnapshot {
|
|
40
|
+
id: string;
|
|
41
|
+
/** ISO timestamp — when artifacts.data BECAME this value. */
|
|
42
|
+
at: string;
|
|
43
|
+
bytes: number;
|
|
44
|
+
/** The layout version live when the data changed (context only). */
|
|
45
|
+
version: number | null;
|
|
46
|
+
}
|
|
47
|
+
/** One stop on the scrubber: a layout publish or a data change. */
|
|
48
|
+
export interface TimelinePoint {
|
|
49
|
+
kind: "version" | "data";
|
|
50
|
+
/** ISO timestamp. */
|
|
51
|
+
at: string;
|
|
52
|
+
/** Epoch ms of `at` (sort key). */
|
|
53
|
+
ms: number;
|
|
54
|
+
version?: number;
|
|
55
|
+
snapshotId?: string;
|
|
56
|
+
}
|
|
57
|
+
/** What the page showed at one instant: which layout + which data. */
|
|
58
|
+
export interface PageStateRef {
|
|
59
|
+
/** Null before the first version (cannot happen for a real artifact). */
|
|
60
|
+
version: number | null;
|
|
61
|
+
/** Null when no snapshot exists at or before the instant. */
|
|
62
|
+
snapshotId: string | null;
|
|
63
|
+
/** When that snapshot's data took effect. */
|
|
64
|
+
dataAt: string | null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Merge versions and snapshots into one chronological list (oldest first).
|
|
68
|
+
* Entries with an unparseable timestamp are dropped — a point the scrubber
|
|
69
|
+
* cannot place is a point it cannot honestly show. At equal instants a
|
|
70
|
+
* version sorts before a data change (a republish then a data push in the
|
|
71
|
+
* same second reads in that order).
|
|
72
|
+
*/
|
|
73
|
+
export declare function buildTimeline(versions: readonly HistoryVersion[], snapshots: readonly HistorySnapshot[]): TimelinePoint[];
|
|
74
|
+
/**
|
|
75
|
+
* The page state live at `atMs`: the newest version created at or before it
|
|
76
|
+
* and the newest snapshot recorded at or before it. Before the first
|
|
77
|
+
* snapshot, snapshotId is null — the page showed its inline params (or the
|
|
78
|
+
* trail was pruned; the caller says which via `trailStart`).
|
|
79
|
+
*/
|
|
80
|
+
export declare function stateAt(versions: readonly HistoryVersion[], snapshots: readonly HistorySnapshot[], atMs: number): PageStateRef;
|
|
81
|
+
/** The oldest instant the trail can answer for, or null with no snapshots. */
|
|
82
|
+
export declare function trailStart(snapshots: readonly HistorySnapshot[]): string | null;
|
|
83
|
+
export interface KpiDelta {
|
|
84
|
+
label: string;
|
|
85
|
+
then: number | null;
|
|
86
|
+
now: number | null;
|
|
87
|
+
/** now - then; null when either side is missing. */
|
|
88
|
+
delta: number | null;
|
|
89
|
+
/** delta / |then| (0.042 = +4.2%); null when then is 0 or missing. */
|
|
90
|
+
pct: number | null;
|
|
91
|
+
}
|
|
92
|
+
export interface RowChange {
|
|
93
|
+
key: string;
|
|
94
|
+
/** Columns whose cell differs (changed rows only). */
|
|
95
|
+
fields: string[];
|
|
96
|
+
}
|
|
97
|
+
export interface LeafChange {
|
|
98
|
+
path: string;
|
|
99
|
+
then: string | number | boolean | null | undefined;
|
|
100
|
+
now: string | number | boolean | null | undefined;
|
|
101
|
+
delta: number | null;
|
|
102
|
+
}
|
|
103
|
+
export type KeyDiff = {
|
|
104
|
+
key: string;
|
|
105
|
+
status: "added" | "removed" | "same";
|
|
106
|
+
} | {
|
|
107
|
+
key: string;
|
|
108
|
+
status: "changed";
|
|
109
|
+
shape: "kpi";
|
|
110
|
+
kpis: KpiDelta[];
|
|
111
|
+
} | {
|
|
112
|
+
key: string;
|
|
113
|
+
status: "changed";
|
|
114
|
+
shape: "table";
|
|
115
|
+
added: RowChange[];
|
|
116
|
+
removed: RowChange[];
|
|
117
|
+
changed: RowChange[];
|
|
118
|
+
/** Rows beyond MAX_DIFF_ENTRIES across the three lists. */
|
|
119
|
+
truncated: number;
|
|
120
|
+
} | {
|
|
121
|
+
key: string;
|
|
122
|
+
status: "changed";
|
|
123
|
+
shape: "value";
|
|
124
|
+
leaves: LeafChange[];
|
|
125
|
+
truncated: number;
|
|
126
|
+
};
|
|
127
|
+
export interface DataDiff {
|
|
128
|
+
keys: KeyDiff[];
|
|
129
|
+
/** Count of keys whose status is not "same". */
|
|
130
|
+
changedKeys: number;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Diff two live-data blobs key by key (`then` → `now`). Keys are reported in
|
|
134
|
+
* `now`'s order, then keys only `then` had. A non-object side reads as {}.
|
|
135
|
+
*/
|
|
136
|
+
export declare function diffData(then: unknown, now: unknown): DataDiff;
|
|
137
|
+
/** "+4.2%", "−1,203", "0" — a signed delta for display (U+2212 minus). */
|
|
138
|
+
export declare function formatDelta(delta: number, pct?: number | null): string;
|
|
139
|
+
/** Parse a `?at=` query value: ISO-8601 or epoch ms. NaN when neither. */
|
|
140
|
+
export declare function parseInstant(raw: string | null): number;
|