UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

138 lines • 6.08 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 { asObject } from "../../utils/records.js"; import { cursorItems, cursorPages } from "../api/paginate.js"; import { completePage } from "./client.js"; import { MAX_PAGE_SIZE } from "./constants.js"; async function paginateTool(transport, toolName, baseArgs, maxResults) { const items = await cursorItems(async (cursor) => completePage(await transport.callTool(toolName, cursor === null ? { ...baseArgs } : { ...baseArgs, start_cursor: cursor })), maxResults); return items.map(asObject); } export async function searchDataSources(transport) { const baseArgs = { filter: { value: 'data_source', property: 'object' }, page_size: 100 }; return paginateTool(transport, 'API-post-search', baseArgs); } export async function getDatabase(transport, databaseId) { return transport.callTool('API-retrieve-a-database', { database_id: databaseId }); } export async function getDataSource(transport, dataSourceId) { return transport.callTool('API-retrieve-a-data-source', { data_source_id: dataSourceId }); } /** * Yield query pages only as the caller requests them. Each page is checked * for an incomplete response before yielding its rows. Closing the iterator * prevents further requests; the shared cursor walker retains its * repeated-cursor and terminal-page rules. Query options are never mutated. */ export async function* queryDataSourcePages(transport, dataSourceId, body = {}) { const baseArgs = { ...body, page_size: MAX_PAGE_SIZE }; for await (const page of cursorPages((cursor) => queryDataSourcePage(transport, dataSourceId, cursor === null ? { ...baseArgs } : { ...baseArgs, start_cursor: cursor }))) { yield page.map(asObject); } } export async function getPage(transport, pageId) { return transport.callTool('API-retrieve-a-page', { page_id: pageId }); } export async function getSelf(transport) { return transport.callTool('API-get-self', {}); } export async function getPageMarkdown(transport, pageId) { return transport.callTool('API-retrieve-page-markdown', { page_id: pageId }); } export async function replacePageMarkdown(transport, pageId, markdown) { return transport.callTool('API-patch-page-markdown', { page_id: pageId, type: 'replace_content', replace_content: { new_str: markdown }, }); } // `ntn datasources query` is explicitly one page at a time: it honors // --limit, reports has_more and hands the caller the cursor, so it cannot // use the paginating helper the mount uses. An incomplete page still // refuses, so a truncated result never prints as a successful query. export async function queryDataSourcePage(transport, dataSourceId, body) { return completePage(await transport.callTool('API-post-data-source-query', { ...body, data_source_id: dataSourceId, })); } export async function listBlockChildren(transport, blockId) { return paginateTool(transport, 'API-retrieve-block-children', { block_id: blockId, page_size: 100, }); } const MAX_BLOCK_DEPTH = 10; export async function listBlockTree(transport, blockId, depth = 0) { const blocks = await listBlockChildren(transport, blockId); if (depth >= MAX_BLOCK_DEPTH) return blocks; for (const block of blocks) { const btype = block.type; if (btype === 'child_page' || btype === 'child_database') continue; if (block.has_children === true && typeof block.id === 'string') { block.children = await listBlockTree(transport, block.id, depth + 1); } } return blocks; } export async function getChildPages(transport, parentBlockId) { const blocks = await listBlockChildren(transport, parentBlockId); const refs = []; for (const block of blocks) { if (block.type !== 'child_page') continue; const id = block.id; if (typeof id !== 'string') continue; const childPage = asObject(block.child_page); const title = childPage.title; const lastEditedTime = block.last_edited_time; refs.push({ id, title: typeof title === 'string' ? title : 'untitled', lastEditedTime: typeof lastEditedTime === 'string' ? lastEditedTime : '', }); } return refs; } export async function searchPages(transport, query = '', pageSize = 100, maxResults) { const baseArgs = { filter: { value: 'page', property: 'object' }, page_size: Math.min(pageSize, MAX_PAGE_SIZE), }; if (query !== '') baseArgs.query = query; return paginateTool(transport, 'API-post-search', baseArgs, maxResults); } export async function createPage(transport, input) { const parentBody = input.parent.type === 'workspace' ? { type: 'workspace', workspace: true } : { type: 'page_id', page_id: input.parent.page_id }; const body = { parent: parentBody, properties: { title: { title: [{ type: 'text', text: { content: input.title } }] }, }, }; return transport.callTool('API-post-page', body); } export async function createPageRaw(transport, body) { return transport.callTool('API-post-page', body); } export async function updatePage(transport, pageId, body) { return transport.callTool('API-patch-page', { ...body, page_id: pageId }); } //# sourceMappingURL=pages.js.map