@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.
Files changed (216) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1535 -0
  4. package/dist/bin/index.js +5121 -0
  5. package/dist/cli/commands/clean.d.ts +17 -0
  6. package/dist/cli/commands/clean.d.ts.map +1 -0
  7. package/dist/cli/commands/clean.js +142 -0
  8. package/dist/cli/commands/clean.js.map +1 -0
  9. package/dist/cli/commands/doctor.d.ts +17 -0
  10. package/dist/cli/commands/doctor.d.ts.map +1 -0
  11. package/dist/cli/commands/doctor.js +202 -0
  12. package/dist/cli/commands/doctor.js.map +1 -0
  13. package/dist/cli/commands/enrich-ai.d.ts +17 -0
  14. package/dist/cli/commands/enrich-ai.d.ts.map +1 -0
  15. package/dist/cli/commands/enrich-ai.js +371 -0
  16. package/dist/cli/commands/enrich-ai.js.map +1 -0
  17. package/dist/cli/commands/index.d.ts +16 -0
  18. package/dist/cli/commands/index.d.ts.map +1 -0
  19. package/dist/cli/commands/index.js +16 -0
  20. package/dist/cli/commands/index.js.map +1 -0
  21. package/dist/cli/commands/ingest-csv.d.ts +17 -0
  22. package/dist/cli/commands/ingest-csv.d.ts.map +1 -0
  23. package/dist/cli/commands/ingest-csv.js +138 -0
  24. package/dist/cli/commands/ingest-csv.js.map +1 -0
  25. package/dist/cli/commands/ingest-db.d.ts +17 -0
  26. package/dist/cli/commands/ingest-db.d.ts.map +1 -0
  27. package/dist/cli/commands/ingest-db.js +159 -0
  28. package/dist/cli/commands/ingest-db.js.map +1 -0
  29. package/dist/cli/commands/init.d.ts +17 -0
  30. package/dist/cli/commands/init.d.ts.map +1 -0
  31. package/dist/cli/commands/init.js +110 -0
  32. package/dist/cli/commands/init.js.map +1 -0
  33. package/dist/cli/commands/normalize-link.d.ts +16 -0
  34. package/dist/cli/commands/normalize-link.d.ts.map +1 -0
  35. package/dist/cli/commands/normalize-link.js +144 -0
  36. package/dist/cli/commands/normalize-link.js.map +1 -0
  37. package/dist/cli/commands/render-markdown.d.ts +17 -0
  38. package/dist/cli/commands/render-markdown.d.ts.map +1 -0
  39. package/dist/cli/commands/render-markdown.js +218 -0
  40. package/dist/cli/commands/render-markdown.js.map +1 -0
  41. package/dist/cli/commands/stats.d.ts +17 -0
  42. package/dist/cli/commands/stats.d.ts.map +1 -0
  43. package/dist/cli/commands/stats.js +175 -0
  44. package/dist/cli/commands/stats.js.map +1 -0
  45. package/dist/cli/commands/validate.d.ts +17 -0
  46. package/dist/cli/commands/validate.d.ts.map +1 -0
  47. package/dist/cli/commands/validate.js +152 -0
  48. package/dist/cli/commands/validate.js.map +1 -0
  49. package/dist/cli/index.d.ts +13 -0
  50. package/dist/cli/index.d.ts.map +1 -0
  51. package/dist/cli/index.js +121 -0
  52. package/dist/cli/index.js.map +1 -0
  53. package/dist/cli/types.d.ts +93 -0
  54. package/dist/cli/types.d.ts.map +1 -0
  55. package/dist/cli/types.js +7 -0
  56. package/dist/cli/types.js.map +1 -0
  57. package/dist/cli/utils.d.ts +29 -0
  58. package/dist/cli/utils.d.ts.map +1 -0
  59. package/dist/cli/utils.js +53 -0
  60. package/dist/cli/utils.js.map +1 -0
  61. package/dist/cli.d.ts +9 -0
  62. package/dist/cli.d.ts.map +1 -0
  63. package/dist/cli.js +1805 -0
  64. package/dist/config/generator.d.ts +90 -0
  65. package/dist/config/generator.d.ts.map +1 -0
  66. package/dist/config/generator.js +320 -0
  67. package/dist/config/generator.js.map +1 -0
  68. package/dist/config/loader.d.ts +107 -0
  69. package/dist/config/loader.d.ts.map +1 -0
  70. package/dist/config/loader.js +251 -0
  71. package/dist/config/loader.js.map +1 -0
  72. package/dist/config/schema.d.ts +107 -0
  73. package/dist/config/schema.d.ts.map +1 -0
  74. package/dist/config/schema.js +169 -0
  75. package/dist/config/schema.js.map +1 -0
  76. package/dist/enrich/audio-transcription.d.ts +77 -0
  77. package/dist/enrich/audio-transcription.d.ts.map +1 -0
  78. package/dist/enrich/audio-transcription.js +370 -0
  79. package/dist/enrich/audio-transcription.js.map +1 -0
  80. package/dist/enrich/checkpoint.d.ts +137 -0
  81. package/dist/enrich/checkpoint.d.ts.map +1 -0
  82. package/dist/enrich/checkpoint.js +205 -0
  83. package/dist/enrich/checkpoint.js.map +1 -0
  84. package/dist/enrich/idempotency.d.ts +90 -0
  85. package/dist/enrich/idempotency.d.ts.map +1 -0
  86. package/dist/enrich/idempotency.js +188 -0
  87. package/dist/enrich/idempotency.js.map +1 -0
  88. package/dist/enrich/image-analysis.d.ts +62 -0
  89. package/dist/enrich/image-analysis.d.ts.map +1 -0
  90. package/dist/enrich/image-analysis.js +264 -0
  91. package/dist/enrich/image-analysis.js.map +1 -0
  92. package/dist/enrich/index.d.ts +60 -0
  93. package/dist/enrich/index.d.ts.map +1 -0
  94. package/dist/enrich/index.js +74 -0
  95. package/dist/enrich/index.js.map +1 -0
  96. package/dist/enrich/link-enrichment.d.ts +37 -0
  97. package/dist/enrich/link-enrichment.d.ts.map +1 -0
  98. package/dist/enrich/link-enrichment.js +202 -0
  99. package/dist/enrich/link-enrichment.js.map +1 -0
  100. package/dist/enrich/pdf-video-handling.d.ts +49 -0
  101. package/dist/enrich/pdf-video-handling.d.ts.map +1 -0
  102. package/dist/enrich/pdf-video-handling.js +325 -0
  103. package/dist/enrich/pdf-video-handling.js.map +1 -0
  104. package/dist/enrich/progress-tracker.d.ts +120 -0
  105. package/dist/enrich/progress-tracker.d.ts.map +1 -0
  106. package/dist/enrich/progress-tracker.js +220 -0
  107. package/dist/enrich/progress-tracker.js.map +1 -0
  108. package/dist/enrich/providers/firecrawl.d.ts +18 -0
  109. package/dist/enrich/providers/firecrawl.d.ts.map +1 -0
  110. package/dist/enrich/providers/firecrawl.js +48 -0
  111. package/dist/enrich/providers/firecrawl.js.map +1 -0
  112. package/dist/enrich/providers/generic.d.ts +16 -0
  113. package/dist/enrich/providers/generic.d.ts.map +1 -0
  114. package/dist/enrich/providers/generic.js +36 -0
  115. package/dist/enrich/providers/generic.js.map +1 -0
  116. package/dist/enrich/providers/index.d.ts +14 -0
  117. package/dist/enrich/providers/index.d.ts.map +1 -0
  118. package/dist/enrich/providers/index.js +13 -0
  119. package/dist/enrich/providers/index.js.map +1 -0
  120. package/dist/enrich/providers/instagram.d.ts +16 -0
  121. package/dist/enrich/providers/instagram.d.ts.map +1 -0
  122. package/dist/enrich/providers/instagram.js +43 -0
  123. package/dist/enrich/providers/instagram.js.map +1 -0
  124. package/dist/enrich/providers/spotify.d.ts +16 -0
  125. package/dist/enrich/providers/spotify.d.ts.map +1 -0
  126. package/dist/enrich/providers/spotify.js +45 -0
  127. package/dist/enrich/providers/spotify.js.map +1 -0
  128. package/dist/enrich/providers/twitter.d.ts +16 -0
  129. package/dist/enrich/providers/twitter.d.ts.map +1 -0
  130. package/dist/enrich/providers/twitter.js +43 -0
  131. package/dist/enrich/providers/twitter.js.map +1 -0
  132. package/dist/enrich/providers/types.d.ts +47 -0
  133. package/dist/enrich/providers/types.d.ts.map +1 -0
  134. package/dist/enrich/providers/types.js +15 -0
  135. package/dist/enrich/providers/types.js.map +1 -0
  136. package/dist/enrich/providers/youtube.d.ts +16 -0
  137. package/dist/enrich/providers/youtube.d.ts.map +1 -0
  138. package/dist/enrich/providers/youtube.js +43 -0
  139. package/dist/enrich/providers/youtube.js.map +1 -0
  140. package/dist/enrich/rate-limiting.d.ts +118 -0
  141. package/dist/enrich/rate-limiting.d.ts.map +1 -0
  142. package/dist/enrich/rate-limiting.js +258 -0
  143. package/dist/enrich/rate-limiting.js.map +1 -0
  144. package/dist/index.d.ts +688 -0
  145. package/dist/index.d.ts.map +1 -0
  146. package/dist/index.js +1729 -0
  147. package/dist/index.js.map +1 -0
  148. package/dist/ingest/dedup-merge.d.ts +82 -0
  149. package/dist/ingest/dedup-merge.d.ts.map +1 -0
  150. package/dist/ingest/dedup-merge.js +262 -0
  151. package/dist/ingest/dedup-merge.js.map +1 -0
  152. package/dist/ingest/ingest-csv.d.ts +62 -0
  153. package/dist/ingest/ingest-csv.d.ts.map +1 -0
  154. package/dist/ingest/ingest-csv.js +300 -0
  155. package/dist/ingest/ingest-csv.js.map +1 -0
  156. package/dist/ingest/ingest-db.d.ts +64 -0
  157. package/dist/ingest/ingest-db.d.ts.map +1 -0
  158. package/dist/ingest/ingest-db.js +172 -0
  159. package/dist/ingest/ingest-db.js.map +1 -0
  160. package/dist/ingest/link-replies-and-tapbacks.d.ts +53 -0
  161. package/dist/ingest/link-replies-and-tapbacks.d.ts.map +1 -0
  162. package/dist/ingest/link-replies-and-tapbacks.js +381 -0
  163. package/dist/ingest/link-replies-and-tapbacks.js.map +1 -0
  164. package/dist/normalize/date-converters.d.ts +45 -0
  165. package/dist/normalize/date-converters.d.ts.map +1 -0
  166. package/dist/normalize/date-converters.js +166 -0
  167. package/dist/normalize/date-converters.js.map +1 -0
  168. package/dist/normalize/path-validator.d.ts +65 -0
  169. package/dist/normalize/path-validator.d.ts.map +1 -0
  170. package/dist/normalize/path-validator.js +221 -0
  171. package/dist/normalize/path-validator.js.map +1 -0
  172. package/dist/normalize/validate-normalized.d.ts +45 -0
  173. package/dist/normalize/validate-normalized.d.ts.map +1 -0
  174. package/dist/normalize/validate-normalized.js +144 -0
  175. package/dist/normalize/validate-normalized.js.map +1 -0
  176. package/dist/render/embeds-blockquotes.d.ts +84 -0
  177. package/dist/render/embeds-blockquotes.d.ts.map +1 -0
  178. package/dist/render/embeds-blockquotes.js +204 -0
  179. package/dist/render/embeds-blockquotes.js.map +1 -0
  180. package/dist/render/grouping.d.ts +78 -0
  181. package/dist/render/grouping.d.ts.map +1 -0
  182. package/dist/render/grouping.js +134 -0
  183. package/dist/render/grouping.js.map +1 -0
  184. package/dist/render/index.d.ts +47 -0
  185. package/dist/render/index.d.ts.map +1 -0
  186. package/dist/render/index.js +245 -0
  187. package/dist/render/index.js.map +1 -0
  188. package/dist/render/reply-rendering.d.ts +88 -0
  189. package/dist/render/reply-rendering.d.ts.map +1 -0
  190. package/dist/render/reply-rendering.js +196 -0
  191. package/dist/render/reply-rendering.js.map +1 -0
  192. package/dist/schema/message.d.ts +125 -0
  193. package/dist/schema/message.d.ts.map +1 -0
  194. package/dist/schema/message.js +331 -0
  195. package/dist/schema/message.js.map +1 -0
  196. package/dist/utils/delta-detection.d.ts +107 -0
  197. package/dist/utils/delta-detection.d.ts.map +1 -0
  198. package/dist/utils/delta-detection.js +199 -0
  199. package/dist/utils/delta-detection.js.map +1 -0
  200. package/dist/utils/enrichment-merge.d.ts +135 -0
  201. package/dist/utils/enrichment-merge.d.ts.map +1 -0
  202. package/dist/utils/enrichment-merge.js +280 -0
  203. package/dist/utils/enrichment-merge.js.map +1 -0
  204. package/dist/utils/human.d.ts +15 -0
  205. package/dist/utils/human.d.ts.map +1 -0
  206. package/dist/utils/human.js +27 -0
  207. package/dist/utils/human.js.map +1 -0
  208. package/dist/utils/incremental-state.d.ts +133 -0
  209. package/dist/utils/incremental-state.d.ts.map +1 -0
  210. package/dist/utils/incremental-state.js +237 -0
  211. package/dist/utils/incremental-state.js.map +1 -0
  212. package/dist/utils/logger.d.ts +40 -0
  213. package/dist/utils/logger.d.ts.map +1 -0
  214. package/dist/utils/logger.js +176 -0
  215. package/dist/utils/logger.js.map +1 -0
  216. package/package.json +165 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/schema/message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,331 @@
