ObjectStackObjectStack

Package Api schema — API Protocol reference

Package API Protocol — REST API endpoint schemas for package lifecycle management.

Package API Protocol

REST API endpoint schemas for package lifecycle management.

Base path: /api/v1/packages

Endpoints

POST   /api/v1/packages                      — Install a package
GET    /api/v1/packages                      — List installed packages
GET    /api/v1/packages/:packageId           — Get package details
POST   /api/v1/packages/:packageId/rollback  — Rollback a package
DELETE /api/v1/packages/:packageId           — Uninstall a package

Five declarations of this API live one file over, on purpose

The two READ responses (ListInstalledPackagesResponseSchema, GetInstalledPackageResponseSchema), the installed-row stages they are bound to (AssembledInstalledPackageSchema, InstalledPackageAtEitherStageSchema) and the PackageApiContracts map that names both responses are declared in ./package-api-assembled.zod.ts and published from @objectstack/spec/api-assembled, not from @objectstack/spec/api.

The reason is weight, not meaning. Four of them carry the ASSEMBLED package body (the fifth, the route map, names two of those four), which is the whole metadata vocabulary (../stack.zod) plus the datasource and driver-config validators behind it. While they sat in this file, every @objectstack/spec/api bundle linked that tree, and a browser consumer that imported two string constants from ./sortability.zod paid for all of it: measured at about twice the gzipped bundle of the same import before the stage declarations arrived. The maintainer ruling on #18576 (letter B) split the entry so the browser-facing half does not carry them.

⛔ Nothing in this file may import ../stack.zod or anything that reaches ../data/datasource.zod: that edge is exactly what the split removed from @objectstack/spec/api, and ./api-entry-graph.pin.test.ts refuses it. A declaration that needs the assembled body goes in the sibling file.

Source: packages/spec/src/api/package-api.zod.ts

TypeScript Usage

import { GetInstalledPackageRequestSchema, ListInstalledPackagesRequestSchema, PackageApiErrorCode, PackageInstallBodySchema, PackageInstallRequestSchema, PackageInstallResponseSchema, PackagePathParamsSchema, PackageRollbackRequestSchema, PackageUpgradeRequestSchema, PackageUpgradeResponseSchema, ResolveDependenciesRequestSchema, ResolveDependenciesResponseSchema, UninstallPackageApiRequestSchema, UninstallPackageApiResponseSchema, UploadArtifactRequestSchema, UploadArtifactResponseSchema } from '@objectstack/spec/api';
import type { GetInstalledPackageRequest, ListInstalledPackagesRequest, PackageApiErrorCode, PackageInstallBody, PackageInstallRequest, PackageInstallResponse, PackagePathParams, PackageRollbackRequest, PackageUpgradeRequest, PackageUpgradeResponse, ResolveDependenciesRequest, ResolveDependenciesResponse, UninstallPackageApiRequest, UninstallPackageApiResponse, UploadArtifactRequest, UploadArtifactResponse } from '@objectstack/spec/api';

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

GetInstalledPackageRequest

Get installed package request

Properties

PropertyTypeRequiredDescription
packageIdstring✅Package identifier
versionstringoptionalScope the read to this exact installed version; latest or omitted reads the installed row

ListInstalledPackagesRequest

List installed packages request

Properties

