@thehammer/template-verification 0.2.9 → 0.2.11
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/README.md +87 -45
- package/dist/components/VerifiedField.vue.d.ts +30 -6
- package/dist/context.d.ts +27 -15
- package/dist/index.d.ts +28 -18
- package/dist/lib/discrepancy.d.ts +8 -0
- package/dist/lib/hostBridge.d.ts +125 -23
- package/dist/lib/resolveDataPoint.d.ts +0 -5
- package/dist/style.css +1 -1
- package/dist/template-verification.js +280 -1450
- package/dist/types.d.ts +52 -7
- package/package.json +1 -1
- package/dist/components/AuditCallCard.vue.d.ts +0 -12
- package/dist/components/CitationEvidence.vue.d.ts +0 -33
- package/dist/components/CitationPage.vue.d.ts +0 -27
- package/dist/components/CitationPageList.vue.d.ts +0 -26
- package/dist/components/TvDisclosure.vue.d.ts +0 -61
- package/dist/components/VerificationModal.vue.d.ts +0 -48
- package/dist/lib/citations.d.ts +0 -84
- package/dist/lib/dataPointDetail.d.ts +0 -41
- package/dist/useSaveDataPoint.d.ts +0 -17
package/README.md
CHANGED
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
# @thehammer/template-verification
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
3
|
+
The **verification overlay** a rendered template app wears, and the one signal it
|
|
4
|
+
sends back out.
|
|
5
|
+
|
|
6
|
+
It draws ONE mark beside every bound data value — a confidence pill, a verified
|
|
7
|
+
check chip once a person has locked the value in, and a discrepancy indicator
|
|
8
|
+
when candidates or source documents disagree. Clicking that mark posts a
|
|
9
|
+
`data-point-activated` message to the embedding application. Nothing else
|
|
10
|
+
happens inside the document.
|
|
11
|
+
|
|
12
|
+
`VerificationChrome` adds the overlay's on/off toggle, a review-progress meter
|
|
13
|
+
(X of Y human-verified) and a needs-review jump button, all hidden under print.
|
|
14
|
+
|
|
15
|
+
Render data + `__meta` arrive via a single `initVerification()` call. **The
|
|
16
|
+
library fetches nothing and saves nothing.**
|
|
17
|
+
|
|
18
|
+
## What this library used to do, and deliberately no longer does
|
|
19
|
+
|
|
20
|
+
Earlier versions rendered the whole review surface INSIDE the iframe: a
|
|
21
|
+
90vw × 90vh **Inspector** dialog with Evidence / Candidates / History / Audit
|
|
22
|
+
tabs, an embedded file viewer over the cited pages, a hover summary panel on
|
|
23
|
+
every mark, and `contenteditable` editing on the value with a save transport
|
|
24
|
+
behind it. All of that is **deleted**, along with `VerificationModal`,
|
|
25
|
+
`CitationEvidence`, `CitationPageList`, `CitationPage`, `citationEvidence`,
|
|
26
|
+
`citationSummary` and `fetchDataPointDetail`.
|
|
27
|
+
|
|
28
|
+
A letter is a document, and a document that grows a second application on top of
|
|
29
|
+
itself is two products fighting over one viewport — in a frame that cannot reach
|
|
30
|
+
any of the viewers the embedding app already has. Reviewing a value now happens
|
|
31
|
+
in that app, which opens the citation and the record beside the letter.
|
|
32
|
+
|
|
33
|
+
`initVerification` still **accepts** `saveOverride` and `detailUrl` and ignores
|
|
34
|
+
both. That is compile-time compatibility for already-built templates, whose
|
|
35
|
+
`App.vue` is generated from a snippet that still passes them; it is not a
|
|
36
|
+
feature. See `src/context.ts`.
|
|
26
37
|
|
|
27
38
|
## Install
|
|
28
39
|
|
|
@@ -33,8 +44,9 @@ npm install @thehammer/template-verification
|
|
|
33
44
|
`vue` and `@thehammer/danx-ui` are peer dependencies (runtime externals) — the
|
|
34
45
|
host template app already loads both.
|
|
35
46
|
|
|
36
|
-
Import the stylesheet once
|
|
37
|
-
overlay chrome on print/export
|
|
47
|
+
Import the stylesheet once. It carries the `@media print` rule that hides the
|
|
48
|
+
overlay chrome on print/export, AND the positioning rule that keeps the mark out
|
|
49
|
+
of the text flow:
|
|
38
50
|
|
|
39
51
|
```ts
|
|
40
52
|
import "@thehammer/template-verification/style.css"
|
|
@@ -52,23 +64,12 @@ import { initVerification, VerificationChrome, VerifiedField } from "@thehammer/
|
|
|
52
64
|
|
|
53
65
|
const props = defineProps<{ data: any }>()
|
|
54
66
|
|
|
55
|
-
// Host-supplied, authenticated transport. Its presence enables inline editing.
|
|
56
|
-
async function saveOverride(args) {
|
|
57
|
-
const res = await fetch(`/api/workflow-inputs/${args.workflow_input_id}/data-point-overrides`, {
|
|
58
|
-
method: "POST",
|
|
59
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
|
|
60
|
-
body: JSON.stringify({ ...args, object_id: args.object_ids.at(-1) })
|
|
61
|
-
})
|
|
62
|
-
return res.json() // recomputed DataPointMeta
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Once, at root setup. Absent saveOverride ⇒ every field is read-only.
|
|
66
67
|
initVerification({
|
|
67
68
|
data: props.data,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
// Echoed on every activation message, so the embedder can tell a click on
|
|
70
|
+
// THIS render from a click on one it has already replaced.
|
|
71
|
+
workflowInputId: props.data.__verification?.workflow_input_id ?? null,
|
|
72
|
+
defaultEnabled: props.data.__verification?.default_enabled ?? false
|
|
72
73
|
})
|
|
73
74
|
</script>
|
|
74
75
|
|
|
@@ -89,6 +90,46 @@ The backing store is a **module singleton** — safe because each rendered templ
|
|
|
89
90
|
runs as its own isolated Vue app inside its own iframe (one JS module instance,
|
|
90
91
|
one app-wide config, no SSR). See `src/context.ts` for the invariant.
|
|
91
92
|
|
|
93
|
+
## The mark occupies no space, and that is a contract
|
|
94
|
+
|
|
95
|
+
The mark is absolutely positioned against its wrapper, overlaying the right-hand
|
|
96
|
+
end of the value it belongs to. Turning the overlay on or off, or a field going
|
|
97
|
+
from unverified to verified, must not move a single character of the document.
|
|
98
|
+
|
|
99
|
+
Measured rather than asserted: `.junk/reflow-probe` in the gpt-manager repo
|
|
100
|
+
mounts `VerifiedField` twice into one paragraph in a real browser, with the
|
|
101
|
+
overlay on and off, and compares `getBoundingClientRect()` for the value and for
|
|
102
|
+
the text after it. `src/__tests__/VerifiedField.test.ts` pins the structural
|
|
103
|
+
half (happy-dom has no layout engine, so a rect assertion there would pass on
|
|
104
|
+
zeroes).
|
|
105
|
+
|
|
106
|
+
## The outbound message
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
{
|
|
110
|
+
source: "danxbot-template", // TEMPLATE_MESSAGE_SOURCE
|
|
111
|
+
version: 1, // TEMPLATE_PROTOCOL_VERSION
|
|
112
|
+
type: "data-point-activated", // DATA_POINT_ACTIVATED
|
|
113
|
+
anchor: { // copied VERBATIM from __meta, unreshaped
|
|
114
|
+
object_ids: [4211, 77], // full root-to-leaf path; LAST is the record
|
|
115
|
+
field: "full_name",
|
|
116
|
+
field_path: "medical_providers.0.full_name"
|
|
117
|
+
},
|
|
118
|
+
workflowInputId: 431 | null,
|
|
119
|
+
label: "full_name" | null,
|
|
120
|
+
value: "Jane Doe" | null
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Posted to `window.parent` at the embedder's **real origin**, never `"*"`. The
|
|
125
|
+
origin is resolved from `location.ancestorOrigins[0]`, falling back to
|
|
126
|
+
`document.referrer`'s origin; when neither resolves, **nothing is posted**. See
|
|
127
|
+
`src/lib/hostBridge.ts`.
|
|
128
|
+
|
|
129
|
+
A receiver must check `event.origin` before it looks at the payload. A payload
|
|
130
|
+
check is not a security check: anyone can post a well-formed message, and only
|
|
131
|
+
the bundle can post from the bundle's origin.
|
|
132
|
+
|
|
92
133
|
## The `__meta` contract
|
|
93
134
|
|
|
94
135
|
Each rendered object node carries a `__meta` map keyed by leaf field name. Each
|
|
@@ -99,7 +140,7 @@ interface DataPointMeta {
|
|
|
99
140
|
anchor: { object_ids: (number | string)[]; field: string; field_path: string }
|
|
100
141
|
candidates: {
|
|
101
142
|
override?: { value; source_choice }
|
|
102
|
-
extracted?: { value; confidence: number | null;
|
|
143
|
+
extracted?: { value; confidence: number | null; state; sources_count; history_count }
|
|
103
144
|
claim?: { value; claim_set_label }
|
|
104
145
|
}
|
|
105
146
|
discrepancy: boolean
|
|
@@ -111,15 +152,16 @@ interface DataPointMeta {
|
|
|
111
152
|
|
|
112
153
|
- **Resolution priority:** `override > extracted > claim`.
|
|
113
154
|
- **Status** buckets the **integer** confidence: `null → unverifiable (gray)`,
|
|
114
|
-
`≤2 → low (red)`, `==3 → medium (yellow)`, `≥4 → high (green)`.
|
|
155
|
+
`≤2 → low (red)`, `==3 → medium (yellow)`, `≥4 → high (green)`. A `failed`
|
|
156
|
+
extraction state is its own bucket, not a confidence.
|
|
115
157
|
- **Discrepancy** is orthogonal to confidence — a high-confidence field can still
|
|
116
158
|
disagree with a differing claim/override.
|
|
117
159
|
|
|
118
160
|
## Activation
|
|
119
161
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
162
|
+
The overlay's own toggle is a fixed bottom-right settings button, persisted to
|
|
163
|
+
`localStorage`. No URL flags and no host activation prop. All library chrome is
|
|
164
|
+
hidden under print/export media.
|
|
123
165
|
|
|
124
166
|
## Develop
|
|
125
167
|
|
|
@@ -4,12 +4,36 @@ import type { MetaCarrier } from "../types";
|
|
|
4
4
|
* `source` object at `field` (`source.__meta[field]`), renders the RESOLVED value
|
|
5
5
|
* (override > extracted > claim) with a HARD fallback to the host's raw value —
|
|
6
6
|
* the document must never lose data because provenance is thin. When the overlay
|
|
7
|
-
* is enabled via `useVerification()` it
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* is enabled via `useVerification()` it draws ONE mark beside the value, and
|
|
8
|
+
* clicking that mark tells the embedding app which data point was activated
|
|
9
|
+
* ({@link notifyDataPointActivated}). With no meta/source it degrades to a bare
|
|
10
|
+
* value — and with no `initVerification` call at all it still renders and never
|
|
11
|
+
* throws.
|
|
12
|
+
*
|
|
13
|
+
* ==== THE MARK IS THE WHOLE SURFACE. THERE IS NOTHING ELSE ====
|
|
14
|
+
*
|
|
15
|
+
* What used to be here as well: a 90vw x 90vh tabbed Inspector dialog, a hover
|
|
16
|
+
* panel summarising confidence and citation counts, and `contenteditable` on
|
|
17
|
+
* the value with a save transport behind it. All three are deleted, not
|
|
18
|
+
* disabled. A letter is a document. Reviewing a value — reading its citations,
|
|
19
|
+
* seeing the record it belongs to, correcting it — is the embedding app's job,
|
|
20
|
+
* and that app already does all three better than a dialog squeezed into an
|
|
21
|
+
* iframe ever could. Everything a reader can do from here is: click the mark.
|
|
22
|
+
*
|
|
23
|
+
* The mark's own summary now lives in its ACCESSIBLE NAME rather than in a
|
|
24
|
+
* hover panel, so the same sentence reaches a screen reader and a mouse
|
|
25
|
+
* hovering the glyph, and neither costs a second piece of chrome in the page.
|
|
26
|
+
*
|
|
27
|
+
* ==== THE MARK IS OUT OF FLOW, AND THAT IS A HARD REQUIREMENT ====
|
|
28
|
+
*
|
|
29
|
+
* It is absolutely positioned against the wrapper (see the `<style>` block at
|
|
30
|
+
* the foot of this file), overlaying the right-hand end of the value it belongs
|
|
31
|
+
* to. It therefore occupies ZERO inline space: turning the overlay on or off,
|
|
32
|
+
* or toggling a field from "unverified" to "verified", must not move a single
|
|
33
|
+
* character of the letter. The previous layout was an `inline-flex` row with a
|
|
34
|
+
* gap, so every mark pushed the rest of its line along — which reflowed the
|
|
35
|
+
* document the moment the overlay was switched on, in a product whose entire
|
|
36
|
+
* point is that the document is the deliverable.
|
|
13
37
|
*/
|
|
14
38
|
type __VLS_Props = {
|
|
15
39
|
source?: MetaCarrier;
|
package/dist/context.d.ts
CHANGED
|
@@ -22,17 +22,33 @@ import type { SaveOverrideFn } from "./types";
|
|
|
22
22
|
export interface InitVerificationConfig {
|
|
23
23
|
/** The bound data tree (carries per-node `__meta`). */
|
|
24
24
|
data: Record<string, unknown>;
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* ACCEPTED AND IGNORED. Nothing in this library saves anything any more.
|
|
27
|
+
*
|
|
28
|
+
* The in-letter review surface this fed — the Inspector dialog and the
|
|
29
|
+
* `contenteditable` value — is gone; correcting a value is the embedding
|
|
30
|
+
* app's job now. The field stays in this interface for exactly one reason:
|
|
31
|
+
* every already-built template's `App.vue` passes it (the wiring snippet
|
|
32
|
+
* that generates them lives in gpt-manager's `SchemaBuilderContextBuilder`),
|
|
33
|
+
* and removing it here turns every one of those into a TypeScript excess-
|
|
34
|
+
* property error the next time it is rebuilt — for a library that cannot
|
|
35
|
+
* rebuild them. It goes when that snippet stops emitting it.
|
|
36
|
+
*/
|
|
26
37
|
saveOverride?: SaveOverrideFn;
|
|
27
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* The workflow input this render is for. Echoed on the outbound activation
|
|
40
|
+
* message so an embedder can tell a click on the CURRENT render from a
|
|
41
|
+
* click on a render it has already replaced — see
|
|
42
|
+
* {@link ../lib/hostBridge.DataPointActivatedMessage}.
|
|
43
|
+
*/
|
|
28
44
|
workflowInputId?: number | string | null;
|
|
29
45
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
46
|
+
* ACCEPTED AND IGNORED, for the same reason as `saveOverride` above.
|
|
47
|
+
*
|
|
48
|
+
* This was the Inspector dialog's lazy per-field detail endpoint. The
|
|
49
|
+
* Inspector is gone, and the embedder fetches a data point's citations and
|
|
50
|
+
* history against its own authenticated session rather than against a
|
|
51
|
+
* token-sealed url handed into an iframe.
|
|
36
52
|
*/
|
|
37
53
|
detailUrl?: string | null;
|
|
38
54
|
/** Seeds the overlay toggle ONLY when localStorage holds no prior value. */
|
|
@@ -53,12 +69,8 @@ export interface Verification {
|
|
|
53
69
|
enabled: Ref<boolean>;
|
|
54
70
|
/** The bound data tree (carries per-node `__meta`). */
|
|
55
71
|
data: Record<string, unknown>;
|
|
56
|
-
/**
|
|
57
|
-
saveOverride?: SaveOverrideFn;
|
|
58
|
-
/** Opaque workflow input id echoed back in saves. */
|
|
72
|
+
/** The workflow input this render is for; echoed on activation messages. */
|
|
59
73
|
workflowInputId?: number | string | null;
|
|
60
|
-
/** Token-sealed per-field detail endpoint base; null/absent hides the Audit tab. */
|
|
61
|
-
detailUrl?: string | null;
|
|
62
74
|
/** True while the host is fetching a new data source; see {@link InitVerificationConfig.loading}. */
|
|
63
75
|
loading: boolean;
|
|
64
76
|
}
|
|
@@ -69,8 +81,8 @@ export interface Verification {
|
|
|
69
81
|
*/
|
|
70
82
|
export declare function initVerification(config: InitVerificationConfig): void;
|
|
71
83
|
/**
|
|
72
|
-
* Consume the live verification state. Returns a default (empty data, disabled
|
|
73
|
-
*
|
|
84
|
+
* Consume the live verification state. Returns a default (empty data, disabled)
|
|
85
|
+
* when {@link initVerification} was never called, so a
|
|
74
86
|
* `<VerifiedField>` used standalone degrades to a bare value instead of throwing.
|
|
75
87
|
* Consumed internally by `VerifiedField` + `VerificationChrome`; exported for
|
|
76
88
|
* advanced hosts.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @thehammer/template-verification —
|
|
3
|
-
* template
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
2
|
+
* @thehammer/template-verification — the verification overlay a rendered
|
|
3
|
+
* template app wears, and the one signal it sends back out.
|
|
4
|
+
*
|
|
5
|
+
* Consumes the host's `__meta` sidecar (override > extracted > claim resolution
|
|
6
|
+
* + discrepancy) and draws ONE mark beside each bound value. Clicking a mark
|
|
7
|
+
* posts {@link DataPointActivatedMessage} to the embedding app; that app opens
|
|
8
|
+
* the citation and the record. The host calls `initVerification` once with
|
|
9
|
+
* `data`.
|
|
10
|
+
*
|
|
11
|
+
* ==== WHAT THIS LIBRARY DELIBERATELY NO LONGER DOES ====
|
|
12
|
+
*
|
|
13
|
+
* It used to render the entire review surface inside the iframe — a tabbed
|
|
14
|
+
* Inspector dialog (citations, extraction history, LLM audit trace), a hover
|
|
15
|
+
* summary panel on every mark, and `contenteditable` editing with a save
|
|
16
|
+
* transport behind it — and it fetched per-field detail from a token-sealed
|
|
17
|
+
* endpoint to fill them. All of that is deleted. It fetches nothing, saves
|
|
18
|
+
* nothing, and opens nothing. A letter is a document; the review happens in the
|
|
19
|
+
* application framing it, which already owns a citation viewer, a page viewer
|
|
20
|
+
* and a record editor.
|
|
21
|
+
*
|
|
22
|
+
* Removed exports, for anyone chasing an import that no longer resolves:
|
|
23
|
+
* `VerificationModal`, `CitationEvidence`, `CitationPageList`, `CitationPage`,
|
|
24
|
+
* `citationEvidence`, `citationSummary`, `fetchDataPointDetail`, and the
|
|
25
|
+
* `CitationPageModel` / `CitationEvidenceModel` / `AuditLlmCall` /
|
|
26
|
+
* `DataPointDetail` types.
|
|
11
27
|
*/
|
|
12
28
|
import "./styles.css";
|
|
13
29
|
export { initVerification, useVerification } from "./context";
|
|
@@ -15,20 +31,14 @@ export type { InitVerificationConfig, Verification } from "./context";
|
|
|
15
31
|
export { default as VerifiedField } from "./components/VerifiedField.vue";
|
|
16
32
|
export { default as VerificationChrome } from "./components/VerificationChrome.vue";
|
|
17
33
|
export { default as ConfidenceIcon } from "./components/ConfidenceIcon.vue";
|
|
18
|
-
export {
|
|
19
|
-
export {
|
|
20
|
-
export { default as CitationPageList } from "./components/CitationPageList.vue";
|
|
21
|
-
export { default as CitationPage } from "./components/CitationPage.vue";
|
|
34
|
+
export { TEMPLATE_MESSAGE_SOURCE, TEMPLATE_PROTOCOL_VERSION, DATA_POINT_ACTIVATED, embedderOrigin, notifyDataPointActivated, } from "./lib/hostBridge";
|
|
35
|
+
export type { DataPointActivatedMessage, DataPointActivation, } from "./lib/hostBridge";
|
|
22
36
|
export { bucketConfidence, STATUS_COLORS, STATUS_LABELS, } from "./lib/confidence";
|
|
23
|
-
export { resolveDataPoint, resolveCandidates,
|
|
37
|
+
export { resolveDataPoint, resolveCandidates, RESOLUTION_PRIORITY, } from "./lib/resolveDataPoint";
|
|
24
38
|
export { hasDiscrepancy, candidatesDisagree } from "./lib/discrepancy";
|
|
25
39
|
export { walkDataPoints } from "./lib/walk";
|
|
26
40
|
export type { WalkedDataPoint } from "./lib/walk";
|
|
27
|
-
export { citationEvidence, citationSummary } from "./lib/citations";
|
|
28
|
-
export type { CitationPage as CitationPageModel, CitationEvidence as CitationEvidenceModel } from "./lib/citations";
|
|
29
41
|
export { computeProgress } from "./lib/progress";
|
|
30
42
|
export type { VerificationProgress } from "./lib/progress";
|
|
31
|
-
export { fetchDataPointDetail } from "./lib/dataPointDetail";
|
|
32
|
-
export type { AuditLlmCall, DataPointDetail } from "./lib/dataPointDetail";
|
|
33
43
|
export { CHROME_CLASS, ENABLED_STORAGE_KEY } from "./constants";
|
|
34
44
|
export type { VerificationStatus, ResolvedSource, SourceChoice, VerificationSource, ExtractedCandidate, OverrideCandidate, ClaimCandidate, CandidateSet, DataPointAnchor, ResolvedValue, DataPointMeta, MetaCarrier, SaveOverrideArgs, SaveOverrideFn, } from "./types";
|
|
@@ -12,3 +12,11 @@ import type { CandidateSet, DataPointMeta } from "../types";
|
|
|
12
12
|
export declare function hasDiscrepancy(meta?: DataPointMeta | null): boolean;
|
|
13
13
|
/** True when >=2 present candidates hold differing values. */
|
|
14
14
|
export declare function candidatesDisagree(candidates?: CandidateSet | null): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* True when a data point's discrepancy (if any) comes from a SOURCE-DOCUMENT conflict the
|
|
17
|
+
* host already reconciled (SG-217), rather than — or in addition to — two candidates
|
|
18
|
+
* disagreeing. Distinguishes the two kinds for copy/icon purposes; both share the same
|
|
19
|
+
* `discrepancy` flag and the same indicator in `VerifiedField.vue` — this only decides
|
|
20
|
+
* which wording the mark's accessible name carries.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isSourceDiscrepancy(meta?: DataPointMeta | null): boolean;
|
package/dist/lib/hostBridge.d.ts
CHANGED
|
@@ -1,25 +1,127 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
2
|
+
* The one outbound channel from a rendered template to the app embedding it.
|
|
3
|
+
*
|
|
4
|
+
* ==== WHY THE LETTER NO LONGER REVIEWS ANYTHING ITSELF ====
|
|
5
|
+
*
|
|
6
|
+
* This library used to render the whole review surface INSIDE the iframe: a
|
|
7
|
+
* 90vw x 90vh dialog with tabs for citations, extraction history and the LLM
|
|
8
|
+
* audit trace, a hover panel on every badge, and contenteditable editing on the
|
|
9
|
+
* value itself. All of it is gone. A letter is a document; a document that
|
|
10
|
+
* grows a second application on top of itself is two products fighting for one
|
|
11
|
+
* viewport, and the embedding app already owns a citation viewer, a record
|
|
12
|
+
* editor and a page viewer that are better than the ones in here ever were.
|
|
13
|
+
*
|
|
14
|
+
* What is left in the letter is the MARK and nothing else. Clicking it posts
|
|
15
|
+
* this message; everything that happens next happens in the embedder.
|
|
16
|
+
*
|
|
17
|
+
* ==== THE TARGET ORIGIN IS RESOLVED, NEVER "*" ====
|
|
18
|
+
*
|
|
19
|
+
* The message names the record and field a reader is looking at, which is this
|
|
20
|
+
* team's data. Posting it to `"*"` hands it to whatever happens to be framing
|
|
21
|
+
* the document, which on a mis-served preview is not the app that asked for it.
|
|
22
|
+
*
|
|
23
|
+
* The embedder's origin is not readable through `window.parent` — that is the
|
|
24
|
+
* whole point of a cross-origin frame — so it is resolved from the two places a
|
|
25
|
+
* browser DOES publish it, in order:
|
|
26
|
+
*
|
|
27
|
+
* 1. `location.ancestorOrigins[0]` — the embedder's origin, stated directly.
|
|
28
|
+
* Chromium and WebKit only.
|
|
29
|
+
* 2. `document.referrer`'s origin — the document that framed this one. Under
|
|
30
|
+
* the default `strict-origin-when-cross-origin` referrer policy a
|
|
31
|
+
* cross-origin embed still sends the ORIGIN, which is exactly and only
|
|
32
|
+
* what is needed here.
|
|
33
|
+
*
|
|
34
|
+
* If neither resolves, NOTHING IS POSTED. A mark that does nothing is a bug
|
|
35
|
+
* worth reporting; a token-shaped payload broadcast to an unknown origin is a
|
|
36
|
+
* leak, and the two are not comparable.
|
|
37
|
+
*/
|
|
38
|
+
import type { DataPointAnchor } from "../types";
|
|
39
|
+
/**
|
|
40
|
+
* The envelope every message out of a rendered template carries.
|
|
41
|
+
*
|
|
42
|
+
* Deliberately the SAME `source` the danxbot host-bridge scaffold already uses
|
|
43
|
+
* for its `ready` handshake and its keyboard/wheel relays. An embedder filters
|
|
44
|
+
* on `source` once and then switches on `type`; a second envelope would mean a
|
|
45
|
+
* second listener and a second thing to keep in step.
|
|
46
|
+
*/
|
|
47
|
+
export declare const TEMPLATE_MESSAGE_SOURCE = "danxbot-template";
|
|
48
|
+
/**
|
|
49
|
+
* The protocol version, matching the one the embedder stamps on its own
|
|
50
|
+
* outbound settings messages. It is on the wire so a receiver can refuse a
|
|
51
|
+
* shape it does not know rather than half-reading it; today every receiver
|
|
52
|
+
* accepts 1.
|
|
53
|
+
*/
|
|
54
|
+
export declare const TEMPLATE_PROTOCOL_VERSION = 1;
|
|
55
|
+
/** A reader clicked the verification mark on a rendered value. */
|
|
56
|
+
export declare const DATA_POINT_ACTIVATED = "data-point-activated";
|
|
57
|
+
/**
|
|
58
|
+
* The activation message.
|
|
59
|
+
*
|
|
60
|
+
* ==== THE ANCHOR IS COPIED VERBATIM, NEVER RESHAPED ====
|
|
61
|
+
*
|
|
62
|
+
* `anchor` carries the host's own three fields under the host's own names —
|
|
63
|
+
* `object_ids` (the FULL root-to-leaf path), `field`, `field_path` — because
|
|
64
|
+
* the receiver's citation endpoint and record lookup both key off exactly
|
|
65
|
+
* those. Renaming them into JS-side camelCase here would put a translation
|
|
66
|
+
* between the two halves of one protocol, and a translation is a place to get
|
|
67
|
+
* it wrong for no gain. `object_ids` is shallow-copied rather than passed by
|
|
68
|
+
* reference only because the source array is a Vue reactive proxy and the
|
|
69
|
+
* structured-clone algorithm has no business being handed one.
|
|
70
|
+
*
|
|
71
|
+
* `object_ids.at(-1)` is the record the field lives on; `object_ids[0]` is the
|
|
72
|
+
* demand itself. That distinction is load-bearing on the receiving side and is
|
|
73
|
+
* the reason the whole path travels rather than one id.
|
|
74
|
+
*
|
|
75
|
+
* ==== WHY `workflowInputId` IS ON THE MESSAGE ====
|
|
76
|
+
*
|
|
77
|
+
* An embedder does not remount the frame when it switches which record it is
|
|
78
|
+
* showing — it posts new data into the frame it already has. So a click can in
|
|
79
|
+
* principle arrive from a render of the PREVIOUS record, and the receiver has
|
|
80
|
+
* no other way to notice. Echoing the id the letter was initialised with lets
|
|
81
|
+
* it be checked in one comparison. Null when the host never supplied one.
|
|
82
|
+
*
|
|
83
|
+
* ==== WHY `value` TRAVELS AND `confidence` DOES NOT ====
|
|
84
|
+
*
|
|
85
|
+
* `value` is what the reader is looking at, so a panel can name the thing that
|
|
86
|
+
* was clicked before it has resolved anything, and a divergence between the
|
|
87
|
+
* letter and the record is visible rather than silent. Everything else about
|
|
88
|
+
* the data point — confidence, candidates, citations, history — the receiver
|
|
89
|
+
* already holds or can fetch against the anchor, and shipping a second copy
|
|
90
|
+
* would create two sources for one fact.
|
|
91
|
+
*/
|
|
92
|
+
export interface DataPointActivatedMessage {
|
|
93
|
+
source: typeof TEMPLATE_MESSAGE_SOURCE;
|
|
94
|
+
version: number;
|
|
95
|
+
type: typeof DATA_POINT_ACTIVATED;
|
|
96
|
+
anchor: DataPointAnchor;
|
|
97
|
+
/** The workflow input this render was initialised for. Null when unknown. */
|
|
98
|
+
workflowInputId: number | string | null;
|
|
99
|
+
/** The field name the template bound, for a panel heading. Null when unbound. */
|
|
100
|
+
label: string | null;
|
|
101
|
+
/** The resolved text currently rendered in the letter. */
|
|
102
|
+
value: string | null;
|
|
103
|
+
}
|
|
104
|
+
/** What {@link notifyDataPointActivated} needs in order to name a data point. */
|
|
105
|
+
export interface DataPointActivation {
|
|
106
|
+
anchor: DataPointAnchor;
|
|
107
|
+
workflowInputId?: number | string | null;
|
|
108
|
+
label?: string | null;
|
|
109
|
+
value?: string | null;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The origin of the document framing this one, or null when it cannot be known.
|
|
113
|
+
*
|
|
114
|
+
* Exported because it is the security property of this module and a test that
|
|
115
|
+
* cannot reach it can only assert it indirectly.
|
|
116
|
+
*/
|
|
117
|
+
export declare function embedderOrigin(): string | null;
|
|
118
|
+
/**
|
|
119
|
+
* Tell the embedder a reader activated one data point.
|
|
120
|
+
*
|
|
121
|
+
* Returns whether anything was actually posted, so a caller (or a test) can
|
|
122
|
+
* tell "the embedder was told" from "there was nobody to tell" without reaching
|
|
123
|
+
* inside. Silent no-op — not a throw — in all three cases where there is no
|
|
124
|
+
* legitimate recipient: no window at all, not framed, or an unresolvable
|
|
125
|
+
* embedder origin.
|
|
24
126
|
*/
|
|
25
|
-
export declare function
|
|
127
|
+
export declare function notifyDataPointActivated(activation: DataPointActivation): boolean;
|
|
@@ -17,8 +17,3 @@ export declare const RESOLUTION_PRIORITY: Array<keyof CandidateSet>;
|
|
|
17
17
|
export declare function resolveDataPoint(meta?: DataPointMeta | null): ResolvedValue;
|
|
18
18
|
/** Derive the winning resolution purely from a candidate set, by priority. */
|
|
19
19
|
export declare function resolveCandidates(candidates?: CandidateSet | null): ResolvedValue;
|
|
20
|
-
/**
|
|
21
|
-
* The extracted candidate's reasoning, normalized to a non-empty string or null.
|
|
22
|
-
* Reasoning is frequently `""`/null — callers render a quiet empty state, never throw.
|
|
23
|
-
*/
|
|
24
|
-
export declare function reasoningOf(meta?: DataPointMeta | null): string | null;
|