What it exports
tabs(doc) returns the studio setup tabs (connection accounts). public_filter(doc) optionally hides fields from the client. The real work lives in server.mjs.
Xuda Developer Plugins
The runtime dispatches plugin behavior by category. A dbs plugin is never asked to render DOM.
A widget plugin is never asked to query a database. Get the category right and the platform
gives you the correct extension hooks for free. Get it wrong and the loader will silently ignore you.
dbs — Database adapters
A dbs plugin teaches the runtime how to read, write, and query a storage backend.
It implements a fixed server-side CRUD contract and declares the connection fields the studio should
prompt for. Built-in examples cover CouchDB, MySQL, and Xuda's own managed store.
tabs(doc) returns the studio setup tabs (connection accounts). public_filter(doc) optionally hides fields from the client. The real work lives in server.mjs.
server.mjs implements read, upsert, delete, index validation, uniqueness checks, and schema migrations as named exports or a default class.
Database plugins are headless by nature. They run on the runtime server. No browser: true capability.
xuda-dbs-plugin-couchdb, xuda-dbs-plugin-mysql, xuda-dbs-plugin-xuda.
index.mjs — from xuda-dbs-plugin-couchdbexport function tabs(doc) {
return {
accounts: {
svg_icon: '<svg ...></svg>',
text: "Connections",
type: "multi",
fields: {
db_name: {
type: "string",
mandatory: true,
label: "Name",
value: "Main Db",
},
db_connection_string: {
type: "string",
placeholder: "https://john:[email protected]:6984/employees",
mandatory: true,
label: "Db Connection String",
value: `https://${doc.app_db_admin_username}:${doc.app_db_admin_password}@xuda.io/db/${doc.app_db_name}`,
},
},
},
};
}
export function public_filter(doc) {
var ret = {};
for (const [key, val] of Object.entries(doc.accounts)) {
ret[key] = {};
}
return ret;
}
framework — CSS framework and shell UI
A framework plugin owns the global UI primitives that every app needs: the theme, the modal
stack, the loader overlay, the toast queue, the popover, the popup, and the page shell. Only one framework
plugin is active per app. Choose it when you want to bring a design system into Xuda.
tabs for theme setup, a core class (init, refresh, renderEngineProperties, rootTagName, customUiClasses), plus bind, toast, loader, popover, popup, modal, and page classes.
Unlike widgets and libraries, a Xuda app picks exactly one framework plugin. The runtime uses it to decide default tags, default classes, and which engine renders modals and toasts.
The tabs schema typically exposes a single init field rendered as a code editor so authors can paste in a design-system config (Tailwind theme object, Ionic CSS variables, etc.).
xuda-framework-plugin-tailwind, xuda-framework-plugin-ionic.
xuda-framework-plugin-tailwind/src/index.mjsexport const core = class {
init(setup) {
const theme_setup = setup?.theme?.init || _fields.init.value;
if (!theme_setup) return null;
const id = 'xuda-framework-plugin-tailwind-script-' + Date.now();
const script = document.createElement('script');
script.setAttribute('id', id);
script.innerHTML = theme_setup;
document.head.append(script);
return id;
}
discard(id) {
document.getElementById(id)?.remove();
}
rootTagName() { return 'div'; }
renderEngineProperties() {
return { restrict_tags: true, engine: function () {}, tags: { /* ... */ } };
}
};
export const toast = class {
async create(type, message, title) { /* ... */ }
};
export const loader = class { /* ... */ };
export const modal = class { /* ... */ };
export const popover = class { /* ... */ };
export const popup = class { /* ... */ };
export const page = class { /* ... */ };
graphics — Icon and asset packs
A graphics plugin ships SVG assets the studio picker can browse. It is the simplest category:
a single runtime.mjs exports a tabs array, and the studio does the rest.
A single named export, tabs: an array of { label, items: [{ name, tags, html }] }. Each item's html is the raw SVG string.
Graphics plugins are stateless. No per-app configuration, no tabs schema, no runtime invocation. The studio just reads the list.
Items include a tags array used by the studio's search. Pack metadata comes from the underlying library (feather-icons, heroicons, phosphor-icons, tabler, iconoir).
xuda-graphics-plugin-feather, -heroicons, -iconoir, -phosphor-icons, -tabler-icons.
xuda-graphics-plugin-feather/src/runtime.mjsimport * as feather from "feather-icons";
import _ from "lodash";
export const tabs = [
{
label: "All",
items: _.map(feather.icons, (e, idx) => ({
name: e.name,
tags: e.tags,
html: feather.toSvg(idx),
})),
},
];
library — Callable actions and integrations
A library plugin adds named, typed actions to the workflow system. Every method becomes a
step authors can drag into an event, a datasource transform, or a rule. Examples include Firebase Auth,
Twilio, Stripe, and the ChatGPT integration. The studio-ai-app-builder plugin is also a
library — it exposes methods like table_builder, component_builder, and so on.
methods, a map of method_id to { name, tooltip, fields, response }. Optional capabilities to pin the method to browser or server.
Browser-safe methods run client-side (runtime.mjs). Server-only methods run in server.mjs. Firebase Auth runs client-side; the AI app builder runs on the server with access to the studio database.
Libraries often accept event_name_for_successful_callback and field_id_to_return_result fields. The runtime invokes the callback event once the async call resolves, and writes the response into the target field.
xuda-library-plugin-firebase-auth, -firebase-push-notification, -firebase-send-email, -firebase-initialize, -stripe-core, -stripe-connect, -twilio, -chatgdp, -studio-ai-app-builder, -xu-workspace-contacts.
xuda-library-plugin-firebase-auth/index.mjsexport const methods = {
create_account: {
name: "Create Account",
tooltip: "Authenticate users with email and password.",
fields: {
name: { label: "Name", type: "string", mandatory: true },
email: { label: "Email", type: "string", mandatory: true },
password: { label: "Password", type: "string", mandatory: true },
profile_image_url: { label: "Profile Image Url", type: "string" },
},
response: {},
},
auth_with_google: { name: "Auth With Google", fields: {}, response: {} },
auth_with_apple: { name: "Auth With Apple", fields: {}, response: {} },
auth_sign_out: { name: "Auth Sign Out", fields: {}, response: {} },
auth_with_email_password:{ name: "Auth With Email and Password",
fields: { email: _fields.email, password: { label: "Password", type: "string" } },
response: {},
},
// ...
};
ui — Behavioral decorators
A ui plugin decorates a DOM element that is already rendered by the framework.
It does not create the container; it enhances it. Think "turn this span into a relative-time display",
"format this input as an international phone number", "turn this list into a sortable list".
properties (studio schema, not per-method) and a runtime fn(plugin_name, el, properties) that takes the mounted element and the evaluated properties.
Browser only. UI plugins always attach to a live DOM node, so they never run headless.
The contract is the opposite of widget: a UI plugin receives the element that already exists in the tree and mutates it in place.
xuda-ui-plugin-moment, -flatpickr, -sortable, -tippy, -timeago, -swiper, -draggabilly, -flag-icons, -jewish-date, -libphonenumber.
xuda-ui-plugin-moment/src/runtime.mjsimport moment from 'moment/min/moment-with-locales';
export const fn = function (plugin_name, el, properties) {
const d = fixTimestampString($(el)?.text()) || null;
const format = properties.moment_format?.value || "YYYY-MM-DD HH:mm:ss";
const locale = properties.moment_locale?.value || "en";
const showCurrentTime = properties.moment_show_current_time?.value || false;
const showRelativeTime = properties.moment_relative_time?.value || false;
const showCalendarTime = properties.moment_calendar_time?.value || false;
moment.locale(locale);
const updateDisplay = () => {
let formatted = showRelativeTime ? moment(d).fromNow()
: showCalendarTime ? moment(d).calendar()
: moment(d).format(format);
el.innerHTML = formatted;
};
updateDisplay();
if (showCurrentTime) setInterval(() => updateDisplay(), 1000);
};
widget — Full visual components
A widget plugin owns a region of the screen. The runtime creates an empty container and
hands it to the plugin; the plugin fills it with whatever it wants, subscribes to its own events,
and cleans up on unmount. Charts, grids, calendars, maps, scanners, avatars — they are all widgets.
capabilities ({ browser, headless }) and methods, a map of method_id to { name, tooltip, fields, response }. runtime.mjs exports one function per method.
async function _default(fields, params). fields holds the resolved typed values. params holds container_node, method, and utility hooks.
A single widget package can expose many variants. xuda-widget-plugin-chartjs's _default method accepts a chart_type field (line, bar, doughnut), so one method covers all Chart.js variants.
26 built-in widgets: chartjs, ag-grid, full-calendar, avatar, google-maps, apple-maps, barcode-qr-scanner, credit-card-scanner, lottiefiles, share, wysiwyg, stripe-elements, and more.
xuda-widget-plugin-chartjs// index.mjs — studio schema
export const capabilities = { browser: true, headless: false };
export const methods = {
_default: {
name: "Default", tooltip: "",
fields: {
chart_type: {
label: "Chart Type", type: "string", render: "select",
options: [
{ label: "Line Chart", value: "line_chart" },
{ label: "Bar Chart", value: "bar_chart" },
{ label: "Doughnut Chart", value: "doughnut_chart" },
],
},
chart_data: { label: "Chart Data", type: "string" },
chart_label: { label: "Chart Label", type: "string" },
chart_labels: { label: "Chart Labels", type: "string" },
chart_background: { label: "Chart background", type: "string" },
},
response: {},
},
};
// runtime.mjs — browser execution
export async function _default(fields, params) {
const container = params.container_node;
const canvas = document.createElement("canvas");
container.replaceChildren(canvas);
new Chart(canvas, {
type: fields.chart_type,
data: { labels: fields.chart_labels, datasets: [{
label: fields.chart_label, data: fields.chart_data,
}]},
});
}
A quick reference for which exports each category needs and where the runtime invokes them.
| Category | index.mjs exports | runtime.mjs exports | server.mjs | Where it runs |
|-----------|----------------------------|------------------------------|------------|----------------|
| dbs | tabs, public_filter | — | required | server |
| framework | tabs, core, bind, toast, | (bundled via index.mjs or | optional | browser |
| | loader, modal, popover, | sibling module) | | |
| | popup, page | | | |
| graphics | — | tabs: [{ label, items }] | — | studio only |
| library | methods, capabilities | one function per method | optional | browser/server |
| ui | properties | fn(plugin_name, el, props) | — | browser |
| widget | methods, capabilities | one async fn per method | optional | browser |