1
+ // src/schema/message.ts
2
+ import { z } from 'zod';
3
+ // ============================================================================
4
+ // Zod Schemas
5
+ // ============================================================================
6
+ // Media Enrichment Schema
7
+ export const MediaEnrichmentSchema = z
8
+ .object({
9
+ kind: z.enum([
10
+ 'image',
11
+ 'audio',
12
+ 'link',
13
+ 'video',
14
+ 'pdf',
15
+ 'unknown',
16
+ 'transcription',
17
+ 'pdf_summary',
18
+ 'video_metadata',
19
+ 'link_context',
20
+ 'image_analysis',
21
+ ]),
22
+ model: z.string().optional(),
23
+ createdAt: z.string().datetime(),
24
+ visionSummary: z.string().optional(),
25
+ shortDescription: z.string().optional(),
26
+ transcription: z.string().optional(),
27
+ transcript: z.string().optional(),
28
+ speakers: z.array(z.string()).optional(),
29
+ timestamps: z
30
+ .array(z.object({
31
+ time: z.string(),
32
+ speaker: z.string(),
33
+ content: z.string(),
34
+ }))
35
+ .optional(),
36
+ pdfSummary: z.string().optional(),
37
+ videoMetadata: z
38
+ .object({
39
+ filename: z.string().optional(),
40
+ size: z.number().optional(),
41
+ duration: z.number().optional(),
42
+ analyzed: z.boolean().optional(),
43
+ note: z.string().optional(),
44
+ })
45
+ .optional(),
46
+ error: z.string().optional(),
47
+ usedFallback: z.boolean().optional(),
48
+ failedProviders: z.array(z.string()).optional(),
49
+ url: z.string().url().optional(),
50
+ title: z.string().optional(),
51
+ summary: z.string().optional(),
52
+ provider: z.enum([
53
+ 'gemini',
54
+ 'firecrawl',
55
+ 'local',
56
+ 'youtube',
57
+ 'spotify',
58
+ 'twitter',
59
+ 'instagram',
60
+ 'generic',
61
+ ]),
62
+ version: z.string(),
63
+ })
64
+ .superRefine((enrichment, ctx) => {
65
+ // Ensure enrichment.createdAt has Z suffix (UTC)
66
+ // Note: Zod's datetime() already validates format, this adds additional check
67
+ if (enrichment.createdAt && !enrichment.createdAt.match(/Z$/)) {
68
+ ctx.addIssue({
69
+ code: z.ZodIssueCode.custom,
70
+ message: 'enrichment.createdAt must be ISO 8601 with Z suffix (UTC)',
71
+ });
72
+ }
73
+ });
74
+ // Media Provenance Schema
75
+ export const MediaProvenanceSchema = z
76
+ .object({
77
+ source: z.enum(['csv', 'db', 'merged']),
78
+ lastSeen: z.string().datetime(),
79
+ resolvedAt: z.string().datetime(),
80
+ })
81
+ .superRefine((prov, ctx) => {
82
+ // Ensure all provenance timestamps have Z suffix (UTC)
83
+ if (prov.lastSeen && !prov.lastSeen.match(/Z$/)) {
84
+ ctx.addIssue({
85
+ code: z.ZodIssueCode.custom,
86
+ message: 'lastSeen must be ISO 8601 with Z suffix (UTC)',
87
+ path: ['lastSeen'],
88
+ });
89
+ }
90
+ if (prov.resolvedAt && !prov.resolvedAt.match(/Z$/)) {
91
+ ctx.addIssue({
92
+ code: z.ZodIssueCode.custom,
93
+ message: 'resolvedAt must be ISO 8601 with Z suffix (UTC)',
94
+ path: ['resolvedAt'],
95
+ });
96
+ }
97
+ });
98
+ // Media Meta Schema
99
+ export const MediaMetaSchema = z
100
+ .object({
101
+ id: z.string(),
102
+ filename: z.string(),
103
+ path: z.string(),
104
+ size: z.number().optional(),
105
+ mimeType: z.string().optional(),
106
+ uti: z.string().nullable().optional(),
107
+ isSticker: z.boolean().optional(),
108
+ hidden: z.boolean().optional(),
109
+ mediaKind: z.enum(['image', 'audio', 'video', 'pdf', 'unknown']).optional(),
110
+ enrichment: z.array(MediaEnrichmentSchema).optional(),
111
+ provenance: MediaProvenanceSchema.optional(),
112
+ })
113
+ .superRefine((media, ctx) => {
114
+ // SCHEMA-T01-AC06: Absolute path validation when file exists
115
+ if (media.path && !media.path.startsWith('/')) {
116
+ ctx.addIssue({
117
+ code: z.ZodIssueCode.custom,
118
+ message: 'media.path must be an absolute path (starting with /)',
119
+ path: ['path'],
120
+ });
121
+ }
122
+ });
123
+ // Reply Info Schema
124
+ export const ReplyInfoSchema = z
125
+ .object({
126
+ sender: z.string().optional(),
127
+ date: z.string().datetime().optional(),
128
+ text: z.string().optional(),
129
+ targetMessageGuid: z.string().optional(),
130
+ })
131
+ .superRefine((reply, ctx) => {
132
+ // SCHEMA-T01-AC05: ISO 8601 date validation with Z suffix enforced
133
+ if (reply.date) {
134
+ if (!reply.date.match(/Z$/)) {
135
+ ctx.addIssue({
136
+ code: z.ZodIssueCode.custom,
137
+ message: 'replyingTo.date must be ISO 8601 with Z suffix (UTC)',
138
+ path: ['date'],
139
+ });
140
+ }
141
+ if (Number.isNaN(Date.parse(reply.date))) {
142
+ ctx.addIssue({
143
+ code: z.ZodIssueCode.custom,
144
+ message: 'replyingTo.date must be a valid ISO 8601 date',
145
+ path: ['date'],
146
+ });
147
+ }
148
+ }
149
+ });
150
+ // Tapback Info Schema
151
+ export const TapbackInfoSchema = z.object({
152
+ type: z.enum([
153
+ 'loved',
154
+ 'liked',
155
+ 'disliked',
156
+ 'laughed',
157
+ 'emphasized',
158
+ 'questioned',
159
+ 'emoji',
160
+ ]),
161
+ action: z.enum(['added', 'removed']),
162
+ targetMessageGuid: z.string().optional(),
163
+ targetMessagePart: z.number().int().optional(),
164
+ targetText: z.string().optional(),
165
+ isMedia: z.boolean().optional(),
166
+ emoji: z.string().optional(),
167
+ });
168
+ // Message Core Schema (without refinements to allow extending)
169
+ export const MessageCoreSchema = z.object({
170
+ guid: z.string(),
171
+ rowid: z.number().optional(),
172
+ chatId: z.string().nullable().optional(),
173
+ service: z.string().nullable().optional(),
174
+ subject: z.string().nullable().optional(),
175
+ handleId: z.number().nullable().optional(),
176
+ handle: z.string().nullable().optional(),
177
+ destinationCallerId: z.string().nullable().optional(),
178
+ isFromMe: z.boolean(),
179
+ otherHandle: z.number().nullable().optional(),
180
+ date: z.string().datetime(),
181
+ dateRead: z.string().datetime().nullable().optional(),
182
+ dateDelivered: z.string().datetime().nullable().optional(),
183
+ dateEdited: z.string().datetime().nullable().optional(),
184
+ isRead: z.boolean().optional(),
185
+ itemType: z.number().optional(),
186
+ groupActionType: z.number().optional(),
187
+ groupTitle: z.string().nullable().optional(),
188
+ shareStatus: z.boolean().optional(),
189
+ shareDirection: z.boolean().nullable().optional(),
190
+ expressiveSendStyleId: z.string().nullable().optional(),
191
+ balloonBundleId: z.string().nullable().optional(),
192
+ threadOriginatorGuid: z.string().nullable().optional(),
193
+ threadOriginatorPart: z.number().nullable().optional(),
194
+ numReplies: z.number().optional(),
195
+ deletedFrom: z.number().nullable().optional(),
196
+ });
197
+ // Message Schema with discriminated union and cross-field invariants
198
+ export const MessageSchema = z
199
+ .object({
200
+ // Core fields from MessageCoreSchema
201
+ guid: z.string(),
202
+ rowid: z.number().optional(),
203
+ chatId: z.string().nullable().optional(),
204
+ service: z.string().nullable().optional(),
205
+ subject: z.string().nullable().optional(),
206
+ handleId: z.number().nullable().optional(),
207
+ handle: z.string().nullable().optional(),
208
+ destinationCallerId: z.string().nullable().optional(),
209
+ isFromMe: z.boolean(),
210
+ otherHandle: z.number().nullable().optional(),
211
+ date: z.string().datetime(),
212
+ dateRead: z.string().datetime().nullable().optional(),
213
+ dateDelivered: z.string().datetime().nullable().optional(),
214
+ dateEdited: z.string().datetime().nullable().optional(),
215
+ isRead: z.boolean().optional(),
216
+ itemType: z.number().optional(),
217
+ groupActionType: z.number().optional(),
218
+ groupTitle: z.string().nullable().optional(),
219
+ shareStatus: z.boolean().optional(),
220
+ shareDirection: z.boolean().nullable().optional(),
221
+ expressiveSendStyleId: z.string().nullable().optional(),
222
+ balloonBundleId: z.string().nullable().optional(),
223
+ threadOriginatorGuid: z.string().nullable().optional(),
224
+ threadOriginatorPart: z.number().nullable().optional(),
225
+ numReplies: z.number().optional(),
226
+ deletedFrom: z.number().nullable().optional(),
227
+ // Message-specific fields
228
+ messageKind: z.enum(['text', 'media', 'tapback', 'notification']),
229
+ text: z.string().nullable().optional(),
230
+ tapback: TapbackInfoSchema.nullable().optional(),
231
+ replyingTo: ReplyInfoSchema.nullable().optional(),
232
+ replyingToRaw: z.string().nullable().optional(),
233
+ media: MediaMetaSchema.nullable().optional(),
234
+ groupGuid: z.string().nullable().optional(),
235
+ exportTimestamp: z.string().datetime().optional(),
236
+ exportVersion: z.string().optional(),
237
+ isUnsent: z.boolean().optional(),
238
+ isEdited: z.boolean().optional(),
239
+ })
240
+ .superRefine((msg, ctx) => {
241
+ // SCHEMA-T01-AC02: Cross-field invariants using superRefine
242
+ // SCHEMA-T01-AC05: ISO 8601 date validation with Z suffix enforced for all date fields
243
+ const dateFields = [
244
+ 'date',
245
+ 'dateRead',
246
+ 'dateDelivered',
247
+ 'dateEdited',
248
+ 'exportTimestamp',
249
+ ];
250
+ for (const field of dateFields) {
251
+ const value = msg[field];
252
+ if (value && typeof value === 'string') {
253
+ if (!value.match(/Z$/)) {
254
+ ctx.addIssue({
255
+ code: z.ZodIssueCode.custom,
256
+ message: `${field} must be ISO 8601 with Z suffix (UTC)`,
257
+ path: [field],
258
+ });
259
+ }
260
+ }
261
+ }
262
+ // SCHEMA-T01-AC04: Tapback payload validation (exists when messageKind='tapback')
263
+ if (msg.messageKind === 'tapback' && !msg.tapback) {
264
+ ctx.addIssue({
265
+ code: z.ZodIssueCode.custom,
266
+ message: 'tapback kind requires tapback payload',
267
+ path: ['tapback'],
268
+ });
269
+ }
270
+ // SCHEMA-T01-AC03: Media payload validation (exists and complete when messageKind='media')
271
+ if (msg.messageKind === 'media' && !msg.media) {
272
+ ctx.addIssue({
273
+ code: z.ZodIssueCode.custom,
274
+ message: 'media kind requires media payload',
275
+ path: ['media'],
276
+ });
277
+ }
278
+ // Non-media messages must NOT carry media payload
279
+ if (msg.messageKind !== 'media' && msg.media) {
280
+ ctx.addIssue({
281
+ code: z.ZodIssueCode.custom,
282
+ message: 'media payload present on non-media message',
283
+ path: ['media'],
284
+ });
285
+ }
286
+ // Additional validation: if media payload exists and is complete
287
+ if (msg.messageKind === 'media' && msg.media) {
288
+ // Ensure media has required fields
289
+ if (!msg.media.id) {
290
+ ctx.addIssue({
291
+ code: z.ZodIssueCode.custom,
292
+ message: 'media.id is required when messageKind is media',
293
+ path: ['media', 'id'],
294
+ });
295
+ }
296
+ if (!msg.media.filename) {
297
+ ctx.addIssue({
298
+ code: z.ZodIssueCode.custom,
299
+ message: 'media.filename is required when messageKind is media',
300
+ path: ['media', 'filename'],
301
+ });
302
+ }
303
+ if (!msg.media.path) {
304
+ ctx.addIssue({
305
+ code: z.ZodIssueCode.custom,
306
+ message: 'media.path is required when messageKind is media',
307
+ path: ['media', 'path'],
308
+ });
309
+ }
310
+ }
311
+ });
312
+ // Export Envelope Schema
313
+ export const ExportEnvelopeSchema = z
314
+ .object({
315
+ schemaVersion: z.string(),
316
+ source: z.enum(['csv', 'db', 'merged']),
317
+ createdAt: z.string().datetime(),
318
+ messages: z.array(MessageSchema),
319
+ meta: z.record(z.any()).optional(),
320
+ })
321
+ .superRefine((envelope, ctx) => {
322
+ // SCHEMA-T01-AC05: ISO 8601 validation for createdAt
323
+ if (envelope.createdAt && !envelope.createdAt.match(/Z$/)) {
324
+ ctx.addIssue({
325
+ code: z.ZodIssueCode.custom,
326
+ message: 'createdAt must be ISO 8601 with Z suffix (UTC)',
327
+ path: ['createdAt'],
328
+ });
329
+ }
330
+ });
331
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/schema/message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Delta Detection Module (INCREMENTAL--T02)
3
+ *
4
+ * Identifies new messages for enrichment by comparing current normalized state
5
+ * with previous enrichment state.
6
+ *
7
+ * Implements:
8
+ * - AC01: Load previous state from .imessage-state.json
9
+ * - AC02: Diff normalized messages against enrichedGuids
10
+ * - AC03: Return only new GUIDs for enrichment
11
+ * - AC04: Handle state file missing (treat as first run)
12
+ * - AC05: Log delta summary: Found X new messages to enrich
13
+ *
14
+ * Architecture:
15
+ * - DeltaResult: Complete delta detection output
16
+ * - detectDelta: Main entry point for delta detection
17
+ * - extractGuidsFromMessages: Convert messages to GUID set
18
+ * - computeDelta: Core diff logic
19
+ * - logDeltaSummary: Human-readable delta report
20
+ */
21
+ import type { Message } from '#schema/message';
22
+ import type { IncrementalState } from './incremental-state';
23
+ /**
24
+ * Result of delta detection
25
+ *
26
+ * Provides:
27
+ * - newGuids: Message GUIDs to enrich
28
+ * - totalMessages: Total current messages
29
+ * - previousEnrichedCount: Messages enriched in prior run
30
+ * - newCount: Number of new messages found
31
+ * - isFirstRun: Whether state file was missing
32
+ * - state: Loaded or created state for update after enrichment
33
+ */
34
+ export type DeltaResult = {
35
+ /** GUIDs of messages to enrich (new since last run) */
36
+ newGuids: string[];
37
+ /** Total messages in normalized dataset */
38
+ totalMessages: number;
39
+ /** Count of previously enriched messages */
40
+ previousEnrichedCount: number;
41
+ /** Number of new messages found in delta */
42
+ newCount: number;
43
+ /** true if no prior state file found */
44
+ isFirstRun: boolean;
45
+ /** IncrementalState to update and save after enrichment */
46
+ state: IncrementalState;
47
+ };
48
+ /**
49
+ * AC02 + AC03: Extract message GUIDs from normalized messages
50
+ *
51
+ * Converts Message[] to Set<guid> for efficient delta computation
52
+ *
53
+ * @param messages - Normalized messages to process
54
+ * @returns Set of unique message GUIDs
55
+ */
56
+ export declare function extractGuidsFromMessages(messages: Message[]): Set<string>;
57
+ /**
58
+ * AC05: Log human-readable delta summary
59
+ *
60
+ * Outputs lines like:
61
+ * - "Found 142 new messages to enrich"
62
+ * - "Previously enriched: 358"
63
+ * - "This is your first enrichment run"
64
+ * - "Delta: 28.3% of 500 total messages"
65
+ *
66
+ * @param result - DeltaResult to summarize
67
+ */
68
+ export declare function logDeltaSummary(result: DeltaResult): void;
69
+ /**
70
+ * AC01-AC05: Perform complete delta detection
71
+ *
72
+ * Workflow:
73
+ * 1. AC04: Load previous state (null if missing)
74
+ * 2. AC02: Extract current message GUIDs
75
+ * 3. AC03: Compute delta (new GUIDs only)
76
+ * 4. AC05: Log summary
77
+ *
78
+ * Returns DeltaResult with:
79
+ * - newGuids to enrich
80
+ * - metadata for progress tracking
81
+ * - state to update after enrichment
82
+ *
83
+ * @param messages - Normalized messages from normalize-link stage
84
+ * @param stateFilePath - Path to .imessage-state.json
85
+ * @returns DeltaResult with new GUIDs and metadata
86
+ * @throws Error if state file can't be read (permission denied, etc.)
87
+ */
88
+ export declare function detectDelta(messages: Message[], stateFilePath: string): Promise<DeltaResult>;
89
+ /**
90
+ * Calculate delta statistics for progress monitoring
91
+ *
92
+ * Useful for:
93
+ * - Progress bars (show percentage to enrich)
94
+ * - ETA calculation
95
+ * - Summary reports
96
+ *
97
+ * @param result - DeltaResult to analyze
98
+ * @returns Statistics object with counts and percentages
99
+ */
100
+ export declare function getDeltaStats(result: DeltaResult): {
101
+ total: number;
102
+ new: number;
103
+ previous: number;
104
+ percentNew: number;
105
+ percentPrevious: number;
106
+ };
107
+ //# sourceMappingURL=delta-detection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta-detection.d.ts","sourceRoot":"","sources":["../../src/utils/delta-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAG9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAO3D;;;;;;;;;;GAUG;AACH,MAAM,MAAM,WAAW,GAAG;IACzB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,EAAE,CAAA;IAElB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,CAAA;IAErB,4CAA4C;IAC5C,qBAAqB,EAAE,MAAM,CAAA;IAE7B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAA;IAEhB,wCAAwC;IACxC,UAAU,EAAE,OAAO,CAAA;IAEnB,2DAA2D;IAC3D,KAAK,EAAE,gBAAgB,CAAA;CACvB,CAAA;AA2BD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAMzE;AAgCD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CA6BzD;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAChC,QAAQ,EAAE,OAAO,EAAE,EACnB,aAAa,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,CAgCtB;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;CACvB,CAYA"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Delta Detection Module (INCREMENTAL--T02)
3
+ *
4
+ * Identifies new messages for enrichment by comparing current normalized state
5
+ * with previous enrichment state.
6
+ *
7
+ * Implements:
8
+ * - AC01: Load previous state from .imessage-state.json
9
+ * - AC02: Diff normalized messages against enrichedGuids
10
+ * - AC03: Return only new GUIDs for enrichment
11
+ * - AC04: Handle state file missing (treat as first run)
12
+ * - AC05: Log delta summary: Found X new messages to enrich
13
+ *
14
+ * Architecture:
15
+ * - DeltaResult: Complete delta detection output
16
+ * - detectDelta: Main entry point for delta detection
17
+ * - extractGuidsFromMessages: Convert messages to GUID set
18
+ * - computeDelta: Core diff logic
19
+ * - logDeltaSummary: Human-readable delta report
20
+ */
21
+ import { humanInfo } from '#utils/human';
22
+ import { createLogger } from '#utils/logger';
23
+ import { detectNewMessages, loadIncrementalState } from './incremental-state';
24
+ // ============================================================================
25
+ // AC01 + AC04: Load previous state safely
26
+ // ============================================================================
27
+ /**
28
+ * AC01 + AC04: Load incremental state from disk
29
+ *
30
+ * Handles missing state file gracefully:
31
+ * - Returns null if file doesn't exist (first run)
32
+ * - Returns null if JSON is corrupted
33
+ * - Returns parsed state if valid
34
+ *
35
+ * @param stateFilePath - Path to .imessage-state.json
36
+ * @returns IncrementalState if found and valid, null if missing or corrupted
37
+ */
38
+ async function loadPreviousState(stateFilePath) {
39
+ return loadIncrementalState(stateFilePath);
40
+ }
41
+ // ============================================================================
42
+ // AC02 + AC03: Extract GUIDs and compute delta
43
+ // ============================================================================
44
+ /**
45
+ * AC02 + AC03: Extract message GUIDs from normalized messages
46
+ *
47
+ * Converts Message[] to Set<guid> for efficient delta computation
48
+ *
49
+ * @param messages - Normalized messages to process
50
+ * @returns Set of unique message GUIDs
51
+ */
52
+ export function extractGuidsFromMessages(messages) {
53
+ const guids = new Set();
54
+ for (const msg of messages) {
55
+ guids.add(msg.guid);
56
+ }
57
+ return guids;
58
+ }
59
+ /**
60
+ * AC02 + AC03: Compute delta between current and previous state
61
+ *
62
+ * Performance: O(n + m) where:
63
+ * - n = number of current messages
64
+ * - m = number of previously enriched messages
65
+ *
66
+ * Uses Set-based deduplication for O(1) lookup
67
+ *
68
+ * @param currentGuids - Set of message GUIDs from normalized state
69
+ * @param previousState - Prior state with enriched GUIDs (null if first run)
70
+ * @returns New GUIDs not in previous state
71
+ */
72
+ function computeDelta(currentGuids, previousState) {
73
+ if (!previousState) {
74
+ // First run: all current messages are "new"
75
+ return Array.from(currentGuids);
76
+ }
77
+ // Use existing delta detection from incremental-state module
78
+ return detectNewMessages(currentGuids, previousState);
79
+ }
80
+ // ============================================================================
81
+ // AC05: Delta Summary Logging
82
+ // ============================================================================
83
+ /**
84
+ * AC05: Log human-readable delta summary
85
+ *
86
+ * Outputs lines like:
87
+ * - "Found 142 new messages to enrich"
88
+ * - "Previously enriched: 358"
89
+ * - "This is your first enrichment run"
90
+ * - "Delta: 28.3% of 500 total messages"
91
+ *
92
+ * @param result - DeltaResult to summarize
93
+ */
94
+ export function logDeltaSummary(result) {
95
+ const logger = createLogger('utils:delta-detection');
96
+ const newCount = result.newCount;
97
+ const totalCount = result.totalMessages;
98
+ const previousCount = result.previousEnrichedCount;
99
+ // Log delta summary (AC05)
100
+ if (result.isFirstRun) {
101
+ // Structured log (machine consumption)
102
+ logger.info('First enrichment run', { totalMessages: totalCount });
103
+ // Human-friendly console output retained for tests & CLI UX
104
+ // Format expected by tests: contains both 'First enrichment run' and '<N> messages'
105
+ humanInfo(`First enrichment run: ${totalCount} messages`);
106
+ }
107
+ else {
108
+ const percentNew = totalCount > 0 ? (newCount / totalCount) * 100 : 0;
109
+ // Structured log
110
+ logger.info('Delta detected', {
111
+ newMessages: newCount,
112
+ percentNew,
113
+ totalMessages: totalCount,
114
+ previouslyEnriched: previousCount,
115
+ });
116
+ // Human-readable lines expected by tests
117
+ // Includes phrases: 'Delta detected', '<X> new messages', '<Y.Y%>' and 'Previously enriched: <N>'
118
+ humanInfo(`Delta detected: ${newCount} new messages (${percentNew.toFixed(1)}%) of ${totalCount} total messages`);
119
+ humanInfo(`Previously enriched: ${previousCount}`);
120
+ }
121
+ }
122
+ // ============================================================================
123
+ // AC01-AC05: Main entry point for delta detection
124
+ // ============================================================================
125
+ /**
126
+ * AC01-AC05: Perform complete delta detection
127
+ *
128
+ * Workflow:
129
+ * 1. AC04: Load previous state (null if missing)
130
+ * 2. AC02: Extract current message GUIDs
131
+ * 3. AC03: Compute delta (new GUIDs only)
132
+ * 4. AC05: Log summary
133
+ *
134
+ * Returns DeltaResult with:
135
+ * - newGuids to enrich
136
+ * - metadata for progress tracking
137
+ * - state to update after enrichment
138
+ *
139
+ * @param messages - Normalized messages from normalize-link stage
140
+ * @param stateFilePath - Path to .imessage-state.json
141
+ * @returns DeltaResult with new GUIDs and metadata
142
+ * @throws Error if state file can't be read (permission denied, etc.)
143
+ */
144
+ export async function detectDelta(messages, stateFilePath) {
145
+ // AC01 + AC04: Load previous state (null if missing)
146
+ const previousState = await loadPreviousState(stateFilePath);
147
+ const isFirstRun = previousState === null;
148
+ // AC02 + AC03: Extract current GUIDs and compute delta
149
+ const currentGuids = extractGuidsFromMessages(messages);
150
+ const newGuids = computeDelta(currentGuids, previousState);
151
+ // Build result
152
+ const result = {
153
+ newGuids,
154
+ totalMessages: messages.length,
155
+ previousEnrichedCount: previousState?.enrichedGuids.length ?? 0,
156
+ newCount: newGuids.length,
157
+ isFirstRun,
158
+ state: previousState ?? {
159
+ version: '1.0',
160
+ lastEnrichedAt: new Date().toISOString(),
161
+ totalMessages: messages.length,
162
+ enrichedGuids: [],
163
+ pipelineConfig: {
164
+ configHash: '',
165
+ },
166
+ enrichmentStats: null,
167
+ },
168
+ };
169
+ // AC05: Log summary
170
+ logDeltaSummary(result);
171
+ return result;
172
+ }
173
+ // ============================================================================
174
+ // Utility: Get delta statistics for progress reporting
175
+ // ============================================================================
176
+ /**
177
+ * Calculate delta statistics for progress monitoring
178
+ *
179
+ * Useful for:
180
+ * - Progress bars (show percentage to enrich)
181
+ * - ETA calculation
182
+ * - Summary reports
183
+ *
184
+ * @param result - DeltaResult to analyze
185
+ * @returns Statistics object with counts and percentages
186
+ */
187
+ export function getDeltaStats(result) {
188
+ const total = result.totalMessages;
189
+ const newCount = result.newCount;
190
+ const previousCount = result.previousEnrichedCount;
191
+ return {
192
+ total,
193
+ new: newCount,
194
+ previous: previousCount,
195
+ percentNew: total > 0 ? (newCount / total) * 100 : 0,
196
+ percentPrevious: total > 0 ? (previousCount / total) * 100 : 0,
197
+ };
198
+ }
199
+ //# sourceMappingURL=delta-detection.js.map