ObjectStackObjectStack

Manifest

Manifest protocol schemas

Source: packages/spec/src/kernel/manifest.zod.ts

TypeScript Usage

import { ManifestSchema, ManifestPermissionsSchema, PluginEnginesSchema, PluginIntegritySchema, PluginPackagingSchema, PluginPermissionsSchema, PluginRuntimeSchema } from '@objectstack/spec/kernel';
import type { ManifestPermissions, PluginEngines, PluginIntegrity, PluginPackaging, PluginPermissions, PluginRuntime } from '@objectstack/spec/kernel';

// Validate data
const result = ManifestSchema.parse(data);

Manifest

Properties

PropertyTypeRequiredDescription
idstringUnique package identifier (reverse domain style)
namespacestringoptionalShort namespace identifier; also the mandatory prefix of every object name (e.g. "todo" → object names "todo_task", "todo_project")
defaultDatasourcestringoptional (default: "default")Default datasource for all objects in this package
versionstringPackage version (semantic versioning)
typeEnum<'plugin' | 'ui' | 'driver' | 'server' | 'app' | 'theme' | 'agent' | 'objectql' | 'module' | 'gateway' | 'adapter'>Type of package
scopeEnum<'cloud' | 'system' | 'project'>optional (default: "project")Deployment scope: cloud | system | project
namestringHuman-readable package name
descriptionstringoptionalPackage description
permissionsstring[] | { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }optionalRequired permissions: legacy string[] or structured plugin block (ADR-0025 §3.2)
objectsstring[]optionalGlob patterns for ObjectQL schemas files
datasourcesstring[]optionalGlob patterns for Datasource definitions
dependenciesRecord<string, string>optionalPackage dependencies
configurationneveroptional[REMOVED] manifest.configuration was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read the block: no settings UI rendered it and no loader resolved a setting from it, so authoring it configured nothing. Worse, properties.*.secret promised "value is encrypted/masked (e.g. API Keys)" while nothing encrypted, masked or even parsed the flag — a false assurance about credential handling. Delete the key. A plugin is configured by the host that composes it: pass options to its constructor in defineStack({ plugins: [new MyPlugin({ … })] }), which is the enforced channel. A declarative settings surface must be designed with an enforcing reader first, not revived here.
contributes{ kinds?: object[] }optionalPlatform contributions
data{ object: string; externalId?: string | string[]; mode?: Enum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>; env?: Enum<'prod' | 'dev' | 'test'>[]; … }[]optionalInitial seed data (prefer top-level data field)
capabilitiesneveroptional[REMOVED] manifest.capabilities was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — no discovery path ever consulted the block: nothing read implements, provides, requires, extensionPoints or extensions, so the declared "interoperability and automatic discovery" never happened. Delete the key. Real dependency resolution runs off top-level manifest.dependencies, which stays. Capability-based discovery must be designed with an enforcing reader first, not revived here.
extensionsneveroptional[REMOVED] manifest.extensions was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — an untyped map with zero readers: whatever was parked here was stored and never consulted. Delete the key. Extend the platform through the enforced channels instead: contributes.kinds registers metadata kinds, navigationContributions injects navigation into other packages' apps, and code-level extension happens in the plugin itself (init/start).
navigationContributions{ app: string; group?: string; priority?: integer; items: (object | … +8 more)[] }[]optionalNavigation items this package contributes into apps owned by other packages
loadingneveroptional[REMOVED] manifest.loading was removed in @objectstack/spec 17.0.0 (ADR-0049 enforce-or-remove) — the entire block (strategy, preload, codeSplitting, dynamicImport, initialization, dependencyResolution, hotReload, caching, sandboxing, monitoring) had no runtime reader in any repo, so authoring it configured nothing. Delete the key. Plugins are composed at boot — defineStack registers them and the kernel runs init then start in an order topologically resolved from each composed plugin's own dependencies / optionalDependencies (resolvePluginOrder); the set is fixed until the process restarts. ⚠️ loading.sandboxing in particular never isolated anything: it did not run plugins in a process, vm, iframe or web-worker, and allowedServices gated no call. If you were relying on it for isolation, you had none — and the plugin trust tier (manifest.runtime) does not give it back: that tier is enforced at the cloud marketplace PUBLISH gate only (an unverified publisher requesting the node tier is rejected with HTTP 422 and forced to manual review), while load-side enforcement is NOT implemented, so a locally installed plugin is not isolated by the tier it declares. Use the permission declarations, which are enforced.
engine{ objectstack: string }optionalPlatform compatibility requirements (legacy; superseded by engines)
engines{ platform?: string; protocol?: string }optionalPlugin compatibility ranges (ADR-0025 §3.2; supersedes engine)
runtimeEnum<'node' | 'sandbox' | 'worker'>optionalPlugin trust tier the plugin declares (ADR-0025 §3.6) — enforced at the cloud marketplace publish gate (unverified publisher requesting node → HTTP 422 + manual review); load-side enforcement is NOT implemented, so a locally installed plugin is not isolated by the tier it declares
packagingEnum<'bundled' | 'manifest-deps'>optionalDependency packaging strategy (ADR-0025 §3.3)
integrityRecord<string, string>optionalPer-file content digests of the plugin artifact (ADR-0025 §3.2)

