@cogenta/agents 0.1.2 → 0.2.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 (145) hide show
  1. package/dist/assist/chat.d.ts +69 -0
  2. package/dist/assist/chat.d.ts.map +1 -0
  3. package/dist/assist/chat.js +108 -0
  4. package/dist/assist/chat.js.map +1 -0
  5. package/dist/assist/classify.d.ts +101 -0
  6. package/dist/assist/classify.d.ts.map +1 -0
  7. package/dist/assist/classify.js +233 -0
  8. package/dist/assist/classify.js.map +1 -0
  9. package/dist/assist/faq.d.ts +61 -0
  10. package/dist/assist/faq.d.ts.map +1 -0
  11. package/dist/assist/faq.js +136 -0
  12. package/dist/assist/faq.js.map +1 -0
  13. package/dist/assist/images.d.ts +45 -0
  14. package/dist/assist/images.d.ts.map +1 -0
  15. package/dist/assist/images.js +79 -0
  16. package/dist/assist/images.js.map +1 -0
  17. package/dist/assist/runtime.d.ts +58 -0
  18. package/dist/assist/runtime.d.ts.map +1 -0
  19. package/dist/assist/runtime.js +84 -0
  20. package/dist/assist/runtime.js.map +1 -0
  21. package/dist/assist/suggestion.d.ts +20 -0
  22. package/dist/assist/suggestion.d.ts.map +1 -0
  23. package/dist/assist/suggestion.js +28 -0
  24. package/dist/assist/suggestion.js.map +1 -0
  25. package/dist/assist/toolset.d.ts +76 -0
  26. package/dist/assist/toolset.d.ts.map +1 -0
  27. package/dist/assist/toolset.js +72 -0
  28. package/dist/assist/toolset.js.map +1 -0
  29. package/dist/assist/writing.d.ts +74 -0
  30. package/dist/assist/writing.d.ts.map +1 -0
  31. package/dist/assist/writing.js +429 -0
  32. package/dist/assist/writing.js.map +1 -0
  33. package/dist/documents/docx.d.ts +6 -0
  34. package/dist/documents/docx.d.ts.map +1 -0
  35. package/dist/documents/docx.js +169 -0
  36. package/dist/documents/docx.js.map +1 -0
  37. package/dist/documents/extract-text.d.ts +35 -0
  38. package/dist/documents/extract-text.d.ts.map +1 -0
  39. package/dist/documents/extract-text.js +134 -0
  40. package/dist/documents/extract-text.js.map +1 -0
  41. package/dist/documents/extract-tool.d.ts +40 -0
  42. package/dist/documents/extract-tool.d.ts.map +1 -0
  43. package/dist/documents/extract-tool.js +65 -0
  44. package/dist/documents/extract-tool.js.map +1 -0
  45. package/dist/documents/limits.d.ts +23 -0
  46. package/dist/documents/limits.d.ts.map +1 -0
  47. package/dist/documents/limits.js +23 -0
  48. package/dist/documents/limits.js.map +1 -0
  49. package/dist/documents/pdf.d.ts +26 -0
  50. package/dist/documents/pdf.d.ts.map +1 -0
  51. package/dist/documents/pdf.js +478 -0
  52. package/dist/documents/pdf.js.map +1 -0
  53. package/dist/documents/zip.d.ts +18 -0
  54. package/dist/documents/zip.d.ts.map +1 -0
  55. package/dist/documents/zip.js +113 -0
  56. package/dist/documents/zip.js.map +1 -0
  57. package/dist/index.d.ts +50 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +25 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/providers/image/openai.d.ts +28 -0
  62. package/dist/providers/image/openai.d.ts.map +1 -0
  63. package/dist/providers/image/openai.js +80 -0
  64. package/dist/providers/image/openai.js.map +1 -0
  65. package/dist/providers/image/registry.d.ts +30 -0
  66. package/dist/providers/image/registry.d.ts.map +1 -0
  67. package/dist/providers/image/registry.js +36 -0
  68. package/dist/providers/image/registry.js.map +1 -0
  69. package/dist/providers/image/stability.d.ts +39 -0
  70. package/dist/providers/image/stability.d.ts.map +1 -0
  71. package/dist/providers/image/stability.js +88 -0
  72. package/dist/providers/image/stability.js.map +1 -0
  73. package/dist/providers/image/types.d.ts +50 -0
  74. package/dist/providers/image/types.d.ts.map +1 -0
  75. package/dist/providers/image/types.js +33 -0
  76. package/dist/providers/image/types.js.map +1 -0
  77. package/dist/rag/semantic/search.d.ts +84 -0
  78. package/dist/rag/semantic/search.d.ts.map +1 -0
  79. package/dist/rag/semantic/search.js +113 -0
  80. package/dist/rag/semantic/search.js.map +1 -0
  81. package/dist/rag/vector/file.d.ts +23 -0
  82. package/dist/rag/vector/file.d.ts.map +1 -0
  83. package/dist/rag/vector/file.js +170 -0
  84. package/dist/rag/vector/file.js.map +1 -0
  85. package/dist/rag/vector/index.d.ts +24 -0
  86. package/dist/rag/vector/index.d.ts.map +1 -0
  87. package/dist/rag/vector/index.js +27 -0
  88. package/dist/rag/vector/index.js.map +1 -0
  89. package/dist/rag/vector/memory.d.ts +16 -0
  90. package/dist/rag/vector/memory.d.ts.map +1 -0
  91. package/dist/rag/vector/memory.js +107 -0
  92. package/dist/rag/vector/memory.js.map +1 -0
  93. package/dist/rag/vector/pgvector.d.ts +34 -0
  94. package/dist/rag/vector/pgvector.d.ts.map +1 -0
  95. package/dist/rag/vector/pgvector.js +273 -0
  96. package/dist/rag/vector/pgvector.js.map +1 -0
  97. package/dist/rag/vector/types.d.ts +113 -0
  98. package/dist/rag/vector/types.d.ts.map +1 -0
  99. package/dist/rag/vector/types.js +51 -0
  100. package/dist/rag/vector/types.js.map +1 -0
  101. package/dist/site-plan/analyse-brief.d.ts +23 -0
  102. package/dist/site-plan/analyse-brief.d.ts.map +1 -0
  103. package/dist/site-plan/analyse-brief.js +207 -0
  104. package/dist/site-plan/analyse-brief.js.map +1 -0
  105. package/dist/site-plan/approval.d.ts +80 -0
  106. package/dist/site-plan/approval.d.ts.map +1 -0
  107. package/dist/site-plan/approval.js +201 -0
  108. package/dist/site-plan/approval.js.map +1 -0
  109. package/dist/site-plan/constraints.d.ts +45 -0
  110. package/dist/site-plan/constraints.d.ts.map +1 -0
  111. package/dist/site-plan/constraints.js +213 -0
  112. package/dist/site-plan/constraints.js.map +1 -0
  113. package/dist/site-plan/content-model.d.ts +22 -0
  114. package/dist/site-plan/content-model.d.ts.map +1 -0
  115. package/dist/site-plan/content-model.js +385 -0
  116. package/dist/site-plan/content-model.js.map +1 -0
  117. package/dist/site-plan/demo-content.d.ts +27 -0
  118. package/dist/site-plan/demo-content.d.ts.map +1 -0
  119. package/dist/site-plan/demo-content.js +170 -0
  120. package/dist/site-plan/demo-content.js.map +1 -0
  121. package/dist/site-plan/draft-store.d.ts +37 -0
  122. package/dist/site-plan/draft-store.d.ts.map +1 -0
  123. package/dist/site-plan/draft-store.js +117 -0
  124. package/dist/site-plan/draft-store.js.map +1 -0
  125. package/dist/site-plan/enforce.d.ts +17 -0
  126. package/dist/site-plan/enforce.d.ts.map +1 -0
  127. package/dist/site-plan/enforce.js +120 -0
  128. package/dist/site-plan/enforce.js.map +1 -0
  129. package/dist/site-plan/json.d.ts +9 -0
  130. package/dist/site-plan/json.d.ts.map +1 -0
  131. package/dist/site-plan/json.js +29 -0
  132. package/dist/site-plan/json.js.map +1 -0
  133. package/dist/site-plan/propose-plan.d.ts +43 -0
  134. package/dist/site-plan/propose-plan.d.ts.map +1 -0
  135. package/dist/site-plan/propose-plan.js +65 -0
  136. package/dist/site-plan/propose-plan.js.map +1 -0
  137. package/dist/site-plan/skin-candidates.d.ts +61 -0
  138. package/dist/site-plan/skin-candidates.d.ts.map +1 -0
  139. package/dist/site-plan/skin-candidates.js +99 -0
  140. package/dist/site-plan/skin-candidates.js.map +1 -0
  141. package/dist/site-plan/types.d.ts +93 -0
  142. package/dist/site-plan/types.d.ts.map +1 -0
  143. package/dist/site-plan/types.js +2 -0
  144. package/dist/site-plan/types.js.map +1 -0
  145. package/package.json +4 -3