PropertyTypeRequiredDescription
statusEnum<'installed' | 'disabled' | 'installing' | 'upgrading' | 'uninstalling' | 'error'>optionalFilter by package status
enabledbooleanoptionalFilter by enabled state
typestringoptionalFilter by the installed manifest's type — exact match, unmatched values select nothing
limitneveroptional[REMOVED] limit / cursor were removed from GET /api/v1/packages in @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — both were declared here and read by nothing: the serving door filters on status / type / enabled and then returns every remaining row, so no page was ever withheld and no continuation token was ever minted. limit also declared .default(50), so a reader of the published schema was entitled to believe an unparameterised list is capped at 50 rows; it has never been capped at all, and nothing parses a query string through this schema, so that default has never been stamped onto anything. Delete the key. This route is NOT paginated — it answers the whole installed set, which is a bounded table of tens of rows, and hasMore on the response is a constant false that is now true by construction. Filter with status, type and enabled instead of asking for a window. A first-class package cursor, if one is ever designed, will be a response-minted opaque token, not this key.
cursorneveroptional[REMOVED] limit / cursor were removed from GET /api/v1/packages in @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — both were declared here and read by nothing: the serving door filters on status / type / enabled and then returns every remaining row, so no page was ever withheld and no continuation token was ever minted. limit also declared .default(50), so a reader of the published schema was entitled to believe an unparameterised list is capped at 50 rows; it has never been capped at all, and nothing parses a query string through this schema, so that default has never been stamped onto anything. Delete the key. This route is NOT paginated — it answers the whole installed set, which is a bounded table of tens of rows, and hasMore on the response is a constant false that is now true by construction. Filter with status, type and enabled instead of asking for a window. A first-class package cursor, if one is ever designed, will be a response-minted opaque token, not this key.

PackageApiErrorCode

Allowed Values

  • package_not_found
  • package_already_installed
  • version_not_found
  • dependency_conflict
  • namespace_conflict
  • platform_incompatible
  • artifact_invalid
  • checksum_mismatch
  • signature_invalid
  • upgrade_failed
  • rollback_failed
  • snapshot_not_found
  • upload_failed

PackageInstallBody

Install package request body, wrapped or as a bare manifest

Union Options

This schema accepts one of the following structures:

Option 1

Install package request

Properties

PropertyTypeRequiredDescription
manifest{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }✅Package manifest to install (AUTHORING stage: objects are glob patterns)
settingsRecord<string, any>optionalUser-provided settings at install time
enableOnInstallbooleanoptionalWhether to enable immediately after install — honoured at POST /api/v1/packages: true enables the installed row, false disables it, and ABSENT keeps the row's current lifecycle state (a fresh install lands enabled)
overwritebooleanoptionalOverwrite an already-installed package id instead of answering 409 Conflict
platformVersionstringoptionalCurrent platform version for compatibility verification
artifactRef{ url: string; sha256: string; size: integer; format?: Enum<'tgz' | 'zip'>; … }optionalArtifact reference for marketplace installation

Nested Shape: PackageInstallBody[option 1].manifest

PropertyTypeRequiredDescription
idstring✅Unique package identifier — must match reverse-domain notation (e.g. com.acme.crm)
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
versionstring✅Package version (SemVer 2.0.0 — e.g. 1.2.3, 2.0.0-beta.1, 1.0.0+20230101)
typeEnum<'plugin' | 'ui' | 'driver' | 'server' | 'app' | 'theme' | 'agent' | 'objectql' | …>✅Type of package
scopeEnum<'cloud' | 'system' | 'project'>optional (default: "project")Deployment scope: cloud | system | project
namestring✅Human-readable package name
descriptionstringoptionalPackage description
permissionsstring[] | { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }optionalRequired permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 PermissionSet[] collection instead (AssembledPackageBodySchema)
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 | … +9 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. ⛔ Nor do the permission declarations give it back: the install-time granted set is REGISTERED on the PluginPermissionEnforcer at load and queried by nothing, so it refuses no operation. Neither surface confines a plugin today — do not author either one expecting isolation.
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)
mainstringoptionalEntry module of a code-bearing plugin, relative to the plugin root; os plugin build bundles it and writes dist/index.mjs here in the compiled manifest (ADR-0025 §3.4)
integrityRecord<string, string>optionalPer-file content digests of the plugin artifact (ADR-0025 §3.2)

Nested Shape: PackageInstallBody[option 1].artifactRef

PropertyTypeRequiredDescription
urlstring✅Artifact download URL
sha256string✅SHA256 checksum
sizeinteger✅Artifact size in bytes
formatEnum<'tgz' | 'zip'>optional (default: "tgz")Artifact format
uploadedAtstring✅Upload timestamp

