@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,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render-Markdown Integration Module (RENDER--T04)
|
|
3
|
+
*
|
|
4
|
+
* Deterministic rendering pipeline:
|
|
5
|
+
* - AC01: Snapshot tests for fixed input → identical output
|
|
6
|
+
* - AC02: No network calls during rendering
|
|
7
|
+
* - AC03: Deterministic ordering of same-timestamp messages
|
|
8
|
+
* - AC04: Reproducible markdown structure
|
|
9
|
+
* - AC05: Performance validation (1000 messages in <10s)
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { renderAllEnrichments } from './embeds-blockquotes.js';
|
|
13
|
+
import { getDatesSorted, groupMessagesByDateAndTimeOfDay } from './grouping.js';
|
|
14
|
+
import { formatReplyThread } from './reply-rendering.js';
|
|
15
|
+
/**
|
|
16
|
+
* Deterministic UTC-time formatter (HH:mm:ss, 00-23 hour range)
|
|
17
|
+
* Uses getUTCHours()/getUTCMinutes()/getUTCSeconds() to ensure consistent output across timezones.
|
|
18
|
+
* CI and local machines will produce identical snapshots regardless of system timezone.
|
|
19
|
+
*/
|
|
20
|
+
function formatTimeLocal(iso) {
|
|
21
|
+
const d = new Date(iso);
|
|
22
|
+
const hh = String(d.getUTCHours()).padStart(2, '0');
|
|
23
|
+
const mm = String(d.getUTCMinutes()).padStart(2, '0');
|
|
24
|
+
const ss = String(d.getUTCSeconds()).padStart(2, '0');
|
|
25
|
+
return `${hh}:${mm}:${ss}`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Main render function: Convert messages to markdown files
|
|
29
|
+
* Returns Map<date, markdown> with deterministic output
|
|
30
|
+
*/
|
|
31
|
+
export function renderMessages(messages) {
|
|
32
|
+
// Normalize all message dates to canonical UTC ISO (YYYY-MM-DDTHH:mm:ss.sssZ)
|
|
33
|
+
// This prevents environment-specific parsing differences for inputs lacking 'Z'.
|
|
34
|
+
const normalized = messages.map((m) => {
|
|
35
|
+
const raw = m.date;
|
|
36
|
+
// If the timestamp lacks any timezone designator (no 'Z' and no +/- offset),
|
|
37
|
+
// interpret it as UTC by appending 'Z' rather than relying on local timezone.
|
|
38
|
+
const hasZ = /Z$/.test(raw);
|
|
39
|
+
const hasOffset = /[+-]\d{2}:?\d{2}$/.test(raw);
|
|
40
|
+
const coerced = hasZ || hasOffset ? raw : `${raw.replace(/\s+$/, '')}Z`;
|
|
41
|
+
// Now coerce to canonical ISO string in UTC
|
|
42
|
+
const iso = new Date(coerced).toISOString();
|
|
43
|
+
return { ...m, date: iso };
|
|
44
|
+
});
|
|
45
|
+
// Sort messages deterministically by timestamp, then by GUID
|
|
46
|
+
const sorted = sortMessagesByTimestamp(normalized);
|
|
47
|
+
// Group by date and time-of-day
|
|
48
|
+
const grouped = groupMessagesByDateAndTimeOfDay(sorted);
|
|
49
|
+
// Render each date
|
|
50
|
+
const output = new Map();
|
|
51
|
+
const dates = getDatesSorted(grouped);
|
|
52
|
+
for (const date of dates) {
|
|
53
|
+
const dayGroup = grouped[date];
|
|
54
|
+
if (dayGroup) {
|
|
55
|
+
const markdown = renderDateSection(date, dayGroup, sorted);
|
|
56
|
+
if (markdown) {
|
|
57
|
+
output.set(date, markdown);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return output;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Render a single date section with all messages for that day
|
|
65
|
+
*/
|
|
66
|
+
function renderDateSection(date, timeOfDayGroup, allMessages) {
|
|
67
|
+
const sections = [];
|
|
68
|
+
// Header
|
|
69
|
+
sections.push(`# ${date}`);
|
|
70
|
+
sections.push('');
|
|
71
|
+
// Morning section
|
|
72
|
+
if (timeOfDayGroup.morning.length > 0) {
|
|
73
|
+
sections.push('## Morning (00:00 - 11:59)');
|
|
74
|
+
sections.push(renderTimeOfDayMessages(timeOfDayGroup.morning, allMessages));
|
|
75
|
+
sections.push('');
|
|
76
|
+
}
|
|
77
|
+
// Afternoon section
|
|
78
|
+
if (timeOfDayGroup.afternoon.length > 0) {
|
|
79
|
+
sections.push('## Afternoon (12:00 - 17:59)');
|
|
80
|
+
sections.push(renderTimeOfDayMessages(timeOfDayGroup.afternoon, allMessages));
|
|
81
|
+
sections.push('');
|
|
82
|
+
}
|
|
83
|
+
// Evening section
|
|
84
|
+
if (timeOfDayGroup.evening.length > 0) {
|
|
85
|
+
sections.push('## Evening (18:00 - 23:59)');
|
|
86
|
+
sections.push(renderTimeOfDayMessages(timeOfDayGroup.evening, allMessages));
|
|
87
|
+
sections.push('');
|
|
88
|
+
}
|
|
89
|
+
return sections.join('\n').trim();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Render all messages for a specific time-of-day group
|
|
93
|
+
*/
|
|
94
|
+
function renderTimeOfDayMessages(messages, allMessages) {
|
|
95
|
+
const parts = [];
|
|
96
|
+
for (const message of messages) {
|
|
97
|
+
const rendered = renderSingleMessage(message, allMessages);
|
|
98
|
+
if (rendered) {
|
|
99
|
+
parts.push(rendered);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return parts.join('\n\n');
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Render a single message with all its enrichments and replies
|
|
106
|
+
*/
|
|
107
|
+
function renderSingleMessage(message, allMessages) {
|
|
108
|
+
const parts = [];
|
|
109
|
+
// Message anchor for deep linking
|
|
110
|
+
const anchor = `[#${message.guid}](#msg-${message.guid})`;
|
|
111
|
+
// Message header with timestamp and sender
|
|
112
|
+
const time = formatTimeLocal(message.date);
|
|
113
|
+
const header = `${anchor} **${message.handle || 'Unknown'}** [${time}]`;
|
|
114
|
+
parts.push(header);
|
|
115
|
+
// Message text
|
|
116
|
+
if (message.text) {
|
|
117
|
+
parts.push(message.text);
|
|
118
|
+
}
|
|
119
|
+
// Render embeds and enrichments
|
|
120
|
+
const enrichments = renderAllEnrichments(message);
|
|
121
|
+
if (enrichments.embeds.length > 0) {
|
|
122
|
+
parts.push(...enrichments.embeds);
|
|
123
|
+
}
|
|
124
|
+
if (enrichments.transcriptions.length > 0) {
|
|
125
|
+
parts.push('**Transcription:**');
|
|
126
|
+
parts.push(...enrichments.transcriptions);
|
|
127
|
+
}
|
|
128
|
+
if (enrichments.linkContexts.length > 0) {
|
|
129
|
+
parts.push('**Link Context:**');
|
|
130
|
+
parts.push(...enrichments.linkContexts);
|
|
131
|
+
}
|
|
132
|
+
if (enrichments.pdfSummaries.length > 0) {
|
|
133
|
+
parts.push('**PDF Summary:**');
|
|
134
|
+
parts.push(...enrichments.pdfSummaries);
|
|
135
|
+
}
|
|
136
|
+
// Render replies
|
|
137
|
+
const replies = formatReplyThread(message.guid, allMessages);
|
|
138
|
+
if (replies && replies.replies.length > 0) {
|
|
139
|
+
parts.push('**Replies:**');
|
|
140
|
+
for (const reply of replies.replies) {
|
|
141
|
+
parts.push(reply.formatted);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Render tapbacks
|
|
145
|
+
if (replies && replies.tapbacks.length > 0) {
|
|
146
|
+
parts.push(`**Reactions:** ${replies.tapbacks.join(' ')}`);
|
|
147
|
+
}
|
|
148
|
+
return parts.join('\n');
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Sort messages deterministically by timestamp, then by GUID
|
|
152
|
+
* Ensures same-timestamp messages are ordered consistently
|
|
153
|
+
*/
|
|
154
|
+
export function sortMessagesByTimestamp(messages) {
|
|
155
|
+
return [...messages].sort((a, b) => {
|
|
156
|
+
const timeA = new Date(a.date).getTime();
|
|
157
|
+
const timeB = new Date(b.date).getTime();
|
|
158
|
+
if (timeA !== timeB) {
|
|
159
|
+
return timeA - timeB;
|
|
160
|
+
}
|
|
161
|
+
// Same timestamp: sort by GUID for deterministic ordering
|
|
162
|
+
return a.guid.localeCompare(b.guid);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Generate deterministic hash of rendered output
|
|
167
|
+
* Uses SHA-256 of concatenated message data
|
|
168
|
+
*/
|
|
169
|
+
export function getMessageHash(messages) {
|
|
170
|
+
const sorted = sortMessagesByTimestamp(messages);
|
|
171
|
+
const data = JSON.stringify(sorted);
|
|
172
|
+
return createHash('sha256').update(data).digest('hex');
|
|
173
|
+
}
|
|
174
|
+
export function verifyDeterminism(messages, runsCount = 5) {
|
|
175
|
+
const outputs = [];
|
|
176
|
+
const hashes = [];
|
|
177
|
+
for (let i = 0; i < runsCount; i++) {
|
|
178
|
+
const output = renderMessages(messages);
|
|
179
|
+
const hash = getMessageHash(messages);
|
|
180
|
+
outputs.push(output);
|
|
181
|
+
hashes.push(hash);
|
|
182
|
+
}
|
|
183
|
+
// Check if all hashes are identical
|
|
184
|
+
const firstHash = hashes[0];
|
|
185
|
+
const hashesAreIdentical = hashes.every((h) => h === firstHash);
|
|
186
|
+
// Check if all outputs are identical
|
|
187
|
+
const firstOutput = outputs[0];
|
|
188
|
+
if (!firstOutput) {
|
|
189
|
+
return {
|
|
190
|
+
isDeterministic: false,
|
|
191
|
+
runsCount,
|
|
192
|
+
hashesAreIdentical,
|
|
193
|
+
outputsAreIdentical: false,
|
|
194
|
+
hashes,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const outputsAreIdentical = outputs.every((output) => {
|
|
198
|
+
if (output.size !== firstOutput.size)
|
|
199
|
+
return false;
|
|
200
|
+
for (const [key, value] of firstOutput.entries()) {
|
|
201
|
+
if (output.get(key) !== value)
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
isDeterministic: hashesAreIdentical && outputsAreIdentical,
|
|
208
|
+
runsCount,
|
|
209
|
+
hashesAreIdentical,
|
|
210
|
+
outputsAreIdentical,
|
|
211
|
+
hashes,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Validate markdown structure
|
|
216
|
+
* Ensures proper formatting and no encoding issues
|
|
217
|
+
*/
|
|
218
|
+
export function validateMarkdownStructure(markdown) {
|
|
219
|
+
if (!markdown || markdown.trim().length === 0) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
// Check for basic markdown structure
|
|
223
|
+
const _hasHeader = /^#\s+/m.test(markdown);
|
|
224
|
+
const _hasSections = /^##\s+/m.test(markdown);
|
|
225
|
+
if (markdown.includes('Morning') ||
|
|
226
|
+
markdown.includes('Afternoon') ||
|
|
227
|
+
markdown.includes('Evening')) {
|
|
228
|
+
// Should have at least basic structure
|
|
229
|
+
if (markdown.length > 100) {
|
|
230
|
+
// Don't require headers for very small content
|
|
231
|
+
// but validate that structure exists
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Verify no unescaped newlines in critical places
|
|
235
|
+
const lines = markdown.split('\n');
|
|
236
|
+
for (const line of lines) {
|
|
237
|
+
// Each line should be valid UTF-8
|
|
238
|
+
const buffer = Buffer.from(line, 'utf-8');
|
|
239
|
+
const decoded = buffer.toString('utf-8');
|
|
240
|
+
if (decoded !== line) {
|
|
241
|
+
throw new Error(`Invalid UTF-8 in markdown: ${line}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/render/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reply and Tapback Rendering Module (RENDER--T02)
|
|
3
|
+
*
|
|
4
|
+
* Implements nested reply and tapback rendering:
|
|
5
|
+
* - AC01: Render replies as nested blockquotes (> prefix)
|
|
6
|
+
* - AC02: Render tapbacks as emoji reactions with mapping
|
|
7
|
+
* - AC03: Handle multi-level nesting (reply to reply)
|
|
8
|
+
* - AC04: Indent levels match conversation depth (2 spaces per level)
|
|
9
|
+
* - AC05: Preserve sender attribution in nested content
|
|
10
|
+
*/
|
|
11
|
+
import type { Message } from '#schema/message';
|
|
12
|
+
/**
|
|
13
|
+
* Reply context for rendering
|
|
14
|
+
*/
|
|
15
|
+
export type ReplyContext = {
|
|
16
|
+
message: Message;
|
|
17
|
+
parentGuid: string;
|
|
18
|
+
depth: number;
|
|
19
|
+
children?: ReplyContext[];
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Tapback context for rendering
|
|
23
|
+
*/
|
|
24
|
+
export type TapbackContext = {
|
|
25
|
+
message: Message;
|
|
26
|
+
parentGuid: string;
|
|
27
|
+
type: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* AC02: Map tapback type to emoji
|
|
31
|
+
*/
|
|
32
|
+
export declare function getTapbackEmoji(tapbackType: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* AC01: Find all replies to a specific message
|
|
35
|
+
*/
|
|
36
|
+
export declare function findRepliesForMessage(parentGuid: string, messages: Message[]): Message[];
|
|
37
|
+
/**
|
|
38
|
+
* AC02: Find all tapbacks for a specific message
|
|
39
|
+
*/
|
|
40
|
+
export declare function findTapbacksForMessage(parentGuid: string, messages: Message[]): Message[];
|
|
41
|
+
/**
|
|
42
|
+
* AC04: Calculate indentation level (how deep in the reply chain)
|
|
43
|
+
*/
|
|
44
|
+
export declare function calculateIndentationLevel(messageGuid: string, messages: Message[]): number;
|
|
45
|
+
/**
|
|
46
|
+
* AC04: Format reply with proper indentation (2 spaces per level)
|
|
47
|
+
* Returns prefix for blockquote (>, > >, > > >, etc.)
|
|
48
|
+
*/
|
|
49
|
+
export declare function formatReplyWithIndentation(_message: Message, level: number): string;
|
|
50
|
+
/**
|
|
51
|
+
* AC01, AC05: Render reply as nested blockquote with sender attribution
|
|
52
|
+
*/
|
|
53
|
+
export declare function renderReplyAsBlockquote(message: Message, level: number): string;
|
|
54
|
+
/**
|
|
55
|
+
* AC02: Render tapback as emoji
|
|
56
|
+
*/
|
|
57
|
+
export declare function renderTapbackAsEmoji(message: Message): string;
|
|
58
|
+
/**
|
|
59
|
+
* AC03: Build reply tree structure for a message
|
|
60
|
+
*/
|
|
61
|
+
export type ReplyTree = {
|
|
62
|
+
message: Message;
|
|
63
|
+
guid: string;
|
|
64
|
+
children: ReplyTree[];
|
|
65
|
+
};
|
|
66
|
+
export declare function buildReplyTree(parentGuid: string, messages: Message[]): ReplyTree | null;
|
|
67
|
+
/**
|
|
68
|
+
* Group tapbacks by type
|
|
69
|
+
*/
|
|
70
|
+
export declare function getTapbacksGrouped(parentGuid: string, messages: Message[]): Record<string, Message[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Get all reply depths for traversal
|
|
73
|
+
*/
|
|
74
|
+
export declare function getReplyChain(messageGuid: string, messages: Message[]): Message[];
|
|
75
|
+
/**
|
|
76
|
+
* Format complete reply thread for rendering
|
|
77
|
+
*/
|
|
78
|
+
export type FormattedReplyThread = {
|
|
79
|
+
parentMessage: Message;
|
|
80
|
+
replies: Array<{
|
|
81
|
+
message: Message;
|
|
82
|
+
level: number;
|
|
83
|
+
formatted: string;
|
|
84
|
+
}>;
|
|
85
|
+
tapbacks: string[];
|
|
86
|
+
};
|
|
87
|
+
export declare function formatReplyThread(parentGuid: string, messages: Message[]): FormattedReplyThread | null;
|
|
88
|
+
//# sourceMappingURL=reply-rendering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-rendering.d.ts","sourceRoot":"","sources":["../../src/render/reply-rendering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAE9C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAA;CACzB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;CACZ,CAAA;AAcD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,EAAE,GACjB,OAAO,EAAE,CAIX;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,EAAE,GACjB,OAAO,EAAE,CAMX;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACxC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,OAAO,EAAE,GACjB,MAAM,CAwBR;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,MAAM,GACX,MAAM,CAIR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACtC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GACX,MAAM,CA8BR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAM7D;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG;IACvB,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,EAAE,CAAA;CACrB,CAAA;AAED,wBAAgB,cAAc,CAC7B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,EAAE,GACjB,SAAS,GAAG,IAAI,CAuBlB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,EAAE,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAa3B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC5B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,OAAO,EAAE,GACjB,OAAO,EAAE,CAgBX;AAED;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAClC,aAAa,EAAE,OAAO,CAAA;IACtB,OAAO,EAAE,KAAK,CAAC;QACd,OAAO,EAAE,OAAO,CAAA;QAChB,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,MAAM,CAAA;KACjB,CAAC,CAAA;IACF,QAAQ,EAAE,MAAM,EAAE,CAAA;CAClB,CAAA;AAED,wBAAgB,iBAAiB,CAChC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,EAAE,GACjB,oBAAoB,GAAG,IAAI,CA4C7B"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reply and Tapback Rendering Module (RENDER--T02)
|
|
3
|
+
*
|
|
4
|
+
* Implements nested reply and tapback rendering:
|
|
5
|
+
* - AC01: Render replies as nested blockquotes (> prefix)
|
|
6
|
+
* - AC02: Render tapbacks as emoji reactions with mapping
|
|
7
|
+
* - AC03: Handle multi-level nesting (reply to reply)
|
|
8
|
+
* - AC04: Indent levels match conversation depth (2 spaces per level)
|
|
9
|
+
* - AC05: Preserve sender attribution in nested content
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Tapback type to emoji mapping per spec
|
|
13
|
+
*/
|
|
14
|
+
const TAPBACK_EMOJI_MAP = {
|
|
15
|
+
liked: '❤️',
|
|
16
|
+
loved: '😍',
|
|
17
|
+
laughed: '😂',
|
|
18
|
+
emphasized: '‼️',
|
|
19
|
+
questioned: '❓',
|
|
20
|
+
disliked: '👎',
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* AC02: Map tapback type to emoji
|
|
24
|
+
*/
|
|
25
|
+
export function getTapbackEmoji(tapbackType) {
|
|
26
|
+
return TAPBACK_EMOJI_MAP[tapbackType] || '👍'; // Default to thumbs up
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* AC01: Find all replies to a specific message
|
|
30
|
+
*/
|
|
31
|
+
export function findRepliesForMessage(parentGuid, messages) {
|
|
32
|
+
return messages.filter((msg) => msg.replyingTo?.targetMessageGuid === parentGuid);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* AC02: Find all tapbacks for a specific message
|
|
36
|
+
*/
|
|
37
|
+
export function findTapbacksForMessage(parentGuid, messages) {
|
|
38
|
+
return messages.filter((msg) => msg.messageKind === 'tapback' &&
|
|
39
|
+
msg.tapback?.targetMessageGuid === parentGuid);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* AC04: Calculate indentation level (how deep in the reply chain)
|
|
43
|
+
*/
|
|
44
|
+
export function calculateIndentationLevel(messageGuid, messages) {
|
|
45
|
+
const messageMap = new Map(messages.map((m) => [m.guid, m]));
|
|
46
|
+
const message = messageMap.get(messageGuid);
|
|
47
|
+
if (!message || !message.replyingTo) {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
let level = 1;
|
|
51
|
+
let currentGuid = message.replyingTo?.targetMessageGuid;
|
|
52
|
+
const visited = new Set([messageGuid]); // Prevent infinite loops
|
|
53
|
+
while (currentGuid && !visited.has(currentGuid)) {
|
|
54
|
+
const parent = messageMap.get(currentGuid);
|
|
55
|
+
if (!parent || !parent.replyingTo?.targetMessageGuid) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
visited.add(currentGuid);
|
|
59
|
+
currentGuid = parent.replyingTo.targetMessageGuid;
|
|
60
|
+
level++;
|
|
61
|
+
}
|
|
62
|
+
return level;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* AC04: Format reply with proper indentation (2 spaces per level)
|
|
66
|
+
* Returns prefix for blockquote (>, > >, > > >, etc.)
|
|
67
|
+
*/
|
|
68
|
+
export function formatReplyWithIndentation(_message, level) {
|
|
69
|
+
const indent = ' '.repeat(level * 2);
|
|
70
|
+
const blockquotePrefix = '>'.repeat(level + 1);
|
|
71
|
+
return `${indent}${blockquotePrefix}`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* AC01, AC05: Render reply as nested blockquote with sender attribution
|
|
75
|
+
*/
|
|
76
|
+
export function renderReplyAsBlockquote(message, level) {
|
|
77
|
+
if (message.messageKind !== 'text' && !message.text) {
|
|
78
|
+
return '';
|
|
79
|
+
}
|
|
80
|
+
const indent = ' '.repeat(level * 2);
|
|
81
|
+
const blockquotePrefix = '>'.repeat(level + 1);
|
|
82
|
+
// Build sender attribution
|
|
83
|
+
let senderLine = '';
|
|
84
|
+
if (message.handle) {
|
|
85
|
+
senderLine = `${indent}${blockquotePrefix} **${message.handle}**: `;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
senderLine = `${indent}${blockquotePrefix} `;
|
|
89
|
+
}
|
|
90
|
+
// Add message text with proper line continuation
|
|
91
|
+
const textLines = (message.text || '').split('\n');
|
|
92
|
+
const firstLine = `${senderLine}${textLines[0]}`;
|
|
93
|
+
if (textLines.length === 1) {
|
|
94
|
+
return firstLine;
|
|
95
|
+
}
|
|
96
|
+
// Additional lines get full blockquote prefix
|
|
97
|
+
const additionalLines = textLines
|
|
98
|
+
.slice(1)
|
|
99
|
+
.map((line) => `${indent}${blockquotePrefix} ${line}`);
|
|
100
|
+
return [firstLine, ...additionalLines].join('\n');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* AC02: Render tapback as emoji
|
|
104
|
+
*/
|
|
105
|
+
export function renderTapbackAsEmoji(message) {
|
|
106
|
+
if (message.messageKind !== 'tapback' || !message.tapback) {
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
return getTapbackEmoji(message.tapback.type);
|
|
110
|
+
}
|
|
111
|
+
export function buildReplyTree(parentGuid, messages) {
|
|
112
|
+
const messageMap = new Map(messages.map((m) => [m.guid, m]));
|
|
113
|
+
const message = messageMap.get(parentGuid);
|
|
114
|
+
if (!message) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const children = [];
|
|
118
|
+
const directReplies = findRepliesForMessage(parentGuid, messages);
|
|
119
|
+
for (const reply of directReplies) {
|
|
120
|
+
const child = buildReplyTree(reply.guid, messages);
|
|
121
|
+
if (child) {
|
|
122
|
+
children.push(child);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
message,
|
|
127
|
+
guid: parentGuid,
|
|
128
|
+
children,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Group tapbacks by type
|
|
133
|
+
*/
|
|
134
|
+
export function getTapbacksGrouped(parentGuid, messages) {
|
|
135
|
+
const tapbacks = findTapbacksForMessage(parentGuid, messages);
|
|
136
|
+
const grouped = {};
|
|
137
|
+
for (const tapback of tapbacks) {
|
|
138
|
+
const type = tapback.tapback?.type || 'unknown';
|
|
139
|
+
if (!grouped[type]) {
|
|
140
|
+
grouped[type] = [];
|
|
141
|
+
}
|
|
142
|
+
grouped[type].push(tapback);
|
|
143
|
+
}
|
|
144
|
+
return grouped;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get all reply depths for traversal
|
|
148
|
+
*/
|
|
149
|
+
export function getReplyChain(messageGuid, messages) {
|
|
150
|
+
const messageMap = new Map(messages.map((m) => [m.guid, m]));
|
|
151
|
+
const chain = [];
|
|
152
|
+
let currentGuid = messageGuid;
|
|
153
|
+
const visited = new Set();
|
|
154
|
+
while (currentGuid && !visited.has(currentGuid)) {
|
|
155
|
+
const msg = messageMap.get(currentGuid);
|
|
156
|
+
if (!msg)
|
|
157
|
+
break;
|
|
158
|
+
chain.unshift(msg); // Add to beginning
|
|
159
|
+
visited.add(currentGuid);
|
|
160
|
+
currentGuid = msg.replyingTo?.targetMessageGuid;
|
|
161
|
+
}
|
|
162
|
+
return chain;
|
|
163
|
+
}
|
|
164
|
+
export function formatReplyThread(parentGuid, messages) {
|
|
165
|
+
const messageMap = new Map(messages.map((m) => [m.guid, m]));
|
|
166
|
+
const parentMessage = messageMap.get(parentGuid);
|
|
167
|
+
if (!parentMessage) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
// Collect all direct replies and their nested replies
|
|
171
|
+
const replies = [];
|
|
172
|
+
const collectReplies = (parent, baseLevel) => {
|
|
173
|
+
const directReplies = findRepliesForMessage(parent, messages);
|
|
174
|
+
for (const reply of directReplies) {
|
|
175
|
+
const level = baseLevel + 1;
|
|
176
|
+
const formatted = renderReplyAsBlockquote(reply, level);
|
|
177
|
+
replies.push({
|
|
178
|
+
message: reply,
|
|
179
|
+
level,
|
|
180
|
+
formatted,
|
|
181
|
+
});
|
|
182
|
+
// Recursively collect nested replies
|
|
183
|
+
collectReplies(reply.guid, level);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
collectReplies(parentGuid, 0);
|
|
187
|
+
// Get tapbacks
|
|
188
|
+
const tapbackMessages = findTapbacksForMessage(parentGuid, messages);
|
|
189
|
+
const tapbacks = tapbackMessages.map((t) => renderTapbackAsEmoji(t));
|
|
190
|
+
return {
|
|
191
|
+
parentMessage,
|
|
192
|
+
replies,
|
|
193
|
+
tapbacks,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=reply-rendering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply-rendering.js","sourceRoot":"","sources":["../../src/render/reply-rendering.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export type MessageGUID = string;
|
|
3
|
+
export type ChatId = string;
|
|
4
|
+
export type MediaKind = 'image' | 'audio' | 'video' | 'pdf' | 'unknown';
|
|
5
|
+
export type MediaEnrichment = {
|
|
6
|
+
kind: MediaKind | 'link' | 'transcription' | 'pdf_summary' | 'video_metadata' | 'link_context' | 'image_analysis';
|
|
7
|
+
model?: string;
|
|
8
|
+
createdAt: string;
|
|
9
|
+
visionSummary?: string;
|
|
10
|
+
shortDescription?: string;
|
|
11
|
+
transcription?: string;
|
|
12
|
+
transcript?: string;
|
|
13
|
+
speakers?: string[];
|
|
14
|
+
timestamps?: Array<{
|
|
15
|
+
time: string;
|
|
16
|
+
speaker: string;
|
|
17
|
+
content: string;
|
|
18
|
+
}>;
|
|
19
|
+
pdfSummary?: string;
|
|
20
|
+
videoMetadata?: {
|
|
21
|
+
filename?: string;
|
|
22
|
+
size?: number;
|
|
23
|
+
duration?: number;
|
|
24
|
+
analyzed?: boolean;
|
|
25
|
+
note?: string;
|
|
26
|
+
};
|
|
27
|
+
error?: string;
|
|
28
|
+
usedFallback?: boolean;
|
|
29
|
+
failedProviders?: string[];
|
|
30
|
+
url?: string;
|
|
31
|
+
title?: string;
|
|
32
|
+
summary?: string;
|
|
33
|
+
provider: 'gemini' | 'firecrawl' | 'local' | 'youtube' | 'spotify' | 'twitter' | 'instagram' | 'generic';
|
|
34
|
+
version: string;
|
|
35
|
+
};
|
|
36
|
+
export type MediaProvenance = {
|
|
37
|
+
source: 'csv' | 'db' | 'merged';
|
|
38
|
+
lastSeen: string;
|
|
39
|
+
resolvedAt: string;
|
|
40
|
+
};
|
|
41
|
+
export type MediaMeta = {
|
|
42
|
+
id: string;
|
|
43
|
+
filename: string;
|
|
44
|
+
path: string;
|
|
45
|
+
size?: number;
|
|
46
|
+
mimeType?: string;
|
|
47
|
+
uti?: string | null;
|
|
48
|
+
isSticker?: boolean;
|
|
49
|
+
hidden?: boolean;
|
|
50
|
+
mediaKind?: MediaKind;
|
|
51
|
+
enrichment?: Array<MediaEnrichment>;
|
|
52
|
+
provenance?: MediaProvenance;
|
|
53
|
+
};
|
|
54
|
+
export type ReplyInfo = {
|
|
55
|
+
sender?: string;
|
|
56
|
+
date?: string;
|
|
57
|
+
text?: string;
|
|
58
|
+
targetMessageGuid?: MessageGUID;
|
|
59
|
+
};
|
|
60
|
+
export type TapbackInfo = {
|
|
61
|
+
type: 'loved' | 'liked' | 'disliked' | 'laughed' | 'emphasized' | 'questioned' | 'emoji';
|
|
62
|
+
action: 'added' | 'removed';
|
|
63
|
+
targetMessageGuid?: MessageGUID;
|
|
64
|
+
targetMessagePart?: number;
|
|
65
|
+
targetText?: string;
|
|
66
|
+
isMedia?: boolean;
|
|
67
|
+
emoji?: string;
|
|
68
|
+
};
|
|
69
|
+
export type MessageCore = {
|
|
70
|
+
guid: MessageGUID;
|
|
71
|
+
rowid?: number;
|
|
72
|
+
chatId?: ChatId | null;
|
|
73
|
+
service?: string | null;
|
|
74
|
+
subject?: string | null;
|
|
75
|
+
handleId?: number | null;
|
|
76
|
+
handle?: string | null;
|
|
77
|
+
destinationCallerId?: string | null;
|
|
78
|
+
isFromMe: boolean;
|
|
79
|
+
otherHandle?: number | null;
|
|
80
|
+
date: string;
|
|
81
|
+
dateRead?: string | null;
|
|
82
|
+
dateDelivered?: string | null;
|
|
83
|
+
dateEdited?: string | null;
|
|
84
|
+
isRead?: boolean;
|
|
85
|
+
itemType?: number;
|
|
86
|
+
groupActionType?: number;
|
|
87
|
+
groupTitle?: string | null;
|
|
88
|
+
shareStatus?: boolean;
|
|
89
|
+
shareDirection?: boolean | null;
|
|
90
|
+
expressiveSendStyleId?: string | null;
|
|
91
|
+
balloonBundleId?: string | null;
|
|
92
|
+
threadOriginatorGuid?: string | null;
|
|
93
|
+
threadOriginatorPart?: number | null;
|
|
94
|
+
numReplies?: number;
|
|
95
|
+
deletedFrom?: number | null;
|
|
96
|
+
};
|
|
97
|
+
export type Message = {
|
|
98
|
+
messageKind: 'text' | 'media' | 'tapback' | 'notification';
|
|
99
|
+
text?: string | null;
|
|
100
|
+
tapback?: TapbackInfo | null;
|
|
101
|
+
replyingTo?: ReplyInfo | null;
|
|
102
|
+
replyingToRaw?: string | null;
|
|
103
|
+
media?: MediaMeta | null;
|
|
104
|
+
groupGuid?: string | null;
|
|
105
|
+
exportTimestamp?: string;
|
|
106
|
+
exportVersion?: string;
|
|
107
|
+
isUnsent?: boolean;
|
|
108
|
+
isEdited?: boolean;
|
|
109
|
+
} & MessageCore;
|
|
110
|
+
export type ExportEnvelope = {
|
|
111
|
+
schemaVersion: string;
|
|
112
|
+
source: 'csv' | 'db' | 'merged';
|
|
113
|
+
createdAt: string;
|
|
114
|
+
messages: Array<Message>;
|
|
115
|
+
meta?: Record<string, unknown>;
|
|
116
|
+
};
|
|
117
|
+
export declare const MediaEnrichmentSchema: z.ZodType<MediaEnrichment>;
|
|
118
|
+
export declare const MediaProvenanceSchema: z.ZodType<MediaProvenance>;
|
|
119
|
+
export declare const MediaMetaSchema: z.ZodType<MediaMeta>;
|
|
120
|
+
export declare const ReplyInfoSchema: z.ZodType<ReplyInfo>;
|
|
121
|
+
export declare const TapbackInfoSchema: z.ZodType<TapbackInfo>;
|
|
122
|
+
export declare const MessageCoreSchema: z.ZodType<MessageCore>;
|
|
123
|
+
export declare const MessageSchema: z.ZodType<Message>;
|
|
124
|
+
export declare const ExportEnvelopeSchema: z.ZodType<ExportEnvelope>;
|
|
125
|
+
//# sourceMappingURL=message.d.ts.map
|