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 installed | Inside your extension, as a private copy | In the user's own toolbox (the target must be installed there) |
| Visible to the user | Not in the toolbox or side menu. It appears in your extension's settings, under "Dependencies". | Shown as a normal app |
| Data, settings, permissions | Separate: the copy has its own storage, quota, settings and permissions. Data namespace <dependency>~<owner>. | Those of the user's own install |
| Versions | Copies 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 own | No: no triggers, no start on launch, no notifications. It runs only when its owner calls it. | Yes, like any extension |
| Use it for | Libraries, helper services, internal engines | Themes, 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.notifyandnuvaka.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.callerrors:not_a_dependency(notusesin your manifest),dependency_missing,dependency_blocked,dependency_unavailable,not_exposed,timeout. In a copy,nuvaka.info()returns the owner inowner.
Rules
| Rule | Checked 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 ≤ 5 | upload |
| 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 includeskindandprivateCopy.- For a
usespackage, theinstalled*fields describe the copy inside the owner.ownInstallVersionis the user's own install, for information only. - For an
extendspackage, those fields describe the user's own install.
- For a
$ 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.
extendstargets 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}withwithDependencies: true). The copies' permissions are asked on the same screen, grouped owner → copy, and sent independencyGrants. - 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. Ifkindis"extends", install the target first.409 extends_version_mismatch: the target's installed version does not match. It can be updated tolatestSatisfying.
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.
extendstargets 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). usescopies 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
extendstarget 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: truebrings the copies to their new versions too. - The same applies when
contributeschanges (Core contributions). - Ship breaking changes as a major version (
2.0.0). Copies inside extensions that ask for^1.xstay on 1.x, and a 2.x copy inside another extension does not affect them.
Dependency status of an installed extension
| Status | Meaning |
|---|---|
ok | all required dependencies are in place and satisfy their ranges |
missing | a copy or extends target is missing, or its version does not satisfy the range |
blocked | a dependency's version was blocked by Nuvaka: the copy stops and the owner's publisher is notified |
abandoned | a 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