Option 2

Properties

PropertyTypeRequiredDescription
idstring✅Unique package identifier — must match reverse-domain notation (e.g. com.acme.crm)
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
versionstring✅Package version (SemVer 2.0.0 — e.g. 1.2.3, 2.0.0-beta.1, 1.0.0+20230101)
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
namestring✅Human-readable package name
descriptionstringoptionalPackage description
permissionsstring[] | { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }optionalRequired permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 PermissionSet[] collection instead (AssembledPackageBodySchema)
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 | … +9 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. ⛔ Nor do the permission declarations give it back: the install-time granted set is REGISTERED on the PluginPermissionEnforcer at load and queried by nothing, so it refuses no operation. Neither surface confines a plugin today — do not author either one expecting isolation.
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)
mainstringoptionalEntry module of a code-bearing plugin, relative to the plugin root; os plugin build bundles it and writes dist/index.mjs here in the compiled manifest (ADR-0025 §3.4)
integrityRecord<string, string>optionalPer-file content digests of the plugin artifact (ADR-0025 §3.2)

Nested Shape: PackageInstallBody[option 2].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: PackageInstallBody[option 2].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: PackageInstallBody[option 2].data[number]

PropertyTypeRequiredDescription
objectstring✅Target 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
localestring[]optionalApplicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn
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: PackageInstallBody[option 2].navigationContributions[number]

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

PropertyTypeRequiredDescription
appstring✅Target 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. Naming a group the target app does not declare is not refused: the items are appended at the app top level anyway and a nav_contribution_group_missing diagnostic is emitted — by the runtime at warn, and by os build and os validate at compile time.
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 } | … +8 more)[]✅Navigation items contributed into the target app/group

Nested Shape: PackageInstallBody[option 2].engine

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

Nested Shape: PackageInstallBody[option 2].engines

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


PackageInstallRequest

Install package request

Properties

PropertyTypeRequiredDescription
manifest{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }✅Package manifest to install (AUTHORING stage: objects are glob patterns)
settingsRecord<string, any>optionalUser-provided settings at install time
enableOnInstallbooleanoptionalWhether to enable immediately after install — honoured at POST /api/v1/packages: true enables the installed row, false disables it, and ABSENT keeps the row's current lifecycle state (a fresh install lands enabled)
overwritebooleanoptionalOverwrite an already-installed package id instead of answering 409 Conflict
platformVersionstringoptionalCurrent platform version for compatibility verification
artifactRef{ url: string; sha256: string; size: integer; format?: Enum<'tgz' | 'zip'>; … }optionalArtifact reference for marketplace installation

Nested Shape: PackageInstallRequest.manifest

PropertyTypeRequiredDescription
idstring✅Unique package identifier — must match reverse-domain notation (e.g. com.acme.crm)
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
versionstring✅Package version (SemVer 2.0.0 — e.g. 1.2.3, 2.0.0-beta.1, 1.0.0+20230101)
typeEnum<'plugin' | 'ui' | 'driver' | 'server' | 'app' | 'theme' | 'agent' | 'objectql' | …>✅Type of package
scopeEnum<'cloud' | 'system' | 'project'>optional (default: "project")Deployment scope: cloud | system | project
namestring✅Human-readable package name
descriptionstringoptionalPackage description
permissionsstring[] | { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }optionalRequired permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 PermissionSet[] collection instead (AssembledPackageBodySchema)
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 | … +9 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. ⛔ Nor do the permission declarations give it back: the install-time granted set is REGISTERED on the PluginPermissionEnforcer at load and queried by nothing, so it refuses no operation. Neither surface confines a plugin today — do not author either one expecting isolation.
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)
mainstringoptionalEntry module of a code-bearing plugin, relative to the plugin root; os plugin build bundles it and writes dist/index.mjs here in the compiled manifest (ADR-0025 §3.4)
integrityRecord<string, string>optionalPer-file content digests of the plugin artifact (ADR-0025 §3.2)

