Documentation Index
Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
Use this file to discover all available pages before exploring further.
The GraphQL API supports normalized package caching to reduce payload sizes and enable efficient client-side caching.
How It Works
Package data is identified by content-addressed SHA-256 hashes. This means:
- The same package content always has the same ID
- Multiple content items can share the same package data
- Packages can be cached indefinitely (they’re immutable)
- Subscription payloads stay under AWS 100KB WebSocket limit
Two Resolution Approaches
Full Resolution (resolvedPackage)
Use resolvedPackage when you need all package data in a single request:
query GetContentResolved($id: ID!) {
content(id: $id) {
id
name
compiled
resolvedPackage {
package {
id
version
components
assets
}
dependencies {
id
version
components
assets
}
}
}
}
Reference Resolution (resolvedRef)
Use resolvedRef for optimal caching and smaller payloads:
query GetContentWithCaching($id: ID!) {
content(id: $id) {
id
name
compiled
resolvedRef {
package
dependencies
}
}
}
Response:
{
"data": {
"content": {
"id": "cont123",
"name": "Getting Started",
"compiled": "const body = () => { ... }",
"resolvedRef": {
"package": "abc123def456...",
"dependencies": ["xyz789ghi012..."]
}
}
}
}
Fetching Package Data
Query package data by ID (only if not cached):
query GetPackageData($packageId: ID!) {
resolvedPackageData(packageId: $packageId) {
id
version
components
assets
cdnUrl
}
}
Response:
{
"data": {
"resolvedPackageData": {
"id": "abc123def456...",
"version": "1.0.0",
"components": "{\"ArticleLayout\":\"const body = ...\"}",
"assets": "{\"ArticleLayout\":[{\"name\":\"hero\",\"url\":\"...\"}]}",
"cdnUrl": "https://cdn.metabind.ai/packages/abc123def456..."
}
}
}
Client Implementation
Caching Strategy
// Package cache (content-addressed, so safe to cache forever)
const packageCache = new Map();
async function getPackageData(id) {
// Check cache first
if (packageCache.has(id)) {
return packageCache.get(id);
}
// Fetch from API
const { data } = await client.query({
query: GET_PACKAGE_DATA,
variables: { packageId: id }
});
// Cache the result
packageCache.set(id, data.resolvedPackageData);
return data.resolvedPackageData;
}
async function fetchMissingPackages(ids) {
const missing = ids.filter(id => !packageCache.has(id));
// Batch fetch missing packages
const results = await Promise.all(
missing.map(id => getPackageData(id))
);
return results;
}
Handling Content with Caching
async function loadContent(id) {
// Fetch content with references only
const { data } = await client.query({
query: GET_CONTENT_WITH_CACHING,
variables: { id }
});
const content = data.content;
// Fetch any missing package data
const packageIds = [
content.resolvedRef.package,
...content.resolvedRef.dependencies
];
await fetchMissingPackages(packageIds);
// Now render with cached packages
renderContent(content, packageCache);
}
Subscription Handler with Caching
client.subscribe({
query: CONTENT_UPDATED_SUBSCRIPTION,
variables: { id: 'cont123' }
}, {
next: async (data) => {
const update = data.data.contentUpdated;
// Fetch any missing packages
await fetchMissingPackages([
update.resolvedRef.package,
...update.resolvedRef.dependencies
]);
// Re-render with updated content and cached packages
if (update.content) {
renderContent(update.content, packageCache);
} else {
// Content was too large - fetch separately
const content = await fetchContent(update.contentId);
renderContent(content, packageCache);
}
}
});
Draft Package Handling
Draft packages use a special ID format: draft:{projectId}:{organizationId}
function isDraftPackage(id) {
return id.startsWith('draft:');
}
async function getPackageData(id) {
// Draft packages should not be cached long-term
if (isDraftPackage(id)) {
// Always fetch fresh or use short TTL
return await fetchPackageData(id);
}
// Published packages can be cached forever
if (packageCache.has(id)) {
return packageCache.get(id);
}
const data = await fetchPackageData(id);
packageCache.set(id, data);
return data;
}
Benefits
- Smaller Payloads: Subscription updates only include IDs, not full package data
- Efficient Caching: Content-addressed IDs mean packages never change
- Shared Data: Multiple content items referencing the same package share cached data
- WebSocket Compliance: Payloads stay under AWS 100KB limit
- Reduced Bandwidth: Only fetch packages once, regardless of how many content items use them