"use strict";
/**
* Context Fetcher
*
* Centralizes logic for fetching project state, collections, and content.
* Used by get_started and other tools that need project context.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchProjectContext = fetchProjectContext;
exports.resolveProjectId = resolveProjectId;
const api_client_1 = require("./api-client");
// ============ Helper Functions ============
/**
* Fetch all projects for the authenticated user
*/
async function fetchProjects() {
const response = await (0, api_client_1.apiRequest)('/api/tenants');
if ((0, api_client_1.isApiError)(response)) {
return [];
}
return response.data;
}
/**
* Fetch collections for a specific project
*/
async function fetchCollections(tenantId) {
const response = await (0, api_client_1.apiRequest)('/api/collections', { tenantId });
if ((0, api_client_1.isApiError)(response)) {
return [];
}
return response.data;
}
/**
* Fetch GitHub connection status for a project
*/
async function fetchGitHubStatus(tenantId) {
const response = await (0, api_client_1.apiRequest)('/api/github/site-connection', { tenantId });
if ((0, api_client_1.isApiError)(response)) {
return null;
}
return response.data;
}
// Note: fetchLatestDeploy could be used for detailed deploy state in the future
// async function fetchLatestDeploy(tenantId: string): Promise<DeployLog | null> {
// const response = await apiRequest<DeployLog[]>('/api/deploy/history?limit=1', { tenantId });
// if (isApiError(response) || !response.data || response.data.length === 0) {
// return null;
// }
// return response.data[0];
// }
/**
* Fetch item counts for collections
*/
async function fetchCollectionItemCounts(tenantId, collectionSlugs) {
const counts = new Map();
// Fetch counts in parallel (limit concurrency)
const promises = collectionSlugs.slice(0, 10).map(async (slug) => {
const response = await (0, api_client_1.apiRequest)(`/api/collections/${slug}/items?limit=0`, { tenantId });
if (!(0, api_client_1.isApiError)(response) && response.data) {
counts.set(slug, response.data.total || 0);
}
});
await Promise.all(promises);
return counts;
}
// ============ Main Functions ============
/**
* Fetch complete project context
*
* @param projectId - Optional specific project to get detailed info for
*/
async function fetchProjectContext(projectId) {
// Check authentication
const isAuthenticated = !(await (0, api_client_1.needsAuthentication)());
if (!isAuthenticated) {
return {
isAuthenticated: false,
projects: [],
};
}
// Fetch all projects
const tenants = await fetchProjects();
// Build project summaries
const projects = await Promise.all(tenants.map(async (tenant) => {
// Fetch collections for this project (for count)
const collections = await fetchCollections(tenant.id);
const collectionCount = collections.length;
// Calculate total items
let totalItems = 0;
for (const col of collections) {
if (col._count?.items) {
totalItems += col._count.items;
}
}
// Fetch GitHub status
const github = await fetchGitHubStatus(tenant.id);
return {
id: tenant.id,
name: tenant.name,
subdomain: tenant.subdomain,
customDomain: tenant.customDomain || null,
status: (tenant.site?.status || 'pending'),
hasCollections: collectionCount > 0,
collectionCount,
hasContent: totalItems > 0,
totalItems,
hasPendingChanges: tenant.site?.hasPendingChanges || false,
lastDeployedAt: tenant.site?.updatedAt || null,
githubConnected: github?.connected || false,
githubRepo: github?.repo || null,
};
}));
// If a specific project is requested, get detailed info
let selectedProject;
if (projectId) {
// Find the project
const tenant = tenants.find(t => t.id === projectId ||
t.name.toLowerCase() === projectId.toLowerCase() ||
t.subdomain.toLowerCase() === projectId.toLowerCase());
if (tenant) {
// Fetch collections with full field details
const collections = await fetchCollections(tenant.id);
// Fetch item counts
const itemCounts = await fetchCollectionItemCounts(tenant.id, collections.map(c => c.slug));
// Fetch GitHub status
const github = await fetchGitHubStatus(tenant.id);
// Build collection summaries
const collectionSummaries = collections.map(col => ({
slug: col.slug,
name: col.name,
nameSingular: col.nameSingular,
fieldCount: col.fields.length,
itemCount: itemCounts.get(col.slug) || col._count?.items || 0,
fields: col.fields.map(f => ({
slug: f.slug,
name: f.name,
type: f.type,
isRequired: f.isRequired || false,
referenceCollection: f.referenceCollection,
})),
}));
selectedProject = {
id: tenant.id,
name: tenant.name,
subdomain: tenant.subdomain,
customDomain: tenant.customDomain || null,
status: (tenant.site?.status || 'pending'),
collections: collectionSummaries,
hasPendingChanges: tenant.site?.hasPendingChanges || false,
lastDeployedAt: tenant.site?.updatedAt || null,
githubConnected: github?.connected || false,
};
}
}
return {
isAuthenticated: true,
projects,
selectedProject,
};
}
/**
* Resolve a project identifier to a tenant ID
*/
async function resolveProjectId(projectIdentifier) {
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const tenants = await fetchProjects();
// Try exact UUID match
if (uuidPattern.test(projectIdentifier)) {
const tenant = tenants.find(t => t.id === projectIdentifier);
if (tenant) {
return { tenantId: tenant.id, name: tenant.name, subdomain: tenant.subdomain };
}
}
// Try exact name match
const exactMatch = tenants.find(t => t.name.toLowerCase() === projectIdentifier.toLowerCase());
if (exactMatch) {
return { tenantId: exactMatch.id, name: exactMatch.name, subdomain: exactMatch.subdomain };
}
// Try subdomain match
const subdomainMatch = tenants.find(t => t.subdomain.toLowerCase() === projectIdentifier.toLowerCase());
if (subdomainMatch) {
return { tenantId: subdomainMatch.id, name: subdomainMatch.name, subdomain: subdomainMatch.subdomain };
}
// Try partial match
const partialMatch = tenants.find(t => t.name.toLowerCase().includes(projectIdentifier.toLowerCase()));
if (partialMatch) {
return { tenantId: partialMatch.id, name: partialMatch.name, subdomain: partialMatch.subdomain };
}
return null;
}