Nested Shape: PackageInstallRequest.artifactRef

PropertyTypeRequiredDescription
urlstring✅Artifact download URL
sha256string✅SHA256 checksum
sizeinteger✅Artifact size in bytes
formatEnum<'tgz' | 'zip'>optional (default: "tgz")Artifact format
uploadedAtstring✅Upload timestamp

PackageInstallResponse

Install package response

Properties

PropertyTypeRequiredDescription
successboolean✅Operation success status
error{ code: Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>; declaredCode?: string; message: string; userMessage?: string; … }optionalError details if success is false
meta{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }optionalResponse metadata
data{ package: object; dependencyResolution?: object; namespaceConflicts?: object[]; message?: string }✅

Nested Shape: PackageInstallResponse.error

PropertyTypeRequiredDescription
codeEnum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>✅Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages)
declaredCodestringoptionalThe producer-declared code, verbatim, when it is not a member of the closed code vocabulary — the open, author-authored channel (app-specific spellings; ADR-0112)
messagestring✅Readable error message
userMessagestringoptionalProducer-marked user-facing refusal text, verbatim. Present exactly when the producer opted in at throw time; consumers render it to end users and keep their generic substitution for anything unmarked. Status-agnostic; never replaces message.
refusaltrueoptionalProducer-declared: the 5xx this envelope carries is a deliberate refusal whose message is authored for the caller, so a boundary that reads the declaration keeps it verbatim (until the withhold arms read it, a declared refusal is still withheld). Absent (the default) on a declared fault, whose message is withheld from the body and logged for the operator; redundant on a 4xx. Presence is the declaration — true is the only value.
categorystringoptionalError category (e.g. validation, authorization)
httpStatusintegeroptionalHTTP status of the response carrying this error
detailsanyoptionalAdditional error context (e.g. field validation errors)
requestIdstringoptionalRequest ID for tracking

Nested Shape: PackageInstallResponse.meta

PropertyTypeRequiredDescription
timestampstring✅
durationintegeroptionalServer-side processing duration in milliseconds
requestIdstringoptional
traceIdstringoptional

Nested Shape: PackageInstallResponse.data

PropertyTypeRequiredDescription
package{ manifest: object; status?: Enum<'installed' | 'disabled' | 'installing' | 'upgrading' | 'uninstalling' | 'error'>; enabled?: boolean; installedAt?: string; … }✅Installed package details
dependencyResolution{ dependencies: object[]; canProceed: boolean; requiredActions: object[]; installOrder: string[]; … }optionalDependency resolution result
namespaceConflicts{ type: 'namespace_conflict'; requestedNamespace: string; conflictingPackageId: string; conflictingPackageName: string; … }[]optionalNamespace conflicts detected
messagestringoptionalInstallation status message

PackagePathParams

Properties

PropertyTypeRequiredDescription
packageIdstring✅Package identifier

PackageRollbackRequest

Rollback package request

Properties

PropertyTypeRequiredDescription
packageIdstring✅Package identifier
snapshotIdstring✅Snapshot ID to restore from
rollbackCustomizationsbooleanoptional (default: true)Whether to restore pre-upgrade customizations

PackageUpgradeRequest

Upgrade package request

Properties

PropertyTypeRequiredDescription
packageIdstring✅Package ID to upgrade
targetVersionstringoptionalTarget version (defaults to latest)
manifest{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }optionalNew manifest for the target version
createSnapshotbooleanoptional (default: true)Whether to create a pre-upgrade backup snapshot
mergeStrategyEnum<'keep-custom' | 'accept-incoming' | 'three-way-merge'>optional (default: "three-way-merge")How to handle customer customizations
dryRunbooleanoptional (default: false)Preview upgrade without making changes
skipValidationbooleanoptional (default: false)Skip pre-upgrade compatibility checks

Nested Shape: PackageUpgradeRequest.manifest

