Type-safe Markdown document management system for TypeScript. Organize and manage technical specifications, product documentation, and any structured Markdown content with schema validation and rich metadata support.
https://interactive-inc.github.io/open-docs/
# Using bun (recommended)
bun add @interactive-inc/docs
# Using npm
npm install @interactive-inc/docs
# Using yarn
yarn add @interactive-inc/docs
# Using pnpm
pnpm add @interactive-inc/docs
import { DocClient, DocFileSystem } from '@interactive-inc/docs-client'
// Initialize the client
const fileSystem = new DocFileSystem({ basePath: './docs' })
const client = new DocClient({ fileSystem })
// Read a document
const file = await client.mdFile('getting-started.md').read()
if (file instanceof Error) throw file
console.log(file.content.title()) // Get document title
console.log(file.content.body()) // Get content without frontmatter
Define and validate document metadata with full TypeScript support:
import { DocSchemaBuilder } from '@interactive-inc/docs-client'
import { z } from 'zod'
// Build a schema with chainable API
const featureSchema = new DocSchemaBuilder()
.addRequired('milestone', z.string())
.addRequired('priority', z.enum(['high', 'medium', 'low']))
.addOptional('assignee', z.string())
.addOptional('tags', z.array(z.string()).default([]))
.build()
// Use with type safety
const fileRef = client.mdFile('features/auth.md', featureSchema)
const entity = await fileRef.read()
if (entity instanceof Error) throw entity
// Access metadata with proper types
const meta = entity.content.meta()
console.log(meta.text('milestone')) // string
console.log(meta.text('priority')) // 'high' | 'medium' | 'low'
console.log(meta.multiText('tags')) // string[]
Organize and link documents with powerful management features:
// Work with directories
const featuresDir = client.directory('products/app/features')
const files = await featuresDir.mdFiles()
// Define relations in frontmatter
// features/login.md:
// ---
// title: Login Feature
// dependencies:
// - /features/user-management
// - /features/session-handling
// ---
// Get related documents
const featureRef = client.mdFile('features/login.md')
const dependencies = await featureRef.relations('dependencies')
// Archive old documents
const oldSpec = client.mdFile('specs/v1/deprecated-api.md')
await oldSpec.archive() // Moves to specs/v1/_/deprecated-api.md
// Update content with type safety
const fileRef = client.mdFile('features/auth.md', {
status: { type: 'text', required: true },
completed_date: { type: 'text', required: false }
})
const entity = await fileRef.read()
if (entity instanceof Error) throw entity
const draft = entity.withMeta(
entity.content.meta()
.withProperty('status', 'completed') // Type-safe: only accepts string values
.withProperty('completed_date', new Date().toISOString())
)
await fileRef.write(draft)
Perfect integration with Studio for visual editing:
- Visual Schema Editor: Design schemas with a GUI
- Live Preview: See changes in real-time
- Relation Navigator: Visualize document connections
- Batch Operations: Update multiple documents at once
- Archive Management: Easily archive and restore documents
bun docs
The library is designed to work seamlessly with Studio, providing both programmatic and visual interfaces for document management.
const client = new DocClient({
fileSystem: new DocFileSystem({
basePath: './docs',
pathSystem: new DocPathSystem(),
}),
config: {
// Customize behavior
indexFileName: 'index.md', // Default index file name
archiveDirectoryName: '_', // Archive directory name
directoryExcludes: ['.git', 'node_modules'], // Ignored directories
defaultIndexIcon: '📁', // Icon for index files
// Schema defaults
indexMetaIncludes: ['author', 'updated'], // Auto-include in index
}
})
docs/ # Document root
├── products/ # Product documentation
│ ├── mobile-app/
│ │ ├── index.md # Product overview
│ │ ├── features/ # Feature specifications
│ │ │ ├── auth.md
│ │ │ ├── profile.md
│ │ │ └── _/ # Archived features
│ │ │ └── old-login.md
│ │ ├── pages/ # UI specifications
│ │ └── api/ # API documentation
│ └── web-app/
├── guides/ # User guides
├── design/ # Design documents
└── index.md # Root documentation
All operations return either a value or an Error instance:
const fileRef = client.mdFile('important-doc.md')
const result = await fileRef.read()
if (result instanceof Error) {
// Handle specific error types
if (result.message.includes('ENOENT')) {
console.error('File not found')
} else {
console.error('Read error:', result.message)
}
return
}
// Safe to use result
console.log(result.content.title())
Full TypeScript support with strict typing:
import type { DocCustomSchema } from '@interactive-inc/docs-client'
// Define custom schema type
type ProjectSchema = DocCustomSchema<{
status: { type: 'text'; required: true }
owner: { type: 'relation'; required: true }
tags: { type: 'multi-text'; required: false }
archived: { type: 'boolean'; required: false }
}>
// Use with full type inference
const projectRef = client.mdFile<ProjectSchema>('projects/new-app.md')
const entity = await projectRef.read()
if (entity instanceof Error) throw entity
// TypeScript knows these types
const status: string = entity.content.meta().status
const owner: string = entity.content.meta().owner
const tags: string[] | undefined = entity.content.meta().tags
const archived: boolean | undefined = entity.content.meta().archived
MIT
See CONTRIBUTING.md for development setup and guidelines.