This document describes the Xedge interface. The implementation is split between:
- the Web File Server (WFS) mounted at
/rtl/apps/, used for files and folders; - the Xedge command endpoint at
/rtl/private/command.lsp, used for IDE and application-management operations; and - the browser and Lua plugin APIs, used to extend Xedge without modifying its core UI or command dispatcher.
The implementation is defined by wfs.lua, xedge.lua, command.lsp, and xedge.js. This reference covers the shared Xedge management interface; platform plugins extend it separately.
- Clients authenticate the same way as the Xedge UI: a session cookie or HTTP authentication when configured. An unconfigured installation may allow access without credentials; these endpoints do not provide a separate API-token scheme.
- Requests to
private/command.lspmust includeX-Requested-With: XMLHttpRequest. A request without this header receives404 Not Found. The handler checks header presence, not its value. - WFS mutation requests should include the same header to select JSON success and error responses.
- The Xedge browser client uses
fetch()andURLSearchParams. Normal command requests are GET requests with URL-encoded query parameters. WFS POST commands use URL-encoded form data. File PUT requests carry the raw file contents. - A
401 Unauthorizedresponse causes the Xedge client to open its login UI and retry the original request after successful authentication. private/command.lsprejects requests whoseSec-Fetch-Siteheader iscross-site, returning404 Not Found.
File requests use this form:
/rtl/apps/{io-or-app-name}/{path}
The first path segment is a string selecting an Xedge I/O root or installed application. The
remaining segments identify a resource inside that root. Encode individual path
segments when constructing a URL; do not encode / separators.
Returns metadata without downloading the resource.
200 OKincludesContent-Length,HttpResMgr: V2.1, andEtag.- A directory has
Content-Length: 0andBaIsDir: true. - A file has a content type inferred from its extension.
- A missing resource returns
404 Not Found.
The Xedge editor uses HEAD to reject directories, unsupported types, and files that are too large before issuing GET.
Streams the file contents. Add download=1 to request an attachment response.
With cmd, executes one of the JSON directory commands below. Without cmd,
the Xedge WFS mount serves the standalone SPA Web File Manager. The directory
command API itself never generates the old Web File Manager HTML.
Creates or replaces a file using the raw request body. An empty body creates an empty file. Existing WebDAV locks and authorization rules are enforced.
With X-Requested-With, success is:
{"ok":true}A URL-encoded request executes a directory command. A multipart request is handled as an upload.
Deletes a file or recursively deletes a directory. Authorization and locks are checked for each affected resource.
Commands are supplied through the string cmd parameter. Directory URLs should end in
/. The methods below are client conventions: the directory dispatcher accepts
these commands through either GET or non-multipart POST. Parameters are strings
unless specified otherwise; repeated n parameters select multiple resources.
| Command | Method | Parameters | Response |
|---|---|---|---|
lj |
GET | none | JSON array of directory entries |
mkdirt |
POST | dir |
{"ok":true} |
mv |
GET | from, to |
{"ok":true} |
rmt |
POST | file |
{"ok":true} |
sesuri |
GET | none | {"uri":"...","tmo":seconds} |
getlock |
GET | name |
Lock owner/time or {"notlocked":true} |
getlocks |
GET | repeated n |
{"files":[...]} |
lock |
POST | repeated n, Unix expiration time |
{"ok":true} |
unlock |
POST | repeated n |
{"ok":true} |
mv is the legacy NetIo-compatible rename/move command. from is relative to
the requested directory. to is a destination path prefixed by the WFS base
URI, such as /rtl/apps/disk/new/path.txt.
rmt is retained for compatibility. New clients may use DELETE directly.
The lj response is an array with one object per resource:
[
{"n":"main.xlua","s":421,"t":1785657600},
{"n":"www","s":-1,"t":1785657600}
]The compatibility fields are:
- string n: resource name;
- number s: file size in bytes, or
-1for a directory; and - number t: modification time as Unix seconds.
These fields must not change because other clients, including NetIo, consume
them. If session URLs are available, the lj
response also includes BaWfsSes: 1. For a file session URL, request sesuri
from its parent directory and append the encoded file name to the returned URI.
getlocks returns entries shaped as {"n":"name","l":false} or
{"n":"name","l":"owner"}. getlock returns
{"owner":"name","time":unixTime} when locked. Here owner, n, and a
locked l are strings; time is a number of Unix seconds; notlocked and an
unlocked l are booleans. getlocks omits directories and missing files.
lock ignores missing files, directories, already locked files, and expiration
times that are not in the future. Its ok: true does not confirm that every
requested file was locked. unlock also succeeds for files without a lock.
The sesuri result contains string uri and number tmo (seconds); tmo
is zero when no session URL was created.
JSON errors contain string err (error code) and string emsg (description):
{"err":"noaccess","emsg":"Cannot delete file: No file system access."}Common status mappings are:
400: invalid command or name;403: authorization or lock failure;404: resource not found;405: destination already exists;409: missing path or non-empty directory;503: storage or capacity failure.
Application configuration is exposed as a virtual .appcfg JSON resource
through WFS. GET /rtl/apps/{app}/.appcfg returns configuration with the live
boolean running state. This is distinct from boolean autostart, which
controls startup after a host restart.
PUT replaces the configuration, rather than merging individual fields. Read
the configuration first and retain settings that are not being changed. To
create an application, write .appcfg beneath its source directory in an I/O
root. The directory path supplies the default source URL.
- string name: application name; required for a complete configuration.
- string url: source path or NET IO URL; defaults to the containing source path when omitted.
- boolean running: requested running state; defaults to false.
- boolean autostart: optional; false prevents automatic launch at startup.
- number startprio: optional startup ordering value; lower values start first, and omission sorts as 100.
- string dirname: optional LSP mount path; omission disables LSP, and an empty string selects the server root.
- string domainname: optional virtual host name for an LSP application.
- number priority: optional LSP mount priority; defaults to zero.
Changing the running state starts or stops the application. Updating other
settings while retaining the same name and running state does not force a
restart. Stop and start the application to apply settings that require one.
A successful PUT acknowledges configuration processing; check getappsstat
and TraceLogger for application startup results. DELETE of an installed
application's .appcfg removes its registration and stops it; it does not
delete the source files.
When a running application's .xlua file is replaced through WFS, closing the
write handle invokes Xedge's manageXLuaFile flow so the program is reloaded.
The upload response does not report the Lua program's execution result; errors
are reported through TraceLogger.
GET /rtl/private/command.lsp?cmd={command}&...
Unless noted otherwise, parameters are URL-encoded strings and responses are
JSON. A successful response normally contains ok: true. Some discovery
commands intentionally return an array instead of an object.
An unknown command returns:
{"err":"Unknown command 'name'"}The native Xedge request wrapper treats a non-2xx HTTP response, err, or
emsg as failure. Its callback receives the response on success and false on
failure. For a JSON application error it calls callback(false, response);
transport or JSON decoding failures call callback(false). An ok: false
value alone is passed to the callback as a normal response, so callers must
check it. Authentication failures are retried after login.
Certificate management uses the required string acmd selector. These commands require writable ACME I/O. They complete asynchronously through a deferred HTTP response.
Parameters for available and auto
- string name: requested device name; required for
available. Forauto, omission retains the saved name, which must exist. - string email: account email for
auto; omission retains the saved value, which must exist. - string manualIdentity:
"true"selects custom portal credentials; omission or another value selects the compiled identity. - string portalUrl: custom portal URL; omission retains the saved value.
- string zoneKey, string secret: custom portal credentials; omitted or
empty values retain the saved values. These are not returned by
isreg. - string revcon:
"true"enables reverse connections forauto; omission or another value disables them. - string staging:
"true"selects the staging certificate authority; another supplied value selects production. Omission retains the selection.
available returns boolean ok, boolean available, and string name
on success, or string err on failure.
auto saves settings, closes the preceding runtime, and starts the selected
configuration. It returns {"ok":true} or {"ok":true,"pending":true} when
activation awaits clock readiness or a scheduled retry. boolean pending
does not mean that a certificate is installed. Failure returns string err.
Use isreg to retrieve subsequent state.
Return values for isreg
- boolean ok: true for the status response.
- boolean isreg: whether the portal confirmed registration; false also covers an unavailable confirmation and does not alone prove deletion.
- string name, string email: optional saved/confirmed device name (first DNS label) and configured email.
- string sockname: optional local address of the connection to the portal. It is not the local address of the browser connection.
- string wan: optional public address observed by the portal.
- string connectionError: optional registration or WAN lookup error.
- string portal, string compiledPortal: selected and compiled portal identities; empty when unavailable.
- boolean compiledIdentity, boolean manualIdentity: availability of a compiled identity and selection of custom credentials, respectively.
- boolean staging, boolean revcon: selected staging and reverse modes.
- object reverseStatus: boolean enabled, boolean connected, number status (native connection status), and number connections (established-connection count).
- boolean certificateRetrying: a runtime startup retry is scheduled.
- boolean certificateWorking: clock readiness or runtime work is pending.
- boolean certificateReady: at least one reported certificate has a future
expiration time and
certificateWorkingis false. This is not a browser trust check; a staging certificate can also satisfy it.
Returns config, a base64url-encoded JSON object containing application
configuration ({"apps":{...}}). This supports browser persistence when disk configuration is
unavailable.
Accepts optional string xedgeconfig, the encoded configuration from
getconfig. It is used only when disk configuration is unavailable and no
application configuration has been loaded. Returns boolean ok, array of
strings ios, and boolean nodisk. I/O names are not sorted:
{"ok":true,"ios":["disk","home","net"],"nodisk":false}During startup this command also establishes the authentication boundary before the client creates its tree and loads plugins.
Returns boolean ok and object apps, mapping application names to live
running values. A stopped application whose internal state is nil is omitted
from this object. Read its .appcfg to obtain an explicit boolean state.
Returns boolean ok and string ip, the request domain from
cmd:domain() for NET IO setup. Despite the field name, this can be a host
name and is not an interface-address discovery operation.
Returns boolean ok and string intro, containing welcome-page HTML.
The default implementation returns boolean ok false. A platform plugin may override it and return boolean ok true and string mac.
Accepts optional string ext. Returns boolean ok and string data, the matching new-file template, or a newline when no template exists.
- With no
name, returns boolean ok and object data with string name, one configured user or an empty string. - With required string name and string pwd, creates or updates the user's digest credential. An
empty password removes the user. The update response is
{"ok":true}.
Requires string fn. Returns boolean ok and string url, the launch URL for a running LSP-enabled application, or string err when the application is missing, stopped, or not LSP-enabled.
Requires string fn. For application resources, returns boolean ok,
boolean isapp, boolean lsp, optional boolean running, and optional
string url. A nil internal running state is omitted; treat an absent
running as stopped. The URL is omitted for .xlua resources. For non-application resources it returns {"ok":true}.
Requires string fn. Runs a selected .xlua resource when its owning
application is running. The {"ok":true} response is also returned if the
application is missing or stopped; it does not report execution success.
Execution errors are reported through TraceLogger.
- With no fields other than
cmd, returns SMTP and email-log configuration. - With string fields email, server, port, user, password,
and connsec, validates
and stores SMTP settings. Complete settings trigger a test email; incomplete
settings disable SMTP.
connsec="tls"selects implicit TLS;connsec="starttls"selects STARTTLS. Other nonempty values leave both options disabled.portmust be numeric text for the completeness check. Send all six fields when updating. Unchanged enabled settings do not send another test email. A failed test returns boolean ok false and optional string err, retaining the previous settings.
The read response places SMTP settings and email-log fields directly in the
response object alongside boolean ok, including the configured password.
enablelog and smtp are booleans; maxbuf and maxtime are numbers;
subject and the SMTP fields are strings.
With no fields other than cmd, returns boolean ok and object data,
containing stored Microsoft Entra OpenID settings or an empty object. This is
an administrative response that includes the configured secret.
To configure SSO, supply these strings:
- string tenant and string client_id: required, each longer than 20 characters.
- string client_secret: required, longer than 10 characters.
- string client_secret_expires: required valid expiration date. A
YYYY-MM-DDdate means the end of that day in UTC.
The server derives redirect_uri from the request origin plus /rtl/login/.
HTTPS is required except for http://localhost development. The redirect URI
must also be registered in Microsoft Entra. Initialization or save failure
returns boolean ok false and string err, restoring the prior in-memory
configuration. Success returns {"ok":true}.
To disable SSO, send tenant, client_id, and client_secret together as
empty strings. An empty secret by itself does not remove the configuration.
Login-page credential recovery is handled separately by
ms-sso.lua and
login/index.lsp.
Requires integer-form strings maxbuf (buffer size in bytes) and
maxtime (hours), string enablelog ("true" enables logging), and
string subject (empty selects "Xedge Log").
Stores email-log settings and returns {"ok":true}.
Accepts string code, defaulting to empty source. Compiles the Lua source and schedules it asynchronously. A
compile failure returns {"ok":false,"err":"..."}. Success returns
{"ok":true} after scheduling; runtime errors appear in TraceLogger and
are not returned in this response.
Returns an alphabetically sorted JSON array of strings containing client plugin paths.
Requires a string name, ending in .js, returned by lsPlugins. Streams JavaScript rather than
JSON and returns 404 when the plugin is unavailable. The native client requests
plugins with cache: "no-store" and executes them sequentially in the returned
order.
Requires string name, the uploaded ZIP name under home on Mako or disk on
standalone Xedge. The optional string deploy selects the mode: deploy=false unpacks the ZIP into developer mode; other
values retain deployed ZIP mode.
The response contains:
- boolean ok: installation success;
- boolean upgrade: whether an existing deployed application was replaced;
- string info: optional text returned by an install or upgrade hook; and
- string err: failure details when
okis false.
Lua plugins under .lua/XedgePlugins receive the command table and may add or
override handlers. Such commands are platform-specific and are not part of the
built-in list. For example, the application-update plugin adds the raw PUT
command uploadfw; Xedge32 plugins may add firmware and device commands.
A plugin handler is responsible for validating its method, headers, body, and parameters, and for sending or aborting the response.
Client plugins are classic scripts loaded after authentication, I/O discovery,
and tree initialization. The Xedge shell itself is an ES module. Its supported plugin functions are
exposed on window (the shell also exposes login integration hooks):
| Name | Purpose |
|---|---|
el(tag, properties, ...children) |
Create a DOM element using native APIs |
ideCfgCB |
Array of callbacks used to add configuration-menu items |
log(...) |
Append normal output to TraceLogger |
logR(...) |
Append highlighted/error-style output without playing the error sound |
mkForm(description, elements?, parent?) |
Build a form and collect named elements |
createEditor(name, value, saveCallback, content?, closeCallback?) |
Open an editor or plugin panel |
closeEditor(id) |
Close an editor or plugin panel |
alertErr(...) |
Report an error through the Xedge error path |
sendCmd(command, callback, data?) |
Call private/command.lsp through the native request layer |
createTree() |
Rebuild the application/file tree after structural changes |
el recognizes the convenience properties text and html; other properties
are assigned to the DOM element when possible and otherwise become attributes.
Plugin code may also use normal modern-browser DOM APIs. It must not depend on
private variables inside the Xedge ES module.
Configuration plugins normally append a callback:
// Add a configuration-menu entry after Xedge has initialized its UI.
ideCfgCB.push((menu, nodisk) => {
const item = el("li", {text: "My Plugin"});
item.onclick = () => createEditor("My Plugin", null, null, el("div", {text: "Ready"}));
menu.append(item);
});The callback receives an HTMLUListElement menu and boolean nodisk. Its
return value is ignored.
Plugins that mutate applications or files should call createTree() after the
server operation succeeds.
Browser and Lua plugins execute with Xedge management privileges. Treat plugin files as trusted code, validate all external input on the server, and do not expose secrets to browser plugins.
el(string tag, object properties, ...children)returns an HTMLElement. Children are DOM nodes or text;htmlis trusted HTML, not escaped text.mkForm(array description, object elements?, HTMLElement parent?)returns the parent HTMLElement (a new form container by default). The suppliedelementsobject is populated by element ID, not by name. Description objects useelfor the tag,childrenfor nested descriptions, andhtmlfor trusted HTML. Form entries can uselabelas the element ID,nameas display text, anddescriptionas tooltip text.createEditor(string name, string|null value, function|null saveCallback, HTMLElement content?, function closeCallback?)returns a string editor ID, or undefined if that editor already has unsaved changes. Usevalue=nullwithcontentto open a plugin panel. The optional save callback receives the data and a completion function; call completion with{ok:true}on success. A booleantruealone does not clear the modified indicator. The optional close callback takes no arguments and releases plugin resources.closeEditor(string id)returns undefined and invokes the registered close callback. It closes directly without the tab button's unsaved-change confirmation.sendCmd(string command, function callback, object data?)returns undefined, addscmdto the supplied data object, and performs a GET. Its callback receives the JSON response or the failure arguments described under the command API. This function does not return a Promise.createTree()returns undefined and starts an asynchronous tree rebuild.log(...),logR(...), andalertErr(...)report output and return undefined; their return values do not indicate server-operation success.