@@ -0,0 +1,478 @@
1
+ import { inflateSync } from 'node:zlib';
2
+ import { CogentaError } from '@cogenta/core';
3
+ import { MAX_TEXT_CHARACTERS } from './limits.js';
4
+ /**
5
+ * Text-layer extraction from a PDF, with no dependency (R9/R10 — `pdf-parse`
6
+ * wraps `pdf.js`, several megabytes of browser-oriented rendering code, to
7
+ * reach the same content streams `node:zlib` already opens; `pdfjs-dist`
8
+ * itself is heavier still and needs a DOM shim on Node).
9
+ *
10
+ * What this reads: the content streams of a PDF (`FlateDecode`d or stored),
11
+ * and the text-showing operators inside them (`Tj`, `TJ`, `'`, `"`), with
12
+ * `Td`/`TD`/`T*`/`ET` treated as line breaks. Simple-font strings are
13
+ * decoded as CP-1252 (what `WinAnsiEncoding` actually is, and what a French
14
+ * brief needs for its accents); UTF-16BE strings are decoded as such.
15
+ *
16
+ * What this deliberately does not do, and says so rather than pretending:
17
+ * a font with a custom `Encoding`/`ToUnicode` CMap (common in PDFs exported
18
+ * with subset CID fonts) shows glyph indices, not characters, and no amount
19
+ * of operator parsing recovers text from those without building the CMap
20
+ * machinery. `extractPdfText` refuses that case outright rather than
21
+ * returning mojibake as if it were the document — as it refuses a scan,
22
+ * which has no text layer at all. Both are `DOCUMENT_NO_TEXT_LAYER`, never
23
+ * an empty or plausible-looking success.
24
+ */
25
+ const MAX_INFLATED_BYTES = 200 * 1024 * 1024;
26
+ /** CP-1252's only departures from Latin-1: the 0x80–0x9F block. */
27
+ const CP1252_HIGH = '€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ';
28
+ function decodeCp1252(bytes) {
29
+ let out = '';
30
+ for (const byte of bytes) {
31
+ out +=
32
+ byte >= 0x80 && byte <= 0x9f ? (CP1252_HIGH[byte - 0x80] ?? '�') : String.fromCharCode(byte);
33
+ }
34
+ return out;
35
+ }
36
+ function decodePdfString(bytes) {
37
+ if (bytes.length >= 2 && bytes[0] === 0xfe && bytes[1] === 0xff) {
38
+ return bytes.subarray(2).swap16().toString('utf16le');
39
+ }
40
+ return decodeCp1252(bytes);
41
+ }
42
+ const DELIMITERS = new Set('()<>[]{}/%'.split('').map((c) => c.charCodeAt(0)));
43
+ function isWhitespace(byte) {
44
+ return byte === 0 || byte === 9 || byte === 10 || byte === 12 || byte === 13 || byte === 32;
45
+ }
46
+ /** A literal `(...)` string, honouring nesting, backslash escapes and octal codes. */
47
+ function readLiteralString(data, start) {
48
+ const out = [];
49
+ let depth = 1;
50
+ let at = start;
51
+ while (at < data.length) {
52
+ const byte = data[at];
53
+ if (byte === 0x5c) {
54
+ const escaped = data[at + 1];
55
+ at += 2;
56
+ if (escaped === undefined)
57
+ break;
58
+ if (escaped >= 0x30 && escaped <= 0x37) {
59
+ let octal = String.fromCharCode(escaped);
60
+ while (octal.length < 3) {
61
+ const more = data[at];
62
+ if (more === undefined || more < 0x30 || more > 0x37)
63
+ break;
64
+ octal += String.fromCharCode(more);
65
+ at++;
66
+ }
67
+ out.push(Number.parseInt(octal, 8) & 0xff);
68
+ continue;
69
+ }
70
+ const simple = { 110: 10, 114: 13, 116: 9, 98: 8, 102: 12 };
71
+ const mapped = simple[escaped];
72
+ if (mapped !== undefined)
73
+ out.push(mapped);
74
+ else if (escaped === 10) {
75
+ // A backslash before a newline is a line continuation: emit nothing.
76
+ }
77
+ else if (escaped === 13) {
78
+ if (data[at] === 10)
79
+ at++;
80
+ }
81
+ else
82
+ out.push(escaped);
83
+ continue;
84
+ }
85
+ if (byte === 0x28)
86
+ depth++;
87
+ if (byte === 0x29) {
88
+ depth--;
89
+ if (depth === 0)
90
+ return { bytes: Buffer.from(out), next: at + 1 };
91
+ }
92
+ out.push(byte);
93
+ at++;
94
+ }
95
+ return { bytes: Buffer.from(out), next: at };
96
+ }
97
+ function readHexString(data, start) {
98
+ let digits = '';
99
+ let at = start;
100
+ while (at < data.length && data[at] !== 0x3e) {
101
+ const ch = String.fromCharCode(data[at]);
102
+ if (/[0-9a-fA-F]/.test(ch))
103
+ digits += ch;
104
+ at++;
105
+ }
106
+ if (digits.length % 2 === 1)
107
+ digits += '0';
108
+ const bytes = Buffer.from(digits, 'hex');
109
+ return { bytes, next: at + 1 };
110
+ }
111
+ /** A real PDF number is a handful of characters; nothing legitimate is near this. */
112
+ const MAX_NUMBER_TOKEN_LENGTH = 64;
113
+ /**
114
+ * Whether a bare token is a PDF number, without a regular expression.
115
+ *
116
+ * The obvious pattern for this — `/^[-+]?(\d+\.?\d*|\.\d+)$/` — backtracks
117
+ * quadratically on a long run of digits that fails at the anchor, which is a
118
+ * denial of service an attacker-supplied content stream can reach for the
119
+ * price of one very long token. A character scan is linear and cannot, and
120
+ * the length cap makes the pathological input impossible before that even
121
+ * matters.
122
+ */
123
+ function isNumberToken(word) {
124
+ if (word.length === 0 || word.length > MAX_NUMBER_TOKEN_LENGTH)
125
+ return false;
126
+ let at = word[0] === '-' || word[0] === '+' ? 1 : 0;
127
+ let digits = 0;
128
+ let dots = 0;
129
+ for (; at < word.length; at++) {
130
+ const char = word[at];
131
+ if (char >= '0' && char <= '9')
132
+ digits++;
133
+ else if (char === '.')
134
+ dots++;
135
+ else
136
+ return false;
137
+ if (dots > 1)
138
+ return false;
139
+ }
140
+ return digits > 0;
141
+ }
142
+ function* tokenize(data) {
143
+ let at = 0;
144
+ while (at < data.length) {
145
+ const byte = data[at];
146
+ if (isWhitespace(byte)) {
147
+ at++;
148
+ continue;
149
+ }
150
+ if (byte === 0x25) {
151
+ // Comment to end of line.
152
+ while (at < data.length && data[at] !== 10 && data[at] !== 13)
153
+ at++;
154
+ continue;
155
+ }
156
+ if (byte === 0x28) {
157
+ const read = readLiteralString(data, at + 1);
158
+ at = read.next;
159
+ yield { kind: 'string', value: decodePdfString(read.bytes) };
160
+ continue;
161
+ }
162
+ if (byte === 0x3c) {
163
+ if (data[at + 1] === 0x3c) {
164
+ at += 2;
165
+ yield { kind: 'other' };
166
+ continue;
167
+ }
168
+ const read = readHexString(data, at + 1);
169
+ at = read.next;
170
+ yield { kind: 'string', value: decodePdfString(read.bytes) };
171
+ continue;
172
+ }
173
+ if (byte === 0x3e) {
174
+ at += data[at + 1] === 0x3e ? 2 : 1;
175
+ yield { kind: 'other' };
176
+ continue;
177
+ }
178
+ if (byte === 0x5b) {
179
+ at++;
180
+ yield { kind: 'arrayStart' };
181
+ continue;
182
+ }
183
+ if (byte === 0x5d) {
184
+ at++;
185
+ yield { kind: 'arrayEnd' };
186
+ continue;
187
+ }
188
+ if (byte === 0x2f) {
189
+ at++;
190
+ while (at < data.length &&
191
+ !isWhitespace(data[at]) &&
192
+ !DELIMITERS.has(data[at]))
193
+ at++;
194
+ yield { kind: 'other' };
195
+ continue;
196
+ }
197
+ if (byte === 0x7b || byte === 0x7d) {
198
+ at++;
199
+ yield { kind: 'other' };
200
+ continue;
201
+ }
202
+ let word = '';
203
+ while (at < data.length &&
204
+ !isWhitespace(data[at]) &&
205
+ !DELIMITERS.has(data[at])) {
206
+ word += String.fromCharCode(data[at]);
207
+ at++;
208
+ }
209
+ if (word === '') {
210
+ at++;
211
+ continue;
212
+ }
213
+ if (isNumberToken(word)) {
214
+ yield { kind: 'number', value: Number.parseFloat(word) };
215
+ continue;
216
+ }
217
+ yield { kind: 'operator', value: word };
218
+ }
219
+ }
220
+ /** Below this (in thousandths of an em, negated) a `TJ` kerning gap reads as a word space. */
221
+ const TJ_SPACE_THRESHOLD = -120;
222
+ function textFromContentStream(data) {
223
+ const lines = [];
224
+ let current = '';
225
+ const pendingStrings = [];
226
+ let arrayDepth = 0;
227
+ let arrayText = '';
228
+ const flushLine = () => {
229
+ const trimmed = current.replace(/[ \t]+$/, '');
230
+ if (trimmed !== '')
231
+ lines.push(trimmed);
232
+ current = '';
233
+ };
234
+ for (const token of tokenize(data)) {
235
+ if (token.kind === 'arrayStart') {
236
+ arrayDepth++;
237
+ arrayText = '';
238
+ continue;
239
+ }
240
+ if (token.kind === 'arrayEnd') {
241
+ arrayDepth = Math.max(0, arrayDepth - 1);
242
+ pendingStrings.push(arrayText);
243
+ arrayText = '';
244
+ continue;
245
+ }
246
+ if (token.kind === 'string') {
247
+ if (arrayDepth > 0)
248
+ arrayText += token.value;
249
+ else
250
+ pendingStrings.push(token.value);
251
+ continue;
252
+ }
253
+ if (token.kind === 'number') {
254
+ if (arrayDepth > 0 && token.value <= TJ_SPACE_THRESHOLD && !arrayText.endsWith(' ')) {
255
+ arrayText += ' ';
256
+ }
257
+ continue;
258
+ }
259
+ if (token.kind !== 'operator')
260
+ continue;
261
+ switch (token.value) {
262
+ case 'Tj':
263
+ case 'TJ':
264
+ case "'":
265
+ case '"': {
266
+ if (token.value === "'" || token.value === '"')
267
+ flushLine();
268
+ current += pendingStrings.join('');
269
+ pendingStrings.length = 0;
270
+ break;
271
+ }
272
+ case 'Td':
273
+ case 'TD':
274
+ case 'T*':
275
+ case 'ET':
276
+ case 'BT':
277
+ flushLine();
278
+ pendingStrings.length = 0;
279
+ break;
280
+ default:
281
+ pendingStrings.length = 0;
282
+ break;
283
+ }
284
+ }
285
+ flushLine();
286
+ return lines.join('\n');
287
+ }
288
+ export function measureReadability(text) {
289
+ if (text.length === 0)
290
+ return { badCharacterRatio: 1, meanWordLength: 0 };
291
+ let bad = 0;
292
+ for (const char of text) {
293
+ const code = char.codePointAt(0) ?? 0;
294
+ if (code === 0xfffd || (code < 32 && code !== 9 && code !== 10 && code !== 13))
295
+ bad++;
296
+ else if (code >= 0xe000 && code <= 0xf8ff)
297
+ bad++;
298
+ }
299
+ const words = text.split(/\s+/).filter((word) => word !== '');
300
+ const meanWordLength = words.length === 0 ? 0 : words.reduce((sum, word) => sum + word.length, 0) / words.length;
301
+ return { badCharacterRatio: bad / text.length, meanWordLength };
302
+ }
303
+ const UNUSABLE_BAD_CHAR_RATIO = 0.3;
304
+ const UNUSABLE_MEAN_WORD_LENGTH = 2.2;
305
+ const SUSPECT_BAD_CHAR_RATIO = 0.1;
306
+ /**
307
+ * A real stream's `<< ... >>` dictionary sits immediately before its
308
+ * `stream` keyword — a handful of entries, at most a few hundred bytes.
309
+ * Bounding how far the search for it looks back keeps a single search
310
+ * O(window) instead of O(offset-into-file) — `String.lastIndexOf` has no
311
+ * "look back no further than N" parameter of its own, so the window is
312
+ * enforced by scanning forward within it instead (see
313
+ * `lastMatchWithinWindow`).
314
+ */
315
+ const DICTIONARY_SEARCH_WINDOW = 2048;
316
+ /**
317
+ * The last occurrence of `needle` within `[windowStart, before)`, at a cost
318
+ * bounded by the window's size regardless of how far into the file `before`
319
+ * is.
320
+ *
321
+ * `haystack.lastIndexOf(needle, before)` looks like it would do this — its
322
+ * second argument reads like a starting offset — but it still walks
323
+ * backward from `before` over the *entire* rest of the string looking for a
324
+ * match, unbounded. Scanning forward with `indexOf` from `windowStart`
325
+ * instead has the same problem in the other direction when the needle never
326
+ * occurs in the window at all: `indexOf` does not stop at `before`, it
327
+ * keeps searching to the end of the whole haystack. `slice` is what
328
+ * actually bounds the work — V8 (and every other engine) represents a
329
+ * substring as a view over the original backing storage rather than a
330
+ * fresh copy, so carving out `[windowStart, before)` is O(window), not
331
+ * O(haystack), and every subsequent operation on it is too.
332
+ */
333
+ function lastMatchWithinWindow(haystack, needle, before, windowStart) {
334
+ const window = haystack.slice(windowStart, before);
335
+ const at = window.lastIndexOf(needle);
336
+ return at === -1 ? -1 : windowStart + at;
337
+ }
338
+ /**
339
+ * A legitimate PDF has, at most, a few thousand objects. Refusing to walk
340
+ * past this many `stream`/`endstream` pairs bounds the total work
341
+ * `collectStreams` can be made to do by a file that is mostly repeated
342
+ * `stream\nendstream\n` markers and nothing else — no real PDF structure,
343
+ * no decompression, just the keyword search itself.
344
+ */
345
+ const MAX_STREAMS = 10_000;
346
+ function collectStreams(buffer) {
347
+ const streams = [];
348
+ const haystack = buffer.toString('latin1');
349
+ let searchFrom = 0;
350
+ while (streams.length < MAX_STREAMS) {
351
+ const keyword = haystack.indexOf('stream', searchFrom);
352
+ if (keyword === -1)
353
+ break;
354
+ // `endstream` also contains "stream"; skip those matches.
355
+ if (haystack.startsWith('endstream', Math.max(0, keyword - 3))) {
356
+ searchFrom = keyword + 6;
357
+ continue;
358
+ }
359
+ let dataStart = keyword + 'stream'.length;
360
+ if (haystack[dataStart] === '\r')
361
+ dataStart++;
362
+ if (haystack[dataStart] === '\n')
363
+ dataStart++;
364
+ const end = haystack.indexOf('endstream', dataStart);
365
+ if (end === -1)
366
+ break;
367
+ const windowStart = Math.max(0, keyword - DICTIONARY_SEARCH_WINDOW);
368
+ const dictStart = lastMatchWithinWindow(haystack, '<<', keyword, windowStart);
369
+ streams.push({
370
+ dictionary: dictStart === -1 ? '' : haystack.slice(dictStart, keyword),
371
+ data: buffer.subarray(dataStart, end),
372
+ });
373
+ searchFrom = end + 'endstream'.length;
374
+ }
375
+ return streams;
376
+ }
377
+ function decodeStream(stream) {
378
+ const filters = stream.dictionary.match(/\/Filter\s*(\/\w+|\[[^\]]*\])/);
379
+ const filter = filters?.[1] ?? '';
380
+ if (filter === '' || filter === '/') {
381
+ return stream.data;
382
+ }
383
+ if (!filter.includes('FlateDecode'))
384
+ return undefined;
385
+ try {
386
+ return inflateSync(stream.data, { maxOutputLength: MAX_INFLATED_BYTES });
387
+ }
388
+ catch {
389
+ // A stream whose bytes we mis-sliced (a binary `endstream` inside an
390
+ // image, say) is skipped, never fatal: the other streams still carry
391
+ // the text.
392
+ return undefined;
393
+ }
394
+ }
395
+ export function extractPdfText(buffer) {
396
+ if (!buffer.subarray(0, 5).toString('latin1').startsWith('%PDF-')) {
397
+ throw new CogentaError({
398
+ code: 'DOCUMENT_EXTRACTION_FAILED',
399
+ message: 'This file does not start with a %PDF- header.',
400
+ hint: 'Upload the original PDF, or export the document as Markdown or plain text.',
401
+ });
402
+ }
403
+ if (/\/Encrypt\b/.test(buffer.toString('latin1'))) {
404
+ throw new CogentaError({
405
+ code: 'DOCUMENT_EXTRACTION_FAILED',
406
+ message: 'This PDF is encrypted, so its text cannot be read.',
407
+ hint: 'Remove the password protection and upload it again, or paste the text directly.',
408
+ });
409
+ }
410
+ const warnings = [];
411
+ const pages = [];
412
+ let skipped = 0;
413
+ let accumulated = 0;
414
+ // `MAX_TEXT_CHARACTERS` is `extractDocumentText`'s final cap, checked only
415
+ // after every format reader has already built its whole result string.
416
+ // Enforcing the same budget here, inside the loop, is what stops a PDF
417
+ // whose individual streams each stay under the per-stream decompression
418
+ // cap but are numerous and highly compressible from accumulating many
419
+ // times that budget in memory before the final truncation ever runs — the
420
+ // truncation itself still happens downstream, unchanged; this only stops
421
+ // reading further pages once there is already more than enough text to
422
+ // fill it.
423
+ for (const stream of collectStreams(buffer)) {
424
+ if (accumulated > MAX_TEXT_CHARACTERS) {
425
+ warnings.push('Stopped reading further pages after the text-length cap was reached; the document has more content than was extracted.');
426
+ break;
427
+ }
428
+ if (/\/Type\s*\/(?:XObject|Metadata|ObjStm|XRef)\b/.test(stream.dictionary))
429
+ continue;
430
+ const decoded = decodeStream(stream);
431
+ if (decoded === undefined) {
432
+ skipped++;
433
+ continue;
434
+ }
435
+ // A content stream is the only thing with text-showing operators in it.
436
+ if (!/\b(?:Tj|TJ)\b/.test(decoded.toString('latin1')))
437
+ continue;
438
+ const text = textFromContentStream(decoded);
439
+ if (text.trim() !== '') {
440
+ pages.push(text);
441
+ accumulated += text.length;
442
+ }
443
+ }
444
+ if (pages.length === 0) {
445
+ throw new CogentaError({
446
+ code: 'DOCUMENT_NO_TEXT_LAYER',
447
+ message: 'No text layer was found in this PDF.',
448
+ hint: 'The file is most likely a scan or an export of images. Run it through OCR first, or upload the source document (DOCX, Markdown, plain text).',
449
+ details: { streamsSkipped: skipped },
450
+ });
451
+ }
452
+ const text = pages.join('\n\n');
453
+ const readability = measureReadability(text);
454
+ if (readability.badCharacterRatio > UNUSABLE_BAD_CHAR_RATIO ||
455
+ readability.meanWordLength < UNUSABLE_MEAN_WORD_LENGTH) {
456
+ // Refused, not warned about. Handing this on as if it were the document
457
+ // is the single most expensive thing this reader could do: everything
458
+ // downstream would happily analyse the mojibake and produce a confident,
459
+ // entirely invented site plan.
460
+ throw new CogentaError({
461
+ code: 'DOCUMENT_NO_TEXT_LAYER',
462
+ message: 'This PDF has a text layer, but it is not readable: its fonts are subset with an encoding the file does not carry.',
463
+ hint: 'Upload the source document instead (DOCX, Markdown, plain text), re-export the PDF with "embed fonts" enabled, or run the file through OCR.',
464
+ details: {
465
+ badCharacterRatio: Number(readability.badCharacterRatio.toFixed(2)),
466
+ meanWordLength: Number(readability.meanWordLength.toFixed(2)),
467
+ },
468
+ });
469
+ }
470
+ if (readability.badCharacterRatio > SUSPECT_BAD_CHAR_RATIO) {
471
+ warnings.push(`${Math.round(readability.badCharacterRatio * 100)}% of the extracted characters are not readable text — check the result before relying on it.`);
472
+ }
473
+ if (skipped > 0) {
474
+ warnings.push(`${skipped} stream(s) used a filter this reader does not decode and were skipped.`);
475
+ }
476
+ return { text, warnings };
477
+ }
478
+ //# sourceMappingURL=pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../src/documents/pdf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface ZipArchive {
2
+ /** Entry names, in central-directory order. */
3
+ readonly names: readonly string[];
4
+ /**
5
+ * `undefined` when the archive has no such entry — a missing part is a
6
+ * caller's decision, not an error here.
7
+ *
8
+ * `maxBytes` overrides the default 200 MiB decompression-bomb cap
9
+ * (`MAX_INFLATED_BYTES`) for this one read. A caller that knows it is
10
+ * about to run an expensive parse over the result — a regular expression
11
+ * or hand-written scanner over XML, say — should pass a much smaller
12
+ * number: the bomb cap alone only bounds memory, not the CPU cost of
13
+ * whatever runs on the inflated bytes afterwards.
14
+ */
15
+ read(name: string, maxBytes?: number): Buffer | undefined;
16
+ }
17
+ export declare function openZip(buffer: Buffer): ZipArchive;
18
+ //# sourceMappingURL=zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/documents/zip.ts"],"names":[],"mappings":"AAkHA,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC;;;;;;;;;;OAUG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAC1D;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAUlD"}
@@ -0,0 +1,113 @@
1
+ import { inflateRawSync } from 'node:zlib';
2
+ import { CogentaError } from '@cogenta/core';
3
+ /**
4
+ * The three-hundred-line half of the ZIP format a `.docx` actually uses:
5
+ * locate the end-of-central-directory record, walk the central directory,
6
+ * and inflate one named entry.
7
+ *
8
+ * R9/R10 — written here rather than pulled in: every maintained Node
9
+ * unzip library (`yauzl`, `adm-zip`, `unzipper`, `jszip`) is either
10
+ * callback-era, unmaintained, or an order of magnitude larger than the
11
+ * ~120 lines a `.docx` needs, and Node already ships the only hard part
12
+ * (`node:zlib`'s raw inflate). A `.docx` is always a stored or deflated
13
+ * ZIP with a real central directory — no encryption, no spanning, no
14
+ * ZIP64 unless the document is over 4 GB, which the size cap in
15
+ * `extract-text.ts` rejects long before this code is reached.
16
+ */
17
+ const EOCD_SIGNATURE = 0x0605_4b50;
18
+ const CENTRAL_SIGNATURE = 0x0201_4b50;
19
+ const LOCAL_SIGNATURE = 0x0403_4b50;
20
+ const EOCD_MIN_SIZE = 22;
21
+ /** The comment field is the only variable-length tail; 64 KiB is its maximum. */
22
+ const EOCD_MAX_SEARCH = EOCD_MIN_SIZE + 0xffff;
23
+ /** Refuses a decompression bomb: 200 MiB out of a document we already capped on the way in. */
24
+ const MAX_INFLATED_BYTES = 200 * 1024 * 1024;
25
+ function corrupt(reason) {
26
+ return new CogentaError({
27
+ code: 'DOCUMENT_EXTRACTION_FAILED',
28
+ message: `This file is not a readable ZIP archive: ${reason}.`,
29
+ hint: 'A .docx is a ZIP container. Re-save the document from your word processor, or upload it as Markdown or plain text instead.',
30
+ });
31
+ }
32
+ function findEndOfCentralDirectory(buffer) {
33
+ const from = Math.max(0, buffer.length - EOCD_MAX_SEARCH);
34
+ for (let at = buffer.length - EOCD_MIN_SIZE; at >= from; at--) {
35
+ if (buffer.readUInt32LE(at) === EOCD_SIGNATURE)
36
+ return at;
37
+ }
38
+ throw corrupt('no end-of-central-directory record was found');
39
+ }
40
+ function readCentralDirectory(buffer) {
41
+ const eocd = findEndOfCentralDirectory(buffer);
42
+ const entryCount = buffer.readUInt16LE(eocd + 10);
43
+ const directoryOffset = buffer.readUInt32LE(eocd + 16);
44
+ if (directoryOffset >= buffer.length)
45
+ throw corrupt('the central directory starts past the file');
46
+ const entries = [];
47
+ let at = directoryOffset;
48
+ for (let index = 0; index < entryCount; index++) {
49
+ if (at + 46 > buffer.length)
50
+ throw corrupt('a central directory entry is truncated');
51
+ if (buffer.readUInt32LE(at) !== CENTRAL_SIGNATURE) {
52
+ throw corrupt(`central directory entry ${index} has a bad signature`);
53
+ }
54
+ const nameLength = buffer.readUInt16LE(at + 28);
55
+ const extraLength = buffer.readUInt16LE(at + 30);
56
+ const commentLength = buffer.readUInt16LE(at + 32);
57
+ entries.push({
58
+ name: buffer.toString('utf8', at + 46, at + 46 + nameLength),
59
+ compression: buffer.readUInt16LE(at + 10),
60
+ compressedSize: buffer.readUInt32LE(at + 20),
61
+ uncompressedSize: buffer.readUInt32LE(at + 24),
62
+ localHeaderOffset: buffer.readUInt32LE(at + 42),
63
+ });
64
+ at += 46 + nameLength + extraLength + commentLength;
65
+ }
66
+ return entries;
67
+ }
68
+ function readEntryData(buffer, entry, maxBytes) {
69
+ const at = entry.localHeaderOffset;
70
+ if (at + 30 > buffer.length)
71
+ throw corrupt(`the local header of "${entry.name}" is truncated`);
72
+ if (buffer.readUInt32LE(at) !== LOCAL_SIGNATURE) {
73
+ throw corrupt(`the local header of "${entry.name}" has a bad signature`);
74
+ }
75
+ const nameLength = buffer.readUInt16LE(at + 26);
76
+ const extraLength = buffer.readUInt16LE(at + 28);
77
+ const start = at + 30 + nameLength + extraLength;
78
+ const end = start + entry.compressedSize;
79
+ if (end > buffer.length)
80
+ throw corrupt(`the data of "${entry.name}" is truncated`);
81
+ if (entry.uncompressedSize > maxBytes) {
82
+ throw new CogentaError({
83
+ code: 'DOCUMENT_TOO_LARGE',
84
+ message: `"${entry.name}" expands to ${entry.uncompressedSize} bytes, over the ${maxBytes}-byte limit.`,
85
+ hint: 'Upload a smaller document, or paste the relevant sections as plain text.',
86
+ details: { entry: entry.name, uncompressedSize: entry.uncompressedSize },
87
+ });
88
+ }
89
+ const raw = buffer.subarray(start, end);
90
+ if (entry.compression === 0)
91
+ return raw;
92
+ if (entry.compression !== 8) {
93
+ throw corrupt(`"${entry.name}" uses unsupported compression method ${entry.compression}`);
94
+ }
95
+ try {
96
+ return inflateRawSync(raw, { maxOutputLength: maxBytes });
97
+ }
98
+ catch (error) {
99
+ throw corrupt(`"${entry.name}" could not be inflated: ${error instanceof Error ? error.message : String(error)}`);
100
+ }
101
+ }
102
+ export function openZip(buffer) {
103
+ const entries = readCentralDirectory(buffer);
104
+ const byName = new Map(entries.map((entry) => [entry.name, entry]));
105
+ return {
106
+ names: entries.map((entry) => entry.name),
107
+ read(name, maxBytes = MAX_INFLATED_BYTES) {
108
+ const entry = byName.get(name);
109
+ return entry === undefined ? undefined : readEntryData(buffer, entry, maxBytes);
110
+ },
111
+ };
112
+ }
113
+ //# sourceMappingURL=zip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/documents/zip.ts"],"names":[],"mappings":"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"}