BundlesLast updated on
Last updated on
Compose multiple artifacts into a distributable package
Bundles group forms, documents, and checklists into a single package. This guide walks through creating a lease transaction bundle.
Define the Artifacts
A lease transaction needs multiple artifacts. Start with the form from the previous guide, then add a disclosure document and a move-in checklist.
import { open } from '@open-form/core'
// Lease Agreement Form
const lease = open.form({
name: 'lease-agreement',
version: '1.0.0',
title: 'Residential Lease Agreement',
fields: {
address: { type: 'address', label: 'Property Address', required: true },
monthlyRent: { type: 'money', label: 'Monthly Rent', required: true },
startDate: { type: 'date', label: 'Start Date', required: true },
endDate: { type: 'date', label: 'End Date', required: true },
},
parties: {
landlord: { label: 'Landlord', signature: { required: true } },
tenant: { label: 'Tenant', signature: { required: true } },
},
defaultLayer: 'markdown',
layers: {
markdown: { kind: 'inline', mimeType: 'text/markdown', text: '# Lease\n\n{{address}}' },
},
})
// Lead Paint Disclosure Document
const disclosure = open.document({
name: 'lead-paint-disclosure',
version: '1.0.0',
title: 'Lead Paint Disclosure',
code: 'EPA-747-K-12-001',
defaultLayer: 'text',
layers: {
text: { kind: 'inline', mimeType: 'text/plain', text: 'Lead Paint Disclosure Notice...' },
},
})
// Move-In Checklist
const moveInChecklist = open.checklist({
name: 'move-in-checklist',
version: '1.0.0',
title: 'Move-In Checklist',
items: [
{ id: 'keys', title: 'Keys Provided' },
{ id: 'utilities', title: 'Utilities Transferred' },
{ id: 'inspection', title: 'Walk-Through Complete' },
],
})Compose the Bundle
Use .inline() to embed artifacts directly in the bundle:
const leaseBundle = open.bundle({
name: 'lease-transaction',
version: '1.0.0',
title: 'Complete Lease Package',
contents: [
{ type: 'inline', key: 'lease', artifact: lease.toJSON({ includeSchema: false }) },
{ type: 'inline', key: 'disclosure', artifact: disclosure.toJSON({ includeSchema: false }) },
{ type: 'inline', key: 'checklist', artifact: moveInChecklist.toJSON({ includeSchema: false }) },
],
})Each content item has a key that identifies it within the bundle.
Validate the Bundle
Check that the bundle and all its contents are valid:
if (leaseBundle.isValid()) {
console.log('Bundle is valid')
console.log(`Contains ${leaseBundle.contents.length} artifacts`)
} else {
const result = leaseBundle.validate()
if ('errors' in result) {
console.log('Validation errors:', result.errors)
}
}Output:
Bundle is valid
Contains 3 artifactsAssemble and Render
Fill the artifacts and assemble the bundle for rendering:
import { textRenderer } from '@open-form/renderer-text'
// Fill the lease form
const filledLease = lease.fill({
fields: {
address: { line1: '123 Main St', locality: 'Portland', region: 'OR', postalCode: '97201', country: 'USA' },
monthlyRent: { amount: 1500, currency: 'USD' },
startDate: '2025-02-01',
endDate: '2026-01-31',
},
parties: {
landlord: { id: 'landlord-1', fullName: 'Jane Smith' },
tenant: { id: 'tenant-1', fullName: 'John Doe' },
},
})
// Assemble the bundle
const assembled = await leaseBundle.assemble({
renderers: {
'text/markdown': textRenderer(),
'text/plain': textRenderer(),
},
contents: {
lease: filledLease,
disclosure: disclosure.prepare(),
checklist: moveInChecklist.fill({ keys: true, utilities: true, inspection: false }),
},
})
// Access rendered outputs
for (const [key, output] of Object.entries(assembled.outputs)) {
console.log(`${key}: ${output.mimeType}`)
}Output:
lease: text/markdown
disclosure: text/plain
checklist: text/plainSave the Artifact
Export the bundle definition to JSON or YAML:
const json = leaseBundle.toJSON() // or leaseBundle.toYAML()
console.log(JSON.stringify(json, null, 2)){
"$schema": "https://schemas.open-form.dev/schema.json",
"kind": "bundle",
"name": "lease-transaction",
"version": "1.0.0",
"title": "Complete Lease Package",
"contents": [
{ "type": "inline", "key": "lease", "artifact": { "kind": "form", "..." } },
{ "type": "inline", "key": "disclosure", "artifact": { "kind": "document", "..." } },
{ "type": "inline", "key": "checklist", "artifact": { "kind": "checklist", "..." } }
]
}Content Types
Bundles support three content types:
| Type | Description |
|---|---|
inline | Artifact embedded directly in the bundle |
path | Reference to a local file path |
registry | Reference to a registry slug (e.g., @org/artifact) |
const bundle = open
.bundle()
.name('mixed-bundle')
.inline('embedded', someForm) // Embedded
.path('local', './forms/other.yaml') // File reference
.registry('shared', '@acme/disclosure') // Registry reference
.build()