Nested Shape: Manifest.permissions

Structured plugin permission grants (ADR-0025 §3.2)

PropertyTypeRequiredDescription
servicesstring[]optionalPlatform services the plugin may resolve (e.g. "object", "http")
hooksstring[]optionalLifecycle hooks the plugin may register (e.g. "record.beforeInsert")
networkstring[]optionalNetwork hosts the plugin may reach (e.g. "api.acme.com")
fsstring[]optionalFilesystem paths the plugin may access

Nested Shape: Manifest.contributes

PropertyTypeRequiredDescription
kinds{ id: string; description?: string }[]optionalMetadata kind identifiers this package registers
eventsneveroptional[REMOVED] manifest.contributes.events was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read the list: its only in-repo author already subscribed imperatively in plugin code, so the declaration was decorative. Delete the key. Subscribe to system events in the plugin itself — ctx.hook('kernel:ready', …) (or the events service) from init/start is the enforced channel; record lifecycle hooks register on the data engine.
menusneveroptional[REMOVED] manifest.contributes.menus was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — no renderer ever read it; two alias maps already redirected this spelling to navigation. Delete the key. Declare navigation in the app's navigation tree, or inject items into another package's app via manifest.navigationContributions (ADR-0029 D7), which the engine registers.
themesneveroptional[REMOVED] manifest.contributes.themes was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: theme registration reaches the registry only through the stack-level themes collection (a ThemeSchema surface, unrelated to this { id, label, path } shape), never through contributes.themes. Delete the key; declare themes in the stack themes collection instead.
translationsneveroptional[REMOVED] manifest.contributes.translations was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — no loader ever read these { locale, path } entries; authoring them registered no translations. Delete the key. Declare translations as translation metadata: defineTranslationBundle({ … }) in the stack's translations collection (defineStack({ translations: […] })), which the engine registers and the i18n pipeline serves.
actionsneveroptional[REMOVED] manifest.contributes.actions was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it; actions declared here were never invocable. Delete the key. Declare actions in the stack actions collection (registered by the engine) or register imperatively via engine.registerAction.
driversneveroptional[REMOVED] manifest.contributes.drivers was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — it never had an effect: a storage driver is wired by registering a kernel SERVICE named driver.* (the objectql plugin picks it up and calls registerDriver), and its only in-repo author was registered that way, not by this declaration. Delete the key.
fieldTypesneveroptional[REMOVED] manifest.contributes.fieldTypes was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — there is no registerFieldType seam anywhere: the declaration advertised an extension point the platform does not have, so authoring it configured nothing. Delete the key. The field-type vocabulary is the spec FieldType enum; extending it is a spec change, not a manifest declaration.
functionsneveroptional[REMOVED] manifest.contributes.functions was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it; ObjectQL functions declared here were never registered. Delete the key. Declare functions on the stack (defineStack({ functions: […] })), which the hook binder registers via engine.registerFunction.
routesneveroptional[REMOVED] manifest.contributes.routes was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — nothing ever read it: the HttpDispatcher never registered a prefix from the declaration, so an entry here parsed cleanly and served nothing while published material kept recommending it. Delete the key. A route that needs real handler CODE is mounted imperatively: resolve the http.server service from the plugin context and register the handler on kernel:ready. A declarative endpoint over a pipeline the platform already runs (query/return records, trigger a flow) is defineStack({ apis }).
commandsneveroptional[REMOVED] manifest.contributes.commands was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) — the CLI never resolved commands from this declaration: commands are auto-discovered through oclif's native plugin system (the plugin package declares an oclif section in its own package.json; see cli-extension.zod.ts), and the objectstack.config.ts plugins array no longer determines CLI commands. Delete the key.

