mcard-js 2.1.48 → 2.1.49

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 (37) hide show
  1. package/dist/AbstractSqlEngine-DKka6XjT.d.cts +451 -0
  2. package/dist/AbstractSqlEngine-DKka6XjT.d.ts +451 -0
  3. package/dist/CardCollection-ZQ3G3Q3A.js +10 -0
  4. package/dist/IndexedDBEngine-BWXAB46W.js +12 -0
  5. package/dist/LLMRuntime-PH3MOQ2Y.js +17 -0
  6. package/dist/LambdaRuntime-YH74FHIW.js +19 -0
  7. package/dist/Loader-WZXYG4GE.js +12 -0
  8. package/dist/NetworkRuntime-S4DZCGVN.js +1598 -0
  9. package/dist/OllamaProvider-SPGO5Z5E.js +9 -0
  10. package/dist/chunk-3FFEA2XK.js +149 -0
  11. package/dist/chunk-7AXRV7NS.js +112 -0
  12. package/dist/chunk-HIVVDGE5.js +497 -0
  13. package/dist/chunk-KVZYFZJ5.js +427 -0
  14. package/dist/chunk-NGTY4P6A.js +275 -0
  15. package/dist/chunk-OUW2SUGM.js +368 -0
  16. package/dist/chunk-QKH3N62B.js +2360 -0
  17. package/dist/chunk-QPVEUPMU.js +299 -0
  18. package/dist/chunk-VYDZR4ZD.js +364 -0
  19. package/dist/chunk-XJZOEM5F.js +903 -0
  20. package/dist/chunk-Z7EFXSTO.js +217 -0
  21. package/dist/index.browser.cjs +37 -1
  22. package/dist/index.browser.d.cts +20 -2
  23. package/dist/index.browser.d.ts +20 -2
  24. package/dist/index.browser.js +10 -6
  25. package/dist/index.cjs +618 -146
  26. package/dist/index.d.cts +723 -4
  27. package/dist/index.d.ts +723 -4
  28. package/dist/index.js +527 -89
  29. package/dist/storage/SqliteNodeEngine.cjs +7 -1
  30. package/dist/storage/SqliteNodeEngine.d.cts +1 -1
  31. package/dist/storage/SqliteNodeEngine.d.ts +1 -1
  32. package/dist/storage/SqliteNodeEngine.js +3 -3
  33. package/dist/storage/SqliteWasmEngine.cjs +7 -1
  34. package/dist/storage/SqliteWasmEngine.d.cts +1 -1
  35. package/dist/storage/SqliteWasmEngine.d.ts +1 -1
  36. package/dist/storage/SqliteWasmEngine.js +3 -3
  37. package/package.json +1 -1
