@deepcitation/deepcitation-js 1.1.49 → 1.1.51
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 +73 -157
- package/lib/chunk-2HINOG74.js +3 -0
- package/lib/chunk-2HINOG74.js.map +1 -0
- package/lib/chunk-4UWAUWYL.cjs +3 -0
- package/lib/chunk-4UWAUWYL.cjs.map +1 -0
- package/lib/chunk-5XGN7UAV.js +2 -0
- package/lib/chunk-5XGN7UAV.js.map +1 -0
- package/lib/chunk-7TORYXU4.cjs +3 -0
- package/lib/chunk-7TORYXU4.cjs.map +1 -0
- package/lib/chunk-BDSA6VGC.js +125 -0
- package/lib/chunk-BDSA6VGC.js.map +1 -0
- package/lib/chunk-BEYJEW3Y.js +2 -0
- package/lib/chunk-BEYJEW3Y.js.map +1 -0
- package/lib/chunk-BWQLFMTV.js +2 -0
- package/lib/chunk-BWQLFMTV.js.map +1 -0
- package/lib/{chunk-F2MMVEVC.cjs → chunk-BYLIBOAU.cjs} +2 -1
- package/lib/chunk-BYLIBOAU.cjs.map +1 -0
- package/lib/chunk-DS6SOU4L.cjs +2 -0
- package/lib/chunk-DS6SOU4L.cjs.map +1 -0
- package/lib/{chunk-UUR2SQKU.cjs → chunk-HL3AXCDL.cjs} +2 -1
- package/lib/chunk-HL3AXCDL.cjs.map +1 -0
- package/lib/chunk-N7FTXSGM.js +3 -0
- package/lib/chunk-N7FTXSGM.js.map +1 -0
- package/lib/chunk-WS4CQVDI.cjs +125 -0
- package/lib/chunk-WS4CQVDI.cjs.map +1 -0
- package/lib/client/index.cjs +2 -1
- package/lib/client/index.cjs.map +1 -0
- package/lib/client/index.d.cts +58 -13
- package/lib/client/index.d.ts +58 -13
- package/lib/client/index.js +2 -1
- package/lib/client/index.js.map +1 -0
- package/lib/{index-fvVBZYVK.d.ts → index-BHjI8Bh1.d.cts} +61 -22
- package/lib/{index-fvVBZYVK.d.cts → index-BHjI8Bh1.d.ts} +61 -22
- package/lib/index.cjs +2 -1
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +137 -16
- package/lib/index.d.ts +137 -16
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -0
- package/lib/prompts/index.cjs +2 -1
- package/lib/prompts/index.cjs.map +1 -0
- package/lib/prompts/index.d.cts +177 -55
- package/lib/prompts/index.d.ts +177 -55
- package/lib/prompts/index.js +2 -1
- package/lib/prompts/index.js.map +1 -0
- package/lib/react/index.cjs +8 -5
- package/lib/react/index.cjs.map +1 -0
- package/lib/react/index.d.cts +348 -21
- package/lib/react/index.d.ts +348 -21
- package/lib/react/index.js +8 -5
- package/lib/react/index.js.map +1 -0
- package/lib/styles.css +1 -1
- package/lib/types/index.cjs +2 -1
- package/lib/types/index.cjs.map +1 -0
- package/lib/types/index.d.cts +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.js +2 -1
- package/lib/types/index.js.map +1 -0
- package/lib/{utils-q6anRKO_.d.cts → utils-CCi9_JTv.d.cts} +5 -5
- package/lib/{utils-DuacFTtu.d.ts → utils-CoSP-i76.d.ts} +5 -5
- package/package.json +165 -152
- package/src/tailwind.css +5 -5
- package/lib/chunk-2PRW5PVT.cjs +0 -2
- package/lib/chunk-3XSZLKJW.js +0 -2
- package/lib/chunk-D2TKEF6D.cjs +0 -2
- package/lib/chunk-DHVODVIA.cjs +0 -71
- package/lib/chunk-HRCAI3NV.js +0 -1
- package/lib/chunk-ND6LFDGK.js +0 -71
- package/lib/chunk-O2XFH626.js +0 -1
- package/lib/chunk-PKXMJNRX.js +0 -2
package/README.md
CHANGED
|
@@ -1,157 +1,73 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# @deepcitation/deepcitation-js
|
|
4
|
-
|
|
5
|
-
**
|
|
6
|
-
|
|
7
|
-
[](https://www.npmjs.com/package/@deepcitation/deepcitation-js)
|
|
8
|
-
[](https://opensource.org/licenses/MIT)
|
|
9
|
-
[ · [
|
|
12
|
-
|
|
13
|
-
</div>
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
});
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Step 2: Post-Prompt
|
|
78
|
-
|
|
79
|
-
Verify citations against the attachments.
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
const result = await deepcitation.verify({
|
|
83
|
-
llmOutput: response.content,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// result.verifications contains verification status + visual proof
|
|
87
|
-
const { verifications } = result;
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### Step 3: Display
|
|
91
|
-
|
|
92
|
-
Parse the LLM output and render verified citations inline with React components.
|
|
93
|
-
|
|
94
|
-
```tsx
|
|
95
|
-
import { CitationComponent } from "@deepcitation/deepcitation-js/react";
|
|
96
|
-
import {
|
|
97
|
-
parseCitation,
|
|
98
|
-
generateCitationKey,
|
|
99
|
-
} from "@deepcitation/deepcitation-js";
|
|
100
|
-
import "@deepcitation/deepcitation-js/react/styles.css";
|
|
101
|
-
|
|
102
|
-
function Response({ llmOutput, verifications }) {
|
|
103
|
-
// Split LLM output by citation tags and render inline
|
|
104
|
-
const renderWithCitations = (text: string) => {
|
|
105
|
-
const parts = text.split(/(<cite\s+[^>]*\/>)/g);
|
|
106
|
-
|
|
107
|
-
return parts.map((part, index) => {
|
|
108
|
-
if (part.startsWith("<cite")) {
|
|
109
|
-
const { citation } = parseCitation(part);
|
|
110
|
-
const citationKey = generateCitationKey(citation);
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<CitationComponent
|
|
114
|
-
key={index}
|
|
115
|
-
citation={citation}
|
|
116
|
-
verification={verifications[citationKey]}
|
|
117
|
-
/>
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
return <span key={index}>{part}</span>;
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
return <div>{renderWithCitations(llmOutput)}</div>;
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## Examples
|
|
131
|
-
|
|
132
|
-
Check out the [examples directory](./examples) for complete, runnable examples:
|
|
133
|
-
|
|
134
|
-
- [**basic-verification**](./examples/basic-verification) – Core 3-step workflow
|
|
135
|
-
- [**nextjs-ai-sdk**](./examples/nextjs-ai-sdk) – Full-stack Next.js chat app
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
cd examples/basic-verification
|
|
139
|
-
npm install
|
|
140
|
-
cp .env.example .env # Add your API keys
|
|
141
|
-
npm run start:openai
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
## Supported Formats
|
|
148
|
-
* **Documents:** PDF (Text & Scanned), DOCX, XLSX, PPTX, HTML
|
|
149
|
-
* **Images:** JPG, PNG, TIFF, WebP, HEIC
|
|
150
|
-
* **Web:** Public URLs
|
|
151
|
-
|
|
152
|
-
## Documentation & Examples
|
|
153
|
-
* **[Full Documentation](https://deepcitation.com/docs)** - API reference and advanced usage.
|
|
154
|
-
* **[Examples Directory](./examples)** - Runnable Next.js and Node.js examples.
|
|
155
|
-
|
|
156
|
-
## License
|
|
157
|
-
MIT License - see [LICENSE](./LICENSE) for details.
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# @deepcitation/deepcitation-js
|
|
4
|
+
|
|
5
|
+
**Verify AI citations against source documents. Visual proof for every claim.**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@deepcitation/deepcitation-js)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://www.npmjs.com/package/@deepcitation/deepcitation-js)
|
|
10
|
+
|
|
11
|
+
[Documentation](https://deepcitation.com/docs) · [Get API Key](https://deepcitation.com/signup) · [Examples](./examples)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<div align="center">
|
|
18
|
+
<img src="https://raw.githubusercontent.com/DeepCitation/deepcitation-js/main/tests/playwright/specs/__snapshots__/visualShowcase.spec.tsx-snapshots/desktop-showcase-chromium-linux.png" alt="DeepCitation Component Showcase" width="700" />
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @deepcitation/deepcitation-js
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { DeepCitation, wrapCitationPrompt } from "@deepcitation/deepcitation-js";
|
|
31
|
+
import { CitationComponent } from "@deepcitation/deepcitation-js/react";
|
|
32
|
+
|
|
33
|
+
// 1. Upload sources
|
|
34
|
+
const dc = new DeepCitation({ apiKey: process.env.DEEPCITATION_API_KEY });
|
|
35
|
+
const { deepTextPromptPortion } = await dc.prepareFiles([{ file: pdfBuffer, filename: "report.pdf" }]);
|
|
36
|
+
|
|
37
|
+
// 2. Wrap prompts & call LLM
|
|
38
|
+
const { enhancedSystemPrompt, enhancedUserPrompt } = wrapCitationPrompt({
|
|
39
|
+
systemPrompt: "You are a helpful assistant...",
|
|
40
|
+
userPrompt: "Analyze this document",
|
|
41
|
+
deepTextPromptPortion,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 3. Verify citations
|
|
45
|
+
const { verifications } = await dc.verify({ llmOutput: response.content });
|
|
46
|
+
|
|
47
|
+
// 4. Display with React
|
|
48
|
+
<CitationComponent citation={citation} verification={verifications[key]} />
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## React Components
|
|
52
|
+
|
|
53
|
+
| Component | Description |
|
|
54
|
+
|-----------|-------------|
|
|
55
|
+
| `CitationComponent` | Inline citations with 6 variants: `brackets`, `chip`, `text`, `superscript`, `minimal`, `linter` |
|
|
56
|
+
| `UrlCitationComponent` | URL citations with favicon and status badges |
|
|
57
|
+
| `SourcesListComponent` | Aggregated sources panel/drawer (like Gemini) |
|
|
58
|
+
|
|
59
|
+
> Requires Tailwind CSS or import `@deepcitation/deepcitation-js/styles.css`
|
|
60
|
+
|
|
61
|
+
## Supported Formats
|
|
62
|
+
|
|
63
|
+
PDF, DOCX, XLSX, PPTX, HTML, Images (JPG, PNG, TIFF, WebP, HEIC), URLs
|
|
64
|
+
|
|
65
|
+
## Resources
|
|
66
|
+
|
|
67
|
+
- [Full Documentation](https://deepcitation.com/docs)
|
|
68
|
+
- [Examples](./examples) – Basic verification, Next.js chat app
|
|
69
|
+
- [Agent Guide](./AGENTS.md) – For AI coding assistants
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import {d as d$1,B}from'./chunk-N7FTXSGM.js';import {a}from'./chunk-5XGN7UAV.js';var w="https://api.deepcitation.com";function C(s,t){if(typeof Buffer<"u"&&Buffer.isBuffer(s)){let e=Uint8Array.from(s);return {blob:new Blob([e]),name:t||"document"}}if(s instanceof Blob)return {blob:s,name:t||(s instanceof File?s.name:"document")};throw new Error("Invalid file type. Expected File, Blob, or Buffer.")}async function d(s,t){return (await s.json().catch(()=>({})))?.error?.message||`${t} failed with status ${s.status}`}var y=class{constructor(t){a(this,"apiKey");a(this,"apiUrl");if(!t.apiKey)throw new Error("DeepCitation API key is required. Get one at https://deepcitation.com/dashboard");this.apiKey=t.apiKey,this.apiUrl=t.apiUrl?.replace(/\/$/,"")||w;}async uploadFile(t,e){let{blob:p,name:n}=C(t,e?.filename),i=new FormData;i.append("file",p,n),e?.attachmentId&&i.append("attachmentId",e.attachmentId),e?.filename&&i.append("filename",e.filename);let a=await fetch(`${this.apiUrl}/prepareFile`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:i});if(!a.ok)throw new Error(await d(a,"Upload"));return await a.json()}async convertToPdf(t){let e=typeof t=="string"?{url:t}:t,{url:p,file:n,filename:i,attachmentId:a}=e;if(!p&&!n)throw new Error("Either url or file must be provided");let o;if(p)o=await fetch(`${this.apiUrl}/convertFile`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({url:p,filename:i,attachmentId:a})});else {let{blob:f,name:l}=C(n,i),r=new FormData;r.append("file",f,l),a&&r.append("attachmentId",a),i&&r.append("filename",i),o=await fetch(`${this.apiUrl}/convertFile`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:r});}if(!o.ok)throw new Error(await d(o,"Conversion"));return await o.json()}async prepareConvertedFile(t){let e=await fetch(`${this.apiUrl}/prepareFile`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({attachmentId:t.attachmentId})});if(!e.ok)throw new Error(await d(e,"Prepare"));return await e.json()}async prepareUrl(t){let e=await fetch(`${this.apiUrl}/prepareFile`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({url:t.url,attachmentId:t.attachmentId,filename:t.filename,unsafeFastUrlOutput:t.unsafeFastUrlOutput})});if(!e.ok)throw new Error(await d(e,"Prepare URL"));return await e.json()}async prepareFiles(t){if(t.length===0)return {fileDataParts:[]};let e=t.map(({file:i,filename:a,attachmentId:o})=>this.uploadFile(i,{filename:a,attachmentId:o}).then(f=>({result:f,filename:a})));return {fileDataParts:(await Promise.all(e)).map(({result:i,filename:a})=>({attachmentId:i.attachmentId,deepTextPromptPortion:i.deepTextPromptPortion,filename:a||i.metadata?.filename}))}}async verifyAttachment(t,e,p){let n={};if(Array.isArray(e))for(let l of e){let r=d$1(l);n[r]=l;}else if(typeof e=="object"&&e!==null)if("fullPhrase"in e||"value"in e){let l=d$1(e);n[l]=e;}else Object.assign(n,e);else throw new Error("Invalid citations format");if(Object.keys(n).length===0)return {verifications:{}};let i=`${this.apiUrl}/verifyCitations`,a={data:{attachmentId:t,citations:n,outputImageFormat:p?.outputImageFormat||"avif"}},o=await fetch(i,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(a)});if(!o.ok)throw new Error(await d(o,"Verification"));return await o.json()}async verify(t,e){let{llmOutput:p,outputImageFormat:n="avif"}=t;if(e||(e=B(p)),Object.keys(e).length===0)return {verifications:{}};let i=new Map;for(let[r,c]of Object.entries(e)){let u=c.attachmentId||"";i.has(u)||i.set(u,{}),i.get(u)[r]=c;}let a=[],o={};for(let[r,c]of i)r?a.push(this.verifyAttachment(r,c,{outputImageFormat:n})):(Object.assign(o,c),typeof console<"u"&&console.warn&&console.warn(`[DeepCitation] ${Object.keys(c).length} citation(s) skipped: missing attachmentId`));let f=await Promise.all(a),l={};for(let r of f)Object.assign(l,r.verifications);for(let r of Object.keys(o))l[r]={status:"skipped"};return {verifications:l}}};
|
|
2
|
+
export{y as a};//# sourceMappingURL=chunk-2HINOG74.js.map
|
|
3
|
+
//# sourceMappingURL=chunk-2HINOG74.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/DeepCitation.ts"],"names":["DEFAULT_API_URL","toBlob","file","filename","uint8","extractErrorMessage","response","fallbackAction","DeepCitation","config","__publicField","options","blob","name","formData","input","inputObj","url","attachmentId","files","uploadPromises","result","citations","citationMap","citation","key","generateCitationKey","requestUrl","requestBody","llmOutput","outputImageFormat","getAllCitationsFromLlmOutput","citationsByAttachment","verificationPromises","skippedCitations","fileCitations","results","allVerifications"],"mappings":"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","file":"chunk-2HINOG74.js","sourcesContent":["import { getAllCitationsFromLlmOutput } from \"../parsing/parseCitation.js\";\nimport { generateCitationKey } from \"../react/utils.js\";\nimport type { Citation } from \"../types/index.js\";\nimport type {\n CitationInput,\n ConvertFileInput,\n ConvertFileResponse,\n DeepCitationConfig,\n FileDataPart,\n FileInput,\n PrepareConvertedFileOptions,\n PrepareFilesResult,\n PrepareUrlOptions,\n UploadFileOptions,\n UploadFileResponse,\n VerifyInput,\n VerifyCitationsOptions,\n VerifyCitationsResponse,\n} from \"./types.js\";\n\nconst DEFAULT_API_URL = \"https://api.deepcitation.com\";\n\n/** Convert File/Blob/Buffer to a Blob suitable for FormData */\nfunction toBlob(\n file: File | Blob | Buffer,\n filename?: string\n): { blob: Blob; name: string } {\n if (typeof Buffer !== \"undefined\" && Buffer.isBuffer(file)) {\n const uint8 = Uint8Array.from(file);\n return { blob: new Blob([uint8]), name: filename || \"document\" };\n }\n if (file instanceof Blob) {\n return {\n blob: file,\n name: filename || (file instanceof File ? file.name : \"document\"),\n };\n }\n throw new Error(\"Invalid file type. Expected File, Blob, or Buffer.\");\n}\n\n/** Extract error message from API response */\nasync function extractErrorMessage(\n response: Response,\n fallbackAction: string\n): Promise<string> {\n const error = await response.json().catch(() => ({}));\n return (\n error?.error?.message ||\n `${fallbackAction} failed with status ${response.status}`\n );\n}\n\n/**\n * DeepCitation client for file upload and citation verification.\n *\n * @example\n * ```typescript\n * import { DeepCitation } from '@deepcitation/deepcitation-js';\n *\n * const dc = new DeepCitation({ apiKey: process.env.DEEPCITATION_API_KEY });\n *\n * // Upload a file\n * const { attachmentId, promptContent } = await deepcitation.uploadFile(file);\n *\n * // Include promptContent in your LLM messages\n * const response = await llm.chat({\n * messages: [\n * { role: \"system\", content: wrapSystemCitationPrompt({ systemPrompt }) },\n * { role: \"user\", content: userMessage + \"\\n\\n\" + promptContent },\n * ]\n * });\n *\n * // Verify citations in the LLM output\n * const citations = getAllCitationsFromLlmOutput(response);\n * const verified = await deepcitation.verifyCitations(attachmentId, citations);\n * ```\n */\nexport class DeepCitation {\n private readonly apiKey: string;\n private readonly apiUrl: string;\n\n /**\n * Create a new DeepCitation client instance.\n *\n * @param config - Configuration options\n * @throws Error if apiKey is not provided\n */\n constructor(config: DeepCitationConfig) {\n if (!config.apiKey) {\n throw new Error(\n \"DeepCitation API key is required. Get one at https://deepcitation.com/dashboard\"\n );\n }\n this.apiKey = config.apiKey;\n this.apiUrl = config.apiUrl?.replace(/\\/$/, \"\") || DEFAULT_API_URL;\n }\n\n /**\n * Upload a file for citation verification.\n *\n * Supported file types:\n * - PDF documents\n * - Images (PNG, JPEG, WebP, AVIF, HEIC)\n * - Coming soon: DOCX, XLSX, plain text\n *\n * @param file - The file to upload (File, Blob, or Buffer)\n * @param options - Optional upload options\n * @returns Upload response with attachmentId and extracted text\n *\n * @example\n * ```typescript\n * // Browser with File object\n * const file = document.querySelector('input[type=\"file\"]').files[0];\n * const result = await deepcitation.uploadFile(file);\n *\n * // Node.js with Buffer\n * const buffer = fs.readFileSync('document.pdf');\n * const result = await deepcitation.uploadFile(buffer, { filename: 'document.pdf' });\n * ```\n */\n async uploadFile(\n file: File | Blob | Buffer,\n options?: UploadFileOptions\n ): Promise<UploadFileResponse> {\n const { blob, name } = toBlob(file, options?.filename);\n const formData = new FormData();\n formData.append(\"file\", blob, name);\n\n if (options?.attachmentId) formData.append(\"attachmentId\", options.attachmentId);\n if (options?.filename) formData.append(\"filename\", options.filename);\n\n const response = await fetch(`${this.apiUrl}/prepareFile`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${this.apiKey}` },\n body: formData,\n });\n\n if (!response.ok) {\n throw new Error(await extractErrorMessage(response, \"Upload\"));\n }\n\n return (await response.json()) as UploadFileResponse;\n }\n\n /**\n * Convert a URL or Office file to PDF for citation verification.\n * The converted file can then be processed with prepareConvertedFile().\n *\n * Supported Office formats:\n * - Microsoft Word (.doc, .docx)\n * - Microsoft Excel (.xls, .xlsx)\n * - Microsoft PowerPoint (.ppt, .pptx)\n * - OpenDocument (.odt, .ods, .odp)\n * - Rich Text Format (.rtf)\n * - CSV (.csv)\n *\n * @param input - URL string or object with URL/file options\n * @returns Conversion result with attachmentId for prepareConvertedFile\n *\n * @example\n * ```typescript\n * // Convert a URL to PDF\n * const result = await deepcitation.convertToPdf({ url: \"https://example.com/article\" });\n *\n * // Convert an Office document\n * const result = await deepcitation.convertToPdf({\n * file: docxBuffer,\n * filename: \"report.docx\"\n * });\n *\n * // Then prepare the file for verification\n * const { deepTextPromptPortion, attachmentId } = await deepcitation.prepareConvertedFile({\n * attachmentId: result.attachmentId\n * });\n * ```\n */\n async convertToPdf(\n input: ConvertFileInput | string\n ): Promise<ConvertFileResponse> {\n const inputObj: ConvertFileInput =\n typeof input === \"string\" ? { url: input } : input;\n const { url, file, filename, attachmentId } = inputObj;\n\n if (!url && !file) {\n throw new Error(\"Either url or file must be provided\");\n }\n\n let response: Response;\n\n if (url) {\n response = await fetch(`${this.apiUrl}/convertFile`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ url, filename, attachmentId }),\n });\n } else {\n const { blob, name } = toBlob(file!, filename);\n const formData = new FormData();\n formData.append(\"file\", blob, name);\n if (attachmentId) formData.append(\"attachmentId\", attachmentId);\n if (filename) formData.append(\"filename\", filename);\n\n response = await fetch(`${this.apiUrl}/convertFile`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${this.apiKey}` },\n body: formData,\n });\n }\n\n if (!response.ok) {\n throw new Error(await extractErrorMessage(response, \"Conversion\"));\n }\n\n return (await response.json()) as ConvertFileResponse;\n }\n\n /**\n * Prepare a previously converted file for citation verification.\n * Use this after calling convertToPdf() to extract text and get deepTextPromptPortion.\n *\n * @param options - Options with attachmentId from convertFile\n * @returns Upload response with attachmentId and extracted text\n *\n * @example\n * ```typescript\n * // First convert the file\n * const converted = await deepcitation.convertToPdf({ url: \"https://example.com/article\" });\n *\n * // Then prepare it for verification\n * const { deepTextPromptPortion, attachmentId } = await deepcitation.prepareConvertedFile({\n * attachmentId: converted.attachmentId\n * });\n *\n * // Use deepTextPromptPortion in your LLM prompt...\n * ```\n */\n async prepareConvertedFile(\n options: PrepareConvertedFileOptions\n ): Promise<UploadFileResponse> {\n const response = await fetch(`${this.apiUrl}/prepareFile`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n attachmentId: options.attachmentId,\n }),\n });\n\n if (!response.ok) {\n throw new Error(await extractErrorMessage(response, \"Prepare\"));\n }\n\n return (await response.json()) as UploadFileResponse;\n }\n\n /**\n * Prepare a URL for citation verification.\n *\n * This is a convenience method that handles URL conversion and text extraction\n * in a single call. The API will convert the URL to PDF and extract text content\n * for citation verification.\n *\n * Note: URLs and Office files take ~30s to process vs. <1s for images/PDFs.\n *\n * @param options - URL and optional settings\n * @returns Upload response with attachmentId and extracted text for LLM prompts\n *\n * @example\n * ```typescript\n * // Prepare a URL for citation verification\n * const { attachmentId, deepTextPromptPortion } = await deepcitation.prepareUrl({\n * url: \"https://example.com/article\"\n * });\n *\n * // Use deepTextPromptPortion in your LLM prompt\n * const { enhancedSystemPrompt, enhancedUserPrompt } = wrapCitationPrompt({\n * systemPrompt,\n * userPrompt: question,\n * deepTextPromptPortion,\n * });\n *\n * // Verify citations\n * const verified = await deepcitation.verifyAttachment(attachmentId, citations);\n * ```\n */\n async prepareUrl(options: PrepareUrlOptions): Promise<UploadFileResponse> {\n const response = await fetch(`${this.apiUrl}/prepareFile`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n url: options.url,\n attachmentId: options.attachmentId,\n filename: options.filename,\n unsafeFastUrlOutput: options.unsafeFastUrlOutput,\n }),\n });\n\n if (!response.ok) {\n throw new Error(await extractErrorMessage(response, \"Prepare URL\"));\n }\n\n return (await response.json()) as UploadFileResponse;\n }\n\n /**\n * Upload multiple files for citation verification and get structured content.\n * This is the recommended way to prepare files for LLM prompts.\n *\n * @param files - Array of files to upload with optional filenames and attachmentIds\n * @returns Object containing fileDataParts for verification and deepTextPromptPortion for LLM\n *\n * @example\n * ```typescript\n * const { fileDataParts, deepTextPromptPortion } = await deepcitation.prepareFiles([\n * { file: pdfBuffer, filename: \"report.pdf\" },\n * { file: invoiceBuffer, filename: \"invoice.pdf\" },\n * ]);\n *\n * // Use deepTextPromptPortion in wrapCitationPrompt\n * const { enhancedSystemPrompt, enhancedUserPrompt } = wrapCitationPrompt({\n * systemPrompt,\n * userPrompt,\n * deepTextPromptPortion\n * });\n *\n * // Use fileDataParts later for verification\n * const result = await deepcitation.verify({ llmOutput, fileDataParts });\n * ```\n */\n async prepareFiles(files: FileInput[]): Promise<PrepareFilesResult> {\n if (files.length === 0) {\n return { fileDataParts: [] };\n }\n\n // Upload all files in parallel\n const uploadPromises = files.map(({ file, filename, attachmentId }) =>\n this.uploadFile(file, { filename, attachmentId }).then((result) => ({\n result,\n filename,\n }))\n );\n\n const uploadResults = await Promise.all(uploadPromises);\n\n // Extract file data parts with deepTextPromptPortion included (single source of truth)\n const fileDataParts: FileDataPart[] = uploadResults.map(\n ({ result, filename }) => ({\n attachmentId: result.attachmentId,\n deepTextPromptPortion: result.deepTextPromptPortion,\n filename: filename || result.metadata?.filename,\n })\n );\n\n return { fileDataParts };\n }\n\n /**\n * Verify citations against a single attachment/file.\n *\n * For most use cases, prefer `verify()` which automatically parses citations\n * from LLM output and handles multiple attachments. Use this method when you\n * need fine-grained control over per-attachment verification.\n *\n * @param attachmentId - The attachment ID returned from uploadFile\n * @param citations - Citations to verify (from getAllCitationsFromLlmOutput)\n * @param options - Optional verification options\n * @returns Verification results with status and proof images\n *\n * @example\n * ```typescript\n * import { getAllCitationsFromLlmOutput } from '@deepcitation/deepcitation-js';\n *\n * const citations = getAllCitationsFromLlmOutput(llmResponse);\n * const verified = await deepcitation.verifyAttachment(attachmentId, citations);\n *\n * for (const [key, result] of Object.entries(verified.verifications)) {\n * console.log(key, result.status);\n * // \"found\", \"partial_text_found\", \"not_found\", etc.\n * }\n * ```\n */\n async verifyAttachment(\n attachmentId: string,\n citations: CitationInput,\n options?: VerifyCitationsOptions\n ): Promise<VerifyCitationsResponse> {\n // Normalize citations to a map with citation keys\n const citationMap: Record<string, Citation> = {};\n\n if (Array.isArray(citations)) {\n // Array of citations - generate keys\n for (const citation of citations) {\n const key = generateCitationKey(citation);\n citationMap[key] = citation;\n }\n } else if (typeof citations === \"object\" && citations !== null) {\n // Check if it's a single citation or a map\n if (\"fullPhrase\" in citations || \"value\" in citations) {\n // Single citation\n const key = generateCitationKey(citations as Citation);\n citationMap[key] = citations as Citation;\n } else {\n // Already a map\n Object.assign(citationMap, citations);\n }\n } else {\n throw new Error(\"Invalid citations format\");\n }\n\n // If no citations to verify, return empty result\n if (Object.keys(citationMap).length === 0) {\n return { verifications: {} };\n }\n\n const requestUrl = `${this.apiUrl}/verifyCitations`;\n const requestBody = {\n data: {\n attachmentId,\n citations: citationMap,\n outputImageFormat: options?.outputImageFormat || \"avif\",\n },\n };\n\n const response = await fetch(requestUrl, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n throw new Error(await extractErrorMessage(response, \"Verification\"));\n }\n\n const result = (await response.json()) as VerifyCitationsResponse;\n return result;\n }\n\n /**\n * Parse and verify all citations from LLM output.\n *\n * This is the recommended method for citation verification. It automatically:\n * 1. Parses citations from LLM output (no raw content sent to our servers)\n * 2. Groups citations by attachment ID\n * 3. Verifies each attachment in parallel\n *\n * For privacy-conscious users: we only receive the parsed citation metadata,\n * not your raw LLM output. This method is a convenience wrapper that parses\n * locally and makes per-attachment verification calls.\n *\n * @param input - Object containing llmOutput and optional outputImageFormat\n * @param citations - Optional pre-parsed citations (skips parsing if provided)\n * @returns Verification results with status and proof images\n *\n * @example\n * ```typescript\n * const result = await deepcitation.verify({\n * llmOutput: response.content,\n * });\n *\n * for (const [key, verification] of Object.entries(result.verifications)) {\n * console.log(key, verification.status);\n * }\n * ```\n */\n async verify(\n input: VerifyInput,\n citations?: { [key: string]: Citation }\n ): Promise<VerifyCitationsResponse> {\n const { llmOutput, outputImageFormat = \"avif\" } = input;\n\n // Parse citations from LLM output\n if (!citations) citations = getAllCitationsFromLlmOutput(llmOutput);\n\n // If no citations found, return empty result\n if (Object.keys(citations).length === 0) {\n return { verifications: {} };\n }\n\n // Group citations by attachmentId\n const citationsByAttachment = new Map<string, Record<string, Citation>>();\n for (const [key, citation] of Object.entries(citations)) {\n const attachmentId = citation.attachmentId || \"\";\n if (!citationsByAttachment.has(attachmentId)) {\n citationsByAttachment.set(attachmentId, {});\n }\n citationsByAttachment.get(attachmentId)![key] = citation;\n }\n\n const verificationPromises: Promise<VerifyCitationsResponse>[] = [];\n const skippedCitations: Record<string, Citation> = {};\n\n for (const [attachmentId, fileCitations] of citationsByAttachment) {\n if (attachmentId) {\n verificationPromises.push(\n this.verifyAttachment(attachmentId, fileCitations, { outputImageFormat })\n );\n } else {\n Object.assign(skippedCitations, fileCitations);\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\n `[DeepCitation] ${Object.keys(fileCitations).length} citation(s) skipped: missing attachmentId`\n );\n }\n }\n }\n\n const results = await Promise.all(verificationPromises);\n const allVerifications: VerifyCitationsResponse[\"verifications\"] = {};\n for (const result of results) {\n Object.assign(allVerifications, result.verifications);\n }\n\n for (const key of Object.keys(skippedCitations)) {\n allVerifications[key] = { status: \"skipped\" };\n }\n\n return { verifications: allVerifications };\n }\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';var chunkWS4CQVDI_cjs=require('./chunk-WS4CQVDI.cjs');function F(t){return new TextEncoder().encode(t)}function G(t){let e=1732584193,i=4023233417,r=2562383102,n=271733878,a=3285377520,l=t.length,c=l*8,o=l+1+8,s=Math.ceil(o/64)*64,u=new ArrayBuffer(s),C=new Uint8Array(u),d=new DataView(u);C.set(t),C[l]=128,d.setUint32(s-8,Math.floor(c/4294967296),false),d.setUint32(s-4,c>>>0,false);let h=new Uint32Array(80);for(let f=0;f<s;f+=64){for(let _=0;_<16;_++)h[_]=d.getUint32(f+_*4,false);for(let _=16;_<80;_++){let A=h[_-3]^h[_-8]^h[_-14]^h[_-16];h[_]=A<<1|A>>>31;}let I=e,m=i,p=r,x=n,k=a;for(let _=0;_<80;_++){let A,y;_<20?(A=m&p|~m&x,y=1518500249):_<40?(A=m^p^x,y=1859775393):_<60?(A=m&p|m&x|p&x,y=2400959708):(A=m^p^x,y=3395469782);let g=(I<<5|I>>>27)+A+k+y+h[_]>>>0;k=x,x=p,p=(m<<30|m>>>2)>>>0,m=I,I=g;}e=e+I>>>0,i=i+m>>>0,r=r+p>>>0,n=n+x>>>0,a=a+k>>>0;}let b=f=>f.toString(16).padStart(8,"0");return b(e)+b(i)+b(r)+b(n)+b(a)}function M(t){try{if(!t)return "";let e=typeof t=="string"?t:JSON.stringify(t);return G(F(e))}catch(e){console.error("Error in making the hash:",e);}return ""}var H={n:"id",a:"attachment_id",r:"reasoning",f:"full_phrase",k:"anchor_text",p:"page_id",l:"line_ids",t:"timestamps"};function Y(t){return typeof t=="object"&&t!==null&&"id"in t&&typeof t.id=="number"}function O(t,e){let i={};for(let[r,n]of Object.entries(t)){let a=H[r]||r;if((r==="t"||r==="timestamps")&&n&&typeof n=="object"){let l=n;i.timestamps={start_time:l.s??l.start_time,end_time:l.e??l.end_time};}else i[a]=n;}if(e&&!i.attachment_id&&(i.attachment_id=e),!Y(i))throw new Error("Invalid citation data: missing or invalid 'id' field");return i}function q(t){if(typeof t!="object"||t===null||Array.isArray(t))return false;let e=Object.values(t);return e.length>0&&e.every(Array.isArray)}function X(t){let e=[];for(let[i,r]of Object.entries(t))for(let n of r)typeof n=="object"&&n!==null&&e.push(O(n,i));return e}function E(t){return q(t)?X(t):(Array.isArray(t)?t:[t]).map(i=>O(i))}function Q(t){let e=t.trim(),i=[],r=e;e=e.replace(/^```(?:json)?\s*/i,"").replace(/\s*```$/,""),e!==r&&i.push("removed markdown code block markers");let n=e;if(e=e.replace(/,(\s*[\]\}])/g,"$1"),e!==n&&i.push("removed trailing commas"),e.startsWith("[")&&!e.endsWith("]")){let a=(e.match(/\[/g)||[]).length,l=(e.match(/\]/g)||[]).length;if(a>l){let c=a-l;e=e+"]".repeat(c),i.push(`added ${c} closing bracket(s)`);}}if(e.includes("{")){let a=(e.match(/\{/g)||[]).length,l=(e.match(/\}/g)||[]).length;if(a>l){let c=a-l;e=e+"}".repeat(c),i.push(`added ${c} closing brace(s)`);}}return {repaired:e,repairs:i}}function K(t){if(!t||typeof t!="string")return {visibleText:"",citations:[],citationMap:new Map,success:false,error:"Invalid input: expected a string"};let e=t.indexOf(chunkWS4CQVDI_cjs.a);if(e===-1)return {visibleText:t.trim(),citations:[],citationMap:new Map,success:true};let i=t.substring(0,e).trim(),r=t.indexOf(chunkWS4CQVDI_cjs.b,e),n=e+chunkWS4CQVDI_cjs.a.length,a=r!==-1?r:t.length,l=t.substring(n,a).trim(),c=[],o=new Map;if(l)try{let s=JSON.parse(l);c=E(s);}catch(s){try{let{repaired:u,repairs:C}=Q(l),d=JSON.parse(u);c=E(d),C.length>0&&console.warn("[DeepCitation] JSON repair was triggered for citation data.",`Repairs applied: ${C.join(", ")}.`,`Initial parse error: ${s instanceof Error?s.message:"Unknown error"}`);}catch(u){return {visibleText:i,citations:[],citationMap:new Map,success:false,error:`Failed to parse citation JSON. Initial error: ${s instanceof Error?s.message:"Unknown error"}. Repair error: ${u instanceof Error?u.message:"Unknown error"}`}}}for(let s of c)typeof s.id=="number"&&o.set(s.id,s);return {visibleText:i,citations:c,citationMap:o,success:true}}function tt(t){let e=t.match(/^(\d+)_(\d+)$/);if(e){let r=parseInt(e[1],10),n=parseInt(e[2],10);return {pageNumber:r,startPageId:`page_number_${r}_index_${n}`}}let i=t.match(/page[_a-zA-Z]*(\d+)_index_(\d+)/i);if(i){let r=parseInt(i[1],10),n=parseInt(i[2],10);return {pageNumber:r,startPageId:`page_number_${r}_index_${n}`}}return {pageNumber:void 0,startPageId:void 0}}function et(t,e){let i,r,n=t.page_id;if(n){let c=tt(n);i=c.pageNumber,r=c.startPageId;}let a;t.timestamps&&(a={startTime:t.timestamps.start_time,endTime:t.timestamps.end_time});let l=t.line_ids?.length?[...t.line_ids].sort((c,o)=>c-o):void 0;return {attachmentId:t.attachment_id,pageNumber:i,startPageId:r,fullPhrase:t.full_phrase,anchorText:t.anchor_text,citationNumber:e??t.id,lineIds:l,reasoning:t.reasoning,timestamps:a}}function z(t){let e=K(t);if(!e.success||e.citations.length===0)return {};let i={};for(let r of e.citations){let n=et(r);if(n.fullPhrase){let a=T(n);i[a]=n;}}return i}function V(t){return typeof t=="string"&&t.includes(chunkWS4CQVDI_cjs.a)}function gt(t){return K(t).visibleText}function ft(t,e){let{citationMap:i,showAnchorText:r,replacer:n}=e||{};return t.replace(/\[(\d+)\]/g,(a,l)=>{let c=parseInt(l,10),o=i?.get(c);return n?n(c,o):r&&o?.anchor_text?o.anchor_text:""})}function mt(t){let e=[],i=/\[(\d+)\]/g,r;for(;(r=i.exec(t))!==null;)e.push(parseInt(r[1],10));return e}var L=new Map;function nt(t){let e=L.get(t);return e||(e=new RegExp(`${t}='((?:[^'\\\\]|\\\\.)*)'`),L.set(t,e)),e}function it(t){if(!t)return;let e=[],i=t.split(",");for(let r of i){let n=r.trim();if(n)if(n.includes("-")){let[a,l]=n.split("-"),c=parseInt(a,10),o=parseInt(l,10);if(!isNaN(c)&&!isNaN(o)&&c<=o)for(let s=c;s<=o;s++)e.push(s);else isNaN(c)||e.push(c);}else {let a=parseInt(n,10);isNaN(a)||e.push(a);}}if(e.length!==0)return [...new Set(e)].sort((r,n)=>r-n)}function B(t){let e=t?.status,i=["not_found"].includes(e||""),r=["found_anchor_text_only","partial_text_found","found_on_other_page","found_on_other_line","first_word_found"].includes(e||""),n=["found","found_phrase_missed_anchor_text"].includes(e||"")||r,a=["pending","loading",null,void 0].includes(e);return {isVerified:n,isMiss:i,isPartialMatch:r,isPending:a}}var rt=(t,e,i,r)=>{let n=y=>{if(!y)return;let g=y;return (g.startsWith("'")||g.startsWith('"'))&&(g=g.slice(1)),(g.endsWith("'")||g.endsWith('"'))&&!g.endsWith("\\'")&&!g.endsWith('\\"')&&(g=g.slice(0,-1)),g=g.replace(/\\"/g,'"'),g=g.replace(/\\'/g,"'"),g=g.replace(/\\n/g," "),g=g.replace(/\\\\/g,"\\"),g},a=i?.current?i.current++:void 0,l=t.substring(0,t.indexOf("<cite")),c=t.includes("/>")?t.slice(t.indexOf("/>")+2):"",o=t.substring(t.indexOf("<cite"),t.indexOf("/>")+2),s=(y,g)=>{for(let P of g){let N=nt(P),D=y.match(N);if(D)return D[1]}},u=s(o,["attachment_id","attachmentId","file_id","fileId"]),C=u?.length===20?u:e||u,d=s(o,["start_page_id","startPageId","start_page_key","startPageKey","start_page"]),h,b;if(d){let y=d.match(/page[\_a-zA-Z]*(\d+)_index_(\d+)/);y&&(h=parseInt(y[1]),b=parseInt(y[2]));}let f=n(s(o,["full_phrase","fullPhrase"])),I=n(s(o,["anchor_text","anchorText","key_span","keySpan"])),m=n(s(o,["reasoning"])),p=n(s(o,["value"])),x;try{let g=s(o,["line_ids","lineIds"])?.replace(/[A-Za-z_[\](){}:]/g,"");x=g?it(g):void 0;}catch(y){r&&console.error("Error parsing lineIds",y);}let k=s(o,["timestamps"]),_;if(k){let[y,g]=k.split("-")||[];_={startTime:y,endTime:g};}let A={attachmentId:C,pageNumber:h,startPageId:`page_number_${h||1}_index_${b||0}`,fullPhrase:f,anchorText:I||p,citationNumber:a,lineIds:x,beforeCite:l,timestamps:_,reasoning:m};return {beforeCite:l,afterCite:c,citation:A}},st=(t,e)=>{if(!t)return null;let i=t.fullPhrase??t.full_phrase,r=t.startPageId??t.start_page_id??t.startPageKey??t.start_page_key,n=t.anchorText??t.anchor_text??t.keySpan??t.key_span,a=t.lineIds??t.line_ids,l=t.attachmentId??t.attachment_id??t.fileId??t.file_id,c=t.reasoning,o=t.value;if(!i)return null;let s;if(r){let d=r.match(/page[_a-zA-Z]*(\d+)_index_(\d+)/i);if(d)s=parseInt(d[1],10);else {let h=r.match(/^(\d+)_(\d+)$/);h&&(s=parseInt(h[1],10));}}let u=a?.length?[...a].sort((d,h)=>d-h):void 0;return {attachmentId:l,pageNumber:s,fullPhrase:i,citationNumber:e,lineIds:u,anchorText:n||o,reasoning:c}},J=t=>typeof t=="object"&&t!==null&&("fullPhrase"in t||"full_phrase"in t||"startPageId"in t||"start_page_id"in t||"startPageKey"in t||"start_page_key"in t||"anchorText"in t||"anchor_text"in t||"keySpan"in t||"key_span"in t||"lineIds"in t||"line_ids"in t),R=t=>Array.isArray(t)?t.length>0&&t.some(J):typeof t=="object"&&t!==null?J(t):false,Z=t=>{let e={},i=Array.isArray(t)?t:[t],r=1;for(let n of i){let a=st(n,r++);if(a&&a.fullPhrase){let l=T(a);e[l]=a;}}return e},$=(t,e)=>{if(!(!t||typeof t!="object")){if(t.citation&&R(t.citation)){let i=Array.isArray(t.citation)?t.citation:[t.citation];e.push(...i);}if(t.citations&&R(t.citations)){let i=Array.isArray(t.citations)?t.citations:[t.citations];e.push(...i);}if(Array.isArray(t))for(let i of t)$(i,e);else for(let i of Object.keys(t))i!=="citation"&&i!=="citations"&&$(t[i],e);}},U=t=>{let e=W(t),i=/<cite\s+(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|[^'">/])*\/>/g,r=e.match(i);if(!r||r.length===0)return {};let n={},a={current:1};for(let l of r){let{citation:c}=rt(l,void 0,a);if(c&&c.fullPhrase){let o=T(c);n[o]=c;}}return n},Ct=t=>{if(!t)return {};let e={};if(typeof t=="object"){if(R(t)){let n=Z(t);Object.assign(e,n);}else {let n=[];if($(t,n),n.length>0){let a=Z(n);Object.assign(e,a);}}let i=JSON.stringify(t),r=U(i);Object.assign(e,r);}else if(typeof t=="string"){if(V(t)){let r=z(t);Object.assign(e,r);}let i=U(t);Object.assign(e,i);}return e};function It(t){let e=new Map,i=Array.isArray(t)?t.map((r,n)=>[T(r)||String(n+1),r]):Object.entries(t);for(let[r,n]of i){let a=n.attachmentId||"";e.has(a)||e.set(a,{}),e.get(a)[r]=n;}return e}function bt(t){let e={},i=Array.isArray(t)?t.map((r,n)=>[T(r)||String(n+1),r]):Object.entries(t);for(let[r,n]of i){let a=n.attachmentId||"";e[a]||(e[a]={}),e[a][r]=n;}return e}var at=t=>{let e={},i=/([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(['"])((?:[^'"\\]|\\.)*)\2/g,r;for(;(r=i.exec(t))!==null;){let n=r[1].toLowerCase().replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase(),a=r[3],l=n==="fileid"||n==="file_id"||n==="attachmentid"?"attachment_id":n==="anchortext"||n==="anchor_text"||n==="keyspan"||n==="key_span"?"anchor_text":n==="fullphrase"?"full_phrase":n==="lineids"?"line_ids":n==="pageid"||n==="page_id"||n==="startpageid"||n==="start_pageid"||n==="start_page_id"||n==="startpagekey"||n==="start_pagekey"||n==="start_page_key"||n==="pagekey"||n==="page_key"?"start_page_id":n;e[l]=a;}return e},ot=t=>{let e=B(t);return e.isMiss?"\u274C":e.isVerified&&!e.isPartialMatch?"\u2611\uFE0F":e.isPartialMatch?"\u2705":e.isPending?"\u231B":"\u25CC"},wt=(t,e={})=>{let{leaveAnchorTextBehind:i=false,verifications:r,showVerificationStatus:n=false}=e,a=0,l=/<cite\s+[^>]*?\/>/g;return t.replace(l,c=>{a++;let o=at(c),s="";if(i&&o.anchor_text&&(s=o.anchor_text.replace(/\\'/g,"'").replace(/\\"/g,'"')),n&&r){let u,C=m=>{if(!m)return;let p=m.match(/page[_a-zA-Z]*(\d+)/);return p?parseInt(p[1],10):void 0},d=m=>{if(!m)return;let x=m.replace(/(\d+)-(\d+)/g,(k,_,A)=>{let y=parseInt(_,10),g=parseInt(A,10);if(y<=g){let P=[];for(let N=y;N<=g;N++)P.push(N);return P.join(",")}return _}).split(",").map(k=>parseInt(k.trim(),10)).filter(k=>!isNaN(k));return x.length>0?x:void 0},h=m=>m?.replace(/\\'/g,"'").replace(/\\"/g,'"'),b={attachmentId:o.attachment_id,pageNumber:C(o.start_page_id),fullPhrase:h(o.full_phrase),anchorText:h(o.anchor_text),lineIds:d(o.line_ids)},f=T(b);if(u=r[f],!u){let m=String(a);u=r[m];}let I=ot(u);s=s?`${s}${I}`:I;}return s})},Nt=t=>t.replace(/<page_number_\d+_index_\d+>/g,"").replace(/<\/page_number_\d+_index_\d+>/g,"").trim(),Pt=t=>{let e=/<line id="[^"]*">|<\/line>/g;return t.replace(e,"")},j=t=>{if(!t)return null;let e=t.match(/\d+/)?.[0];return e?parseInt(e):null},ct=t=>{let e=t.match(/^(<cite\s+(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|[^'">/])*>)([\s\S]*?)<\/cite>$/);if(!e){let c=t.match(/^(<cite\s+(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|[^'">/])*>)$/);if(c){let o=c[1].replace(/>$/," />");return w(o)}return w(t)}let[,i,r]=e;if(!r||!r.trim())return w(t);let n=i.replace(/>$/," />"),a=r.trim(),l=w(n);return a+l},W=t=>{let e=t?.trim()||"";e=e.replace(/(?<![<a-zA-Z])cite\s+(attachment_id|file_id|fileId|attachmentId)\s*=/gi,"<cite $1=");let i=e.split(/(<cite[\s\S]*?(?:\/>|<\/cite>|>(?=\s*$|[\r\n])(?![\s\S]*<\/cite>)))/gm);if(i.length<=1){let r=e.match(/<cite\s+(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|[^'">/])*>/g);if(r&&r.length>0){let n=e.replace(/<cite\s+(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|[^'">/])*>/g,a=>a.replace(/>$/," />"));return w(n)}return w(e)}return e=i.map(r=>r.startsWith("<cite")?ct(r):r).join(""),e},w=t=>{let e=t;e=e.replace(/\\_/g,"_"),e=e.replace(/><\/cite>/g,"/>");let i=o=>{let s=o.toLowerCase();return s==="fullphrase"||s==="full_phrase"?"full_phrase":s==="lineids"||s==="line_ids"?"line_ids":s==="startpageid"||s==="start_pageid"||s==="start_page_id"||s==="startpagekey"||s==="start_pagekey"||s==="start_page_key"?"start_page_id":s==="fileid"||s==="file_id"||s==="attachmentid"||s==="attachment_id"?"attachment_id":s==="anchortext"||s==="anchor_text"||s==="keyspan"||s==="key_span"?"anchor_text":s==="reasoning"||s==="value"?s:s==="timestamps"||s==="timestamp"||s==="timestamps"?"timestamps":s},r={""":'"',"'":"'","<":"<",">":">","&":"&"},n=/&(?:quot|apos|lt|gt|amp);/g,a=o=>o.replace(n,s=>r[s]||s),l=/(fullPhrase|full_phrase|anchorText|anchor_text|keySpan|key_span|reasoning|value)\s*=\s*(['"])([\s\S]*?)(?=\s+(?:line_ids|lineIds|timestamps|fileId|file_id|attachmentId|attachment_id|start_page_id|start_pageId|startPageId|start_page_key|start_pageKey|startPageKey|anchorText|anchor_text|keySpan|key_span|reasoning|value|full_phrase)\s*=|\s*\/>|['"]>)/gm;e=e.replace(l,(o,s,u,C)=>{let d=C;return d.endsWith(u)&&(d=d.slice(0,-1)),d=d.replace(/(\r?\n)+|(\*|_){2,}|\*/g,h=>h.includes(`
|
|
2
|
+
`)||h.includes("\r")?" ":""),d=a(d),d=d.replace(/\\\\'/g,"'").replace(/\\'/g,"'").replace(/'/g,"\\'"),d=d.replace(/\\\\"/g,'"').replace(/\\"/g,'"').replace(/"/g,'\\"'),`${i(s)}='${d}'`}),e=e.replace(/(line_ids|lineIds|timestamps)=['"]?([\[\]\(\){}A-Za-z0-9_\-, ]+)['"]?(\s*\/?>|\s+)/gm,(o,s,u,C)=>{let d=u.replace(/[A-Za-z\[\]\(\){}]/g,"");return d=d.replace(/(\d+)-(\d+)/g,(h,b,f)=>{let I=parseInt(b,10),m=parseInt(f,10),p=[];if(I<=m)for(let x=I;x<=m;x++)p.push(x);else p.push(I);return p.join(",")}),d=d.replace(/,+/g,",").replace(/^,|,$/g,""),`${i(s)}='${d}'${C}`});let c=o=>{let s=/([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(['"])((?:[^'"\\\n]|\\.)*)(?:\2)/g,u={},C;for(;C=s.exec(o);){let p=C[1],x=C[3],k=i(p);u[k]=x;}let d=Object.keys(u);if(d.length===0)return o;let h=typeof u.timestamps=="string"&&u.timestamps.length>0,b=d.filter(p=>p.startsWith("start_page")),f=[];u.attachment_id&&f.push("attachment_id"),h?(u.full_phrase&&f.push("full_phrase"),u.anchor_text&&f.push("anchor_text"),f.push("timestamps")):(b.includes("start_page_id")&&f.push("start_page_id"),b.filter(p=>p!=="start_page_id").sort().forEach(p=>f.push(p)),u.full_phrase&&f.push("full_phrase"),u.anchor_text&&f.push("anchor_text"),u.line_ids&&f.push("line_ids")),u.reasoning&&f.push("reasoning"),u.value&&f.push("value");let I=new Set(f);return d.filter(p=>!I.has(p)).sort().forEach(p=>f.push(p)),`<cite ${f.map(p=>`${p}='${u[p]}'`).join(" ")} />`};return e=e.replace(/<cite\b[\s\S]*?\/>/gm,o=>c(o)),e};function $t(...t){return t.filter(Boolean).join(" ")}function lt(t){return t.type==="url"||typeof t.url=="string"&&t.url.length>0}function T(t){let e=t.pageNumber||j(t.startPageId),i=[t.attachmentId||"",e?.toString()||"",t.fullPhrase||"",t.anchorText?.toString()||"",t.lineIds?.join(",")||"",t.timestamps?.startTime||"",t.timestamps?.endTime||""];return lt(t)&&i.push(t.url||"",t.title||"",t.domain||""),M(i.join("|")).slice(0,16)}function Dt(t){let e=[t.attachmentId||"",t.label||"",t.verifiedFullPhrase||"",t.verifiedAnchorText||"",t.verifiedLineIds?.join(",")||"",t.verifiedPageNumber?.toString()||"",t.verifiedTimestamps?.startTime||"",t.verifiedTimestamps?.endTime||"",t.verifiedMatchSnippet||"",t.hitIndexWithinPage?.toString()||""];return M(e.join("|")).slice(0,16)}function vt(t){let e=Math.random().toString(36).slice(2,11);return `${t}-${e}`}function Et(t,e={}){let{fallbackDisplay:i}=e;return t.anchorText?.toString()||t.citationNumber?.toString()||i||"1"}function Ot(t){return t.citationNumber?.toString()||"1"}function Kt(t){return t.anchorText?.toString()||""}function zt(...t){return t.filter(Boolean).join(" ")}var Vt=4,Lt=1;exports.A=rt;exports.B=Ct;exports.C=It;exports.D=bt;exports.a=M;exports.b=$t;exports.c=lt;exports.d=T;exports.e=Dt;exports.f=vt;exports.g=Et;exports.h=Ot;exports.i=Kt;exports.j=zt;exports.k=Vt;exports.l=Lt;exports.m=ot;exports.n=wt;exports.o=Nt;exports.p=Pt;exports.q=j;exports.r=W;exports.s=K;exports.t=et;exports.u=z;exports.v=V;exports.w=gt;exports.x=ft;exports.y=mt;exports.z=B;//# sourceMappingURL=chunk-4UWAUWYL.cjs.map
|
|
3
|
+
//# sourceMappingURL=chunk-4UWAUWYL.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/sha.ts","../src/parsing/citationParser.ts","../src/parsing/parseCitation.ts","../src/parsing/normalizeCitation.ts","../src/react/utils.ts"],"names":["utf8Encode","str","sha1","message","h0","h1","h2","h3","h4","msgLen","bitLen","totalLen","paddedLen","padded","paddedView","dataView","w","offset","i","val","a","b","c","d","e","f","k","temp","hex","n","sha1Hash","data","error","COMPACT_KEY_MAP","isValidCitationData","obj","expandCompactKeys","attachmentId","result","key","value","fullKey","ts","isGroupedFormat","parsed","values","flattenGroupedCitations","grouped","citations","citationArray","citation","parseCitationsFromJson","repairJson","jsonString","repaired","repairs","beforeMarkdownRemoval","beforeTrailingCommas","openBrackets","closeBrackets","addedCount","openBraces","closeBraces","parseDeferredCitationResponse","llmResponse","startIndex","CITATION_DATA_START_DELIMITER","visibleText","endIndex","CITATION_DATA_END_DELIMITER","jsonStartIndex","jsonEndIndex","citationMap","initialError","repairError","parsePageId","pageId","compactMatch","pageNum","index","legacyMatch","deferredCitationToCitation","citationNumber","pageNumber","startPageId","timestamps","lineIds","getAllCitationsFromDeferredResponse","citationKey","generateCitationKey","hasDeferredCitations","response","extractVisibleText","replaceDeferredMarkers","text","options","showAnchorText","replacer","match","idStr","id","getCitationMarkerIds","ids","regex","attributeRegexCache","getAttributeRegex","name","parseLineIds","lineIdsString","parts","part","trimmed","startStr","endStr","start","end","num","getCitationStatus","verification","status","isMiss","isPartialMatch","isVerified","isPending","parseCitation","fragment","mdAttachmentId","citationCounterRef","isVerbose","cleanAndUnescape","beforeCite","afterCite","middleCite","extractAttribute","tag","attrNames","rawAttachmentId","startPageIdRaw","pageIndex","pageMatch","fullPhrase","anchorText","reasoning","timestampsRaw","startTime","endTime","parseJsonCitation","jsonCitation","rawLineIds","simpleMatch","hasCitationProperties","item","isJsonCitationFormat","extractJsonCitations","items","findJsonCitationsInObject","found","extractXmlCitations","normalizedText","normalizeCitations","citeRegex","matches","getAllCitationsFromLlmOutput","llmOutput","jsonCitations","foundJsonCitations","xmlCitations","deferredCitations","groupCitationsByAttachmentId","entries","idx","groupCitationsByAttachmentIdObject","parseCiteAttributes","citeTag","attrs","attrRegex","normalizedKey","getVerificationTextIndicator","replaceCitations","markdownWithCitations","leaveAnchorTextBehind","verifications","showVerificationStatus","citationIndex","citationRegex","output","parsePageNumber","lineIdsStr","nums","_match","startNum","endNum","range","s","unescapeQuotes","numericKey","indicator","removePageNumberMetadata","pageText","removeLineIdMetadata","lineIdRegex","getCitationPageNumber","extractAndRelocateCitationContent","citePart","nonSelfClosingMatch","unclosedMatch","selfClosingTag","normalizeCitationContent","openingTag","innerContent","relocatedContent","normalizedCitation","trimmedResponse","citationParts","input","normalized","canonicalizeCiteAttributeKey","lowerKey","htmlEntityMap","htmlEntityRegex","decodeHtmlEntities","textAttributeRegex","openQuote","rawContent","content","rawValue","trailingChars","cleanedValue","_rangeMatch","reorderCiteTagAttributes","rawKey","keys","hasTimestamps","startPageIds","ordered","used","cn","classes","isUrlCitation","keyParts","generateVerificationKey","generateCitationInstanceId","randomSuffix","getCitationDisplayText","fallbackDisplay","getCitationNumber","getCitationAnchorText","classNames","CITATION_X_PADDING","CITATION_Y_PADDING"],"mappings":"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","file":"chunk-4UWAUWYL.cjs","sourcesContent":["/**\n * Pure JavaScript SHA-1 implementation.\n * Based on the FIPS 180-4 specification.\n * No external dependencies.\n */\n\nfunction utf8Encode(str: string): Uint8Array {\n const encoder = new TextEncoder();\n return encoder.encode(str);\n}\n\nfunction sha1(message: Uint8Array): string {\n // Initial hash values\n let h0 = 0x67452301;\n let h1 = 0xefcdab89;\n let h2 = 0x98badcfe;\n let h3 = 0x10325476;\n let h4 = 0xc3d2e1f0;\n\n // Pre-processing: adding padding bits\n const msgLen = message.length;\n const bitLen = msgLen * 8;\n\n // Calculate padded length: message + 1 (0x80) + padding + 8 (length)\n // Total must be multiple of 64 bytes (512 bits)\n const totalLen = msgLen + 1 + 8; // minimum: msg + 0x80 + 64-bit length\n const paddedLen = Math.ceil(totalLen / 64) * 64;\n\n // Create padded buffer\n const padded = new ArrayBuffer(paddedLen);\n const paddedView = new Uint8Array(padded);\n const dataView = new DataView(padded);\n\n // Copy message\n paddedView.set(message);\n\n // Append bit '1' (0x80)\n paddedView[msgLen] = 0x80;\n\n // Append length as 64-bit big-endian (in bits)\n // High 32 bits (for messages > 512MB, which we don't support)\n dataView.setUint32(paddedLen - 8, Math.floor(bitLen / 0x100000000), false);\n // Low 32 bits\n dataView.setUint32(paddedLen - 4, bitLen >>> 0, false);\n\n // Process each 512-bit (64-byte) chunk\n const w = new Uint32Array(80);\n\n for (let offset = 0; offset < paddedLen; offset += 64) {\n // Break chunk into sixteen 32-bit big-endian words\n for (let i = 0; i < 16; i++) {\n w[i] = dataView.getUint32(offset + i * 4, false);\n }\n\n // Extend the sixteen 32-bit words into eighty 32-bit words\n for (let i = 16; i < 80; i++) {\n const val = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];\n w[i] = (val << 1) | (val >>> 31);\n }\n\n // Initialize working variables\n let a = h0;\n let b = h1;\n let c = h2;\n let d = h3;\n let e = h4;\n\n // Main loop\n for (let i = 0; i < 80; i++) {\n let f: number;\n let k: number;\n\n if (i < 20) {\n f = (b & c) | (~b & d);\n k = 0x5a827999;\n } else if (i < 40) {\n f = b ^ c ^ d;\n k = 0x6ed9eba1;\n } else if (i < 60) {\n f = (b & c) | (b & d) | (c & d);\n k = 0x8f1bbcdc;\n } else {\n f = b ^ c ^ d;\n k = 0xca62c1d6;\n }\n\n const temp = (((a << 5) | (a >>> 27)) + f + e + k + w[i]) >>> 0;\n e = d;\n d = c;\n c = ((b << 30) | (b >>> 2)) >>> 0;\n b = a;\n a = temp;\n }\n\n // Add this chunk's hash to result\n h0 = (h0 + a) >>> 0;\n h1 = (h1 + b) >>> 0;\n h2 = (h2 + c) >>> 0;\n h3 = (h3 + d) >>> 0;\n h4 = (h4 + e) >>> 0;\n }\n\n // Produce the final hash value (160-bit) as hex string\n const hex = (n: number) => n.toString(16).padStart(8, \"0\");\n return hex(h0) + hex(h1) + hex(h2) + hex(h3) + hex(h4);\n}\n\n/**\n * Computes a SHA-1 hash of the provided data.\n * Used internally by generateCitationKey in react/utils.ts\n */\nexport function sha1Hash(data: string | any): string {\n try {\n if (!data) return \"\";\n const str = typeof data === \"string\" ? data : JSON.stringify(data);\n return sha1(utf8Encode(str));\n } catch (error) {\n console.error(\"Error in making the hash:\", error);\n }\n return \"\";\n}\n","/**\n * Citation Parser\n *\n * Implements the \"Split & Parse\" strategy for the deferred JSON citation pattern.\n * This parser extracts citations from LLM responses that use [N] markers in text\n * and include a JSON data block at the end.\n *\n * Algorithm:\n * 1. Detection: Look for the start delimiter <<<CITATION_DATA>>>\n * 2. Splitting: Separate visible content from the citation data block\n * 3. Data Extraction: Extract the JSON string between delimiters\n * 4. Sanitization: Parse with JSON.parse, with fallback repair for common issues\n * 5. Hydration: Map the JSON objects to a usable format\n */\n\nimport { type Citation } from \"../types/citation.js\";\nimport { generateCitationKey } from \"../react/utils.js\";\nimport {\n CITATION_DATA_START_DELIMITER,\n CITATION_DATA_END_DELIMITER,\n type CitationData,\n type CompactCitationData,\n type ParsedCitationResponse,\n} from \"../prompts/citationPrompts.js\";\n\n/**\n * Map of compact keys to their full CitationData equivalents.\n */\nconst COMPACT_KEY_MAP: Record<string, keyof CitationData> = {\n n: \"id\",\n a: \"attachment_id\",\n r: \"reasoning\",\n f: \"full_phrase\",\n k: \"anchor_text\",\n p: \"page_id\",\n l: \"line_ids\",\n t: \"timestamps\",\n} as const;\n\n/**\n * Map for timestamp sub-keys.\n */\nconst TIMESTAMP_KEY_MAP: Record<string, string> = {\n s: \"start_time\",\n e: \"end_time\",\n} as const;\n\n/**\n * Type guard to validate that an object has the required CitationData structure.\n * Ensures at minimum the id field is present and is a number.\n */\nfunction isValidCitationData(obj: unknown): obj is CitationData {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"id\" in obj &&\n typeof (obj as Record<string, unknown>).id === \"number\"\n );\n}\n\n/**\n * Expands compact citation data to the full CitationData format.\n * Handles both compact keys (n, a, r, f, k, p, l, t) and full keys.\n *\n * @param data - Raw citation object (may have compact or full keys)\n * @param attachmentId - Optional attachment_id to inject (for grouped format)\n * @returns Normalized CitationData with full keys\n * @throws Error if the resulting data doesn't have a valid id field\n */\nfunction expandCompactKeys(\n data: CompactCitationData | CitationData | Record<string, unknown>,\n attachmentId?: string\n): CitationData {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(data)) {\n // Check if this is a compact key\n const fullKey = COMPACT_KEY_MAP[key] || key;\n\n // Handle timestamps specially (nested object with s/e keys)\n if ((key === \"t\" || key === \"timestamps\") && value && typeof value === \"object\") {\n const ts = value as Record<string, unknown>;\n result.timestamps = {\n start_time: ts.s ?? ts.start_time,\n end_time: ts.e ?? ts.end_time,\n };\n } else {\n result[fullKey] = value;\n }\n }\n\n // Inject attachment_id if provided (from grouped format)\n if (attachmentId && !result.attachment_id) {\n result.attachment_id = attachmentId;\n }\n\n // Runtime validation to ensure type safety\n if (!isValidCitationData(result)) {\n throw new Error(\"Invalid citation data: missing or invalid 'id' field\");\n }\n\n return result;\n}\n\n/**\n * Checks if the parsed JSON is in grouped format (object with attachment IDs as keys)\n * vs flat format (array of citations).\n */\nfunction isGroupedFormat(parsed: unknown): parsed is Record<string, unknown[]> {\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return false;\n }\n // Check if all values are arrays (grouped format)\n const values = Object.values(parsed);\n return values.length > 0 && values.every(Array.isArray);\n}\n\n/**\n * Flattens grouped citation format into a flat array.\n * Grouped format: { \"attachmentId\": [citations...], ... }\n * Flat format: [{ attachment_id: \"...\", ...citation }, ...]\n */\nfunction flattenGroupedCitations(\n grouped: Record<string, unknown[]>\n): CitationData[] {\n const citations: CitationData[] = [];\n\n for (const [attachmentId, citationArray] of Object.entries(grouped)) {\n for (const citation of citationArray) {\n if (typeof citation === \"object\" && citation !== null) {\n citations.push(expandCompactKeys(citation as Record<string, unknown>, attachmentId));\n }\n }\n }\n\n return citations;\n}\n\n/**\n * Helper to parse citations from JSON, handling both grouped and flat formats.\n */\nfunction parseCitationsFromJson(parsed: unknown): CitationData[] {\n // Check for grouped format: { \"attachmentId\": [citations...], ... }\n if (isGroupedFormat(parsed)) {\n return flattenGroupedCitations(parsed);\n }\n\n // Flat format: array of citations or single citation\n const rawCitations = Array.isArray(parsed) ? parsed : [parsed];\n return rawCitations.map((c) => expandCompactKeys(c as Record<string, unknown>));\n}\n\nexport type { CitationData, ParsedCitationResponse } from \"../prompts/citationPrompts.js\";\n\n/**\n * Attempts to repair malformed JSON.\n * Handles common LLM output issues like:\n * - Trailing commas\n * - Single quotes instead of double quotes (in JSON context)\n * - Missing closing brackets\n * - Unescaped newlines in strings\n *\n * @param jsonString - The potentially malformed JSON string\n * @returns The repaired JSON string\n */\nfunction repairJson(jsonString: string): { repaired: string; repairs: string[] } {\n let repaired = jsonString.trim();\n const repairs: string[] = [];\n\n // Remove any markdown code block markers that might be present\n const beforeMarkdownRemoval = repaired;\n repaired = repaired.replace(/^```(?:json)?\\s*/i, \"\").replace(/\\s*```$/, \"\");\n if (repaired !== beforeMarkdownRemoval) {\n repairs.push(\"removed markdown code block markers\");\n }\n\n // Fix trailing commas before ] or }\n const beforeTrailingCommas = repaired;\n repaired = repaired.replace(/,(\\s*[\\]\\}])/g, \"$1\");\n if (repaired !== beforeTrailingCommas) {\n repairs.push(\"removed trailing commas\");\n }\n\n // Fix missing closing bracket if we have an opening [\n if (repaired.startsWith(\"[\") && !repaired.endsWith(\"]\")) {\n // Check if we have unclosed array\n const openBrackets = (repaired.match(/\\[/g) || []).length;\n const closeBrackets = (repaired.match(/\\]/g) || []).length;\n if (openBrackets > closeBrackets) {\n const addedCount = openBrackets - closeBrackets;\n repaired = repaired + \"]\".repeat(addedCount);\n repairs.push(`added ${addedCount} closing bracket(s)`);\n }\n }\n\n // Fix missing closing brace if we have an opening {\n if (repaired.includes(\"{\")) {\n const openBraces = (repaired.match(/\\{/g) || []).length;\n const closeBraces = (repaired.match(/\\}/g) || []).length;\n if (openBraces > closeBraces) {\n const addedCount = openBraces - closeBraces;\n repaired = repaired + \"}\".repeat(addedCount);\n repairs.push(`added ${addedCount} closing brace(s)`);\n }\n }\n\n return { repaired, repairs };\n}\n\n\n/**\n * Parses a citation response from an LLM.\n *\n * This function:\n * 1. Finds the <<<CITATION_DATA>>> delimiter in the response\n * 2. Splits the response into visible text and citation data\n * 3. Parses the JSON citation data\n * 4. Returns a structured result with both\n *\n * @param llmResponse - The full LLM response text\n * @returns ParsedCitationResponse with visible text and parsed citations\n *\n * @example\n * ```typescript\n * const response = `\n * The company grew 45% [1].\n *\n * <<<CITATION_DATA>>>\n * [{\"id\": 1, \"attachment_id\": \"abc\", \"full_phrase\": \"grew 45%\", \"anchor_text\": \"45%\"}]\n * <<<END_CITATION_DATA>>>\n * `;\n *\n * const parsed = parseDeferredCitationResponse(response);\n * console.log(parsed.visibleText); // \"The company grew 45% [1].\"\n * console.log(parsed.citations); // [{id: 1, attachment_id: \"abc\", ...}]\n * ```\n */\nexport function parseDeferredCitationResponse(\n llmResponse: string\n): ParsedCitationResponse {\n if (!llmResponse || typeof llmResponse !== \"string\") {\n return {\n visibleText: \"\",\n citations: [],\n citationMap: new Map(),\n success: false,\n error: \"Invalid input: expected a string\",\n };\n }\n\n // Find the start delimiter\n const startIndex = llmResponse.indexOf(CITATION_DATA_START_DELIMITER);\n\n // No citation data block found - return full text as visible\n if (startIndex === -1) {\n return {\n visibleText: llmResponse.trim(),\n citations: [],\n citationMap: new Map(),\n success: true,\n };\n }\n\n // Extract visible text (everything before the delimiter)\n const visibleText = llmResponse.substring(0, startIndex).trim();\n\n // Find the end delimiter\n const endIndex = llmResponse.indexOf(\n CITATION_DATA_END_DELIMITER,\n startIndex\n );\n\n // Extract the JSON block\n const jsonStartIndex = startIndex + CITATION_DATA_START_DELIMITER.length;\n const jsonEndIndex =\n endIndex !== -1 ? endIndex : llmResponse.length;\n const jsonString = llmResponse.substring(jsonStartIndex, jsonEndIndex).trim();\n\n // Parse the JSON\n let citations: CitationData[] = [];\n const citationMap = new Map<number, CitationData>();\n\n if (jsonString) {\n try {\n // First attempt: direct JSON.parse\n const parsed = JSON.parse(jsonString);\n citations = parseCitationsFromJson(parsed);\n } catch (initialError) {\n // Second attempt: repair and retry\n try {\n const { repaired, repairs } = repairJson(jsonString);\n const parsed = JSON.parse(repaired);\n citations = parseCitationsFromJson(parsed);\n\n // Log warning when repair was necessary\n if (repairs.length > 0) {\n console.warn(\n \"[DeepCitation] JSON repair was triggered for citation data.\",\n `Repairs applied: ${repairs.join(\", \")}.`,\n `Initial parse error: ${initialError instanceof Error ? initialError.message : \"Unknown error\"}`\n );\n }\n } catch (repairError) {\n return {\n visibleText,\n citations: [],\n citationMap: new Map(),\n success: false,\n error: `Failed to parse citation JSON. Initial error: ${initialError instanceof Error ? initialError.message : \"Unknown error\"}. Repair error: ${repairError instanceof Error ? repairError.message : \"Unknown error\"}`,\n };\n }\n }\n }\n\n // Map citations by ID for O(1) lookups\n for (const citation of citations) {\n if (typeof citation.id === \"number\") {\n citationMap.set(citation.id, citation);\n }\n }\n\n return {\n visibleText,\n citations,\n citationMap,\n success: true,\n };\n}\n\n/**\n * Parses a page_id string to extract page number and index.\n * Supports both compact \"N_I\" format and legacy \"page_number_N_index_I\" format.\n *\n * @param pageId - The page ID string\n * @returns Object with pageNumber and normalized startPageId, or undefined values\n */\nfunction parsePageId(pageId: string): { pageNumber?: number; startPageId?: string } {\n // Try compact format first: \"N_I\" (e.g., \"2_1\")\n const compactMatch = pageId.match(/^(\\d+)_(\\d+)$/);\n if (compactMatch) {\n const pageNum = parseInt(compactMatch[1], 10);\n const index = parseInt(compactMatch[2], 10);\n return {\n pageNumber: pageNum,\n startPageId: `page_number_${pageNum}_index_${index}`,\n };\n }\n\n // Try legacy format: \"page_number_N_index_I\" or variations\n const legacyMatch = pageId.match(/page[_a-zA-Z]*(\\d+)_index_(\\d+)/i);\n if (legacyMatch) {\n const pageNum = parseInt(legacyMatch[1], 10);\n const index = parseInt(legacyMatch[2], 10);\n return {\n pageNumber: pageNum,\n startPageId: `page_number_${pageNum}_index_${index}`,\n };\n }\n\n return { pageNumber: undefined, startPageId: undefined };\n}\n\n/**\n * Converts a CitationData object to the standard Citation format.\n *\n * @param data - The citation data\n * @param citationNumber - Optional override for citation number (defaults to data.id)\n * @returns Standard Citation object\n */\nexport function deferredCitationToCitation(\n data: CitationData,\n citationNumber?: number\n): Citation {\n // Parse page number from page_id (supports both \"N_I\" and \"page_number_N_index_I\")\n let pageNumber: number | undefined;\n let startPageId: string | undefined;\n const pageId = data.page_id;\n if (pageId) {\n const parsed = parsePageId(pageId);\n pageNumber = parsed.pageNumber;\n startPageId = parsed.startPageId;\n }\n\n // Parse timestamps for AV citations\n let timestamps: { startTime?: string; endTime?: string } | undefined;\n if (data.timestamps) {\n timestamps = {\n startTime: data.timestamps.start_time,\n endTime: data.timestamps.end_time,\n };\n }\n\n // Sort lineIds if present\n const lineIds = data.line_ids?.length\n ? [...data.line_ids].sort((a, b) => a - b)\n : undefined;\n\n return {\n attachmentId: data.attachment_id,\n pageNumber,\n startPageId,\n fullPhrase: data.full_phrase,\n anchorText: data.anchor_text,\n citationNumber: citationNumber ?? data.id,\n lineIds,\n reasoning: data.reasoning,\n timestamps,\n };\n}\n\n/**\n * Extracts all citations from a citation response and returns them\n * in the standard dictionary format used by the verification API.\n *\n * This function parses the response, converts each citation to the standard\n * Citation format, and generates deterministic keys for each.\n *\n * @param llmResponse - The full LLM response with citation block\n * @returns Dictionary of parsed Citation objects keyed by citation key\n *\n * @example\n * ```typescript\n * const citations = getAllCitationsFromDeferredResponse(llmOutput);\n * // Returns: { \"abc123...\": { attachmentId: \"...\", fullPhrase: \"...\", ... }, ... }\n * ```\n */\nexport function getAllCitationsFromDeferredResponse(\n llmResponse: string\n): { [key: string]: Citation } {\n const parsed = parseDeferredCitationResponse(llmResponse);\n\n if (!parsed.success || parsed.citations.length === 0) {\n return {};\n }\n\n const citations: { [key: string]: Citation } = {};\n\n for (const data of parsed.citations) {\n const citation = deferredCitationToCitation(data);\n if (citation.fullPhrase) {\n const citationKey = generateCitationKey(citation);\n citations[citationKey] = citation;\n }\n }\n\n return citations;\n}\n\n/**\n * Checks if a response contains citation markers.\n *\n * @param response - The LLM response to check\n * @returns True if the response contains the citation data delimiter\n */\nexport function hasDeferredCitations(response: string): boolean {\n return (\n typeof response === \"string\" &&\n response.includes(CITATION_DATA_START_DELIMITER)\n );\n}\n\n/**\n * Extracts just the visible text from a response,\n * removing the citation data block.\n *\n * @param llmResponse - The full LLM response\n * @returns The visible text portion only\n */\nexport function extractVisibleText(llmResponse: string): string {\n const parsed = parseDeferredCitationResponse(llmResponse);\n return parsed.visibleText;\n}\n\n/**\n * Replaces [N] citation markers in text with optional content.\n *\n * @param text - The text containing [N] markers\n * @param options - Configuration for replacement\n * @returns The text with markers replaced\n *\n * @example\n * ```typescript\n * const text = \"Revenue grew 45% [1] in Q4 [2].\";\n *\n * // Remove markers entirely\n * replaceDeferredMarkers(text);\n * // Returns: \"Revenue grew 45% in Q4.\"\n *\n * // Replace with anchor texts\n * replaceDeferredMarkers(text, {\n * citationMap: new Map([[1, { anchor_text: \"45%\" }], [2, { anchor_text: \"Q4\" }]]),\n * showAnchorText: true,\n * });\n * // Returns: \"Revenue grew 45% 45% in Q4 Q4.\"\n * ```\n */\nexport function replaceDeferredMarkers(\n text: string,\n options?: {\n /** Map of citation IDs to their data */\n citationMap?: Map<number, CitationData>;\n /** Whether to show the anchor text after the marker */\n showAnchorText?: boolean;\n /** Custom replacement function */\n replacer?: (id: number, data?: CitationData) => string;\n }\n): string {\n const { citationMap, showAnchorText, replacer } = options || {};\n\n // Match [N] patterns where N is one or more digits\n return text.replace(/\\[(\\d+)\\]/g, (match, idStr) => {\n const id = parseInt(idStr, 10);\n const data = citationMap?.get(id);\n\n // Custom replacer takes precedence\n if (replacer) {\n return replacer(id, data);\n }\n\n // Show anchor text if requested\n if (showAnchorText && data?.anchor_text) {\n return data.anchor_text;\n }\n\n // Default: remove marker\n return \"\";\n });\n}\n\n/**\n * Gets all citation marker IDs found in a text.\n *\n * @param text - The text to scan for [N] markers\n * @returns Array of citation IDs in order of appearance\n */\nexport function getCitationMarkerIds(text: string): number[] {\n const ids: number[] = [];\n const regex = /\\[(\\d+)\\]/g;\n let match;\n\n while ((match = regex.exec(text)) !== null) {\n ids.push(parseInt(match[1], 10));\n }\n\n return ids;\n}\n","import { type Verification } from \"../types/verification.js\";\nimport { type Citation, type CitationStatus } from \"../types/citation.js\";\nimport { normalizeCitations } from \"./normalizeCitation.js\";\nimport { generateCitationKey } from \"../react/utils.js\";\nimport {\n hasDeferredCitations,\n getAllCitationsFromDeferredResponse,\n} from \"./citationParser.js\";\n\nconst attributeRegexCache = new Map<string, RegExp>();\n\nfunction getAttributeRegex(name: string): RegExp {\n let regex = attributeRegexCache.get(name);\n if (!regex) {\n regex = new RegExp(`${name}='((?:[^'\\\\\\\\]|\\\\\\\\.)*)'`);\n attributeRegexCache.set(name, regex);\n }\n return regex;\n}\n\n/**\n * Parses a line_ids string that may contain individual numbers, ranges, or both.\n * Examples: \"1,2,3\", \"5-10\", \"1,5-7,10\", \"20-20\"\n *\n * @param lineIdsString - The raw line_ids string (e.g., \"1,5-7,10\")\n * @returns Sorted array of unique line IDs, or undefined if empty/invalid\n */\nfunction parseLineIds(lineIdsString: string): number[] | undefined {\n if (!lineIdsString) return undefined;\n\n const lineIds: number[] = [];\n const parts = lineIdsString.split(\",\");\n\n for (const part of parts) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n\n // Check if this part is a range (e.g., \"5-10\")\n if (trimmed.includes(\"-\")) {\n const [startStr, endStr] = trimmed.split(\"-\");\n const start = parseInt(startStr, 10);\n const end = parseInt(endStr, 10);\n\n if (!isNaN(start) && !isNaN(end) && start <= end) {\n // Expand the range\n for (let i = start; i <= end; i++) {\n lineIds.push(i);\n }\n } else if (!isNaN(start)) {\n // If only start is valid, just use it\n lineIds.push(start);\n }\n } else {\n // Single number\n const num = parseInt(trimmed, 10);\n if (!isNaN(num)) {\n lineIds.push(num);\n }\n }\n }\n\n if (lineIds.length === 0) return undefined;\n\n // Sort and deduplicate\n return [...new Set(lineIds)].sort((a, b) => a - b);\n}\n\n/**\n * Calculates the verification status of a citation based on the found highlight and search state.\n *\n * @param verification - The found highlight location, or null/undefined if not found\n * @returns An object containing boolean flags for verification status\n */\nexport function getCitationStatus(\n verification: Verification | null | undefined\n): CitationStatus {\n const status = verification?.status;\n\n const isMiss = [\"not_found\"].includes(status || \"\");\n\n // Partial matches: something found but not ideal (amber indicator)\n const isPartialMatch = [\n \"found_anchor_text_only\", // Only anchor text found, not full phrase\n \"partial_text_found\",\n \"found_on_other_page\",\n \"found_on_other_line\",\n \"first_word_found\"\n ].includes(status || \"\");\n\n // Verified: exact match or partial match (green or amber indicator)\n const isVerified = [\"found\", \"found_phrase_missed_anchor_text\"].includes(status || \"\") || isPartialMatch;\n\n const isPending = [\"pending\", \"loading\", null, undefined].includes(status);\n\n return { isVerified, isMiss, isPartialMatch, isPending };\n}\n\nexport const parseCitation = (\n fragment: string,\n mdAttachmentId?: string | null,\n citationCounterRef?: any | null,\n isVerbose?: boolean\n) => {\n // Helper: Remove wrapper quotes and fully unescape content\n // Handles: \\' -> ', \\\" -> \", \\n -> space, \\\\ -> \\\n const cleanAndUnescape = (str?: string) => {\n if (!str) return undefined;\n let result = str;\n // Remove surrounding quotes if present, but only if not escaped\n // Check start: remove leading quote only if it exists\n if (result.startsWith(\"'\") || result.startsWith('\"')) {\n result = result.slice(1);\n }\n // Check end: remove trailing quote only if it's not escaped (not preceded by \\)\n if ((result.endsWith(\"'\") || result.endsWith('\"')) && !result.endsWith(\"\\\\'\") && !result.endsWith('\\\\\"')) {\n result = result.slice(0, -1);\n }\n // Replace escaped double quotes with actual double quotes\n result = result.replace(/\\\\\"/g, '\"');\n // Replace escaped single quotes with actual single quotes\n result = result.replace(/\\\\'/g, \"'\");\n // Replace literal \\n sequences with spaces (newlines in attribute values)\n result = result.replace(/\\\\n/g, \" \");\n // Replace double backslashes with single backslash\n result = result.replace(/\\\\\\\\/g, \"\\\\\");\n return result;\n };\n\n const citationNumber = citationCounterRef?.current\n ? citationCounterRef.current++\n : undefined;\n\n const beforeCite = fragment.substring(0, fragment.indexOf(\"<cite\"));\n const afterCite = fragment.includes(\"/>\")\n ? fragment.slice(fragment.indexOf(\"/>\") + 2)\n : \"\";\n const middleCite = fragment.substring(\n fragment.indexOf(\"<cite\"),\n fragment.indexOf(\"/>\") + 2\n );\n\n const extractAttribute = (tag: string, attrNames: string[]): string | undefined => {\n for (const name of attrNames) {\n const regex = getAttributeRegex(name);\n const match = tag.match(regex);\n if (match) {\n return match[1];\n }\n }\n return undefined;\n };\n\n // Extract all attributes by name (order-independent)\n let rawAttachmentId = extractAttribute(middleCite, ['attachment_id', 'attachmentId', 'file_id', 'fileId']);\n let attachmentId = rawAttachmentId?.length === 20 ? rawAttachmentId : mdAttachmentId || rawAttachmentId;\n\n const startPageIdRaw = extractAttribute(middleCite, ['start_page_id', 'startPageId', 'start_page_key', 'startPageKey', 'start_page']);\n let pageNumber: number | undefined;\n let pageIndex: number | undefined;\n if (startPageIdRaw) {\n const pageMatch = startPageIdRaw.match(/page[\\_a-zA-Z]*(\\d+)_index_(\\d+)/);\n if (pageMatch) {\n pageNumber = parseInt(pageMatch[1]);\n pageIndex = parseInt(pageMatch[2]);\n }\n }\n\n // Use helper to handle escaped quotes inside the phrase\n let fullPhrase = cleanAndUnescape(extractAttribute(middleCite, ['full_phrase', 'fullPhrase']));\n let anchorText = cleanAndUnescape(extractAttribute(middleCite, ['anchor_text', 'anchorText', 'key_span', 'keySpan']));\n let reasoning = cleanAndUnescape(extractAttribute(middleCite, ['reasoning']));\n let value = cleanAndUnescape(extractAttribute(middleCite, ['value']));\n\n let lineIds: number[] | undefined;\n try {\n const lineIdsRaw = extractAttribute(middleCite, ['line_ids', 'lineIds']);\n const lineIdsString = lineIdsRaw?.replace(/[A-Za-z_[\\](){}:]/g, \"\");\n lineIds = lineIdsString ? parseLineIds(lineIdsString) : undefined;\n } catch (e) {\n if (isVerbose) console.error(\"Error parsing lineIds\", e);\n }\n\n // Check for AV citation (has timestamps instead of line_ids)\n const timestampsRaw = extractAttribute(middleCite, ['timestamps']);\n let timestamps: { startTime?: string; endTime?: string } | undefined;\n\n if (timestampsRaw) {\n const [startTime, endTime] = timestampsRaw.split(\"-\") || [];\n timestamps = { startTime, endTime };\n }\n\n const citation: Citation = {\n attachmentId: attachmentId,\n pageNumber,\n startPageId: `page_number_${pageNumber || 1}_index_${pageIndex || 0}`,\n fullPhrase,\n anchorText: anchorText || value,\n citationNumber,\n lineIds,\n beforeCite,\n timestamps,\n reasoning,\n };\n\n return {\n beforeCite,\n afterCite,\n citation,\n };\n};\n\n/**\n * Parses a JSON-based citation object into a Citation.\n * Supports both camelCase and snake_case property names.\n *\n * @param jsonCitation - The JSON citation object (can have camelCase or snake_case properties)\n * @param citationNumber - Optional citation number for ordering\n * @returns Parsed Citation object\n */\nconst parseJsonCitation = (\n jsonCitation: any,\n citationNumber?: number\n): Citation | null => {\n if (!jsonCitation) {\n return null;\n }\n\n // Support both camelCase and snake_case property names (with backward compatibility)\n const fullPhrase = jsonCitation.fullPhrase ?? jsonCitation.full_phrase;\n const startPageId = jsonCitation.startPageId ?? jsonCitation.start_page_id ?? jsonCitation.startPageKey ?? jsonCitation.start_page_key;\n const anchorText = jsonCitation.anchorText ?? jsonCitation.anchor_text ?? jsonCitation.keySpan ?? jsonCitation.key_span;\n const rawLineIds = jsonCitation.lineIds ?? jsonCitation.line_ids;\n const attachmentId = jsonCitation.attachmentId ?? jsonCitation.attachment_id ?? jsonCitation.fileId ?? jsonCitation.file_id;\n const reasoning = jsonCitation.reasoning;\n const value = jsonCitation.value;\n\n if (!fullPhrase) {\n return null;\n }\n\n // Parse startPageId format: \"page_number_PAGE_index_INDEX\" or simple \"PAGE_INDEX\"\n let pageNumber: number | undefined;\n if (startPageId) {\n // Try full format first: page_number_5_index_2 or pageId_5_index_2\n const pageMatch = startPageId.match(/page[_a-zA-Z]*(\\d+)_index_(\\d+)/i);\n if (pageMatch) {\n pageNumber = parseInt(pageMatch[1], 10);\n } else {\n // Try simple n_m format: 5_4 (page 5, index 4)\n const simpleMatch = startPageId.match(/^(\\d+)_(\\d+)$/);\n if (simpleMatch) {\n pageNumber = parseInt(simpleMatch[1], 10);\n }\n }\n }\n\n // Sort lineIds if present\n const lineIds = rawLineIds?.length\n ? [...rawLineIds].sort((a: number, b: number) => a - b)\n : undefined;\n\n const citation: Citation = {\n attachmentId,\n pageNumber,\n fullPhrase,\n citationNumber,\n lineIds,\n anchorText: anchorText || value,\n reasoning,\n };\n\n return citation;\n};\n\n/**\n * Checks if an object has citation-like properties (camelCase or snake_case).\n */\nconst hasCitationProperties = (item: any): boolean =>\n typeof item === \"object\" &&\n item !== null &&\n (\"fullPhrase\" in item ||\n \"full_phrase\" in item ||\n \"startPageId\" in item ||\n \"start_page_id\" in item ||\n \"startPageKey\" in item ||\n \"start_page_key\" in item ||\n \"anchorText\" in item ||\n \"anchor_text\" in item ||\n \"keySpan\" in item ||\n \"key_span\" in item ||\n \"lineIds\" in item ||\n \"line_ids\" in item);\n\n/**\n * Checks if the input appears to be JSON-based citations.\n * Looks for array of objects with citation-like properties (supports both camelCase and snake_case).\n */\nconst isJsonCitationFormat = (data: any): data is Citation[] | Citation => {\n if (Array.isArray(data)) {\n return data.length > 0 && data.some(hasCitationProperties);\n }\n if (typeof data === \"object\" && data !== null) {\n return hasCitationProperties(data);\n }\n return false;\n};\n\n/**\n * Extracts citations from JSON format (array or single object).\n */\nconst extractJsonCitations = (\n data: Citation[] | Citation\n): { [key: string]: Citation } => {\n const citations: { [key: string]: Citation } = {};\n const items = Array.isArray(data) ? data : [data];\n\n let citationNumber = 1;\n for (const item of items) {\n const citation = parseJsonCitation(item, citationNumber++);\n if (citation && citation.fullPhrase) {\n const citationKey = generateCitationKey(citation);\n citations[citationKey] = citation;\n }\n }\n\n return citations;\n};\n\n/**\n * Recursively traverses an object looking for `citation` or `citations` properties\n * that match our JSON citation format.\n */\nconst findJsonCitationsInObject = (obj: any, found: Citation[]): void => {\n if (!obj || typeof obj !== \"object\") return;\n\n // Check for citation/citations properties\n if (obj.citation && isJsonCitationFormat(obj.citation)) {\n const items = Array.isArray(obj.citation) ? obj.citation : [obj.citation];\n found.push(...items);\n }\n if (obj.citations && isJsonCitationFormat(obj.citations)) {\n const items = Array.isArray(obj.citations)\n ? obj.citations\n : [obj.citations];\n found.push(...items);\n }\n\n // Recurse into object properties\n if (Array.isArray(obj)) {\n for (const item of obj) {\n findJsonCitationsInObject(item, found);\n }\n } else {\n for (const key of Object.keys(obj)) {\n if (key !== \"citation\" && key !== \"citations\") {\n findJsonCitationsInObject(obj[key], found);\n }\n }\n }\n};\n\n/**\n * Extracts XML citations from text using <cite ... /> tags.\n */\nconst extractXmlCitations = (text: string): { [key: string]: Citation } => {\n const normalizedText = normalizeCitations(text);\n\n // Find all <cite ... /> tags\n // This regex handles > characters inside quoted attribute values and escaped quotes:\n // - '(?:[^'\\\\]|\\\\.)*' matches single-quoted strings with escaped chars\n // - \"(?:[^\"\\\\]|\\\\.)*\" matches double-quoted strings with escaped chars\n // - [^'\">/] matches any char that's not a quote, >, or /\n // - The whole pattern repeats until we hit />\n const citeRegex = /<cite\\s+(?:'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"|[^'\">/])*\\/>/g;\n const matches = normalizedText.match(citeRegex);\n\n if (!matches || matches.length === 0) return {};\n\n const citations: { [key: string]: Citation } = {};\n const citationCounterRef = { current: 1 };\n\n for (const match of matches) {\n const { citation } = parseCitation(match, undefined, citationCounterRef);\n if (citation && citation.fullPhrase) {\n const citationKey = generateCitationKey(citation);\n citations[citationKey] = citation;\n }\n }\n\n return citations;\n};\n\n/**\n * Extracts all citations from LLM output.\n * Supports both XML <cite ... /> tags (embedded in strings/markdown) and JSON-based citation formats.\n *\n * For object input:\n * - Traverses the object looking for `citation` or `citations` properties matching JSON format\n * - Also stringifies the object to find embedded XML citations in markdown content\n *\n * @param llmOutput - The LLM output (string or object)\n * @returns Dictionary of parsed Citation objects keyed by citation key\n */\nexport const getAllCitationsFromLlmOutput = (\n llmOutput: any\n): { [key: string]: Citation } => {\n if (!llmOutput) return {};\n\n const citations: { [key: string]: Citation } = {};\n\n if (typeof llmOutput === \"object\") {\n // Check if the root object itself is JSON citation format\n if (isJsonCitationFormat(llmOutput)) {\n const jsonCitations = extractJsonCitations(llmOutput);\n Object.assign(citations, jsonCitations);\n } else {\n // Traverse object for nested citation/citations properties\n const foundJsonCitations: Citation[] = [];\n findJsonCitationsInObject(llmOutput, foundJsonCitations);\n\n if (foundJsonCitations.length > 0) {\n const jsonCitations = extractJsonCitations(foundJsonCitations);\n Object.assign(citations, jsonCitations);\n }\n }\n\n // Also stringify and parse for embedded XML citations in markdown\n const text = JSON.stringify(llmOutput);\n const xmlCitations = extractXmlCitations(text);\n Object.assign(citations, xmlCitations);\n } else if (typeof llmOutput === \"string\") {\n // Check for deferred JSON format (<<<CITATION_DATA>>>)\n if (hasDeferredCitations(llmOutput)) {\n const deferredCitations = getAllCitationsFromDeferredResponse(llmOutput);\n Object.assign(citations, deferredCitations);\n }\n // Also parse for XML citations (both formats can coexist)\n const xmlCitations = extractXmlCitations(llmOutput);\n Object.assign(citations, xmlCitations);\n }\n\n return citations;\n};\n\n/**\n * Groups citations by their attachmentId for multi-file verification scenarios.\n * This is useful when you have citations from multiple files and need to\n * verify them against their respective attachments.\n *\n * @param citations - Array of Citation objects or a dictionary of citations\n * @returns Map of attachmentId to dictionary of citations from that file\n *\n * @example\n * ```typescript\n * const citations = getAllCitationsFromLlmOutput(response.content);\n * const citationsByAttachment = groupCitationsByAttachmentId(citations);\n *\n * // Verify citations for each file\n * for (const [attachmentId, fileCitations] of citationsByAttachment) {\n * const verified = await deepcitation.verifyCitations(attachmentId, fileCitations);\n * // Process verification results...\n * }\n * ```\n */\nexport function groupCitationsByAttachmentId(\n citations: Citation[] | { [key: string]: Citation }\n): Map<string, { [key: string]: Citation }> {\n const grouped = new Map<string, { [key: string]: Citation }>();\n\n // Normalize input to entries\n const entries: [string, Citation][] = Array.isArray(citations)\n ? citations.map((c, idx) => [generateCitationKey(c) || String(idx + 1), c])\n : Object.entries(citations);\n\n for (const [key, citation] of entries) {\n const attachmentId = citation.attachmentId || \"\";\n\n if (!grouped.has(attachmentId)) {\n grouped.set(attachmentId, {});\n }\n\n grouped.get(attachmentId)![key] = citation;\n }\n\n return grouped;\n}\n\n/**\n * Groups citations by their attachmentId and returns as a plain object.\n * Alternative to groupCitationsByAttachmentId that returns a plain object instead of a Map.\n *\n * @param citations - Array of Citation objects or a dictionary of citations\n * @returns Object with attachmentId keys mapping to citation dictionaries\n *\n * @example\n * ```typescript\n * const citations = getAllCitationsFromLlmOutput(response.content);\n * const citationsByAttachment = groupCitationsByAttachmentIdObject(citations);\n *\n * // Verify citations for each file using Promise.all\n * const verificationPromises = Object.entries(citationsByAttachment).map(\n * ([attachmentId, fileCitations]) => deepcitation.verifyCitations(attachmentId, fileCitations)\n * );\n * const results = await Promise.all(verificationPromises);\n * ```\n */\nexport function groupCitationsByAttachmentIdObject(\n citations: Citation[] | { [key: string]: Citation }\n): { [attachmentId: string]: { [key: string]: Citation } } {\n const grouped: { [attachmentId: string]: { [key: string]: Citation } } = {};\n\n // Normalize input to entries\n const entries: [string, Citation][] = Array.isArray(citations)\n ? citations.map((c, idx) => [generateCitationKey(c) || String(idx + 1), c])\n : Object.entries(citations);\n\n for (const [key, citation] of entries) {\n const attachmentId = citation.attachmentId || \"\";\n\n if (!grouped[attachmentId]) {\n grouped[attachmentId] = {};\n }\n\n grouped[attachmentId][key] = citation;\n }\n\n return grouped;\n}\n","import type { Verification } from \"../types/verification.js\";\nimport type { Citation } from \"../types/citation.js\";\nimport { getCitationStatus } from \"./parseCitation.js\";\nimport { generateCitationKey } from \"../react/utils.js\";\n\nexport interface ReplaceCitationsOptions {\n /**\n * If true, leaves the anchor_text text behind when removing citations.\n * @default false\n */\n leaveAnchorTextBehind?: boolean;\n\n /**\n * Map of citation keys to verification results.\n * Used to determine verification status for each citation.\n */\n verifications?: Record<string, Verification>;\n\n /**\n * If true and verifications are provided, appends a verification status indicator.\n * Uses: ✓ (verified), ⚠ (partial), ✗ (not found), ◌ (pending)\n * @default false\n */\n showVerificationStatus?: boolean;\n}\n\n/**\n * Parse attributes from a cite tag in any order.\n * Returns an object with all found attributes.\n */\nconst parseCiteAttributes = (\n citeTag: string\n): Record<string, string | undefined> => {\n const attrs: Record<string, string | undefined> = {};\n\n // Match attribute patterns: key='value' or key=\"value\"\n const attrRegex =\n /([a-zA-Z_][a-zA-Z0-9_]*)\\s*=\\s*(['\"])((?:[^'\"\\\\]|\\\\.)*)\\2/g;\n let match;\n\n while ((match = attrRegex.exec(citeTag)) !== null) {\n const key = match[1]\n .toLowerCase()\n .replace(/([a-z])([A-Z])/g, \"$1_$2\")\n .toLowerCase();\n const value = match[3];\n\n // Normalize key names\n const normalizedKey =\n key === \"fileid\" || key === \"file_id\" || key === \"attachmentid\"\n ? \"attachment_id\"\n : key === \"anchortext\" || key === \"anchor_text\" || key === \"keyspan\" || key === \"key_span\"\n ? \"anchor_text\"\n : key === \"fullphrase\"\n ? \"full_phrase\"\n : key === \"lineids\"\n ? \"line_ids\"\n : key === \"pageid\" || key === \"page_id\" || key === \"startpageid\" || key === \"start_pageid\" || key === \"start_page_id\" || key === \"startpagekey\" || key === \"start_pagekey\" || key === \"start_page_key\" || key === \"pagekey\" || key === \"page_key\"\n ? \"start_page_id\"\n : key;\n\n attrs[normalizedKey] = value;\n }\n\n return attrs;\n};\n\n/**\n * Get verification status indicator character for plain text/terminal output.\n * Returns: ☑️ (fully verified), ✅ (partial match), ❌ (not found), ⌛ (pending/null), ◌ (unknown)\n *\n * For web UI, use the React CitationComponent instead which provides\n * proper styled indicators with colors and accessibility.\n */\nexport const getVerificationTextIndicator = (\n verification: Verification | null | undefined\n): string => {\n const status = getCitationStatus(verification);\n\n if (status.isMiss) return \"❌\";\n // Check for fully verified (not partial) first\n if (status.isVerified && !status.isPartialMatch) return \"☑️\";\n // Then check for partial match\n if (status.isPartialMatch) return \"✅\";\n\n if (status.isPending) return \"⌛\";\n\n return \"◌\";\n};\n\n/**\n * Replaces citation tags in markdown text with optional replacement content.\n *\n * @param markdownWithCitations - The text containing <cite /> tags\n * @param options - Configuration options\n * @returns The text with citations replaced\n *\n * @example\n * ```typescript\n * // Remove all citations\n * const clean = replaceCitations(llmOutput);\n *\n * // Leave anchor_text text behind\n * const withAnchorTexts = replaceCitations(llmOutput, { leaveAnchorTextBehind: true });\n *\n * // Show verification status indicators\n * const withStatus = replaceCitations(llmOutput, {\n * leaveAnchorTextBehind: true,\n * verifications: verificationMap,\n * showVerificationStatus: true,\n * });\n * // Output: \"Revenue grew 45% year-over-year Revenue Growth✓\"\n * ```\n */\nexport const replaceCitations = (\n markdownWithCitations: string,\n options: ReplaceCitationsOptions = {}\n): string => {\n const {\n leaveAnchorTextBehind = false,\n verifications,\n showVerificationStatus = false,\n } = options;\n\n // Track citation index for matching with numbered verification keys\n let citationIndex = 0;\n\n // Flexible regex that matches any <cite ... /> tag\n const citationRegex = /<cite\\s+[^>]*?\\/>/g;\n\n return markdownWithCitations.replace(citationRegex, (match) => {\n citationIndex++;\n const attrs = parseCiteAttributes(match);\n\n // Determine what to output\n let output = \"\";\n\n if (leaveAnchorTextBehind && attrs.anchor_text) {\n // Unescape the anchor_text value\n output = attrs.anchor_text.replace(/\\\\'/g, \"'\").replace(/\\\\\"/g, '\"');\n }\n\n // Add verification status if requested\n if (showVerificationStatus && verifications) {\n // Try to find verification by various key strategies\n let verification: Verification | undefined;\n\n // Build a Citation object from parsed attributes to generate the key\n const parsePageNumber = (startPageId?: string): number | undefined => {\n if (!startPageId) return undefined;\n const match = startPageId.match(/page[_a-zA-Z]*(\\d+)/);\n return match ? parseInt(match[1], 10) : undefined;\n };\n\n const parseLineIds = (lineIdsStr?: string): number[] | undefined => {\n if (!lineIdsStr) return undefined;\n\n // First expand ranges (e.g., \"62-63\" -> \"62,63\")\n let expanded = lineIdsStr.replace(\n /(\\d+)-(\\d+)/g,\n (_match, start, end) => {\n const startNum = parseInt(start, 10);\n const endNum = parseInt(end, 10);\n if (startNum <= endNum) {\n const range = [];\n for (let i = startNum; i <= endNum; i++) {\n range.push(i);\n }\n return range.join(\",\");\n }\n return start;\n }\n );\n\n const nums = expanded.split(\",\").map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n));\n return nums.length > 0 ? nums : undefined;\n };\n\n // Unescape quotes in fullPhrase and anchorText to match how citations are parsed\n // by getAllCitationsFromLlmOutput (which returns unescaped values)\n const unescapeQuotes = (str: string | undefined): string | undefined =>\n str?.replace(/\\\\'/g, \"'\").replace(/\\\\\"/g, '\"');\n\n const citation: Citation = {\n attachmentId: attrs.attachment_id,\n pageNumber: parsePageNumber(attrs.start_page_id),\n fullPhrase: unescapeQuotes(attrs.full_phrase),\n anchorText: unescapeQuotes(attrs.anchor_text),\n lineIds: parseLineIds(attrs.line_ids),\n };\n\n // Strategy 1: Match by citationKey (hash) - most reliable\n const citationKey = generateCitationKey(citation);\n verification = verifications[citationKey];\n\n // Strategy 2: Fall back to numbered keys (1, 2, 3, etc.)\n if (!verification) {\n const numericKey = String(citationIndex);\n verification = verifications[numericKey];\n }\n\n const indicator = getVerificationTextIndicator(verification);\n output = output ? `${output}${indicator}` : indicator;\n }\n\n return output;\n });\n};\n\nexport const removePageNumberMetadata = (pageText: string): string => {\n return pageText\n .replace(/<page_number_\\d+_index_\\d+>/g, \"\")\n .replace(/<\\/page_number_\\d+_index_\\d+>/g, \"\")\n .trim();\n};\n\nexport const removeLineIdMetadata = (pageText: string): string => {\n const lineIdRegex = /<line id=\"[^\"]*\">|<\\/line>/g;\n return pageText.replace(lineIdRegex, \"\");\n};\n\nexport const getCitationPageNumber = (\n startPageId?: string | null\n): number | null => {\n //page_number_{page_number}_index_{page_index} or page_number_{page_number} or page_id_{page_number}_index_{page_index}\n if (!startPageId) return null;\n\n //regex first \\d+ is the page number\n const pageNumber = startPageId.match(/\\d+/)?.[0];\n return pageNumber ? parseInt(pageNumber) : null;\n};\n\n/**\n * Extracts content from a non-self-closing citation tag and moves it before the citation.\n * Converts <cite ...>content</cite> to: content<cite ... />\n *\n * @param citePart - The citation part that may contain inner content\n * @returns The normalized citation with content moved before it\n */\nconst extractAndRelocateCitationContent = (citePart: string): string => {\n // Check if this is a non-self-closing citation: <cite ...>content</cite>\n // Match: <cite with attributes> then content then </cite>\n // The attribute regex handles escaped quotes: (?:[^'\\\\]|\\\\.)* matches non-quote/non-backslash OR backslash+any\n const nonSelfClosingMatch = citePart.match(\n /^(<cite\\s+(?:'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"|[^'\">/])*>)([\\s\\S]*?)<\\/cite>$/\n );\n\n if (!nonSelfClosingMatch) {\n // Check if this is an unclosed citation ending with just >\n // Pattern: <cite attributes> (no closing tag)\n const unclosedMatch = citePart.match(\n /^(<cite\\s+(?:'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"|[^'\">/])*>)$/\n );\n if (unclosedMatch) {\n // Convert <cite ... > to self-closing <cite ... />\n const selfClosingTag = unclosedMatch[1].replace(/>$/, \" />\");\n return normalizeCitationContent(selfClosingTag);\n }\n // Already self-closing or doesn't match pattern, normalize as-is\n return normalizeCitationContent(citePart);\n }\n\n const [, openingTag, innerContent] = nonSelfClosingMatch;\n\n // If there's no inner content, just normalize the citation\n if (!innerContent || !innerContent.trim()) {\n return normalizeCitationContent(citePart);\n }\n\n // Extract the attributes from the opening tag\n // Convert <cite attributes> to <cite attributes />\n const selfClosingTag = openingTag.replace(/>$/, \" />\");\n\n // Move inner content before the citation and normalize\n // The inner content is trimmed to avoid extra whitespace issues\n const relocatedContent = innerContent.trim();\n\n // Normalize the self-closing citation tag\n const normalizedCitation = normalizeCitationContent(selfClosingTag);\n\n // Return content followed by the citation\n return relocatedContent + normalizedCitation;\n};\n\nexport const normalizeCitations = (response: string): string => {\n let trimmedResponse = response?.trim() || \"\";\n\n // Fix missing < before cite tags\n // LLMs sometimes output 'cite' without the leading '<'\n // Match 'cite' followed by a space and attribute pattern, but NOT preceded by '<' or a letter\n // This avoids matching words like \"excite\" or \"recite\"\n trimmedResponse = trimmedResponse.replace(\n /(?<![<a-zA-Z])cite\\s+(attachment_id|file_id|fileId|attachmentId)\\s*=/gi,\n \"<cite $1=\"\n );\n\n // Split on citation tags - captures three patterns:\n // 1. Self-closing: <cite ... />\n // 2. With closing tag: <cite ...>content</cite>\n // 3. Unclosed (ends with >): <cite ...> (no closing tag, no </cite> anywhere after)\n // Pattern 3 uses negative lookahead to avoid matching when </cite> follows\n const citationParts = trimmedResponse.split(\n /(<cite[\\s\\S]*?(?:\\/>|<\\/cite>|>(?=\\s*$|[\\r\\n])(?![\\s\\S]*<\\/cite>)))/gm\n );\n if (citationParts.length <= 1) {\n // Handle unclosed citations by converting to self-closing\n const unclosedMatch = trimmedResponse.match(/<cite\\s+(?:'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"|[^'\">/])*>/g);\n if (unclosedMatch && unclosedMatch.length > 0) {\n const result = trimmedResponse.replace(\n /<cite\\s+(?:'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"|[^'\">/])*>/g,\n (match) => match.replace(/>$/, ' />')\n );\n return normalizeCitationContent(result);\n }\n return normalizeCitationContent(trimmedResponse);\n }\n\n trimmedResponse = citationParts\n .map((part) =>\n part.startsWith(\"<cite\")\n ? extractAndRelocateCitationContent(part)\n : part\n )\n .join(\"\");\n\n return trimmedResponse;\n};\n\nconst normalizeCitationContent = (input: string): string => {\n let normalized = input;\n\n // 0. Unescape all backslash-escaped underscores\n // This handles Markdown-processed output where underscores get escaped (e.g., attachment\\_id -> attachment_id, page\\_number\\_1 -> page_number_1)\n normalized = normalized.replace(/\\\\_/g, \"_\");\n\n // 1. Standardize self-closing tags\n // Replace ></cite> with /> for consistency\n normalized = normalized.replace(/><\\/cite>/g, \"/>\");\n\n const canonicalizeCiteAttributeKey = (key: string): string => {\n const lowerKey = key.toLowerCase();\n if (lowerKey === \"fullphrase\" || lowerKey === \"full_phrase\")\n return \"full_phrase\";\n if (lowerKey === \"lineids\" || lowerKey === \"line_ids\") return \"line_ids\";\n if (\n lowerKey === \"startpageid\" ||\n lowerKey === \"start_pageid\" ||\n lowerKey === \"start_page_id\" ||\n lowerKey === \"startpagekey\" ||\n lowerKey === \"start_pagekey\" ||\n lowerKey === \"start_page_key\"\n )\n return \"start_page_id\";\n if (\n lowerKey === \"fileid\" ||\n lowerKey === \"file_id\" ||\n lowerKey === \"attachmentid\" ||\n lowerKey === \"attachment_id\"\n )\n return \"attachment_id\";\n if (lowerKey === \"anchortext\" || lowerKey === \"anchor_text\" || lowerKey === \"keyspan\" || lowerKey === \"key_span\") return \"anchor_text\";\n if (lowerKey === \"reasoning\" || lowerKey === \"value\") return lowerKey;\n if (\n lowerKey === \"timestamps\" ||\n lowerKey === \"timestamp\" ||\n lowerKey === \"timestamps\"\n )\n return \"timestamps\";\n\n return lowerKey;\n };\n\n const htmlEntityMap: Record<string, string> = {\n '"': '\"',\n ''': \"'\",\n '<': '<',\n '>': '>',\n '&': '&',\n };\n const htmlEntityRegex = /&(?:quot|apos|lt|gt|amp);/g;\n const decodeHtmlEntities = (str: string) => {\n return str.replace(htmlEntityRegex, (match) => htmlEntityMap[match] || match);\n };\n\n const textAttributeRegex =\n /(fullPhrase|full_phrase|anchorText|anchor_text|keySpan|key_span|reasoning|value)\\s*=\\s*(['\"])([\\s\\S]*?)(?=\\s+(?:line_ids|lineIds|timestamps|fileId|file_id|attachmentId|attachment_id|start_page_id|start_pageId|startPageId|start_page_key|start_pageKey|startPageKey|anchorText|anchor_text|keySpan|key_span|reasoning|value|full_phrase)\\s*=|\\s*\\/>|['\"]>)/gm;\n\n normalized = normalized.replace(\n textAttributeRegex,\n (_match, key, openQuote, rawContent) => {\n let content = rawContent;\n\n if (content.endsWith(openQuote)) {\n content = content.slice(0, -1);\n }\n\n // Flatten newlines and remove markdown markers\n content = content.replace(/(\\r?\\n)+|(\\*|_){2,}|\\*/g, (match: string) => {\n if (match.includes('\\n') || match.includes('\\r')) return ' ';\n return '';\n });\n\n content = decodeHtmlEntities(content);\n\n // Normalize quotes\n content = content.replace(/\\\\\\\\'/g, \"'\").replace(/\\\\'/g, \"'\").replace(/'/g, \"\\\\'\");\n content = content.replace(/\\\\\\\\\"/g, '\"').replace(/\\\\\"/g, '\"').replace(/\"/g, '\\\\\"');\n\n return `${canonicalizeCiteAttributeKey(key)}='${content}'`;\n }\n );\n normalized = normalized.replace(\n /(line_ids|lineIds|timestamps)=['\"]?([\\[\\]\\(\\){}A-Za-z0-9_\\-, ]+)['\"]?(\\s*\\/?>|\\s+)/gm,\n (_match, key, rawValue, trailingChars) => {\n // Clean up the value (remove generic text, keep numbers/separators)\n let cleanedValue = rawValue.replace(/[A-Za-z\\[\\]\\(\\){}]/g, \"\");\n\n // Expand ranges (e.g., \"1-3\" -> \"1,2,3\")\n cleanedValue = cleanedValue.replace(\n /(\\d+)-(\\d+)/g,\n (_rangeMatch: string, start: string, end: string) => {\n const startNum = parseInt(start, 10);\n const endNum = parseInt(end, 10);\n const range = [];\n\n // Handle ascending range\n if (startNum <= endNum) {\n for (let i = startNum; i <= endNum; i++) {\n range.push(i);\n }\n } else {\n // Fallback for weird descending ranges or just return start\n range.push(startNum);\n }\n return range.join(\",\");\n }\n );\n\n // Normalize commas\n cleanedValue = cleanedValue.replace(/,+/g, \",\").replace(/^,|,$/g, \"\");\n\n // Return standardized format: key='value' + preserved trailing characters (space or />)\n return `${canonicalizeCiteAttributeKey(\n key\n )}='${cleanedValue}'${trailingChars}`;\n }\n );\n\n // 4. Re-order <cite ... /> attributes to match the strict parsing expectations in `citationParser.ts`\n // (the parser uses regexes that assume a canonical attribute order).\n const reorderCiteTagAttributes = (tag: string): string => {\n // Match both single-quoted and double-quoted attributes\n const attrRegex =\n /([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(['\"])((?:[^'\"\\\\\\n]|\\\\.)*)(?:\\2)/g;\n const attrs: Record<string, string> = {};\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(tag))) {\n const rawKey = match[1];\n const value = match[3]; // match[2] is the quote character\n const key = canonicalizeCiteAttributeKey(rawKey);\n attrs[key] = value;\n }\n\n // If we didn't find any parsable attrs, don't touch the tag.\n const keys = Object.keys(attrs);\n if (keys.length === 0) return tag;\n\n const hasTimestamps =\n typeof attrs.timestamps === \"string\" && attrs.timestamps.length > 0;\n const startPageIds = keys.filter((k) => k.startsWith(\"start_page\"));\n\n const ordered: string[] = [];\n\n // Shared first\n if (attrs.attachment_id) ordered.push(\"attachment_id\");\n\n if (hasTimestamps) {\n // AV citations: attachment_id, full_phrase, anchor_text, timestamps, (optional reasoning/value), then any extras\n if (attrs.full_phrase) ordered.push(\"full_phrase\");\n if (attrs.anchor_text) ordered.push(\"anchor_text\");\n ordered.push(\"timestamps\");\n } else {\n // Document citations: attachment_id, start_page*, full_phrase, anchor_text, line_ids, (optional reasoning/value), then any extras\n if (startPageIds.includes(\"start_page_id\"))\n ordered.push(\"start_page_id\");\n startPageIds\n .filter((k) => k !== \"start_page_id\")\n .sort()\n .forEach((k) => ordered.push(k));\n\n if (attrs.full_phrase) ordered.push(\"full_phrase\");\n if (attrs.anchor_text) ordered.push(\"anchor_text\");\n if (attrs.line_ids) ordered.push(\"line_ids\");\n }\n\n // Optional attrs supported by the parser (but not required)\n if (attrs.reasoning) ordered.push(\"reasoning\");\n if (attrs.value) ordered.push(\"value\");\n\n // Any remaining attributes, stable + deterministic (alpha)\n const used = new Set(ordered);\n keys\n .filter((k) => !used.has(k))\n .sort()\n .forEach((k) => ordered.push(k));\n\n const rebuiltAttrs = ordered.map((k) => `${k}='${attrs[k]}'`).join(\" \");\n return `<cite ${rebuiltAttrs} />`;\n };\n\n normalized = normalized.replace(/<cite\\b[\\s\\S]*?\\/>/gm, (tag) =>\n reorderCiteTagAttributes(tag)\n );\n\n return normalized;\n};\n","import type { Citation } from \"../types/citation.js\";\nimport type { Verification } from \"../types/verification.js\";\nimport { sha1Hash } from \"../utils/sha.js\";\nimport { getCitationPageNumber } from \"../parsing/normalizeCitation.js\";\n\n// =============================================================================\n// UTILITY FUNCTIONS\n// =============================================================================\n\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * Type guard to check if a citation is a URL citation (type: \"url\" or has url field).\n */\nexport function isUrlCitation(citation: Citation): boolean {\n return citation.type === \"url\" || (typeof citation.url === \"string\" && citation.url.length > 0);\n}\n\n/**\n * Generates a unique, deterministic key for a citation based on its content.\n * Works with both document and URL citation types.\n *\n * For URL citations, the URL is included in the key generation for uniqueness.\n *\n * @param citation - The citation to generate a key for\n * @returns A unique, deterministic key for the citation\n */\nexport function generateCitationKey(citation: Citation): string {\n const pageNumber =\n citation.pageNumber || getCitationPageNumber(citation.startPageId);\n\n // Base key parts for all citations\n const keyParts = [\n citation.attachmentId || \"\",\n pageNumber?.toString() || \"\",\n citation.fullPhrase || \"\",\n citation.anchorText?.toString() || \"\",\n citation.lineIds?.join(\",\") || \"\",\n citation.timestamps?.startTime || \"\",\n citation.timestamps?.endTime || \"\",\n ];\n\n // Add URL-specific fields if present\n if (isUrlCitation(citation)) {\n keyParts.push(\n citation.url || \"\",\n citation.title || \"\",\n citation.domain || \"\",\n );\n }\n\n return sha1Hash(keyParts.join(\"|\")).slice(0, 16);\n}\n\n/**\n * Generates a unique, deterministic key for a verification based on its content.\n * @param verification - The verification to generate a key for\n * @returns\n */\nexport function generateVerificationKey(verification: Verification): string {\n const keyParts = [\n verification.attachmentId || \"\",\n verification.label || \"\",\n verification.verifiedFullPhrase || \"\",\n verification.verifiedAnchorText || \"\",\n verification.verifiedLineIds?.join(\",\") || \"\",\n verification.verifiedPageNumber?.toString() || \"\",\n\n verification.verifiedTimestamps?.startTime || \"\",\n verification.verifiedTimestamps?.endTime || \"\",\n\n verification.verifiedMatchSnippet || \"\",\n verification.hitIndexWithinPage?.toString() || \"\",\n ];\n\n return sha1Hash(keyParts.join(\"|\")).slice(0, 16);\n}\n\n/**\n * Generates a unique instance ID for a citation component render.\n * Combines the citation key with a random suffix for uniqueness.\n */\nexport function generateCitationInstanceId(citationKey: string): string {\n const randomSuffix = Math.random().toString(36).slice(2, 11);\n return `${citationKey}-${randomSuffix}`;\n}\n\n/**\n * Gets the display text for a citation (anchorText with fallback to number).\n */\nexport function getCitationDisplayText(\n citation: Citation,\n options: {\n fallbackDisplay?: string | null;\n } = {}\n): string {\n const { fallbackDisplay } = options;\n return (\n citation.anchorText?.toString() ||\n citation.citationNumber?.toString() ||\n fallbackDisplay ||\n \"1\"\n );\n}\n\n/**\n * Gets the citation number as a string.\n */\nexport function getCitationNumber(citation: Citation): string {\n return citation.citationNumber?.toString() || \"1\";\n}\n\n/**\n * Gets the anchorText text from a citation.\n */\nexport function getCitationAnchorText(citation: Citation): string {\n return citation.anchorText?.toString() || \"\";\n}\n\n/**\n * Joins class names, filtering out falsy values.\n * This is a minimal implementation for the base component.\n */\nexport function classNames(\n ...classes: (string | undefined | null | false)[]\n): string {\n return classes.filter(Boolean).join(\" \");\n}\n\n/**\n * Default padding values for citation styling.\n */\nexport const CITATION_X_PADDING = 4;\nexport const CITATION_Y_PADDING = 1;\n"]}
|