PropertyTypeRequiredDescription
idstring✅Unique package identifier — must match reverse-domain notation (e.g. com.acme.crm)
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
versionstring✅Package version (SemVer 2.0.0 — e.g. 1.2.3, 2.0.0-beta.1, 1.0.0+20230101)
typeEnum<'plugin' | 'ui' | 'driver' | 'server' | 'app' | 'theme' | 'agent' | 'objectql' | …>✅Type of package
scopeEnum<'cloud' | 'system' | 'project'>optional (default: "project")Deployment scope: cloud | system | project
namestring✅Human-readable package name
descriptionstringoptionalPackage description
permissionsstring[] | { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }optionalRequired permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 PermissionSet[] collection instead (AssembledPackageBodySchema)
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 | … +9 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. ⛔ Nor do the permission declarations give it back: the install-time granted set is REGISTERED on the PluginPermissionEnforcer at load and queried by nothing, so it refuses no operation. Neither surface confines a plugin today — do not author either one expecting isolation.
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)
mainstringoptionalEntry module of a code-bearing plugin, relative to the plugin root; os plugin build bundles it and writes dist/index.mjs here in the compiled manifest (ADR-0025 §3.4)
integrityRecord<string, string>optionalPer-file content digests of the plugin artifact (ADR-0025 §3.2)

PackageUpgradeResponse

Upgrade package response

Properties

PropertyTypeRequiredDescription
successboolean✅Operation success status
error{ code: Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>; declaredCode?: string; message: string; userMessage?: string; … }optionalError details if success is false
meta{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }optionalResponse metadata
data{ success: boolean; phase: string; plan?: object; snapshotId?: string; … }✅

Nested Shape: PackageUpgradeResponse.error

PropertyTypeRequiredDescription
codeEnum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>✅Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages)
declaredCodestringoptionalThe producer-declared code, verbatim, when it is not a member of the closed code vocabulary — the open, author-authored channel (app-specific spellings; ADR-0112)
messagestring✅Readable error message
userMessagestringoptionalProducer-marked user-facing refusal text, verbatim. Present exactly when the producer opted in at throw time; consumers render it to end users and keep their generic substitution for anything unmarked. Status-agnostic; never replaces message.
refusaltrueoptionalProducer-declared: the 5xx this envelope carries is a deliberate refusal whose message is authored for the caller, so a boundary that reads the declaration keeps it verbatim (until the withhold arms read it, a declared refusal is still withheld). Absent (the default) on a declared fault, whose message is withheld from the body and logged for the operator; redundant on a 4xx. Presence is the declaration — true is the only value.
categorystringoptionalError category (e.g. validation, authorization)
httpStatusintegeroptionalHTTP status of the response carrying this error
detailsanyoptionalAdditional error context (e.g. field validation errors)
requestIdstringoptionalRequest ID for tracking

Nested Shape: PackageUpgradeResponse.meta

PropertyTypeRequiredDescription
timestampstring✅
durationintegeroptionalServer-side processing duration in milliseconds
requestIdstringoptional
traceIdstringoptional

Nested Shape: PackageUpgradeResponse.data

PropertyTypeRequiredDescription
successboolean✅Whether the upgrade succeeded
phasestring✅Current upgrade phase
plan{ packageId: string; fromVersion: string; toVersion: string; impactLevel: Enum<'none' | 'low' | 'medium' | 'high' | 'critical'>; … }optionalUpgrade plan that was executed
snapshotIdstringoptionalSnapshot ID for rollback
conflicts{ path: string; baseValue: any; incomingValue: any; customValue: any }[]optionalUnresolved merge conflicts
errorMessagestringoptionalError message if failed
messagestringoptionalHuman-readable status message

ResolveDependenciesRequest

Resolve dependencies request

Properties

PropertyTypeRequiredDescription
manifest{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }✅Package manifest to resolve dependencies for
platformVersionstringoptionalCurrent platform version for compatibility filtering

Nested Shape: ResolveDependenciesRequest.manifest

