@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
117 lines • 4.45 kB
JavaScript
// ========= 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 { jsonlBytes } from "../render/json.js";
/** Whether a decoded JSON value is an object. */
export function isRow(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
/** A decoded JSON object, or an empty one for anything else. */
export function asRow(value) {
return isRow(value) ? value : {};
}
/** The objects of a decoded JSON array; anything else holds none. */
export function asRows(value) {
return Array.isArray(value) ? value.filter(isRow) : [];
}
function field(row, key) {
return row[key] ?? null;
}
/** One base as the listing names it: id, name and permission level. */
export function normalizeBaseSummary(base) {
return {
base_id: field(base, 'id'),
base_name: field(base, 'name'),
permission_level: field(base, 'permissionLevel'),
};
}
/** base.json: the base and the tables it holds. */
export function normalizeBase(base, tables) {
return {
...normalizeBaseSummary(base),
tables: tables.map((table) => ({
table_id: field(table, 'id'),
table_name: field(table, 'name'),
primary_field_id: field(table, 'primaryFieldId'),
})),
};
}
/** One column: its id, name, type and the type's options. */
export function normalizeField(column) {
return {
field_id: field(column, 'id'),
field_name: field(column, 'name'),
type: field(column, 'type'),
description: field(column, 'description'),
options: field(column, 'options'),
};
}
/** One saved view: its id, name and kind (grid, kanban, ...). */
export function normalizeView(view) {
return {
view_id: field(view, 'id'),
view_name: field(view, 'name'),
type: field(view, 'type'),
};
}
/** table.json: the column schema and the saved views. */
export function normalizeTable(table, baseId) {
return {
table_id: field(table, 'id'),
table_name: field(table, 'name'),
base_id: baseId,
description: field(table, 'description'),
primary_field_id: field(table, 'primaryFieldId'),
fields: asRows(table.fields).map(normalizeField),
views: asRows(table.views).map(normalizeView),
};
}
/**
* One records.jsonl row. `fields` is Airtable's cell map, keyed by field
* name and passed through untouched: an empty cell is absent (Airtable never
* sends one), a link is a list of record ids, and an attachment's url is the
* API's own, which expires two hours after it was fetched.
*/
export function normalizeRecord(record) {
return {
record_id: field(record, 'id'),
created_time: field(record, 'createdTime'),
fields: asRow(record.fields),
};
}
/** One comment on a record, with its author flattened. */
export function normalizeComment(comment) {
const who = asRow(comment.author);
return {
comment_id: field(comment, 'id'),
author_id: field(who, 'id'),
author_email: field(who, 'email'),
author_name: field(who, 'name'),
text: field(comment, 'text'),
created_time: field(comment, 'createdTime'),
last_updated_time: field(comment, 'lastUpdatedTime'),
};
}
/** One deleted record, as the delete answer names it. */
export function normalizeDeletion(row) {
return { record_id: field(row, 'id'), deleted: field(row, 'deleted') };
}
/** Render records one per line, in the order they were listed. */
export function recordsJsonl(listed) {
return jsonlBytes(listed.map(normalizeRecord));
}
/** Render deleted records one per line, in the order they were deleted. */
export function deletionsJsonl(rows) {
return jsonlBytes(rows.map(normalizeDeletion));
}
//# sourceMappingURL=normalize.js.map