UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

128 lines • 5.65 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { ContentType, FileStat, FileType } from "../../types.js"; import { epochToIso } from "../../utils/dates.js"; import { gnuBasename } from "../../utils/path.js"; import { stripSlash } from "../../utils/slash.js"; import { dirRows, dropCollisions, normalizeSlug, scalarString } from "../slug_tree/rows.js"; import { SlugTree } from "../slug_tree/tree.js"; import { listAllDocuments } from "./client.js"; export const SLUG_NOUN = 'Dify document slug'; async function loadTree(accessor) { return buildDirEntries(await listAllDocuments(accessor), accessor.config.slugMetadataName); } export function buildDirEntries(documents, slugMetadataName = 'slug') { const files = new Map(); const rawSlugs = new Map(); const hasSlugs = new Map(); for (const document of documents) { let path; let slug; let hasSlug; const documentId = scalarString(document.id); try { if (documentId === null || documentId.trim() === '') { throw new Error('missing document id'); } ; [slug, hasSlug] = extractSlug(document, slugMetadataName); path = normalizeSlug(slug, SLUG_NOUN); } catch (err) { console.warn(`Skipping invalid Dify document ${documentId ?? '?'}: ${String(err)}`); continue; } if (files.has(path)) { console.warn(`Skipping duplicate Dify document slug '${stripSlash(path)}': documents ` + `${scalarString(files.get(path)?.id) ?? '?'} and ${documentId} share the same path.`); continue; } files.set(path, document); rawSlugs.set(path, slug); hasSlugs.set(path, hasSlug); } const kept = dropCollisions(files, (ancestor, path) => { console.warn(`Skipping Dify document path collision: document ${scalarString(files.get(ancestor)?.id) ?? '?'} ` + `uses file path '${stripSlash(ancestor)}' but document ${scalarString(files.get(path)?.id) ?? '?'} ` + `requires it as a directory prefix.`); }); // No size: the API's is the uploaded source file (a PDF, say), not the // segment text this mount serves, so it rides in extra. return dirRows(kept, (path, document) => { const created = epochText(document.created_at); return new FileStat({ name: gnuBasename(path), type: FileType.FILE, content: ContentType.TEXT, modified: created, birthtime: created, extra: { slug: stripSlash(path), source_size: extractDocumentSize(document), slug_metadata_name: slugMetadataName, raw_slug: rawSlugs.get(path) ?? '', has_slug: hasSlugs.get(path) ?? false, tokens: document.tokens ?? null, indexing_status: document.indexing_status ?? null, data_source_type: document.data_source_type ?? null, document_id: scalarString(document.id) ?? '', }, }); }); } export function extractSlug(document, slugMetadataName = 'slug') { const metadata = document.doc_metadata; if (Array.isArray(metadata)) { for (const item of metadata) { if (item !== null && typeof item === 'object' && !Array.isArray(item)) { const record = item; if (record.name === slugMetadataName) { const value = scalarString(record.value); if (value !== null) return [value, true]; } } } } if (metadata !== null && typeof metadata === 'object' && !Array.isArray(metadata)) { const value = scalarString(metadata[slugMetadataName]); if (value !== null) return [value, true]; } const name = scalarString(document.name); if (name === null) throw new Error('missing document name'); return [name, false]; } export function extractDocumentSize(document) { for (const candidate of [document.data_source_detail_dict, document.data_source_info]) { if (candidate !== null && typeof candidate === 'object' && !Array.isArray(candidate)) { const uploadFile = candidate.upload_file; if (uploadFile !== null && typeof uploadFile === 'object' && !Array.isArray(uploadFile)) { const size = uploadFile.size; if (typeof size === 'number' && Number.isInteger(size)) return size; } } } return null; } /** A Dify timestamp (epoch seconds) as `YYYY-MM-DDTHH:MM:SSZ`; a string passes through. */ export function epochText(value) { if (typeof value === 'number') return epochToIso(value); return typeof value === 'string' ? value : null; } export const DIFY_TREE = new SlugTree(loadTree); //# sourceMappingURL=tree.js.map