; ════════════════════════════════════════════════════════════════════════════ ; KUMOS.sbi — SpiderBasic SDK for KUMOS third-party apps ; ; Usage: ; IncludeFile "KUMOS.sbi" ; KUMOS::Init() ; call once at startup, before anything else ; ; All async procedures accept a *Callback procedure pointer. ; Callbacks always have the signature: Procedure Cb(Success.i, Data.s) ; Exception: KUMOS::Notify_Confirm uses: Procedure Cb(Result.i) ; ; The "storage.*" namespace is always available. ; "fs.*" requires the "fs.read" / "fs.write" permission in manifest.json. ; "notify.*" requires the "notify" permission in manifest.json. ; ════════════════════════════════════════════════════════════════════════════ DeclareModule KUMOS ; Toast types — pass to Notify_Toast() Enumeration #Info #Success #Warning #Error EndEnumeration ; ── Lifecycle ────────────────────────────────────────────────────────── Declare Init() Declare Ready(*Callback) ; Cb(Success, Data) — Data: '{"app_id":"..."}' Declare Window_SetTitle(Title.s) Declare Window_Close() ; ── Private storage (always available) ──────────────────────────────── Declare Storage_Read (Path.s, *Callback) ; Cb(Success, Content.s) Declare Storage_Write (Path.s, Content.s, *Callback); Cb(Success, "") Declare Storage_List (Path.s, *Callback) ; Cb(Success, JSON array) Declare Storage_Stat (Path.s, *Callback) ; Cb(Success, JSON object) Declare Storage_Mkdir (Path.s, *Callback) ; Cb(Success, "") Declare Storage_Delete(Path.s, *Callback) ; Cb(Success, "") ; ── User filesystem (requires fs.read / fs.write) ───────────────────── Declare FS_Read (Path.s, *Callback) ; Cb(Success, Content.s) Declare FS_Write (Path.s, Content.s, *Callback) ; Cb(Success, "") Declare FS_List (Path.s, *Callback) ; Cb(Success, JSON array) Declare FS_Stat (Path.s, *Callback) ; Cb(Success, JSON object) ; ── Notifications (requires notify) ─────────────────────────────────── Declare Notify_Toast (Message.s, Type.i = #Info) ; fire-and-forget Declare Notify_Confirm (Title_.s, Message.s, *Callback) ; Cb(Result.i) EndDeclareModule Module KUMOS EnableExplicit ; Inject the JS runtime once, guarded so multiple IncludeFile calls are safe. Procedure Init() !if (window._kumos_sb) { return; } !window._kumos_sb = { ! pending: {}, ! uuid: function() { ! 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); ! }); ! }, ! send: function(action, args, onSuccess, onError) { ! var kmid = window._kumos_sb.uuid(); ! var timer = setTimeout(function() { ! var p = window._kumos_sb.pending[kmid]; ! if (p) { delete window._kumos_sb.pending[kmid]; p.onError('Timeout: ' + action); } ! }, 15000); ! window._kumos_sb.pending[kmid] = { onSuccess: onSuccess, onError: onError, timer: timer }; ! window.parent.postMessage( ! JSON.stringify({ kmid: kmid, action: action, args: args || {} }), '*' ! ); ! } !}; !window.addEventListener('message', function(e) { ! if (e.source !== window.parent) { return; } ! var msg; ! try { msg = JSON.parse(e.data); } catch(ex) { return; } ! if (!msg || !msg.kmid) { return; } ! var p = window._kumos_sb.pending[msg.kmid]; ! if (!p) { return; } ! clearTimeout(p.timer); ! delete window._kumos_sb.pending[msg.kmid]; ! if (msg.success) { ! var data = msg.data; ! if (data === null || data === undefined) { data = ''; } ! else if (typeof data === 'object') { data = JSON.stringify(data); } ! else if (typeof data === 'boolean') { data = data ? 'true' : 'false'; } ! else { data = String(data); } ! p.onSuccess(data); ! } else { ! p.onError(msg.error || 'Error'); ! } !}); EndProcedure ; ── Internal send helper ────────────────────────────────────────────────── ; *Callback must be Procedure Cb(Success.i, Data.s) ; *ConfirmCallback must be Procedure Cb(Result.i) [used only for confirm] Procedure _Send(Action.s, ArgsJSON.s, *Callback) ! var cb = p_callback; !window._kumos_sb.send( ! v_action, ! (v_argsjson ? JSON.parse(v_argsjson) : {}), ! function(data) { cb(1, data); }, ! function(err) { cb(0, err); } !); EndProcedure ; ── Args builders ───────────────────────────────────────────────────────── Procedure.s _PathArgs(Path.s) ProcedureReturn ~"{\"path\":\"" + ReplaceString(Path, ~"\"", ~"\\\"") + ~"\"}" EndProcedure Procedure.s _PathContentArgs(Path.s, Content.s) ProcedureReturn ~"{\"path\":\"" + ReplaceString(Path, ~"\"", ~"\\\"") + ~"\"," + ~"\"content\":\"" + ReplaceString(Content, ~"\"", ~"\\\"") + ~"\"}" EndProcedure Procedure.s _TitleMsgArgs(Title_.s, Message.s) ProcedureReturn ~"{\"title\":\"" + ReplaceString(Title_, ~"\"", ~"\\\"") + ~"\"," + ~"\"message\":\"" + ReplaceString(Message, ~"\"", ~"\\\"") + ~"\"}" EndProcedure Procedure.s _TypeStr(Type.i) Select Type Case #Success : ProcedureReturn "success" Case #Warning : ProcedureReturn "warning" Case #Error : ProcedureReturn "error" Default : ProcedureReturn "info" EndSelect EndProcedure ; ── Lifecycle ───────────────────────────────────────────────────────────── Procedure Ready(*Callback) _Send("window.ready", "{}", *Callback) EndProcedure Procedure Window_SetTitle(Title.s) ; Fire-and-forget — no callback needed ! window._kumos_sb.send('window.setTitle', ! { title: v_title }, function(){}, function(){}); EndProcedure Procedure Window_Close() ! window._kumos_sb.send('window.close', {}, function(){}, function(){}); EndProcedure ; ── Storage ─────────────────────────────────────────────────────────────── Procedure Storage_Read(Path.s, *Callback) _Send("storage.read", _PathArgs(Path), *Callback) EndProcedure Procedure Storage_Write(Path.s, Content.s, *Callback) _Send("storage.write", _PathContentArgs(Path, Content), *Callback) EndProcedure Procedure Storage_List(Path.s, *Callback) _Send("storage.list", _PathArgs(Path), *Callback) EndProcedure Procedure Storage_Stat(Path.s, *Callback) _Send("storage.stat", _PathArgs(Path), *Callback) EndProcedure Procedure Storage_Mkdir(Path.s, *Callback) _Send("storage.mkdir", _PathArgs(Path), *Callback) EndProcedure Procedure Storage_Delete(Path.s, *Callback) _Send("storage.delete", _PathArgs(Path), *Callback) EndProcedure ; ── User filesystem ─────────────────────────────────────────────────────── Procedure FS_Read(Path.s, *Callback) _Send("fs.read", _PathArgs(Path), *Callback) EndProcedure Procedure FS_Write(Path.s, Content.s, *Callback) _Send("fs.write", _PathContentArgs(Path, Content), *Callback) EndProcedure Procedure FS_List(Path.s, *Callback) _Send("fs.list", _PathArgs(Path), *Callback) EndProcedure Procedure FS_Stat(Path.s, *Callback) _Send("fs.stat", _PathArgs(Path), *Callback) EndProcedure ; ── Notifications ───────────────────────────────────────────────────────── Procedure Notify_Toast(Message.s, Type.i = #Info) Protected Args.s = ~"{\"message\":\"" + ReplaceString(Message, ~"\"", ~"\\\"") + ~"\"," + ~"\"type\":\"" + _TypeStr(Type) + ~"\"}" ! window._kumos_sb.send('notify.toast', ! JSON.parse(v_args), function(){}, function(){}); EndProcedure ; *Callback must be Procedure Cb(Result.i) — 1 = OK, 0 = Cancel Procedure Notify_Confirm(Title_.s, Message.s, *Callback) Protected Args.s = _TitleMsgArgs(Title_, Message) ! var cb = p_callback; !window._kumos_sb.send( ! 'notify.confirm', ! JSON.parse(v_args), ! function(data) { cb(data === 'true' ? 1 : 0); }, ! function() { cb(0); } !); EndProcedure EndModule ; IDE Options = SpiderBasic 3.20 (Windows - x86) ; CursorPosition = 1 ; Folding = ---- ; iOSAppOrientation = 0 ; AndroidAppCode = 0 ; AndroidAppOrientation = 0 ; EnableXP ; DPIAware ; CompileSourceDirectory