Nested Shape: Manifest.data[number]

PropertyTypeRequiredDescription
objectstringTarget Object Name
externalIdstring | string[]optional (default: "name")Field (or composite list of fields) matched for the uniqueness check
modeEnum<'insert' | 'update' | 'upsert' | 'replace' | 'ignore'>optional (default: "upsert")Conflict resolution strategy
envEnum<'prod' | 'dev' | 'test'>[]optional (default: ["prod","dev","test"])Applicable environments
recordsRecord<string, any>[]Data records
_lockEnum<'none' | 'no-overlay' | 'no-delete' | 'full'>optionalItem-level lock — controls overlay & delete (ADR-0010).
_lockReasonstringoptionalHuman-readable reason shown when a write is refused by _lock.
_lockSourceEnum<'artifact' | 'package' | 'env-forced'>optionalLayer that set _lock (artifact | package | env-forced).
_provenanceEnum<'package' | 'org' | 'env-forced'>optionalOrigin of the item (package | org | env-forced).
_packageIdstringoptionalOwning package machine id.
_packageVersionstringoptionalOwning package version.
_lockDocsUrlstringoptionalOptional documentation link surfaced next to _lockReason.

Nested Shape: Manifest.navigationContributions[number]

A navigation contribution: a package injecting nav items into an app it does not own (ADR-0029 D7)

PropertyTypeRequiredDescription
appstringTarget app name to contribute navigation into (e.g. "setup")
groupstringoptionalTarget group nav-item id to append into (e.g. "group_integrations"); omit to append at the app top level
priorityintegeroptional (default: 200)Merge priority within the target group — lower applied first (matches object extender priority)
items({ id: string; label: string | Record<string, string>; icon?: string; order?: number; … } | { type: 'separator'; id?: string; order?: number } | … +7 more)[]Navigation items contributed into the target app/group

Nested Shape: Manifest.engine

PropertyTypeRequiredDescription
objectstackstringObjectStack platform version requirement (SemVer range, e.g. ">=3.0.0")

Nested Shape: Manifest.engines

PropertyTypeRequiredDescription
platformstringoptionalObjectStack platform release range (SemVer, e.g. ">=4.0 <5")
protocolstringoptionalRuntime/metadata protocol range, checked first (ADR §3.10 #3)

ManifestPermissions

Union Options

This schema accepts one of the following structures:

Option 1

Type: string[]


Option 2

Structured plugin permission grants (ADR-0025 §3.2)

Properties

PropertyTypeRequiredDescription
servicesstring[]optionalPlatform services the plugin may resolve (e.g. "object", "http")
hooksstring[]optionalLifecycle hooks the plugin may register (e.g. "record.beforeInsert")
networkstring[]optionalNetwork hosts the plugin may reach (e.g. "api.acme.com")
fsstring[]optionalFilesystem paths the plugin may access


PluginEngines

Plugin compatibility ranges (ADR-0025 §3.2)

Properties

PropertyTypeRequiredDescription
platformstringoptionalObjectStack platform release range (SemVer, e.g. ">=4.0 <5")
protocolstringoptionalRuntime/metadata protocol range, checked first (ADR §3.10 #3)

PluginIntegrity

Per-file content digests of the plugin artifact (ADR-0025 §3.2)

Type: Record<string, string>


PluginPackaging

Dependency packaging strategy (ADR-0025 §3.3)

Allowed Values

  • bundled
  • manifest-deps

PluginPermissions

Structured plugin permission grants (ADR-0025 §3.2)

Properties

PropertyTypeRequiredDescription
servicesstring[]optionalPlatform services the plugin may resolve (e.g. "object", "http")
hooksstring[]optionalLifecycle hooks the plugin may register (e.g. "record.beforeInsert")
networkstring[]optionalNetwork hosts the plugin may reach (e.g. "api.acme.com")
fsstring[]optionalFilesystem paths the plugin may access

PluginRuntime

Plugin trust tier the plugin declares (ADR-0025 §3.6) — enforced at the cloud marketplace publish gate (an unverified publisher requesting node is rejected with HTTP 422 and forced to manual review); load-side enforcement is NOT implemented, so a locally installed plugin is not isolated by the tier it declares

Allowed Values

  • node
  • sandbox
  • worker

On this page