@@ -0,0 +1,299 @@
1
+ import {
2
+ DEFAULT_PAGE_SIZE
3
+ } from "./chunk-3FFEA2XK.js";
4
+ import {
5
+ MCard
6
+ } from "./chunk-GGQCF7ZK.js";
7
+
8
+ // src/monads/Maybe.ts
9
+ var Maybe = class _Maybe {
10
+ constructor(_value, _isNothing) {
11
+ this._value = _value;
12
+ this._isNothing = _isNothing;
13
+ }
14
+ /**
15
+ * Create a Just (has value)
16
+ */
17
+ static just(value) {
18
+ return new _Maybe(value, false);
19
+ }
20
+ /**
21
+ * Create a Nothing (no value)
22
+ */
23
+ static nothing() {
24
+ return new _Maybe(null, true);
25
+ }
26
+ /**
27
+ * Check if this is Nothing
28
+ */
29
+ get isNothing() {
30
+ return this._isNothing;
31
+ }
32
+ /**
33
+ * Check if this is Just
34
+ */
35
+ get isJust() {
36
+ return !this._isNothing;
37
+ }
38
+ /**
39
+ * Get the value (throws if Nothing)
40
+ */
41
+ get value() {
42
+ if (this._isNothing) {
43
+ throw new Error("Cannot get value from Nothing");
44
+ }
45
+ return this._value;
46
+ }
47
+ /**
48
+ * Monadic bind - chain operations
49
+ * Short-circuits on Nothing
50
+ */
51
+ bind(fn) {
52
+ if (this._isNothing) {
53
+ return _Maybe.nothing();
54
+ }
55
+ return fn(this._value);
56
+ }
57
+ /**
58
+ * Map a function over the value
59
+ */
60
+ map(fn) {
61
+ if (this._isNothing) {
62
+ return _Maybe.nothing();
63
+ }
64
+ return _Maybe.just(fn(this._value));
65
+ }
66
+ /**
67
+ * Get value or default
68
+ */
69
+ getOrElse(defaultValue) {
70
+ return this._isNothing ? defaultValue : this._value;
71
+ }
72
+ };
73
+
74
+ // src/model/CardCollection.ts
75
+ var CardCollection = class {
76
+ engine;
77
+ constructor(engine) {
78
+ this.engine = engine;
79
+ }
80
+ // =========== Standard Operations ===========
81
+ /**
82
+ * Add a card to the collection
83
+ * Handles duplicates (same content, same hash) and collisions (diff content, same hash)
84
+ */
85
+ async add(card) {
86
+ const existingCard = await this.engine.get(card.hash);
87
+ if (existingCard) {
88
+ const isDuplicate = this.areContentsEqual(existingCard.content, card.content);
89
+ if (isDuplicate) {
90
+ const { generateDuplicationEvent } = await import("./EventProducer-VFDOM5W2.js");
91
+ const eventStr = generateDuplicationEvent(card);
92
+ const eventCard = await MCard.create(eventStr);
93
+ await this.engine.add(eventCard);
94
+ return card.hash;
95
+ } else {
96
+ const { generateCollisionEvent } = await import("./EventProducer-VFDOM5W2.js");
97
+ const eventStr = await generateCollisionEvent(card);
98
+ const eventCard = await MCard.create(eventStr);
99
+ await this.engine.add(eventCard);
100
+ const eventObj = JSON.parse(eventStr);
101
+ const nextAlgo = eventObj.upgraded_function;
102
+ if (!nextAlgo) {
103
+ throw new Error("Failed to determine next hash algorithm for collision");
104
+ }
105
+ const upgradedCard = await MCard.create(card.content, nextAlgo);
106
+ return this.engine.add(upgradedCard);
107
+ }
108
+ }
109
+ return this.engine.add(card);
110
+ }
111
+ areContentsEqual(a, b) {
112
+ if (a.length !== b.length) return false;
113
+ for (let i = 0; i < a.length; i++) {
114
+ if (a[i] !== b[i]) return false;
115
+ }
116
+ return true;
117
+ }
118
+ /**
119
+ * Get a card by hash
120
+ */
121
+ async get(hash) {
122
+ return this.engine.get(hash);
123
+ }
124
+ /**
125
+ * Delete a card by hash
126
+ */
127
+ async delete(hash) {
128
+ return this.engine.delete(hash);
129
+ }
130
+ /**
131
+ * Get a page of cards
132
+ */
133
+ async getPage(pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
134
+ return this.engine.getPage(pageNumber, pageSize);
135
+ }
136
+ /**
137
+ * Count total cards
138
+ */
139
+ async count() {
140
+ return this.engine.count();
141
+ }
142
+ // =========== Handle Operations ===========
143
+ /**
144
+ * Add a card and register a handle for it
145
+ */
146
+ async addWithHandle(card, handle) {
147
+ const hash = await this.add(card);
148
+ await this.engine.registerHandle(handle, hash);
149
+ return hash;
150
+ }
151
+ /**
152
+ * Get card by handle
153
+ */
154
+ async getByHandle(handle) {
155
+ return this.engine.getByHandle(handle);
156
+ }
157
+ /**
158
+ * Resolve handle to hash
159
+ */
160
+ async resolveHandle(handle) {
161
+ return this.engine.resolveHandle(handle);
162
+ }
163
+ /**
164
+ * Update handle to point to new card
165
+ */
166
+ async updateHandle(handle, newCard) {
167
+ const hash = await this.add(newCard);
168
+ await this.engine.updateHandle(handle, hash);
169
+ return hash;
170
+ }
171
+ /**
172
+ * Get version history for a handle
173
+ */
174
+ async getHandleHistory(handle) {
175
+ return this.engine.getHandleHistory(handle);
176
+ }
177
+ // =========== Monadic Operations ===========
178
+ /**
179
+ * Monadic get - returns Maybe<MCard>
180
+ */
181
+ async getM(hash) {
182
+ const card = await this.get(hash);
183
+ return card ? Maybe.just(card) : Maybe.nothing();
184
+ }
185
+ /**
186
+ * Monadic getByHandle - returns Maybe<MCard>
187
+ */
188
+ async getByHandleM(handle) {
189
+ const card = await this.getByHandle(handle);
190
+ return card ? Maybe.just(card) : Maybe.nothing();
191
+ }
192
+ /**
193
+ * Monadic resolveHandle - returns Maybe<string>
194
+ */
195
+ async resolveHandleM(handle) {
196
+ const hash = await this.resolveHandle(handle);
197
+ return hash ? Maybe.just(hash) : Maybe.nothing();
198
+ }
199
+ /**
200
+ * Resolve handle and get card in one monadic operation
201
+ */
202
+ async resolveAndGetM(handle) {
203
+ const maybeHash = await this.resolveHandleM(handle);
204
+ if (maybeHash.isNothing) return Maybe.nothing();
205
+ return this.getM(maybeHash.value);
206
+ }
207
+ /**
208
+ * Prune version history for a handle.
209
+ * @param handle The handle string.
210
+ * @param options Options for pruning (olderThan date, or deleteAll).
211
+ * @returns Number of deleted entries.
212
+ */
213
+ async pruneHandleHistory(handle, options = {}) {
214
+ if (this.engine.pruneHandleHistory) {
215
+ return this.engine.pruneHandleHistory(handle, options);
216
+ }
217
+ return 0;
218
+ }
219
+ // =========== Search & Bulk Operations ===========
220
+ async clear() {
221
+ return this.engine.clear();
222
+ }
223
+ async searchByString(query, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
224
+ return this.engine.search(query, pageNumber, pageSize);
225
+ }
226
+ async searchByContent(query, pageNumber = 1, pageSize = DEFAULT_PAGE_SIZE) {
227
+ return this.engine.search(query, pageNumber, pageSize);
228
+ }
229
+ async searchByHash(hashPrefix) {
230
+ return this.engine.searchByHash(hashPrefix);
231
+ }
232
+ async getAllMCardsRaw() {
233
+ return this.engine.getAll();
234
+ }
235
+ async getAllCards(pageSize = DEFAULT_PAGE_SIZE, processCallback) {
236
+ const cards = [];
237
+ let pageNumber = 1;
238
+ let total = 0;
239
+ while (true) {
240
+ const page = await this.getPage(pageNumber, pageSize);
241
+ if (!page.items || page.items.length === 0) break;
242
+ for (const card of page.items) {
243
+ if (processCallback) {
244
+ processCallback(card);
245
+ }
246
+ cards.push(card);
247
+ }
248
+ total = page.totalItems;
249
+ if (!page.hasNext) break;
250
+ pageNumber++;
251
+ }
252
+ return { cards, total };
253
+ }
254
+ async printAllCards() {
255
+ const cards = await this.getAllMCardsRaw();
256
+ cards.forEach((card) => {
257
+ console.log(`Hash: ${card.hash}`);
258
+ try {
259
+ const text = new TextDecoder().decode(card.content);
260
+ const preview = text.slice(0, 100).replace(/\n/g, " ");
261
+ console.log(`Content: ${preview}${text.length > 100 ? "..." : ""}`);
262
+ } catch {
263
+ console.log(`Content (binary): ${card.content.length} bytes`);
264
+ }
265
+ console.log("---");
266
+ });
267
+ }
268
+ // =========== Handle Management Operations ===========
269
+ /**
270
+ * List all registered handles with their current hashes.
271
+ */
272
+ async getAllHandles() {
273
+ return this.engine.getAllHandles();
274
+ }
275
+ /**
276
+ * Remove a handle and all its history entries.
277
+ * Does NOT delete the underlying card(s).
278
+ */
279
+ async removeHandle(handle) {
280
+ return this.engine.removeHandle(handle);
281
+ }
282
+ /**
283
+ * Rename a handle atomically: updates handle registry and all history entries.
284
+ */
285
+ async renameHandle(oldHandle, newHandle) {
286
+ return this.engine.renameHandle(oldHandle, newHandle);
287
+ }
288
+ /**
289
+ * Delete a single history entry by handle + previousHash, stitching the chain.
290
+ */
291
+ async deleteHistoryEntry(handle, previousHash) {
292
+ return this.engine.deleteHistoryEntry(handle, previousHash);
293
+ }
294
+ };
295
+
296
+ export {
297
+ Maybe,
298
+ CardCollection
299
+ };
@@ -0,0 +1,364 @@
1
+ import {
2
+ MAX_FILE_SIZE,
3
+ READ_TIMEOUT_MS
4
+ } from "./chunk-3FFEA2XK.js";
5
+ import {
6
+ ContentTypeInterpreter,
7
+ MCard
8
+ } from "./chunk-GGQCF7ZK.js";
9
+ import {
10
+ __export
11
+ } from "./chunk-PNKVD2UK.js";
12
+
13
+ // src/Loader.ts
14
+ var Loader_exports = {};
15
+ __export(Loader_exports, {
16
+ loadFileToCollection: () => loadFileToCollection,
17
+ processAndStoreFile: () => processAndStoreFile
18
+ });
19
+ import * as fs2 from "fs/promises";
20
+ import * as path2 from "path";
21
+
22
+ // src/FileIO.ts
23
+ var FileIO_exports = {};
24
+ __export(FileIO_exports, {
25
+ isProblematicFile: () => isProblematicFile,
26
+ listFiles: () => listFiles,
27
+ processFileContent: () => processFileContent,
28
+ readFileSafely: () => readFileSafely,
29
+ streamReadNormalizedText: () => streamReadNormalizedText
30
+ });
31
+ import * as crypto from "crypto";
32
+ import * as fs from "fs/promises";
33
+ import * as path from "path";
34
+ async function streamReadNormalizedText(filePath, options) {
35
+ const { byteCap, wrapWidth } = options;
36
+ const sha = crypto.createHash("sha256");
37
+ let totalSize = 0;
38
+ let producedText = "";
39
+ let currentLen = 0;
40
+ const handle = await fs.open(filePath, "r");
41
+ try {
42
+ const buffer = new Uint8Array(8192);
43
+ let remaining = byteCap;
44
+ const decoder = new TextDecoder("utf-8", { fatal: false });
45
+ let position = 0;
46
+ while (remaining > 0) {
47
+ const { bytesRead } = await handle.read(buffer, 0, Math.min(buffer.length, remaining), position);
48
+ if (bytesRead === 0) break;
49
+ position += bytesRead;
50
+ const chunk = buffer.subarray(0, bytesRead);
51
+ sha.update(chunk);
52
+ totalSize += bytesRead;
53
+ remaining -= bytesRead;
54
+ const s2 = decoder.decode(chunk, { stream: true });
55
+ for (const ch of s2) {
56
+ if (ch === "\r") continue;
57
+ producedText += ch;
58
+ if (ch === "\n") {
59
+ currentLen = 0;
60
+ } else {
61
+ currentLen++;
62
+ if (wrapWidth > 0 && currentLen >= wrapWidth) {
63
+ producedText += "\n";
64
+ currentLen = 0;
65
+ }
66
+ }
67
+ }
68
+ }
69
+ const s = decoder.decode();
70
+ for (const ch of s) {
71
+ if (ch === "\r") continue;
72
+ producedText += ch;
73
+ if (ch === "\n") {
74
+ currentLen = 0;
75
+ } else {
76
+ currentLen++;
77
+ if (wrapWidth > 0 && currentLen >= wrapWidth) {
78
+ producedText += "\n";
79
+ currentLen = 0;
80
+ }
81
+ }
82
+ }
83
+ } finally {
84
+ await handle.close();
85
+ }
86
+ return {
87
+ text: producedText,
88
+ originalSize: totalSize,
89
+ originalSha256Prefix: sha.digest("hex").substring(0, 16)
90
+ };
91
+ }
92
+ var MAX_FILE_SIZE2 = MAX_FILE_SIZE;
93
+ var READ_TIMEOUT_MS2 = READ_TIMEOUT_MS;
94
+ async function isProblematicFile(filePath) {
95
+ try {
96
+ const stats = await fs.stat(filePath);
97
+ if (stats.size === 0) return false;
98
+ if (path.basename(filePath).startsWith(".")) return true;
99
+ if (stats.size > MAX_FILE_SIZE2) return true;
100
+ const ext = path.extname(filePath);
101
+ const isKnownType = ContentTypeInterpreter.isKnownLongLineExtension(ext);
102
+ if (isKnownType && stats.size > 1024 * 1024) return true;
103
+ const handle = await fs.open(filePath, "r");
104
+ try {
105
+ const buffer = new Uint8Array(32 * 1024);
106
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
107
+ const sample = buffer.subarray(0, bytesRead);
108
+ if (ContentTypeInterpreter.isUnstructuredBinary(sample)) return true;
109
+ if (ContentTypeInterpreter.hasPathologicalLines(sample, isKnownType)) return true;
110
+ } finally {
111
+ await handle.close();
112
+ }
113
+ return false;
114
+ } catch {
115
+ return true;
116
+ }
117
+ }
118
+ async function readFileSafely(filePath, options = {}) {
119
+ const stats = await fs.stat(filePath);
120
+ if (stats.size > MAX_FILE_SIZE2) throw new Error(`File too large: ${stats.size}`);
121
+ const controller = new AbortController();
122
+ const timeout = setTimeout(() => controller.abort(), READ_TIMEOUT_MS2);
123
+ try {
124
+ const handle = await fs.open(filePath, "r");
125
+ try {
126
+ const buffer = new Uint8Array(stats.size);
127
+ await handle.read(buffer, 0, stats.size, 0);
128
+ return buffer;
129
+ } finally {
130
+ await handle.close();
131
+ }
132
+ } catch (e) {
133
+ const error = e;
134
+ if (error.name === "AbortError") throw new Error(`Read timeout for ${filePath}`);
135
+ throw e;
136
+ } finally {
137
+ clearTimeout(timeout);
138
+ }
139
+ }
140
+ async function listFiles(dirPath, recursive = false) {
141
+ let files = [];
142
+ try {
143
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
144
+ for (const entry of entries) {
145
+ const fullPath = path.join(dirPath, entry.name);
146
+ if (entry.name.startsWith(".")) continue;
147
+ if (entry.isDirectory()) {
148
+ if (recursive) {
149
+ files = files.concat(await listFiles(fullPath, true));
150
+ }
151
+ } else if (entry.isFile()) {
152
+ if (!await isProblematicFile(fullPath)) {
153
+ files.push(fullPath);
154
+ }
155
+ }
156
+ }
157
+ } catch (e) {
158
+ console.warn(`Error listing directory ${dirPath}:`, e);
159
+ }
160
+ return files;
161
+ }
162
+ async function processFileContent(filePath, options = {}) {
163
+ const rawContent = await readFileSafely(filePath, { allowPathological: options.allowPathological, maxBytes: options.maxBytes });
164
+ const sample = rawContent.subarray(0, 1024 * 1024);
165
+ const detection = ContentTypeInterpreter.detectContentType(sample, path.extname(filePath));
166
+ let isBinary = ContentTypeInterpreter.isBinaryContent(sample, detection.mimeType);
167
+ if (options.forceBinary) isBinary = true;
168
+ let content = rawContent;
169
+ if (!isBinary) {
170
+ try {
171
+ content = new TextDecoder("utf-8", { fatal: true }).decode(rawContent);
172
+ } catch {
173
+ content = new TextDecoder("utf-8", { fatal: false }).decode(rawContent);
174
+ }
175
+ }
176
+ return {
177
+ content,
178
+ filename: path.basename(filePath),
179
+ mimeType: detection.mimeType,
180
+ extension: detection.extension,
181
+ isBinary,
182
+ size: rawContent.length
183
+ };
184
+ }
185
+
186
+ // src/Loader.ts
187
+ var DEFAULT_MAX_PROBLEM_BYTES = 2 * 1024 * 1024;
188
+ var WRAP_WIDTH_KNOWN = 1e3;
189
+ var WRAP_WIDTH_DEFAULT = 80;
190
+ var Logger = {
191
+ info: (...args) => console.log("[Loader]", ...args),
192
+ warn: (...args) => console.warn("[Loader]", ...args),
193
+ error: (...args) => console.error("[Loader]", ...args),
194
+ debug: (...args) => {
195
+ if (process.env.DEBUG) console.log("[Loader]", ...args);
196
+ }
197
+ };
198
+ async function processAndStoreFile(filePath, collection, options = {}) {
199
+ const {
200
+ allowProblematic = false,
201
+ maxBytesOnProblem = DEFAULT_MAX_PROBLEM_BYTES,
202
+ metadataOnly = false,
203
+ rootPath
204
+ } = options;
205
+ try {
206
+ let fileInfo;
207
+ if (await isProblematicFile(filePath)) {
208
+ if (!allowProblematic) {
209
+ Logger.warn(`Skipping problematic file: ${filePath}`);
210
+ return null;
211
+ }
212
+ const extension = path2.extname(filePath).toLowerCase();
213
+ const isKnownType = ContentTypeInterpreter.isKnownLongLineExtension(extension);
214
+ const wrapWidth = isKnownType ? WRAP_WIDTH_KNOWN : WRAP_WIDTH_DEFAULT;
215
+ Logger.warn(`Problematic file detected, processing as safe text: ${filePath}`);
216
+ try {
217
+ const streamed = await streamReadNormalizedText(filePath, {
218
+ byteCap: maxBytesOnProblem,
219
+ wrapWidth
220
+ });
221
+ fileInfo = {
222
+ content: streamed.text,
223
+ filename: path2.basename(filePath),
224
+ mimeType: "text/plain",
225
+ extension,
226
+ isBinary: false,
227
+ size: streamed.text.length,
228
+ originalSize: streamed.originalSize,
229
+ originalSha256Prefix: streamed.originalSha256Prefix,
230
+ normalized: true,
231
+ wrapWidth
232
+ };
233
+ } catch (e) {
234
+ Logger.warn(`Safe text processing failed, falling back to capped binary: ${filePath}`, e);
235
+ fileInfo = await processFileContent(filePath, {
236
+ forceBinary: true,
237
+ allowPathological: true,
238
+ maxBytes: maxBytesOnProblem
239
+ });
240
+ }
241
+ } else {
242
+ Logger.info(`Processing file: ${filePath}`);
243
+ fileInfo = await processFileContent(filePath);
244
+ }
245
+ if (!fileInfo) return null;
246
+ const content = fileInfo.content;
247
+ if (!content || typeof content === "string" && content.length === 0 || content instanceof Uint8Array && content.length === 0) {
248
+ Logger.debug(`Skipping empty file: ${filePath} (empty files cannot be stored as MCards)`);
249
+ return {
250
+ hash: "",
251
+ contentType: fileInfo.mimeType,
252
+ isBinary: fileInfo.isBinary,
253
+ filename: fileInfo.filename,
254
+ size: 0,
255
+ filePath
256
+ };
257
+ }
258
+ let mcard = null;
259
+ const isProblematic = await isProblematicFile(filePath);
260
+ if (metadataOnly && isProblematic) {
261
+ mcard = null;
262
+ } else {
263
+ mcard = await MCard.create(fileInfo.content);
264
+ const handle = path2.basename(filePath);
265
+ try {
266
+ await collection.addWithHandle(mcard, handle);
267
+ } catch (e) {
268
+ let registered = false;
269
+ if (rootPath) {
270
+ const relPath = path2.relative(rootPath, filePath);
271
+ if (relPath !== handle) {
272
+ try {
273
+ await collection.addWithHandle(mcard, relPath);
274
+ registered = true;
275
+ } catch (e2) {
276
+ Logger.debug(
277
+ `Handle name '${handle}' already in use (common for files like README.md, LICENSE). MCard stored successfully with hash ${mcard.hash.slice(0, 8)}... (accessible by hash, not by handle)`
278
+ );
279
+ }
280
+ }
281
+ }
282
+ if (!registered) {
283
+ try {
284
+ await collection.add(mcard);
285
+ } catch (e3) {
286
+ Logger.warn(`Hash fallback also failed for ${handle}:`, e3);
287
+ }
288
+ }
289
+ }
290
+ }
291
+ const result = {
292
+ hash: mcard ? mcard.hash : "METADATA_ONLY",
293
+ contentType: fileInfo.mimeType,
294
+ isBinary: fileInfo.isBinary,
295
+ filename: fileInfo.filename,
296
+ size: fileInfo.size,
297
+ filePath
298
+ };
299
+ if (fileInfo.originalSize !== void 0) result.originalSize = fileInfo.originalSize;
300
+ if (fileInfo.originalSha256Prefix) result.originalSha256Prefix = fileInfo.originalSha256Prefix;
301
+ if (metadataOnly && isProblematic) result.metadataOnly = true;
302
+ return result;
303
+ } catch (e) {
304
+ Logger.error(`Error processing ${filePath}:`, e);
305
+ return null;
306
+ }
307
+ }
308
+ async function loadFileToCollection(targetPath, collection, options = {}) {
309
+ const {
310
+ recursive = false,
311
+ includeProblematic = false,
312
+ maxBytesOnProblem = DEFAULT_MAX_PROBLEM_BYTES,
313
+ metadataOnly = false
314
+ } = options;
315
+ const resolvedPath = path2.resolve(targetPath);
316
+ const stats = await fs2.stat(resolvedPath);
317
+ const results = [];
318
+ let files = [];
319
+ let rootPath = resolvedPath;
320
+ if (stats.isFile()) {
321
+ files = [resolvedPath];
322
+ rootPath = path2.dirname(resolvedPath);
323
+ } else if (stats.isDirectory()) {
324
+ files = await listFiles(resolvedPath, recursive);
325
+ rootPath = resolvedPath;
326
+ } else {
327
+ throw new Error(`Path ${targetPath} is not a file or directory`);
328
+ }
329
+ const uniqueDirs = /* @__PURE__ */ new Set();
330
+ let maxDepth = 0;
331
+ for (const file of files) {
332
+ const dir = path2.dirname(file);
333
+ if (dir.startsWith(rootPath)) {
334
+ uniqueDirs.add(dir);
335
+ const rel = path2.relative(rootPath, file);
336
+ const parts = rel.split(path2.sep);
337
+ const depth = parts.length - 1;
338
+ if (depth > maxDepth) maxDepth = depth;
339
+ }
340
+ }
341
+ const metrics = {
342
+ filesCount: files.length,
343
+ directoriesCount: uniqueDirs.size,
344
+ directoryLevels: maxDepth
345
+ };
346
+ Logger.info(`About to process ${files.length} files`);
347
+ for (const file of files) {
348
+ const result = await processAndStoreFile(file, collection, {
349
+ allowProblematic: includeProblematic,
350
+ maxBytesOnProblem,
351
+ metadataOnly,
352
+ rootPath
353
+ });
354
+ if (result) results.push(result);
355
+ }
356
+ return { metrics, results };
357
+ }
358
+
359
+ export {
360
+ FileIO_exports,
361
+ processAndStoreFile,
362
+ loadFileToCollection,
363
+ Loader_exports
364
+ };