Nuvaka › Developer docs › Dependencies

Dependencies

An extension can need other extensions: a shared helper, a data service, a theme or a translation pack. You declare this with the dependencies field in the manifest. There are two kinds: uses is installed as a private copy inside your extension, and extends plugs into an extension the user installed themselves.

Declaring

"dependencies": [
  { "id": "ali.tray", "version": "^1.5.0" },
  { "id": "ali.charts", "version": "~2.1", "optional": true },
  { "id": "ali.notebook", "version": "^3.0.0", "kind": "extends" }
]

Without kind, a dependency is uses. At most 10 entries. The full range syntax is on Manifest › dependencies. In short: 1.2.3, ^1.2.3, ^1.2, ~1.2.3, ~1.2, 1.x, 1.2.x, *, and comparators such as >=1.0.0 <2.0.0. There are no pre-releases and no ||.

Two kinds: uses and extends

uses (default)extends
Where it is installedInside your extension, as a private copyIn the user's own toolbox (the target must be installed there)
Visible to the userNot in the toolbox or side menu. It appears in your extension's settings, under "Dependencies".Shown as a normal app
Data, settings, permissionsSeparate: the copy has its own storage, quota, settings and permissions. Data namespace <dependency>~<owner>.Those of the user's own install
VersionsCopies inside different extensions can sit side by side at different versions. They are independent of the user's own install.The user's installed version must satisfy the range
Runs on its ownNo: no triggers, no start on launch, no notifications. It runs only when its owner calls it.Yes, like any extension
Use it forLibraries, helper services, internal enginesThemes, translations, add-ons for an app

A package cannot be both uses and extends in one tree. An extends target is not descended into: its own dependencies belong to its own install.

Calling a private copy (uses)

The copy opens functions in its background code with nuvaka.expose. The owner calls them with nuvaka.deps.call. If the copy is not running, its background starts on the first call. The result comes back as JSON, and the call waits at most 60 seconds.

// ali.tray — background.js (the copy)
nuvaka.expose('summary', async ({ text }) => {
  const rec = await nuvaka.storage.get('counter')   // the copy's own data
  return { length: text.length, previous: rec?.value ?? 0 }
})

// Owner — UI or background
const r = await nuvaka.deps.call('ali.tray', 'summary', { text: 'hello' })
  • The copy runs with its own permissions. The user approves them at install, on the same screen as your extension's permissions.
  • A copy cannot send notifications (nuvaka.ui.notify and nuvaka.push → dependency_no_notify). It also cannot use the single-file handles opened from My Files.
  • Critical permission prompts name the owner too: "Tray (for Notebook) wants to read your mail".
  • deps.call errors: not_a_dependency (not uses in your manifest), dependency_missing, dependency_blocked, dependency_unavailable, not_exposed, timeout. In a copy, nuvaka.info() returns the owner in owner.

Rules

RuleChecked at
At most 10 direct dependencies. No self-dependency and no duplicates. Valid range syntax; kind is uses or extends.nuvaka-ext lint and upload
The dependency is in the store and not blocked, and a published version satisfies the range.upload
No cycles (A → B → A; root included)upload
Depth ≤ 5upload
At most 10 packages in total (all packages in the install, root included; optional ones count too)upload
Within one owner's uses tree a package has one version. Incompatible ranges are a conflict error. Different owners do not affect each other.upload and install

If an upload is rejected, the errors arrive in scan.errors prefixed with "Bağımlılık: …". You can see the tree before publishing with nuvaka-ext deps (CLI).

Resolution

  • For each dependency, the highest published version that satisfies the range is chosen. Yanked versions and versions still in review are never chosen.
  • An optional dependency (optional: true) is still part of the tree and counts toward the 10-package limit, but installing it is not required.
  • The server resolves the tree: GET /api/ext/v1/store/{id}/dependencies?version= (anonymous). Every package includes kind and privateCopy.
    • For a uses package, the installed* fields describe the copy inside the owner. ownInstallVersion is the user's own install, for information only.
    • For an extends package, those fields describe the user's own install.
$ nuvaka-ext deps [email protected]
tarikgkhsn.invoice 1.3.0
  ✓ ali.tray 1.5.6  (^1.5.0)
    ✓ ali.http-helper 2.0.1  (2.x) ← ali.tray
  ✓ ali.charts 2.1.5  (~2.1) [optional]
Total packages (root included): 4 / 10
Installable

Install

The install screen shows the tree: each package's kind, version and requested permissions, and whether its developer has abandoned it.

  • extends targets come first. If a target is missing from the user's toolbox, or its version does not satisfy the range, it is installed or updated first.
  • Then the extension itself. The server installs the private copies (PUT installs/{id} with withDependencies: true). The copies' permissions are asked on the same screen, grouped owner → copy, and sent in dependencyGrants.
  • Install only this is offered only when the missing dependencies are all optional.
  • If a required dependency cannot be installed right now (it is blocked, or no version satisfies the range), the install does not start and the reason is shown (409 dependencies_unavailable).
  • Server responses:
    • 409 dependencies_required: something is missing. If kind is "extends", install the target first.
    • 409 extends_version_mismatch: the target's installed version does not match. It can be updated to latestSatisfying.

Plan for an optional dependency not being installed: nuvaka.deps.call can fail with dependency_missing.

Settings

In the Apps screen, your extension's settings have a collapsible Dependencies section.

  • The user changes the private copies' permissions and settings there: PATCH /api/ext/v1/installs/{dependency}?owner={owner} { settings?, grants? }.
  • Stopping and updating a copy follow its owner.
  • extends targets only show their status. Their own settings are on their own page.

Uninstall

  • Removing an extension also removes its private copies. Their data follows the same rule as the owner's (keepData).
  • uses copies are independent, so they never block a removal.
  • If one of the user's own installs requires an extension through extends, the user is warned before removing it: "X is used by other apps". They can still remove it, and dependent extensions are marked "dependency missing".

Updates

  • If a new version needs a new required copy or an extends target that is not installed, auto-update stops and the user is asked (newDependencies). The old version keeps running until they approve.
  • Copy version changes are shown on the update card (copyVersionChanges). On approval, withDependencies: true brings the copies to their new versions too.
  • The same applies when contributes changes (Core contributions).
  • Ship breaking changes as a major version (2.0.0). Copies inside extensions that ask for ^1.x stay on 1.x, and a 2.x copy inside another extension does not affect them.

Dependency status of an installed extension

StatusMeaning
okall required dependencies are in place and satisfy their ranges
missinga copy or extends target is missing, or its version does not satisfy the range
blockeda dependency's version was blocked by Nuvaka: the copy stops and the owner's publisher is notified
abandoneda dependency's developer abandoned the package (it still works, but may not get updates)

Abandoned dependencies

A package other extensions depend on cannot be deleted, but its developer can abandon it. The package stays in the store at its last version, dependent extensions keep working, and their developers are notified. Another developer can ask to adopt it; see Abandoned packages and ownership.

Nuvaka Apps API v1 · last updated 2026-09-27