@gmickel/gno 1.12.0 → 1.12.2
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/package.json
CHANGED
|
@@ -40,6 +40,7 @@ const CFB_SIGNATURE = new Uint8Array([
|
|
|
40
40
|
]);
|
|
41
41
|
const ENCRYPTION_INFO = utf16le("EncryptionInfo");
|
|
42
42
|
const ENCRYPTED_PACKAGE = utf16le("EncryptedPackage");
|
|
43
|
+
const PDF_TRAILER_SCAN_BYTES = 2048;
|
|
43
44
|
const MAX_MESSAGE_LENGTH = 200;
|
|
44
45
|
const PASSWORD_ERROR_REGEX = /password(?:-protected)?|no password given/i;
|
|
45
46
|
|
|
@@ -100,6 +101,19 @@ function isPasswordProtectedPdf(bytes: Uint8Array): boolean {
|
|
|
100
101
|
return /\/Encrypt\b/.test(tail);
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
function hasCompletePdfTrailer(bytes: Uint8Array): boolean {
|
|
105
|
+
if (!hasPrefix(bytes, PDF_SIGNATURE)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const tailStart = Math.max(0, bytes.length - PDF_TRAILER_SCAN_BYTES);
|
|
110
|
+
const tail = Buffer.from(bytes.subarray(tailStart)).toString("latin1");
|
|
111
|
+
const eofIndex = tail.lastIndexOf("%%EOF");
|
|
112
|
+
const startXrefIndex = tail.lastIndexOf("startxref");
|
|
113
|
+
|
|
114
|
+
return startXrefIndex >= 0 && eofIndex > startXrefIndex;
|
|
115
|
+
}
|
|
116
|
+
|
|
103
117
|
function isPasswordProtectedXlsx(bytes: Uint8Array): boolean {
|
|
104
118
|
return (
|
|
105
119
|
hasPrefix(bytes, CFB_SIGNATURE) &&
|
|
@@ -162,7 +176,20 @@ export const markitdownAdapter: Converter = {
|
|
|
162
176
|
return { ok: false, error: tooLargeError(input, CONVERTER_ID) };
|
|
163
177
|
}
|
|
164
178
|
|
|
165
|
-
// 1b.
|
|
179
|
+
// 1b. Reject obviously truncated PDFs before markitdown-ts logs a parser
|
|
180
|
+
// stack trace. ISO 32000 requires the final %%EOF marker near the file end.
|
|
181
|
+
if (input.ext === ".pdf" && !hasCompletePdfTrailer(input.bytes)) {
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
error: corruptError(
|
|
185
|
+
input,
|
|
186
|
+
CONVERTER_ID,
|
|
187
|
+
"Invalid or incomplete PDF structure"
|
|
188
|
+
),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// 1c. Detect password-protected documents before calling markitdown-ts.
|
|
166
193
|
// markitdown-ts logs dependency stack traces to stderr for these files.
|
|
167
194
|
if (isPasswordProtected(input)) {
|
|
168
195
|
return {
|
package/src/ingestion/sync.ts
CHANGED
|
@@ -75,6 +75,12 @@ const MAX_CONCURRENCY = 16;
|
|
|
75
75
|
export const INGEST_VERSION = 6;
|
|
76
76
|
const EMPTY_CONTENT_TYPE_RULES_FINGERPRINT = fingerprintContentTypeRules([]);
|
|
77
77
|
const RELATION_EDGE_TYPE_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
78
|
+
const NON_RETRYABLE_CONVERSION_ERROR_CODES = new Set([
|
|
79
|
+
"CORRUPT",
|
|
80
|
+
"PERMISSION",
|
|
81
|
+
"TOO_LARGE",
|
|
82
|
+
"UNSUPPORTED",
|
|
83
|
+
]);
|
|
78
84
|
|
|
79
85
|
type RelationMap = Record<string, string[]>;
|
|
80
86
|
|
|
@@ -219,6 +225,20 @@ function decideAction(
|
|
|
219
225
|
|
|
220
226
|
// Source unchanged, but check for repair cases:
|
|
221
227
|
|
|
228
|
+
// Preserve non-retryable conversion failures until the source or ingest
|
|
229
|
+
// version changes. Re-running an unchanged corrupt/protected file on every
|
|
230
|
+
// sync only repeats expensive work and noisy diagnostics.
|
|
231
|
+
if (
|
|
232
|
+
existing.lastErrorCode &&
|
|
233
|
+
NON_RETRYABLE_CONVERSION_ERROR_CODES.has(existing.lastErrorCode) &&
|
|
234
|
+
existing.ingestVersion === INGEST_VERSION
|
|
235
|
+
) {
|
|
236
|
+
return {
|
|
237
|
+
kind: "skip",
|
|
238
|
+
reason: "unchanged non-retryable conversion failure",
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
222
242
|
// 1. Previous conversion failed (mirrorHash is null)
|
|
223
243
|
if (!existing.mirrorHash) {
|
|
224
244
|
return { kind: "repair", reason: "previous conversion failed" };
|
|
@@ -738,6 +758,8 @@ export class SyncService {
|
|
|
738
758
|
sourceCtime,
|
|
739
759
|
lastErrorCode: convertResult.error.code,
|
|
740
760
|
lastErrorMessage: convertResult.error.message,
|
|
761
|
+
ingestVersion: INGEST_VERSION,
|
|
762
|
+
contentTypeRulesFingerprint,
|
|
741
763
|
// mirrorHash intentionally omitted (will be null)
|
|
742
764
|
});
|
|
743
765
|
|