PropertyTypeRequiredDescription
idstring✅Unique package identifier — must match reverse-domain notation (e.g. com.acme.crm)
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
versionstring✅Package version (SemVer 2.0.0 — e.g. 1.2.3, 2.0.0-beta.1, 1.0.0+20230101)
typeEnum<'plugin' | 'ui' | 'driver' | 'server' | 'app' | 'theme' | 'agent' | 'objectql' | …>✅Type of package
scopeEnum<'cloud' | 'system' | 'project'>optional (default: "project")Deployment scope: cloud | system | project
namestring✅Human-readable package name
descriptionstringoptionalPackage description
permissionsstring[] | { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }optionalRequired permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 PermissionSet[] collection instead (AssembledPackageBodySchema)
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 | … +9 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. ⛔ Nor do the permission declarations give it back: the install-time granted set is REGISTERED on the PluginPermissionEnforcer at load and queried by nothing, so it refuses no operation. Neither surface confines a plugin today — do not author either one expecting isolation.
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)
mainstringoptionalEntry module of a code-bearing plugin, relative to the plugin root; os plugin build bundles it and writes dist/index.mjs here in the compiled manifest (ADR-0025 §3.4)
integrityRecord<string, string>optionalPer-file content digests of the plugin artifact (ADR-0025 §3.2)

ResolveDependenciesResponse

Resolve dependencies response

Properties

PropertyTypeRequiredDescription
successboolean✅Operation success status
error{ code: Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>; declaredCode?: string; message: string; userMessage?: string; … }optionalError details if success is false
meta{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }optionalResponse metadata
data{ dependencies: object[]; canProceed: boolean; requiredActions: object[]; installOrder: string[]; … }✅Dependency resolution result with topological sort

Nested Shape: ResolveDependenciesResponse.error

PropertyTypeRequiredDescription
codeEnum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>✅Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages)
declaredCodestringoptionalThe producer-declared code, verbatim, when it is not a member of the closed code vocabulary — the open, author-authored channel (app-specific spellings; ADR-0112)
messagestring✅Readable error message
userMessagestringoptionalProducer-marked user-facing refusal text, verbatim. Present exactly when the producer opted in at throw time; consumers render it to end users and keep their generic substitution for anything unmarked. Status-agnostic; never replaces message.
refusaltrueoptionalProducer-declared: the 5xx this envelope carries is a deliberate refusal whose message is authored for the caller, so a boundary that reads the declaration keeps it verbatim (until the withhold arms read it, a declared refusal is still withheld). Absent (the default) on a declared fault, whose message is withheld from the body and logged for the operator; redundant on a 4xx. Presence is the declaration — true is the only value.
categorystringoptionalError category (e.g. validation, authorization)
httpStatusintegeroptionalHTTP status of the response carrying this error
detailsanyoptionalAdditional error context (e.g. field validation errors)
requestIdstringoptionalRequest ID for tracking

Nested Shape: ResolveDependenciesResponse.meta

PropertyTypeRequiredDescription
timestampstring✅
durationintegeroptionalServer-side processing duration in milliseconds
requestIdstringoptional
traceIdstringoptional

Nested Shape: ResolveDependenciesResponse.data

PropertyTypeRequiredDescription
dependencies{ packageId: string; requiredRange: string; resolvedVersion?: string; installedVersion?: string; … }[]✅Resolution result for each dependency
canProceedboolean✅Whether installation can proceed
requiredActions{ type: Enum<'install' | 'upgrade' | 'confirm_conflict'>; packageId: string; description: string }[]✅Actions required before proceeding
installOrderstring[]✅Topologically sorted package IDs for installation
circularDependenciesstring[][]optionalCircular dependency chains detected (e.g. [["A", "B", "A"]])

UninstallPackageApiRequest

Uninstall package request

Properties

PropertyTypeRequiredDescription
packageIdstring✅Package identifier
keepDatabooleanoptionalPreserve object tables and remove metadata only; on the wire, ?keepData=true or ?keepData=1

UninstallPackageApiResponse

Uninstall package response

Properties

