Lifecycle States
Content: Lifecycle States
User Intent
"What do content states mean? When should I use each state?"
Operation
SDK Method:
updateContent()withstateparameterGraphQL Field:
content.state(EntityState enum)Entity Type: Content
Common Use Cases: Content management, soft delete, archival, workflow states
Content States Overview
Content progresses through states during its lifecycle. Understanding states is critical for content management and querying.
TypeScript (Canonical)
import { Graphlit } from 'graphlit-client';
import { EntityState } from 'graphlit-client/dist/generated/graphql-types';
const graphlit = new Graphlit();
// Check content state
const content = await graphlit.getContent('content-id');
console.log(`State: ${content.content.state}`);
// Update content state
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Disabled // Hide from queries
});
// Query only enabled content
const activeContent = await graphlit.queryContents({
filter: {
states: [EntityState.Enabled]
}
});
// Query disabled content (hidden)
const hiddenContent = await graphlit.queryContents({
filter: {
states: [EntityState.Disabled]
}
});
// Query all states (including disabled)
const allContent = await graphlit.queryContents({
filter: {
states: [
EntityState.Enabled,
EntityState.Disabled,
EntityState.Created
]
}
});Entity States
enum EntityState {
CREATED = 'CREATED', // Just ingested, not yet processed
ENABLED = 'ENABLED', // Fully processed, searchable, active
DISABLED = 'DISABLED', // Hidden from default queries (soft delete)
DELETED = 'DELETED', // Permanently deleted (rarely seen)
ARCHIVED = 'ARCHIVED' // Preserved but not actively used
}CREATED
When: Immediately after ingestion
Duration: Brief (during workflow processing)
Searchable: No (processing not complete)
Use Case: Content is being prepared/extracted
Example:
const content = await graphlit.ingestUri(
'https://example.com/document.pdf',
undefined,
undefined,
undefined,
false, // Returns immediately
{ id: 'workflow-id' }
);
console.log(content.ingestUri.state); // CREATED
// Wait for processing
let isDone = false;
while (!isDone) {
const status = await graphlit.isContentDone(content.ingestUri.id);
isDone = status.isContentDone.result;
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Check state after processing
const processed = await graphlit.getContent(content.ingestUri.id);
console.log(processed.content.state); // ENABLEDENABLED
When: After successful workflow processing
Searchable: Yes (default state for queries)
Use Case: Active, searchable content
Example:
// Default queries only return ENABLED content
const results = await graphlit.queryContents({
search: "graphlit"
});
// All results will have state = ENABLED
results.contents.results.forEach(content => {
console.log(content.state); // ENABLED
});DISABLED
When: Manually disabled by user
Searchable: No (unless explicitly queried)
Use Case: Soft delete, hide temporarily, compliance hold
Example:
// Disable content (soft delete)
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Disabled
});
// Default queries won't return it
const results = await graphlit.queryContents({
search: "query"
});
// Content with DISABLED state won't appear
// Must explicitly query disabled content
const disabled = await graphlit.queryContents({
filter: {
states: [EntityState.Disabled]
}
});DELETED
When: Permanently deleted via deleteContent()
Searchable: No (content is gone)
Use Case: Permanent removal
Example:
// Permanent delete
await graphlit.deleteContent('content-id');
// Content no longer exists
// Can't query or retrieveARCHIVED
When: Manually archived by user
Searchable: No (unless explicitly queried)
Use Case: Long-term retention, compliance, not actively used
Example:
// Archive content
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Archived
});
// Query archived content
const archived = await graphlit.queryContents({
filter: {
states: [EntityState.Archived]
}
});State Transitions
Ingest → CREATED
↓
Workflow Processing
↓
ENABLED ←→ DISABLED (soft delete/restore)
↓
ARCHIVED (long-term storage)
↓
DELETED (permanent removal)Valid Transitions:
CREATED→ENABLED(automatic after processing)ENABLED→DISABLED(soft delete)DISABLED→ENABLED(restore)ENABLED→ARCHIVED(archive)ARCHIVED→ENABLED(restore from archive)Any →
DELETED(permanent delete)
Check state
content = await graphlit.getContent('content-id') print(f"State: {content.content.state}")
Update state (snake_case)
await graphlit.updateContent( id='content-id', state=EntityState.DISABLED )
Query by state
results = await graphlit.queryContents( filter=ContentFilterInput( states=[EntityState.ENABLED] ) )
**C#**:
```csharp
using Graphlit;
var client = new Graphlit();
// Check state
var content = await graphlit.GetContent("content-id");
Console.WriteLine($"State: {content.Content.State}");
// Update state (PascalCase)
await graphlit.UpdateContent(new ContentUpdateInput
{
Id = "content-id",
State = EntityState.Disabled
});
// Query by state
var results = await graphlit.QueryContents(new ContentFilter
{
States = new[] { EntityState.Enabled }
});Developer Hints
Default Query Behavior
// This query...
const results = await graphlit.queryContents({
search: "query"
});
// ...is equivalent to:
const results = await graphlit.queryContents({
search: "query",
filter: {
states: [EntityState.Enabled] // Default!
}
});
// DISABLED, ARCHIVED content won't appear unless explicitly queriedSoft Delete vs Hard Delete
// Soft delete (reversible)
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Disabled
});
// Can restore later
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Enabled
});
// Hard delete (permanent)
await graphlit.deleteContent('content-id');
// Content is gone foreverQuerying Multiple States
// Query both enabled and archived
const results = await graphlit.queryContents({
filter: {
states: [
EntityState.Enabled,
EntityState.Archived
]
}
});
// Query everything except deleted
const everything = await graphlit.queryContents({
filter: {
states: [
EntityState.Created,
EntityState.Enabled,
EntityState.Disabled,
EntityState.Archived
]
}
});Variations
1. Soft Delete Content
// Hide from queries but preserve
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Disabled
});2. Restore Soft-Deleted Content
// Make searchable again
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Enabled
});3. Archive Old Content
// Archive content older than 1 year
const oneYearAgo = new Date();
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
const oldContent = await graphlit.queryContents({
filter: {
creationDateRange: {
to: oneYearAgo.toISOString()
},
states: [EntityState.Enabled]
}
});
// Archive each
for (const content of oldContent.contents.results) {
await graphlit.updateContent({
id: content.id,
state: EntityState.Archived
});
console.log(`Archived: ${content.name}`);
}4. Query Only Active Content
// Explicit enabled filter (best practice)
const active = await graphlit.queryContents({
filter: {
states: [EntityState.Enabled]
}
});5. View Disabled Content (Admin View)
// Show hidden content
const hidden = await graphlit.queryContents({
filter: {
states: [EntityState.Disabled]
}
});
console.log(`${hidden.contents.results.length} hidden items`);6. Bulk State Changes
// Disable multiple content items
const contentIds = ['id1', 'id2', 'id3'];
for (const id of contentIds) {
await graphlit.updateContent({
id,
state: EntityState.Disabled
});
}
// Or use batch operations
await Promise.all(
contentIds.map(id =>
graphlit.updateContent({
id,
state: EntityState.Disabled
})
)
);7. Compliance Archival
// Archive but preserve for compliance
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Archived,
metadata: {
archivedDate: new Date().toISOString(),
archivedReason: 'Compliance retention',
retainUntil: '2030-01-01'
}
});Common Issues & Solutions
Issue: Content not appearing in queries Solution: Check if content is disabled or archived
// Check content state
const content = await graphlit.getContent('content-id');
console.log(`State: ${content.content.state}`);
if (content.content.state !== EntityState.Enabled) {
console.log('Content is not enabled');
}Issue: Accidentally deleted content Solution: Use soft delete (DISABLED) instead
// DON'T - Permanent delete
await graphlit.deleteContent('content-id');
// DO - Soft delete
await graphlit.updateContent({
id: 'content-id',
state: EntityState.Disabled
});Issue: Archived content still appearing Solution: Default queries only return ENABLED
// This won't return archived content
const results = await graphlit.queryContents({});
// Must explicitly exclude if needed
const onlyActive = await graphlit.queryContents({
filter: {
states: [EntityState.Enabled]
}
});Issue: Content stuck in CREATED state Solution: Check workflow processing status
const content = await graphlit.getContent('content-id');
if (content.content.state === EntityState.Created) {
// Check if processing is done
const status = await graphlit.isContentDone('content-id');
if (!status.isContentDone.result) {
console.log('Still processing...');
} else if (content.content.error) {
console.log(`Error: ${content.content.error}`);
}
}Production Example
async function manageContentLifecycle(contentId: string) {
const content = await graphlit.getContent(contentId);
console.log(`\n=== CONTENT LIFECYCLE ===`);
console.log(`ID: ${content.content.id}`);
console.log(`Name: ${content.content.name}`);
console.log(`Current State: ${content.content.state}`);
console.log(`Created: ${content.content.creationDate}`);
// State-based actions
switch (content.content.state) {
case EntityState.Created:
console.log('\n⏳ Processing...');
const isDone = await graphlit.isContentDone(contentId);
if (isDone.isContentDone.result) {
console.log('✓ Processing complete');
} else {
console.log('Still processing workflow');
}
break;
case EntityState.Enabled:
console.log('\n✓ Active and searchable');
// Check if old enough to archive
const age = Date.now() - new Date(content.content.creationDate).getTime();
const daysOld = age / (1000 * 60 * 60 * 24);
if (daysOld > 365) {
console.log(`📦 Content is ${Math.floor(daysOld)} days old - consider archiving`);
}
break;
case EntityState.Disabled:
console.log('\n🔒 Hidden (soft deleted)');
console.log('Can be restored with state: ENABLED');
break;
case EntityState.Archived:
console.log('\n📦 Archived');
console.log('Preserved for compliance, not actively used');
break;
}
return content.content.state;
}
// Usage
await manageContentLifecycle('content-id');Last updated
Was this helpful?