@nathanvale/chatline 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/LICENSE +21 -0
- package/README.md +1535 -0
- package/dist/bin/index.js +5121 -0
- package/dist/cli/commands/clean.d.ts +17 -0
- package/dist/cli/commands/clean.d.ts.map +1 -0
- package/dist/cli/commands/clean.js +142 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +17 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +202 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/enrich-ai.d.ts +17 -0
- package/dist/cli/commands/enrich-ai.d.ts.map +1 -0
- package/dist/cli/commands/enrich-ai.js +371 -0
- package/dist/cli/commands/enrich-ai.js.map +1 -0
- package/dist/cli/commands/index.d.ts +16 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +16 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/ingest-csv.d.ts +17 -0
- package/dist/cli/commands/ingest-csv.d.ts.map +1 -0
- package/dist/cli/commands/ingest-csv.js +138 -0
- package/dist/cli/commands/ingest-csv.js.map +1 -0
- package/dist/cli/commands/ingest-db.d.ts +17 -0
- package/dist/cli/commands/ingest-db.d.ts.map +1 -0
- package/dist/cli/commands/ingest-db.js +159 -0
- package/dist/cli/commands/ingest-db.js.map +1 -0
- package/dist/cli/commands/init.d.ts +17 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +110 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/normalize-link.d.ts +16 -0
- package/dist/cli/commands/normalize-link.d.ts.map +1 -0
- package/dist/cli/commands/normalize-link.js +144 -0
- package/dist/cli/commands/normalize-link.js.map +1 -0
- package/dist/cli/commands/render-markdown.d.ts +17 -0
- package/dist/cli/commands/render-markdown.d.ts.map +1 -0
- package/dist/cli/commands/render-markdown.js +218 -0
- package/dist/cli/commands/render-markdown.js.map +1 -0
- package/dist/cli/commands/stats.d.ts +17 -0
- package/dist/cli/commands/stats.d.ts.map +1 -0
- package/dist/cli/commands/stats.js +175 -0
- package/dist/cli/commands/stats.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +17 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +152 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +121 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/types.d.ts +93 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +7 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/utils.d.ts +29 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/utils.js +53 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1805 -0
- package/dist/config/generator.d.ts +90 -0
- package/dist/config/generator.d.ts.map +1 -0
- package/dist/config/generator.js +320 -0
- package/dist/config/generator.js.map +1 -0
- package/dist/config/loader.d.ts +107 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +251 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +107 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +169 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/enrich/audio-transcription.d.ts +77 -0
- package/dist/enrich/audio-transcription.d.ts.map +1 -0
- package/dist/enrich/audio-transcription.js +370 -0
- package/dist/enrich/audio-transcription.js.map +1 -0
- package/dist/enrich/checkpoint.d.ts +137 -0
- package/dist/enrich/checkpoint.d.ts.map +1 -0
- package/dist/enrich/checkpoint.js +205 -0
- package/dist/enrich/checkpoint.js.map +1 -0
- package/dist/enrich/idempotency.d.ts +90 -0
- package/dist/enrich/idempotency.d.ts.map +1 -0
- package/dist/enrich/idempotency.js +188 -0
- package/dist/enrich/idempotency.js.map +1 -0
- package/dist/enrich/image-analysis.d.ts +62 -0
- package/dist/enrich/image-analysis.d.ts.map +1 -0
- package/dist/enrich/image-analysis.js +264 -0
- package/dist/enrich/image-analysis.js.map +1 -0
- package/dist/enrich/index.d.ts +60 -0
- package/dist/enrich/index.d.ts.map +1 -0
- package/dist/enrich/index.js +74 -0
- package/dist/enrich/index.js.map +1 -0
- package/dist/enrich/link-enrichment.d.ts +37 -0
- package/dist/enrich/link-enrichment.d.ts.map +1 -0
- package/dist/enrich/link-enrichment.js +202 -0
- package/dist/enrich/link-enrichment.js.map +1 -0
- package/dist/enrich/pdf-video-handling.d.ts +49 -0
- package/dist/enrich/pdf-video-handling.d.ts.map +1 -0
- package/dist/enrich/pdf-video-handling.js +325 -0
- package/dist/enrich/pdf-video-handling.js.map +1 -0
- package/dist/enrich/progress-tracker.d.ts +120 -0
- package/dist/enrich/progress-tracker.d.ts.map +1 -0
- package/dist/enrich/progress-tracker.js +220 -0
- package/dist/enrich/progress-tracker.js.map +1 -0
- package/dist/enrich/providers/firecrawl.d.ts +18 -0
- package/dist/enrich/providers/firecrawl.d.ts.map +1 -0
- package/dist/enrich/providers/firecrawl.js +48 -0
- package/dist/enrich/providers/firecrawl.js.map +1 -0
- package/dist/enrich/providers/generic.d.ts +16 -0
- package/dist/enrich/providers/generic.d.ts.map +1 -0
- package/dist/enrich/providers/generic.js +36 -0
- package/dist/enrich/providers/generic.js.map +1 -0
- package/dist/enrich/providers/index.d.ts +14 -0
- package/dist/enrich/providers/index.d.ts.map +1 -0
- package/dist/enrich/providers/index.js +13 -0
- package/dist/enrich/providers/index.js.map +1 -0
- package/dist/enrich/providers/instagram.d.ts +16 -0
- package/dist/enrich/providers/instagram.d.ts.map +1 -0
- package/dist/enrich/providers/instagram.js +43 -0
- package/dist/enrich/providers/instagram.js.map +1 -0
- package/dist/enrich/providers/spotify.d.ts +16 -0
- package/dist/enrich/providers/spotify.d.ts.map +1 -0
- package/dist/enrich/providers/spotify.js +45 -0
- package/dist/enrich/providers/spotify.js.map +1 -0
- package/dist/enrich/providers/twitter.d.ts +16 -0
- package/dist/enrich/providers/twitter.d.ts.map +1 -0
- package/dist/enrich/providers/twitter.js +43 -0
- package/dist/enrich/providers/twitter.js.map +1 -0
- package/dist/enrich/providers/types.d.ts +47 -0
- package/dist/enrich/providers/types.d.ts.map +1 -0
- package/dist/enrich/providers/types.js +15 -0
- package/dist/enrich/providers/types.js.map +1 -0
- package/dist/enrich/providers/youtube.d.ts +16 -0
- package/dist/enrich/providers/youtube.d.ts.map +1 -0
- package/dist/enrich/providers/youtube.js +43 -0
- package/dist/enrich/providers/youtube.js.map +1 -0
- package/dist/enrich/rate-limiting.d.ts +118 -0
- package/dist/enrich/rate-limiting.d.ts.map +1 -0
- package/dist/enrich/rate-limiting.js +258 -0
- package/dist/enrich/rate-limiting.js.map +1 -0
- package/dist/index.d.ts +688 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1729 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/dedup-merge.d.ts +82 -0
- package/dist/ingest/dedup-merge.d.ts.map +1 -0
- package/dist/ingest/dedup-merge.js +262 -0
- package/dist/ingest/dedup-merge.js.map +1 -0
- package/dist/ingest/ingest-csv.d.ts +62 -0
- package/dist/ingest/ingest-csv.d.ts.map +1 -0
- package/dist/ingest/ingest-csv.js +300 -0
- package/dist/ingest/ingest-csv.js.map +1 -0
- package/dist/ingest/ingest-db.d.ts +64 -0
- package/dist/ingest/ingest-db.d.ts.map +1 -0
- package/dist/ingest/ingest-db.js +172 -0
- package/dist/ingest/ingest-db.js.map +1 -0
- package/dist/ingest/link-replies-and-tapbacks.d.ts +53 -0
- package/dist/ingest/link-replies-and-tapbacks.d.ts.map +1 -0
- package/dist/ingest/link-replies-and-tapbacks.js +381 -0
- package/dist/ingest/link-replies-and-tapbacks.js.map +1 -0
- package/dist/normalize/date-converters.d.ts +45 -0
- package/dist/normalize/date-converters.d.ts.map +1 -0
- package/dist/normalize/date-converters.js +166 -0
- package/dist/normalize/date-converters.js.map +1 -0
- package/dist/normalize/path-validator.d.ts +65 -0
- package/dist/normalize/path-validator.d.ts.map +1 -0
- package/dist/normalize/path-validator.js +221 -0
- package/dist/normalize/path-validator.js.map +1 -0
- package/dist/normalize/validate-normalized.d.ts +45 -0
- package/dist/normalize/validate-normalized.d.ts.map +1 -0
- package/dist/normalize/validate-normalized.js +144 -0
- package/dist/normalize/validate-normalized.js.map +1 -0
- package/dist/render/embeds-blockquotes.d.ts +84 -0
- package/dist/render/embeds-blockquotes.d.ts.map +1 -0
- package/dist/render/embeds-blockquotes.js +204 -0
- package/dist/render/embeds-blockquotes.js.map +1 -0
- package/dist/render/grouping.d.ts +78 -0
- package/dist/render/grouping.d.ts.map +1 -0
- package/dist/render/grouping.js +134 -0
- package/dist/render/grouping.js.map +1 -0
- package/dist/render/index.d.ts +47 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +245 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/reply-rendering.d.ts +88 -0
- package/dist/render/reply-rendering.d.ts.map +1 -0
- package/dist/render/reply-rendering.js +196 -0
- package/dist/render/reply-rendering.js.map +1 -0
- package/dist/schema/message.d.ts +125 -0
- package/dist/schema/message.d.ts.map +1 -0
- package/dist/schema/message.js +331 -0
- package/dist/schema/message.js.map +1 -0
- package/dist/utils/delta-detection.d.ts +107 -0
- package/dist/utils/delta-detection.d.ts.map +1 -0
- package/dist/utils/delta-detection.js +199 -0
- package/dist/utils/delta-detection.js.map +1 -0
- package/dist/utils/enrichment-merge.d.ts +135 -0
- package/dist/utils/enrichment-merge.d.ts.map +1 -0
- package/dist/utils/enrichment-merge.js +280 -0
- package/dist/utils/enrichment-merge.js.map +1 -0
- package/dist/utils/human.d.ts +15 -0
- package/dist/utils/human.d.ts.map +1 -0
- package/dist/utils/human.js +27 -0
- package/dist/utils/human.js.map +1 -0
- package/dist/utils/incremental-state.d.ts +133 -0
- package/dist/utils/incremental-state.d.ts.map +1 -0
- package/dist/utils/incremental-state.js +237 -0
- package/dist/utils/incremental-state.js.map +1 -0
- package/dist/utils/logger.d.ts +40 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +176 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +165 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { parse } from 'csv-parse/sync';
|
|
5
|
+
import { MessageSchema } from '../schema/message.js';
|
|
6
|
+
/**
|
|
7
|
+
* Main entry point: Ingest CSV file and convert to unified Message schema
|
|
8
|
+
*/
|
|
9
|
+
export function ingestCSV(csvFilePath, options) {
|
|
10
|
+
const csvContent = readFileSync(csvFilePath, 'utf-8');
|
|
11
|
+
const rows = parse(csvContent, { columns: true });
|
|
12
|
+
const messages = [];
|
|
13
|
+
let lineNumber = 2; // Start at 2 (header is line 1)
|
|
14
|
+
for (const row of rows) {
|
|
15
|
+
const rowMessages = parseCSVRow(row, lineNumber, options);
|
|
16
|
+
messages.push(...rowMessages);
|
|
17
|
+
lineNumber++;
|
|
18
|
+
}
|
|
19
|
+
return messages;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parse a single CSV row and produce 1-N messages
|
|
23
|
+
* Maps iMazing CSV format to unified Message schema
|
|
24
|
+
*
|
|
25
|
+
* AC01: Parse iMazing CSV rows with correct field mapping per CSV header
|
|
26
|
+
*/
|
|
27
|
+
export function parseCSVRow(row, lineNumber, options) {
|
|
28
|
+
const messages = [];
|
|
29
|
+
// Extract iMazing CSV fields (headers have spaces, not underscores)
|
|
30
|
+
const messageDate = row['Message Date'];
|
|
31
|
+
const deliveredDate = row['Delivered Date'];
|
|
32
|
+
const readDate = row['Read Date'];
|
|
33
|
+
const editedDate = row['Edited Date'];
|
|
34
|
+
const service = row.Service;
|
|
35
|
+
const type = row.Type;
|
|
36
|
+
const senderName = row['Sender Name'];
|
|
37
|
+
const senderID = row['Sender ID'];
|
|
38
|
+
const status = row.Status;
|
|
39
|
+
const text = row.Text;
|
|
40
|
+
const subject = row.Subject;
|
|
41
|
+
const attachment = row.Attachment;
|
|
42
|
+
const attachmentType = row['Attachment type'];
|
|
43
|
+
const replyingTo = row['Replying to'];
|
|
44
|
+
// AC03: Convert CSV dates to ISO 8601 UTC with Z suffix
|
|
45
|
+
const date = convertToISO8601(messageDate || '');
|
|
46
|
+
if (!date)
|
|
47
|
+
return []; // Skip rows with invalid dates
|
|
48
|
+
// AC02: Split rows into text/media/tapback/notification by analyzing content
|
|
49
|
+
// Determine messageKind and isFromMe from Type field
|
|
50
|
+
const isFromMe = type === 'Outgoing' || type === 'Sent';
|
|
51
|
+
let messageKind = 'text';
|
|
52
|
+
if (type === 'Notification') {
|
|
53
|
+
messageKind = 'notification';
|
|
54
|
+
}
|
|
55
|
+
// Base message object with common fields
|
|
56
|
+
const baseMessage = {
|
|
57
|
+
isFromMe,
|
|
58
|
+
date,
|
|
59
|
+
};
|
|
60
|
+
// Conditionally add optional fields to satisfy exactOptionalPropertyTypes
|
|
61
|
+
const handle = senderName || senderID;
|
|
62
|
+
if (handle)
|
|
63
|
+
baseMessage.handle = handle;
|
|
64
|
+
if (service)
|
|
65
|
+
baseMessage.service = service;
|
|
66
|
+
if (subject)
|
|
67
|
+
baseMessage.subject = subject;
|
|
68
|
+
if (readDate)
|
|
69
|
+
baseMessage.dateRead = convertToISO8601(readDate);
|
|
70
|
+
if (deliveredDate)
|
|
71
|
+
baseMessage.dateDelivered = convertToISO8601(deliveredDate);
|
|
72
|
+
if (editedDate) {
|
|
73
|
+
baseMessage.dateEdited = convertToISO8601(editedDate);
|
|
74
|
+
baseMessage.isEdited = true;
|
|
75
|
+
}
|
|
76
|
+
if (status === 'Read')
|
|
77
|
+
baseMessage.isRead = true;
|
|
78
|
+
else if (status === 'Unread')
|
|
79
|
+
baseMessage.isRead = false;
|
|
80
|
+
// AC05: Preserve row metadata (source, line number) for provenance
|
|
81
|
+
const baseExportMetadata = {
|
|
82
|
+
source: 'csv',
|
|
83
|
+
lineNumber,
|
|
84
|
+
csvGuid: `csv:${lineNumber}:0`,
|
|
85
|
+
...(replyingTo && { replyingTo }),
|
|
86
|
+
};
|
|
87
|
+
// Create text message
|
|
88
|
+
if (messageKind === 'text' && text) {
|
|
89
|
+
const textMessage = {
|
|
90
|
+
...baseMessage,
|
|
91
|
+
guid: `csv:${lineNumber}:0`,
|
|
92
|
+
messageKind: 'text',
|
|
93
|
+
text,
|
|
94
|
+
exportMetadata: baseExportMetadata,
|
|
95
|
+
};
|
|
96
|
+
messages.push(textMessage);
|
|
97
|
+
}
|
|
98
|
+
// AC04: Resolve iMazing attachment paths to absolute paths when files exist
|
|
99
|
+
if (attachment && attachment.trim() !== '') {
|
|
100
|
+
const resolvedPath = resolveAttachmentPath({ filename: attachment }, {
|
|
101
|
+
...options,
|
|
102
|
+
messageDate: date,
|
|
103
|
+
});
|
|
104
|
+
// Only create media message if path can be resolved to absolute path (schema requirement)
|
|
105
|
+
if (resolvedPath) {
|
|
106
|
+
const mediaMessage = {
|
|
107
|
+
...baseMessage,
|
|
108
|
+
guid: `csv:${lineNumber}:0:media`,
|
|
109
|
+
messageKind: 'media',
|
|
110
|
+
media: {
|
|
111
|
+
id: `media:csv:${lineNumber}:0`,
|
|
112
|
+
filename: attachment,
|
|
113
|
+
path: resolvedPath,
|
|
114
|
+
mimeType: attachmentType || undefined,
|
|
115
|
+
mediaKind: inferMediaKind(attachmentType || ''),
|
|
116
|
+
},
|
|
117
|
+
exportMetadata: {
|
|
118
|
+
...baseExportMetadata,
|
|
119
|
+
attachmentIndex: 0,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
messages.push(mediaMessage);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Create notification message if explicitly marked
|
|
126
|
+
if (messageKind === 'notification') {
|
|
127
|
+
const notificationMessage = {
|
|
128
|
+
...baseMessage,
|
|
129
|
+
guid: `csv:${lineNumber}:0`,
|
|
130
|
+
messageKind: 'notification',
|
|
131
|
+
exportMetadata: baseExportMetadata,
|
|
132
|
+
};
|
|
133
|
+
messages.push(notificationMessage);
|
|
134
|
+
}
|
|
135
|
+
// Fallback: If no messages created but we have text, create text message
|
|
136
|
+
if (messages.length === 0 && text) {
|
|
137
|
+
const fallbackMessage = {
|
|
138
|
+
...baseMessage,
|
|
139
|
+
guid: `csv:${lineNumber}:0`,
|
|
140
|
+
messageKind: 'text',
|
|
141
|
+
text,
|
|
142
|
+
exportMetadata: baseExportMetadata,
|
|
143
|
+
};
|
|
144
|
+
messages.push(fallbackMessage);
|
|
145
|
+
}
|
|
146
|
+
return messages;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Convert CSV date to ISO 8601 UTC with Z suffix
|
|
150
|
+
* Input format: "YYYY-MM-DD HH:MM:SS" (space-separated)
|
|
151
|
+
*/
|
|
152
|
+
export function convertToISO8601(csvDate) {
|
|
153
|
+
if (!csvDate || csvDate.trim() === '') {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
// Normalize: convert space to T (CSV uses space, ISO 8601 uses T)
|
|
158
|
+
const normalized = csvDate.trim().replace(' ', 'T');
|
|
159
|
+
// Basic validation: should contain date separators
|
|
160
|
+
if (!normalized.includes('-') && !normalized.includes('/')) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
// Append Z if not present (assuming UTC)
|
|
164
|
+
let isoString = normalized;
|
|
165
|
+
if (!normalized.includes('Z') && !normalized.match(/[+-]\d{2}:/)) {
|
|
166
|
+
isoString = `${normalized}Z`;
|
|
167
|
+
}
|
|
168
|
+
// Parse and validate
|
|
169
|
+
const date = new Date(isoString);
|
|
170
|
+
if (Number.isNaN(date.getTime())) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
// Return ISO 8601 with Z suffix
|
|
174
|
+
return date.toISOString();
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Resolve attachment path to absolute path when file exists
|
|
182
|
+
*/
|
|
183
|
+
export function resolveAttachmentPath(attachment, options) {
|
|
184
|
+
if (!attachment)
|
|
185
|
+
return null;
|
|
186
|
+
const { attachmentRoots, messageDate } = options;
|
|
187
|
+
// If already absolute and exists, return it
|
|
188
|
+
if (attachment.copied_path?.startsWith('/')) {
|
|
189
|
+
if (existsSync(attachment.copied_path)) {
|
|
190
|
+
return attachment.copied_path;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Expand tilde if present
|
|
194
|
+
if (attachment.copied_path?.startsWith('~')) {
|
|
195
|
+
const expanded = attachment.copied_path.replace('~', os.homedir());
|
|
196
|
+
if (existsSync(expanded)) {
|
|
197
|
+
return expanded;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Search using timestamp pattern in attachment roots
|
|
201
|
+
if (messageDate && attachmentRoots.length > 0) {
|
|
202
|
+
const dateStr = formatDateForAttachmentSearch(messageDate);
|
|
203
|
+
const filename = attachment.filename || 'unknown';
|
|
204
|
+
const senderName = attachment.senderName || '*';
|
|
205
|
+
for (const root of attachmentRoots) {
|
|
206
|
+
// Try exact pattern: YYYY-MM-DD HH MM SS - SenderName - filename
|
|
207
|
+
const pattern = `${dateStr} - ${senderName} - ${filename}`;
|
|
208
|
+
const fullPath = path.join(root, pattern);
|
|
209
|
+
if (existsSync(fullPath)) {
|
|
210
|
+
return fullPath;
|
|
211
|
+
}
|
|
212
|
+
// Try wildcard pattern if sender name unknown
|
|
213
|
+
if (senderName === '*' && existsSync(root)) {
|
|
214
|
+
try {
|
|
215
|
+
const files = readdirSync(root).filter((f) => {
|
|
216
|
+
return f.includes(dateStr) && f.endsWith(filename);
|
|
217
|
+
});
|
|
218
|
+
if (files.length > 0 && files[0]) {
|
|
219
|
+
return path.join(root, files[0]);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Directory doesn't exist or can't be read
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Not found
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Infer media kind from MIME type
|
|
233
|
+
*/
|
|
234
|
+
export function inferMediaKind(mimeType) {
|
|
235
|
+
if (!mimeType)
|
|
236
|
+
return 'unknown';
|
|
237
|
+
if (mimeType.startsWith('image/'))
|
|
238
|
+
return 'image';
|
|
239
|
+
if (mimeType.startsWith('audio/'))
|
|
240
|
+
return 'audio';
|
|
241
|
+
if (mimeType.startsWith('video/'))
|
|
242
|
+
return 'video';
|
|
243
|
+
if (mimeType.includes('pdf'))
|
|
244
|
+
return 'pdf';
|
|
245
|
+
return 'unknown';
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Format ISO 8601 date for attachment search pattern
|
|
249
|
+
* Converts: 2023-10-23T06:52:57.000Z → 2023-10-23 06 52 57
|
|
250
|
+
*/
|
|
251
|
+
export function formatDateForAttachmentSearch(isoDate) {
|
|
252
|
+
try {
|
|
253
|
+
const date = new Date(isoDate);
|
|
254
|
+
const year = date.getUTCFullYear();
|
|
255
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
256
|
+
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
257
|
+
const hours = String(date.getUTCHours()).padStart(2, '0');
|
|
258
|
+
const minutes = String(date.getUTCMinutes()).padStart(2, '0');
|
|
259
|
+
const seconds = String(date.getUTCSeconds()).padStart(2, '0');
|
|
260
|
+
return `${year}-${month}-${day} ${hours} ${minutes} ${seconds}`;
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return '';
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Export envelope wrapper for CSV ingestion output
|
|
268
|
+
*/
|
|
269
|
+
export function createExportEnvelope(messages) {
|
|
270
|
+
return {
|
|
271
|
+
schemaVersion: '2.0.0',
|
|
272
|
+
source: 'csv',
|
|
273
|
+
createdAt: new Date().toISOString(),
|
|
274
|
+
messages,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Validate all messages pass schema validation
|
|
279
|
+
*/
|
|
280
|
+
export function validateMessages(messages) {
|
|
281
|
+
const errors = [];
|
|
282
|
+
for (let i = 0; i < messages.length; i++) {
|
|
283
|
+
const message = messages[i];
|
|
284
|
+
if (!message)
|
|
285
|
+
continue;
|
|
286
|
+
const result = MessageSchema.safeParse(message);
|
|
287
|
+
if (!result.success) {
|
|
288
|
+
errors.push({
|
|
289
|
+
index: i,
|
|
290
|
+
message,
|
|
291
|
+
issues: result.error.issues,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
valid: errors.length === 0,
|
|
297
|
+
errors,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=ingest-csv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-csv.js","sourceRoot":"","sources":["../../src/ingest/ingest-csv.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ExportEnvelope, Message } from '../schema/message.js';
|
|
2
|
+
export type DBMessage = {
|
|
3
|
+
guid: string;
|
|
4
|
+
rowid?: number;
|
|
5
|
+
text?: string | null;
|
|
6
|
+
is_from_me: number;
|
|
7
|
+
date: number;
|
|
8
|
+
chat_id?: string;
|
|
9
|
+
handle?: string;
|
|
10
|
+
service?: string;
|
|
11
|
+
subject?: string | null;
|
|
12
|
+
attachments?: DBAttachment[];
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
export type DBAttachment = {
|
|
16
|
+
id: string;
|
|
17
|
+
filename: string;
|
|
18
|
+
mime_type?: string;
|
|
19
|
+
uti?: string | null;
|
|
20
|
+
copied_path?: string;
|
|
21
|
+
total_bytes?: number;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
};
|
|
24
|
+
export type IngestOptions = {
|
|
25
|
+
attachmentRoots: string[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Split a single DB message into multiple Message objects
|
|
29
|
+
* - 1 text message (if text exists)
|
|
30
|
+
* - N media messages (one per attachment)
|
|
31
|
+
* All parts share same groupGuid (original DB guid) and timestamps
|
|
32
|
+
*/
|
|
33
|
+
export declare function splitDBMessage(dbMessage: DBMessage, lineNumber: number, _options: IngestOptions): Message[];
|
|
34
|
+
/**
|
|
35
|
+
* Generate stable part GUID using format: p:<index>/<original_guid>
|
|
36
|
+
* This ensures:
|
|
37
|
+
* - Deterministic generation (same input → same output)
|
|
38
|
+
* - Stable ordering (index reflects order in split)
|
|
39
|
+
* - Uniqueness within a message's parts
|
|
40
|
+
*/
|
|
41
|
+
export declare function generatePartGUID(originalGuid: string, index: number): string;
|
|
42
|
+
/**
|
|
43
|
+
* Convert Apple epoch timestamp to ISO 8601 UTC with Z suffix
|
|
44
|
+
* Apple epoch = seconds since 2001-01-01 00:00:00 UTC
|
|
45
|
+
*
|
|
46
|
+
* Handles:
|
|
47
|
+
* - Seconds precision: 718110777
|
|
48
|
+
* - Milliseconds precision: 718110777000
|
|
49
|
+
* - Nanoseconds precision: 718110777123456789 (truncate to seconds)
|
|
50
|
+
*/
|
|
51
|
+
export declare function convertAppleEpochToISO8601(appleEpoch: number): string | null;
|
|
52
|
+
/**
|
|
53
|
+
* Infer media kind from MIME type
|
|
54
|
+
*/
|
|
55
|
+
export declare function inferMediaKind(mimeType: string): 'image' | 'audio' | 'video' | 'pdf' | 'unknown';
|
|
56
|
+
/**
|
|
57
|
+
* Main entry point: Ingest DB messages and split into normalized schema
|
|
58
|
+
*/
|
|
59
|
+
export declare function ingestDBMessages(dbMessages: DBMessage[], options: IngestOptions): Message[];
|
|
60
|
+
/**
|
|
61
|
+
* Create export envelope for DB ingestion output
|
|
62
|
+
*/
|
|
63
|
+
export declare function createExportEnvelope(messages: Message[]): ExportEnvelope;
|
|
64
|
+
//# sourceMappingURL=ingest-db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-db.d.ts","sourceRoot":"","sources":["../../src/ingest/ingest-db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAEnE,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,WAAW,CAAC,EAAE,YAAY,EAAE,CAAA;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAA;CACzB,CAAA;AASD;;;;;GAKG;AACH,wBAAgB,cAAc,CAC7B,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,aAAa,GACrB,OAAO,EAAE,CAyEX;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA6B5E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC7B,QAAQ,EAAE,MAAM,GACd,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,CASjD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC/B,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,EAAE,aAAa,GACpB,OAAO,EAAE,CAWX;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,cAAc,CAOxE"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apple epoch reference: seconds since 2001-01-01 00:00:00 UTC
|
|
3
|
+
* Unix epoch reference: seconds since 1970-01-01 00:00:00 UTC
|
|
4
|
+
* Difference: 31 years = 978307200 seconds
|
|
5
|
+
*/
|
|
6
|
+
const APPLE_EPOCH_OFFSET = 978307200;
|
|
7
|
+
/**
|
|
8
|
+
* Split a single DB message into multiple Message objects
|
|
9
|
+
* - 1 text message (if text exists)
|
|
10
|
+
* - N media messages (one per attachment)
|
|
11
|
+
* All parts share same groupGuid (original DB guid) and timestamps
|
|
12
|
+
*/
|
|
13
|
+
export function splitDBMessage(dbMessage, lineNumber, _options) {
|
|
14
|
+
const messages = [];
|
|
15
|
+
const originalGuid = dbMessage.guid;
|
|
16
|
+
const attachments = dbMessage.attachments || [];
|
|
17
|
+
const date = convertAppleEpochToISO8601(dbMessage.date);
|
|
18
|
+
const isFromMe = dbMessage.is_from_me === 1;
|
|
19
|
+
if (!date)
|
|
20
|
+
return []; // Skip invalid dates
|
|
21
|
+
// Common fields for all parts
|
|
22
|
+
const baseMessage = {
|
|
23
|
+
isFromMe,
|
|
24
|
+
date,
|
|
25
|
+
groupGuid: originalGuid,
|
|
26
|
+
};
|
|
27
|
+
// Conditionally add optional fields to satisfy exactOptionalPropertyTypes
|
|
28
|
+
if (dbMessage.handle)
|
|
29
|
+
baseMessage.handle = dbMessage.handle;
|
|
30
|
+
if (dbMessage.chat_id)
|
|
31
|
+
baseMessage.chatId = dbMessage.chat_id;
|
|
32
|
+
if (dbMessage.service)
|
|
33
|
+
baseMessage.service = dbMessage.service;
|
|
34
|
+
if (dbMessage.subject)
|
|
35
|
+
baseMessage.subject = dbMessage.subject;
|
|
36
|
+
// Part index counter (0 = text, 1+ = media)
|
|
37
|
+
let partIndex = 0;
|
|
38
|
+
// 1. Create text message if text exists
|
|
39
|
+
if (dbMessage.text) {
|
|
40
|
+
const textMessage = {
|
|
41
|
+
...baseMessage,
|
|
42
|
+
guid: generatePartGUID(originalGuid, partIndex),
|
|
43
|
+
messageKind: 'text',
|
|
44
|
+
text: dbMessage.text,
|
|
45
|
+
exportMetadata: {
|
|
46
|
+
source: 'db',
|
|
47
|
+
lineNumber,
|
|
48
|
+
parentGUID: originalGuid,
|
|
49
|
+
partIndex,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
messages.push(textMessage);
|
|
53
|
+
partIndex++;
|
|
54
|
+
}
|
|
55
|
+
// 2. Create media messages for each attachment
|
|
56
|
+
attachments.forEach((att, attachmentIndex) => {
|
|
57
|
+
const mediaMessage = {
|
|
58
|
+
...baseMessage,
|
|
59
|
+
guid: generatePartGUID(originalGuid, partIndex),
|
|
60
|
+
messageKind: 'media',
|
|
61
|
+
media: {
|
|
62
|
+
id: att.id || `media:${originalGuid}:${attachmentIndex}`,
|
|
63
|
+
filename: att.filename || 'unknown',
|
|
64
|
+
path: att.copied_path || null,
|
|
65
|
+
mimeType: att.mime_type || undefined,
|
|
66
|
+
uti: att.uti || undefined,
|
|
67
|
+
size: att.total_bytes || undefined,
|
|
68
|
+
mediaKind: inferMediaKind(att.mime_type || ''),
|
|
69
|
+
},
|
|
70
|
+
exportMetadata: {
|
|
71
|
+
source: 'db',
|
|
72
|
+
lineNumber,
|
|
73
|
+
parentGUID: originalGuid,
|
|
74
|
+
partIndex,
|
|
75
|
+
attachmentIndex,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
messages.push(mediaMessage);
|
|
79
|
+
partIndex++;
|
|
80
|
+
});
|
|
81
|
+
return messages;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate stable part GUID using format: p:<index>/<original_guid>
|
|
85
|
+
* This ensures:
|
|
86
|
+
* - Deterministic generation (same input → same output)
|
|
87
|
+
* - Stable ordering (index reflects order in split)
|
|
88
|
+
* - Uniqueness within a message's parts
|
|
89
|
+
*/
|
|
90
|
+
export function generatePartGUID(originalGuid, index) {
|
|
91
|
+
return `p:${index}/${originalGuid}`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Convert Apple epoch timestamp to ISO 8601 UTC with Z suffix
|
|
95
|
+
* Apple epoch = seconds since 2001-01-01 00:00:00 UTC
|
|
96
|
+
*
|
|
97
|
+
* Handles:
|
|
98
|
+
* - Seconds precision: 718110777
|
|
99
|
+
* - Milliseconds precision: 718110777000
|
|
100
|
+
* - Nanoseconds precision: 718110777123456789 (truncate to seconds)
|
|
101
|
+
*/
|
|
102
|
+
export function convertAppleEpochToISO8601(appleEpoch) {
|
|
103
|
+
try {
|
|
104
|
+
// Determine if input is in seconds, milliseconds, or nanoseconds
|
|
105
|
+
// Apple epoch realistic ranges:
|
|
106
|
+
// - Seconds: 0 to ~5,000,000,000 (2001 to ~2159)
|
|
107
|
+
// - Milliseconds: 0 to ~5,000,000,000,000 (2001 to ~2159)
|
|
108
|
+
// - Nanoseconds: anything > 1e15
|
|
109
|
+
let seconds;
|
|
110
|
+
if (appleEpoch > 1000000000000000) {
|
|
111
|
+
// Clearly nanoseconds (> 1 quadrillion)
|
|
112
|
+
seconds = Math.floor(appleEpoch / 1000000000);
|
|
113
|
+
}
|
|
114
|
+
else if (appleEpoch > 100000000000) {
|
|
115
|
+
// Likely milliseconds (> 100 billion, beyond realistic seconds range)
|
|
116
|
+
seconds = Math.floor(appleEpoch / 1000);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// Seconds (includes values up to ~5 billion, covering years 2001-2159)
|
|
120
|
+
seconds = appleEpoch;
|
|
121
|
+
}
|
|
122
|
+
// Convert Apple epoch to Unix epoch
|
|
123
|
+
const unixSeconds = seconds + APPLE_EPOCH_OFFSET;
|
|
124
|
+
// Create Date and convert to ISO 8601
|
|
125
|
+
const date = new Date(unixSeconds * 1000);
|
|
126
|
+
return date.toISOString();
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Infer media kind from MIME type
|
|
134
|
+
*/
|
|
135
|
+
export function inferMediaKind(mimeType) {
|
|
136
|
+
if (!mimeType)
|
|
137
|
+
return 'unknown';
|
|
138
|
+
if (mimeType.startsWith('image/'))
|
|
139
|
+
return 'image';
|
|
140
|
+
if (mimeType.startsWith('audio/'))
|
|
141
|
+
return 'audio';
|
|
142
|
+
if (mimeType.startsWith('video/'))
|
|
143
|
+
return 'video';
|
|
144
|
+
if (mimeType.includes('pdf'))
|
|
145
|
+
return 'pdf';
|
|
146
|
+
return 'unknown';
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Main entry point: Ingest DB messages and split into normalized schema
|
|
150
|
+
*/
|
|
151
|
+
export function ingestDBMessages(dbMessages, options) {
|
|
152
|
+
const messages = [];
|
|
153
|
+
let lineNumber = 1;
|
|
154
|
+
for (const dbMsg of dbMessages) {
|
|
155
|
+
const splitMessages = splitDBMessage(dbMsg, lineNumber, options);
|
|
156
|
+
messages.push(...splitMessages);
|
|
157
|
+
lineNumber++;
|
|
158
|
+
}
|
|
159
|
+
return messages;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Create export envelope for DB ingestion output
|
|
163
|
+
*/
|
|
164
|
+
export function createExportEnvelope(messages) {
|
|
165
|
+
return {
|
|
166
|
+
schemaVersion: '2.0.0',
|
|
167
|
+
source: 'db',
|
|
168
|
+
createdAt: new Date().toISOString(),
|
|
169
|
+
messages,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=ingest-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest-db.js","sourceRoot":"","sources":["../../src/ingest/ingest-db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Message } from '#schema/message';
|
|
2
|
+
type ScoredCandidate = {
|
|
3
|
+
message: Message;
|
|
4
|
+
score: number;
|
|
5
|
+
reasons: string[];
|
|
6
|
+
};
|
|
7
|
+
type AmbiguousLink = {
|
|
8
|
+
messageGuid: string;
|
|
9
|
+
selectedTarget: string;
|
|
10
|
+
candidates: ScoredCandidate[];
|
|
11
|
+
tieCount: number;
|
|
12
|
+
confidenceScore: number;
|
|
13
|
+
};
|
|
14
|
+
type LinkingOptions = {
|
|
15
|
+
trackAmbiguous?: boolean;
|
|
16
|
+
minConfidenceThreshold?: number;
|
|
17
|
+
};
|
|
18
|
+
type LinkingResult = {
|
|
19
|
+
messages: Message[];
|
|
20
|
+
ambiguousLinks?: AmbiguousLink[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* AC01 + AC02: Link replies to their parent messages
|
|
24
|
+
*
|
|
25
|
+
* Primary: DB association_guid when present
|
|
26
|
+
* Fallback: Heuristics using timestamp and content matching
|
|
27
|
+
*/
|
|
28
|
+
export declare function linkRepliesToParents(messages: Message[], options?: LinkingOptions): Message[] | LinkingResult;
|
|
29
|
+
/**
|
|
30
|
+
* AC03: Link tapbacks to their parent messages
|
|
31
|
+
*
|
|
32
|
+
* Primary: DB association_guid when present
|
|
33
|
+
* Fallback: Heuristics preferring media messages
|
|
34
|
+
*/
|
|
35
|
+
export declare function linkTapbacksToParents(messages: Message[], options?: LinkingOptions): Message[] | LinkingResult;
|
|
36
|
+
/**
|
|
37
|
+
* AC04: Detect and report ambiguous links with confidence scores
|
|
38
|
+
*/
|
|
39
|
+
export declare function detectAmbiguousLinks(messages: Message[]): {
|
|
40
|
+
tieCount: number;
|
|
41
|
+
ambiguousMessages: {
|
|
42
|
+
messageGuid: string;
|
|
43
|
+
selectedTarget: string;
|
|
44
|
+
tieCount: number;
|
|
45
|
+
topCandidates: {
|
|
46
|
+
guid: string;
|
|
47
|
+
score: number;
|
|
48
|
+
reasons: string[];
|
|
49
|
+
}[];
|
|
50
|
+
}[];
|
|
51
|
+
};
|
|
52
|
+
export type { LinkingResult, AmbiguousLink };
|
|
53
|
+
//# sourceMappingURL=link-replies-and-tapbacks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-replies-and-tapbacks.d.ts","sourceRoot":"","sources":["../../src/ingest/link-replies-and-tapbacks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAiB9C,KAAK,eAAe,GAAG;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AAED,KAAK,aAAa,GAAG;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,KAAK,cAAc,GAAG;IACrB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAC/B,CAAA;AAED,KAAK,aAAa,GAAG;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,cAAc,CAAC,EAAE,aAAa,EAAE,CAAA;CAChC,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,GAAE,cAAmB,GAC1B,OAAO,EAAE,GAAG,aAAa,CAuF3B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,GAAE,cAAmB,GAC1B,OAAO,EAAE,GAAG,aAAa,CAkF3B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE;;;;;;;;;;;;EA0BvD;AA2PD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,CAAA"}
|