PropertyTypeRequiredDescription
successboolean✅Operation success status
error{ code: Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>; declaredCode?: string; message: string; userMessage?: string; … }optionalError details if success is false
meta{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }optionalResponse metadata
data{ packageId: string; success: boolean; message?: string }✅

Nested Shape: UninstallPackageApiResponse.error

PropertyTypeRequiredDescription
codeEnum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>✅Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages)
declaredCodestringoptionalThe producer-declared code, verbatim, when it is not a member of the closed code vocabulary — the open, author-authored channel (app-specific spellings; ADR-0112)
messagestring✅Readable error message
userMessagestringoptionalProducer-marked user-facing refusal text, verbatim. Present exactly when the producer opted in at throw time; consumers render it to end users and keep their generic substitution for anything unmarked. Status-agnostic; never replaces message.
refusaltrueoptionalProducer-declared: the 5xx this envelope carries is a deliberate refusal whose message is authored for the caller, so a boundary that reads the declaration keeps it verbatim (until the withhold arms read it, a declared refusal is still withheld). Absent (the default) on a declared fault, whose message is withheld from the body and logged for the operator; redundant on a 4xx. Presence is the declaration — true is the only value.
categorystringoptionalError category (e.g. validation, authorization)
httpStatusintegeroptionalHTTP status of the response carrying this error
detailsanyoptionalAdditional error context (e.g. field validation errors)
requestIdstringoptionalRequest ID for tracking

Nested Shape: UninstallPackageApiResponse.meta

PropertyTypeRequiredDescription
timestampstring✅
durationintegeroptionalServer-side processing duration in milliseconds
requestIdstringoptional
traceIdstringoptional

Nested Shape: UninstallPackageApiResponse.data

PropertyTypeRequiredDescription
packageIdstring✅Uninstalled package ID
successboolean✅Whether uninstall succeeded
messagestringoptionalUninstall status message

UploadArtifactRequest

Upload artifact request

Properties

PropertyTypeRequiredDescription
artifact{ formatVersion?: string; packageId: string; version: string; format?: Enum<'tgz' | 'zip'>; … }✅Package artifact metadata
sha256stringoptionalSHA256 checksum of the uploaded file
tokenstringoptionalPublisher authentication token
releaseNotesstringoptionalRelease notes for this version

Nested Shape: UploadArtifactRequest.artifact

PropertyTypeRequiredDescription
formatVersionstringoptional (default: "1.0")Artifact format version (e.g. "1.0")
packageIdstring✅Package identifier from manifest
versionstring✅Package version from manifest
formatEnum<'tgz' | 'zip'>optional (default: "tgz")Archive format of the artifact
sizeintegeroptionalTotal artifact file size in bytes
builtAtstring✅ISO 8601 timestamp of when the artifact was built
builtWithstringoptionalBuild tool identifier (e.g. "os-cli@3.2.0")
files{ path: string; size: integer; category?: Enum<'objects' | 'views' | 'pages' | 'flows' | 'dashboards' | 'permissions' | …> }[]optionalList of files contained in the artifact
metadataCategoriesEnum<'objects' | 'views' | 'pages' | 'flows' | 'dashboards' | 'permissions' | …>[]optionalMetadata categories included in this artifact
checksums{ algorithm?: Enum<'sha256' | 'sha384' | 'sha512'>; files: Record<string, string> }optionalSHA256 checksums for artifact integrity verification
signature{ algorithm?: Enum<'RSA-SHA256' | 'RSA-SHA384' | 'RSA-SHA512' | 'ECDSA-SHA256'>; publicKeyRef: string; signature: string; signedAt?: string; … }optionalDigital signature for artifact authenticity verification

UploadArtifactResponse

Upload artifact response

Properties

PropertyTypeRequiredDescription
successboolean✅Operation success status
error{ code: Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>; declaredCode?: string; message: string; userMessage?: string; … }optionalError details if success is false
meta{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }optionalResponse metadata
data{ success: boolean; artifactRef?: object; submissionId?: string; message?: string }✅

Nested Shape: UploadArtifactResponse.error

