Nuvaka › Developer docs › Manifest (nuvaka.json)
Manifest: nuvaka.json
nuvaka.json at the package root describes the extension. The server, the app and nuvaka-ext lint apply the same rules. Unknown fields are rejected.
Example
{
"id": "tarikgkhsn.github-watcher",
"name": "GitHub takipçisi",
"version": "0.1.0",
"apiVersion": 1,
"description": {
"tr": "Seçtiğin GitHub depolarının yeni sürümlerini saatte bir denetler ve yeni sürüm çıkınca tüm cihazlarına ya da yalnız bu cihaza bildirim gönderir.",
"en": "Checks the GitHub repositories you choose for new releases every hour and notifies all your devices, or only this one, when a new release appears."
},
"storeCategory": "developer",
"icon": "icon.svg",
"entry": { "ui": "index.html", "background": "background.js" },
"pages": [
{ "id": "releases", "title": { "tr": "Sürümler", "en": "Releases" } }
],
"permissions": [
{ "net": ["api.github.com"], "reason": { "tr": "Depoların son sürümünü GitHub API'den okumak için", "en": "To read the latest release of each repository from the GitHub API" } },
{ "nuvaka.push": true, "reason": { "tr": "Yeni sürümü tüm cihazlarına bildirmek için", "en": "To announce a new release on all your devices" } },
{ "notifications": true, "reason": { "tr": "Yeni sürümü yalnız bu cihazda bildirmek için", "en": "To announce a new release on this device only" } },
{ "background": true, "reason": { "tr": "Sürümleri saatte bir, sayfa kapalıyken de denetlemek için", "en": "To check releases every hour, even when the page is closed" } }
],
"storage": { "quotaMB": 1 },
"triggers": [{ "schedule": "hourly" }, { "event": "network.online" }],
"settings": [
{ "key": "repos", "type": "string", "label": { "tr": "Depolar (sahip/ad, virgülle ayır)", "en": "Repositories (owner/name, comma separated)" }, "default": "tauri-apps/tauri, nodejs/node" },
{ "key": "channel", "type": "select", "label": { "tr": "Bildirim", "en": "Notification" }, "default": "push", "options": ["push", "local", "none"] }
]
}
Source: examples/apps/github-watcher/nuvaka.json
Fields
| Field | Type | Required | Rule |
|---|---|---|---|
id | string | ✓ | <publisher>.<name>; publisher [a-z0-9][a-z0-9_-]{1,31}, name [a-z0-9][a-z0-9-]{1,39} |
name | string | ✓ | 2–40 characters |
version | string | ✓ | semver x.y.z, no prefix; every upload greater than the previous one |
apiVersion | integer | ✓ | 1 |
minAppVersion | string | semver; the lowest Nuvaka app version the extension needs | |
description | { tr, en? } | ✓ | tr required; each 1–300 characters |
storeCategory | string | ✓ | productivity, developer, files, communication, finance, media, games, system, education, other |
icon | string | ✓ | path of an .svg or .png in the package |
homepage | string | https:// URL, 8–300 characters | |
entry | { ui?, background? } | ✓ | at least one; file paths in the package (ui: .html/.htm, background: .js/.mjs) |
pages | array | ✓ if entry.ui | 1–10 pages: { id, title: { tr, en? }, icon? } |
permissions | array | at most 30; each item is one permission + reason | |
storage | { quotaMB } | 1–100 MB; default 10 | |
shared | { exports?, imports? } | sharing between extensions | |
triggers | array | at most 10; needs entry.background | |
settings | array | at most 30 settings | |
$schema | string | for editors; ignored |
Localized texts use the { "tr": "…", "en": "…" } form; tr (Turkish) is always required.
id
The publisher prefix is the uploading account's username (lower case) and is enforced by the server: nobody else can publish with your prefix. The ID never changes once published, even if the name does.
version and minAppVersion
Only x.y.z (e.g. 1.4.0); no v prefix, no -beta suffix. You cannot upload the same or a lower version. minAppVersion is the lowest Nuvaka app version the extension requires.
entry and pages
entry.ui is the UI's HTML file and entry.background the background script. Both must be in the package.
pagesis required whenentry.uiis present. Every page is an item in the Apps menu under the publisher heading; all of them open the same HTML file. The open page comes in thenuvaka.readycontext (ctx.page) andnuvaka.ui.onPage(fn)fires when it changes.- Page
id:[a-z0-9][a-z0-9-]{0,29}, unique.title:{ tr, en? }, at most 40 characters each.icon: optional icon name, up to 40 characters. entry.backgroundrequires thebackgroundpermission.
permissions
Each item holds exactly one permission key and a reason. The reason is shown on the install screen: { tr, en? }, 1–200 characters each.
"permissions": [
{ "files": "read", "reason": { "tr": "Seçtiğin klasördeki dosyaları okumak için", "en": "To read files in the folder you pick" } },
{ "files": "write", "reason": { "tr": "Düzenlenen dosyayı kaydetmek için", "en": "To save the edited file" } },
{ "net": ["api.github.com"], "reason": { "tr": "Sürümleri GitHub'dan okumak için", "en": "To read releases from GitHub" } },
{ "notifications": true, "reason": { "tr": "Yeni sürümü bildirmek için", "en": "To announce a new release" } }
]
- The same scope cannot appear twice.
files: readandfiles: writeare separate scopes and may both be requested. net: 1–20 full host names, lower case.*, IP addresses,localhostand names ending in.local/.localhost/.internalare not accepted.- The
sharedpermission is not written in the manifest; it is added automatically whenshared.importsis present. - Storage needs no permission; every extension has its own space.
All permissions, their values and risk classes: Permissions reference.
storage
"storage": { "quotaMB": 25 }
An integer from 1 to 100; default 10 MB. The quota is per user and per extension. See Quota.
shared
Extensions can expose named values to each other. Names are [a-z0-9][a-z0-9-]{0,29}.
"shared": {
"exports": [{ "name": "rates", "description": { "tr": "Günlük döviz kurları", "en": "Daily exchange rates" } }],
"imports": [{ "from": "tarikgkhsn.faturaci", "name": "customers" }]
}
exports: the names this extension may write withnuvaka.shared.set(name, …), with a description shown to the user ({ tr, en? }, ≤ 200).imports: values to read withnuvaka.shared.get(from, name). Reading requires the user to grant thesharedpermission and the source extension to be installed.
triggers
Events that wake the background script. Requires entry.background. Each item is either { "schedule": … } or { "event": … }.
Schedules
| Form | Meaning |
|---|---|
every Nm | every N minutes; 15 ≤ N ≤ 1440 (e.g. every 15m, every 360m) |
hourly | every hour |
daily HH:MM | every day, local time (e.g. daily 09:00) |
weekly mon HH:MM | once a week; day mon tue wed thu fri sat sun |
When it fires, nuvaka.on('schedule', ({ schedule, at }) => …) runs in the background; schedule is the manifest text and at the firing time (unix seconds). A schedule missed while the app was closed fires once at the next start.
Events
| Event | When | Permission needed |
|---|---|---|
app.started | when the background starts (app start) | — |
app.focused | when the app window gets focus | — |
network.online | when the network comes back | — |
notes.changed | when notes change | nuvaka.notes: read |
cloud.fileAdded | when a file is added to Nuvaka cloud | nuvaka.cloud: read |
mail.received | when mail arrives | nuvaka.mail: read |
clipboard.added | when an item is added to the clipboard pool | nuvaka.clipboard: read |
Server-originated events are not delivered unless the matching read permission is granted. The payload does not contain the change itself; read the data again through the API.
settings
Settings the user can change. The app draws the settings screen; values are the same across devices and are read with nuvaka.settings.get() (default when the user has not set a value).
| Field | Rule |
|---|---|
key | 1–40 characters |
type | string, number, bool, select |
label | { tr, en? }, ≤ 80 each |
default | default value |
options | array of choices; required for select |
"settings": [
{ "key": "greeting", "type": "string", "label": { "tr": "Selamlama", "en": "Greeting" }, "default": "Hello" },
{ "key": "channel", "type": "select", "label": { "tr": "Bildirim", "en": "Notification" }, "default": "push", "options": ["push", "local", "none"] }
]
Extra rules
Rules the JSON schema cannot express but the server and lint enforce:
entryandiconpaths must exist in the package.entry.uirequirespages;entry.backgroundrequires thebackgroundpermission;triggersrequireentry.background.every Nmrequires 15 ≤ N ≤ 1440.- The same permission scope cannot appear twice.
- The
idprefix must be the uploading account's username. nethosts cannot be.local,.localhostor.internal.
Nuvaka Apps API v1 · last updated 2026-09-27