/** * KUMO.S App SDK — include in your app with: * * * All methods return Promises. Call KUMOS.ready() first. * * Permissions required per namespace: * storage.* — always available (private app namespace) * fs.* — requires "fs.read" or "fs.write" grant * notify.* — requires "notify" grant * window.* — always available */ (function (global) { 'use strict'; var _pending = {}; // kmid → { resolve, reject, timer } // ── Internal helpers ────────────────────────────────────────────────────── function _uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0; return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); }); } function _send(action, args) { return new Promise(function (resolve, reject) { var kmid = _uuid(); var timer = setTimeout(function () { if (_pending[kmid]) { delete _pending[kmid]; reject(new Error('KUMOS timeout: ' + action)); } }, 15000); _pending[kmid] = { resolve: resolve, reject: reject, timer: timer }; window.parent.postMessage( JSON.stringify({ kmid: kmid, action: action, args: args || {} }), '*' ); }); } // Incoming responses from the shell window.addEventListener('message', function (e) { if (e.source !== window.parent) return; var msg; try { msg = JSON.parse(e.data); } catch (err) { return; } if (!msg || !msg.kmid) return; var p = _pending[msg.kmid]; if (!p) return; clearTimeout(p.timer); delete _pending[msg.kmid]; if (msg.success) { p.resolve(msg.data !== undefined ? msg.data : null); } else { p.reject(new Error(msg.error || 'Unknown error')); } }); // ── Public API ──────────────────────────────────────────────────────────── var KUMOS = { /** * Handshake with the shell. Resolves with { app_id }. * Always call this first and await it before using any other APIs. */ ready: function () { return _send('window.ready', {}); }, // ── Private app storage (no extra permission required) ─────────────── storage: { /** Read a file. Resolves with the content string. */ read: function (path) { return _send('storage.read', { path: path }); }, /** Write content to a file. Creates it if it does not exist. */ write: function (path, content) { return _send('storage.write', { path: path, content: content }); }, /** List a directory. Resolves with an array of entry objects. */ list: function (path) { return _send('storage.list', { path: path || '/' }); }, /** Stat a path. */ stat: function (path) { return _send('storage.stat', { path: path }); }, /** Create a directory. */ mkdir: function (path) { return _send('storage.mkdir', { path: path }); }, /** Delete a file. */ delete: function (path) { return _send('storage.delete', { path: path }); } }, // ── User filesystem (requires fs.read / fs.write permission) ───────── fs: { /** Read a file from the user's filesystem. */ read: function (path) { return _send('fs.read', { path: path }); }, /** Write content to a file in the user's filesystem. */ write: function (path, content) { return _send('fs.write', { path: path, content: content }); }, /** List a directory. */ list: function (path) { return _send('fs.list', { path: path || '/' }); }, /** Stat a path. */ stat: function (path) { return _send('fs.stat', { path: path }); } }, // ── Notifications (requires notify permission) ──────────────────────── notify: { /** Show a toast. type: 'info' | 'success' | 'warning' | 'error' */ toast: function (message, type) { return _send('notify.toast', { message: message, type: type || 'info' }); }, /** Show a confirm dialog. Resolves with true (OK) or false (Cancel). */ confirm: function (title, message) { return _send('notify.confirm', { title: title, message: message }); } }, // ── Window control ──────────────────────────────────────────────────── window: { /** Update the host window title. */ setTitle: function (title) { return _send('window.setTitle', { title: title }); }, /** Close this app instance. */ close: function () { return _send('window.close', {}); } } }; global.KUMOS = KUMOS; }(window));