PropertyTypeRequiredDescription
codeEnum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>✅Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages)
declaredCodestringoptionalThe producer-declared code, verbatim, when it is not a member of the closed code vocabulary — the open, author-authored channel (app-specific spellings; ADR-0112)
messagestring✅Readable error message
userMessagestringoptionalProducer-marked user-facing refusal text, verbatim. Present exactly when the producer opted in at throw time; consumers render it to end users and keep their generic substitution for anything unmarked. Status-agnostic; never replaces message.
refusaltrueoptionalProducer-declared: the 5xx this envelope carries is a deliberate refusal whose message is authored for the caller, so a boundary that reads the declaration keeps it verbatim (until the withhold arms read it, a declared refusal is still withheld). Absent (the default) on a declared fault, whose message is withheld from the body and logged for the operator; redundant on a 4xx. Presence is the declaration — true is the only value.
categorystringoptionalError category (e.g. validation, authorization)
httpStatusintegeroptionalHTTP status of the response carrying this error
detailsanyoptionalAdditional error context (e.g. field validation errors)
requestIdstringoptionalRequest ID for tracking

Nested Shape: UploadArtifactResponse.meta

PropertyTypeRequiredDescription
timestampstring✅
durationintegeroptionalServer-side processing duration in milliseconds
requestIdstringoptional
traceIdstringoptional

Nested Shape: UploadArtifactResponse.data

PropertyTypeRequiredDescription
successboolean✅Whether the upload succeeded
artifactRef{ url: string; sha256: string; size: integer; format?: Enum<'tgz' | 'zip'>; … }optionalArtifact reference in the registry
submissionIdstringoptionalMarketplace submission ID for review tracking
messagestringoptionalUpload status message

On this page

Package API ProtocolFive declarations of this API live one file over, on purposeTypeScript UsageGetInstalledPackageRequestPropertiesListInstalledPackagesRequestPropertiesPackageApiErrorCodeAllowed ValuesPackageInstallBodyUnion OptionsOption 1PropertiesNested Shape: PackageInstallBody[option 1].manifestNested Shape: PackageInstallBody[option 1].artifactRefOption 2PropertiesNested Shape: PackageInstallBody[option 2].permissionsNested Shape: PackageInstallBody[option 2].contributesNested Shape: PackageInstallBody[option 2].data[number]Nested Shape: PackageInstallBody[option 2].navigationContributions[number]Nested Shape: PackageInstallBody[option 2].engineNested Shape: PackageInstallBody[option 2].enginesPackageInstallRequestPropertiesNested Shape: PackageInstallRequest.manifestNested Shape: PackageInstallRequest.artifactRefPackageInstallResponsePropertiesNested Shape: PackageInstallResponse.errorNested Shape: PackageInstallResponse.metaNested Shape: PackageInstallResponse.dataPackagePathParamsPropertiesPackageRollbackRequestPropertiesPackageUpgradeRequestPropertiesNested Shape: PackageUpgradeRequest.manifestPackageUpgradeResponsePropertiesNested Shape: PackageUpgradeResponse.errorNested Shape: PackageUpgradeResponse.metaNested Shape: PackageUpgradeResponse.dataResolveDependenciesRequestPropertiesNested Shape: ResolveDependenciesRequest.manifestResolveDependenciesResponsePropertiesNested Shape: ResolveDependenciesResponse.errorNested Shape: ResolveDependenciesResponse.metaNested Shape: ResolveDependenciesResponse.dataUninstallPackageApiRequestPropertiesUninstallPackageApiResponsePropertiesNested Shape: UninstallPackageApiResponse.errorNested Shape: UninstallPackageApiResponse.metaNested Shape: UninstallPackageApiResponse.dataUploadArtifactRequestPropertiesNested Shape: UploadArtifactRequest.artifactUploadArtifactResponsePropertiesNested Shape: UploadArtifactResponse.errorNested Shape: UploadArtifactResponse.metaNested Shape: UploadArtifactResponse.data