doc: add JSDoc annotations in the core folder

start documenting a bit, mostly inconsequential changes
This commit is contained in:
Tasia Iso 2024-02-19 19:12:42 +01:00
parent 4f869252a2
commit ce5ca1875b
7 changed files with 600 additions and 12 deletions

View File

@ -6,20 +6,37 @@ let g_calls = {};
let gSessionIndex = 0; let gSessionIndex = 0;
/**
* TODOC
* @returns
*/
function makeSessionId() { function makeSessionId() {
return (gSessionIndex++).toString(); return (gSessionIndex++).toString();
} }
/**
* TODOC
* @returns
*/
function App() { function App() {
this._on_output = null; this._on_output = null;
this._send_queue = []; this._send_queue = [];
return this; return this;
} }
/**
* TODOC
* @param {*} callback
*/
App.prototype.readOutput = function(callback) { App.prototype.readOutput = function(callback) {
this._on_output = callback; this._on_output = callback;
} }
/**
* TODOC
* @param {*} api
* @returns
*/
App.prototype.makeFunction = function(api) { App.prototype.makeFunction = function(api) {
let self = this; let self = this;
let result = function() { let result = function() {
@ -43,6 +60,10 @@ App.prototype.makeFunction = function(api) {
return result; return result;
} }
/**
* TODOC
* @param {*} message
*/
App.prototype.send = function(message) { App.prototype.send = function(message) {
if (this._send_queue) { if (this._send_queue) {
if (this._on_output) { if (this._on_output) {
@ -57,11 +78,17 @@ App.prototype.send = function(message) {
} }
} }
/**
* TODOC
* @param {*} request
* @param {*} response
* @param {*} client
*/
function socket(request, response, client) { function socket(request, response, client) {
let process; let process;
let options = {}; let options = {};
let credentials = auth.query(request.headers); let credentials = auth.query(request.headers);
let refresh = auth.make_refresh(credentials); let refresh = auth.makeRefresh(credentials);
response.onClose = async function() { response.onClose = async function() {
if (process && process.task) { if (process && process.task) {

View File

@ -5,9 +5,15 @@ let gDatabase = new Database("auth");
const kRefreshInterval = 1 * 7 * 24 * 60 * 60 * 1000; const kRefreshInterval = 1 * 7 * 24 * 60 * 60 * 1000;
/**
* Makes a Base64 value URL safe
* @param {string} value
* @returns TODOC
*/
function b64url(value) { function b64url(value) {
value = value.replaceAll('+', '-').replaceAll('/', '_'); value = value.replaceAll('+', '-').replaceAll('/', '_');
let equals = value.indexOf('='); let equals = value.indexOf('=');
if (equals !== -1) { if (equals !== -1) {
return value.substring(0, equals); return value.substring(0, equals);
} else { } else {
@ -15,9 +21,15 @@ function b64url(value) {
} }
} }
/**
* TODOC
* @param {string} value
* @returns
*/
function unb64url(value) { function unb64url(value) {
value = value.replaceAll('-', '+').replaceAll('_', '/'); value = value.replaceAll('-', '+').replaceAll('_', '/');
let remainder = value.length % 4; let remainder = value.length % 4;
if (remainder == 3) { if (remainder == 3) {
return value + '='; return value + '=';
} else if (remainder == 2) { } else if (remainder == 2) {
@ -27,31 +39,68 @@ function unb64url(value) {
} }
} }
/**
* Creates a JSON Web Token
* @param {object} payload Object: {"name": "username"}
* @returns the JWT
*/
function makeJwt(payload) { function makeJwt(payload) {
let ids = ssb.getIdentities(':auth'); const ids = ssb.getIdentities(':auth');
let id; let id;
if (ids?.length) { if (ids?.length) {
id = ids[0]; id = ids[0];
} else { } else {
id = ssb.createIdentity(':auth'); id = ssb.createIdentity(':auth');
} }
let final_payload = b64url(base64Encode(JSON.stringify(Object.assign({}, payload, {exp: (new Date().valueOf()) + kRefreshInterval})))); const final_payload = b64url(
let jwt = [b64url(base64Encode(JSON.stringify({alg: 'HS256', typ: 'JWT'}))), final_payload, b64url(ssb.hmacsha256sign(final_payload, ':auth', id))].join('.'); base64Encode(
JSON.stringify(
Object.assign({}, payload, {exp: (new Date().valueOf()) + kRefreshInterval}
)
)
)
);
const jwt = [
b64url(
base64Encode(
JSON.stringify({
alg: 'HS256',
typ: 'JWT'
})
)
),
final_payload,
b64url(
ssb.hmacsha256sign(final_payload, ':auth', id)
)
].join('.');
return jwt; return jwt;
} }
/**
* Validates a JWT ?
* @param {*} session TODOC
* @returns
*/
function readSession(session) { function readSession(session) {
let jwt_parts = session?.split('.'); let jwt_parts = session?.split('.');
if (jwt_parts?.length === 3) { if (jwt_parts?.length === 3) {
let [header, payload, signature] = jwt_parts; let [header, payload, signature] = jwt_parts;
header = JSON.parse(utf8Decode(base64Decode(unb64url(header)))); header = JSON.parse(utf8Decode(base64Decode(unb64url(header))));
if (header.typ === 'JWT' && header.alg === 'HS256') { if (header.typ === 'JWT' && header.alg === 'HS256') {
signature = unb64url(signature); signature = unb64url(signature);
let id = ssb.getIdentities(':auth'); let id = ssb.getIdentities(':auth');
if (id?.length && ssb.hmacsha256verify(id[0], payload, signature)) { if (id?.length && ssb.hmacsha256verify(id[0], payload, signature)) {
let result = JSON.parse(utf8Decode(base64Decode(unb64url(payload)))); const result = JSON.parse(utf8Decode(base64Decode(unb64url(payload))));
let now = new Date().valueOf() const now = new Date().valueOf()
if (now < result.exp) { if (now < result.exp) {
print(`JWT valid for another ${(result.exp - now) / 1000} seconds.`); print(`JWT valid for another ${(result.exp - now) / 1000} seconds.`);
return result; return result;
@ -67,21 +116,42 @@ function readSession(session) {
} }
} }
/**
* Check the provided password matches the hash
* @param {string} password
* @param {string} hash bcrypt hash
* @returns true if the password matches the hash
*/
function verifyPassword(password, hash) { function verifyPassword(password, hash) {
return bCrypt.hashpw(password, hash) == hash; return bCrypt.hashpw(password, hash) === hash;
} }
/**
* Hashes a password
* @param {string} password
* @returns {string} TODOC
*/
function hashPassword(password) { function hashPassword(password) {
let salt = bCrypt.gensalt(12); let salt = bCrypt.gensalt(12);
return bCrypt.hashpw(password, salt); return bCrypt.hashpw(password, salt);
} }
/**
* Check if there is an administrator on the instance
* @returns TODOC
*/
function noAdministrator() { function noAdministrator() {
return !core.globalSettings || !core.globalSettings.permissions || !Object.keys(core.globalSettings.permissions).some(function(name) { return !core.globalSettings ||
!core.globalSettings.permissions ||
!Object.keys(core.globalSettings.permissions).some(function(name) {
return core.globalSettings.permissions[name].indexOf("administration") != -1; return core.globalSettings.permissions[name].indexOf("administration") != -1;
}); });
} }
/**
* Makes a user an administrator
* @param {string} name the user's name
*/
function makeAdministrator(name) { function makeAdministrator(name) {
if (!core.globalSettings.permissions) { if (!core.globalSettings.permissions) {
core.globalSettings.permissions = {}; core.globalSettings.permissions = {};
@ -92,9 +162,15 @@ function makeAdministrator(name) {
if (core.globalSettings.permissions[name].indexOf("administration") == -1) { if (core.globalSettings.permissions[name].indexOf("administration") == -1) {
core.globalSettings.permissions[name].push("administration"); core.globalSettings.permissions[name].push("administration");
} }
core.setGlobalSettings(core.globalSettings); core.setGlobalSettings(core.globalSettings);
} }
/**
* TODOC
* @param {*} headers most likely an object
* @returns
*/
function getCookies(headers) { function getCookies(headers) {
let cookies = {}; let cookies = {};
@ -111,13 +187,27 @@ function getCookies(headers) {
return cookies; return cookies;
} }
/**
* Validates a username
* @param {string} name
* @returns false | boolean[] ?
*/
function isNameValid(name) { function isNameValid(name) {
// TODO(tasiaiso): convert this into a regex
let c = name.charAt(0); let c = name.charAt(0);
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) && name.split().map(x => x >= ('a' && x <= 'z') || x >= ('A' && x <= 'Z') || x >= ('0' && x <= '9')); return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) && name.split().map(x => x >= ('a' && x <= 'z') || x >= ('A' && x <= 'Z') || x >= ('0' && x <= '9'));
} }
/**
* Request handler ?
* @param {*} request TODOC
* @param {*} response
* @returns
*/
function handler(request, response) { function handler(request, response) {
// TODO(tasiaiso): split this function
let session = getCookies(request.headers).session; let session = getCookies(request.headers).session;
if (request.uri == "/login") { if (request.uri == "/login") {
let formData = form.decodeForm(request.query); let formData = form.decodeForm(request.query);
if (query(request.headers)?.permissions?.authenticated) { if (query(request.headers)?.permissions?.authenticated) {
@ -226,6 +316,11 @@ function handler(request, response) {
} }
} }
/**
* Gets a user's permissions based on it's session ?
* @param {*} session TODOC
* @returns
*/
function getPermissions(session) { function getPermissions(session) {
let permissions; let permissions;
let entry = readSession(session); let entry = readSession(session);
@ -236,6 +331,11 @@ function getPermissions(session) {
return permissions || {}; return permissions || {};
} }
/**
* Get a user's permissions ?
* @param {string} userName TODOC
* @returns
*/
function getPermissionsForUser(userName) { function getPermissionsForUser(userName) {
let permissions = {}; let permissions = {};
if (core.globalSettings && core.globalSettings.permissions && core.globalSettings.permissions[userName]) { if (core.globalSettings && core.globalSettings.permissions && core.globalSettings.permissions[userName]) {
@ -246,6 +346,11 @@ function getPermissionsForUser(userName) {
return permissions; return permissions;
} }
/**
* TODOC
* @param {*} headers
* @returns
*/
function query(headers) { function query(headers) {
let session = getCookies(headers).session; let session = getCookies(headers).session;
let entry; let entry;
@ -258,7 +363,12 @@ function query(headers) {
} }
} }
function make_refresh(credentials) { /**
* Refreshes a JWT ?
* @param {*} credentials TODOC
* @returns
*/
function makeRefresh(credentials) {
if (credentials?.session?.name) { if (credentials?.session?.name) {
return { return {
token: makeJwt({name: credentials.session.name}), token: makeJwt({name: credentials.session.name}),
@ -267,4 +377,4 @@ function make_refresh(credentials) {
} }
} }
export { handler, query, make_refresh }; export { handler, query, makeRefresh };

View File

@ -12,7 +12,7 @@ let gOriginalInput;
let kErrorColor = "#dc322f"; let kErrorColor = "#dc322f";
let kStatusColor = "#fff"; let kStatusColor = "#fff";
/* Functions that server-side app code can call through the app object. */ // Functions that server-side app code can call through the app object.
const k_api = { const k_api = {
setDocument: {args: ['content'], func: api_setDocument}, setDocument: {args: ['content'], func: api_setDocument},
postMessage: {args: ['message'], func: api_postMessage}, postMessage: {args: ['message'], func: api_postMessage},
@ -24,6 +24,7 @@ const k_api = {
setHash: {args: ['hash'], func: api_setHash}, setHash: {args: ['hash'], func: api_setHash},
}; };
// TODO(tasiaiso): this is only used once, move it down ?
const k_global_style = css` const k_global_style = css`
a:link { a:link {
color: #268bd2; color: #268bd2;
@ -42,6 +43,9 @@ const k_global_style = css`
} }
`; `;
/**
* Class that represents the top bar
*/
class TfNavigationElement extends LitElement { class TfNavigationElement extends LitElement {
static get properties() { static get properties() {
return { return {
@ -63,6 +67,10 @@ class TfNavigationElement extends LitElement {
this.spark_lines = {}; this.spark_lines = {};
} }
/**
* TODOC
* @param {*} event
*/
toggle_edit(event) { toggle_edit(event) {
event.preventDefault(); event.preventDefault();
if (editing()) { if (editing()) {
@ -72,10 +80,20 @@ class TfNavigationElement extends LitElement {
} }
} }
/**
* TODOC
* @param {*} key
*/
reset_permission(key) { reset_permission(key) {
send({action: "resetPermission", permission: key}); send({action: "resetPermission", permission: key});
} }
/**
* TODOC
* @param {*} key
* @param {*} options
* @returns
*/
get_spark_line(key, options) { get_spark_line(key, options) {
if (!this.spark_lines[key]) { if (!this.spark_lines[key]) {
let spark_line = document.createElement('tf-sparkline'); let spark_line = document.createElement('tf-sparkline');
@ -94,6 +112,10 @@ class TfNavigationElement extends LitElement {
return this.spark_lines[key]; return this.spark_lines[key];
} }
/**
* TODOC
* @returns
*/
render_login() { render_login() {
if (this?.credentials?.session?.name) { if (this?.credentials?.session?.name) {
return html`<a id="login" href="/login/logout?return=${url() + hash()}">logout ${this.credentials.session.name}</a>`; return html`<a id="login" href="/login/logout?return=${url() + hash()}">logout ${this.credentials.session.name}</a>`;
@ -102,6 +124,10 @@ class TfNavigationElement extends LitElement {
} }
} }
/**
* TODOC
* @returns
*/
render_permissions() { render_permissions() {
if (this.show_permissions) { if (this.show_permissions) {
return html` return html`
@ -122,6 +148,10 @@ class TfNavigationElement extends LitElement {
} }
} }
/**
* TODOC
* @returns
*/
render() { render() {
let self = this; let self = this;
return html` return html`
@ -157,8 +187,12 @@ class TfNavigationElement extends LitElement {
`; `;
} }
} }
customElements.define('tf-navigation', TfNavigationElement); customElements.define('tf-navigation', TfNavigationElement);
/**
* TODOC
*/
class TfFilesElement extends LitElement { class TfFilesElement extends LitElement {
static get properties() { static get properties() {
return { return {
@ -174,6 +208,10 @@ class TfFilesElement extends LitElement {
this.dropping = 0; this.dropping = 0;
} }
/**
* TODOC
* @param {*} file
*/
file_click(file) { file_click(file) {
this.dispatchEvent(new CustomEvent('file_click', { this.dispatchEvent(new CustomEvent('file_click', {
detail: { detail: {
@ -184,6 +222,11 @@ class TfFilesElement extends LitElement {
})); }));
} }
/**
* TODOC
* @param {*} file
* @returns
*/
render_file(file) { render_file(file) {
let classes = ['file']; let classes = ['file'];
if (file == this.current) { if (file == this.current) {
@ -195,6 +238,10 @@ class TfFilesElement extends LitElement {
return html`<div class="${classes.join(' ')}" @click=${x => this.file_click(file)}>${file}</div>`; return html`<div class="${classes.join(' ')}" @click=${x => this.file_click(file)}>${file}</div>`;
} }
/**
* TODOC
* @param {*} event
*/
async drop(event) { async drop(event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -213,15 +260,27 @@ class TfFilesElement extends LitElement {
updateFiles(); updateFiles();
} }
/**
* TODOC
* @param {*} event
*/
drag_enter(event) { drag_enter(event) {
this.dropping++; this.dropping++;
event.preventDefault(); event.preventDefault();
} }
/**
* TODOC
* @param {*} event
*/
drag_leave(event) { drag_leave(event) {
this.dropping--; this.dropping--;
} }
/**
* TODOC
* @returns
*/
render() { render() {
let self = this; let self = this;
return html` return html`
@ -258,8 +317,12 @@ class TfFilesElement extends LitElement {
`; `;
} }
} }
customElements.define('tf-files', TfFilesElement); customElements.define('tf-files', TfFilesElement);
/**
* TODOC
*/
class TfFilesPaneElement extends LitElement { class TfFilesPaneElement extends LitElement {
static get properties() { static get properties() {
return { return {
@ -275,11 +338,19 @@ class TfFilesPaneElement extends LitElement {
this.files = {}; this.files = {};
} }
/**
* TODOC
* @param {*} expanded
*/
set_expanded(expanded) { set_expanded(expanded) {
this.expanded = expanded; this.expanded = expanded;
window.localStorage.setItem('files', expanded ? '1' : '0'); window.localStorage.setItem('files', expanded ? '1' : '0');
} }
/**
* TODOC
* @returns
*/
render() { render() {
let self = this; let self = this;
let expander = this.expanded ? let expander = this.expanded ?
@ -302,8 +373,12 @@ class TfFilesPaneElement extends LitElement {
`; `;
} }
} }
customElements.define('tf-files-pane', TfFilesPaneElement); customElements.define('tf-files-pane', TfFilesPaneElement);
/**
* TODOC
*/
class TfSparkLineElement extends LitElement { class TfSparkLineElement extends LitElement {
static get properties() { static get properties() {
return { return {
@ -321,6 +396,11 @@ class TfSparkLineElement extends LitElement {
this.k_values_max = 100; this.k_values_max = 100;
} }
/**
* TODOC
* @param {*} key
* @param {*} value
*/
append(key, value) { append(key, value) {
let line = null; let line = null;
for (let it of this.lines) { for (let it of this.lines) {
@ -345,6 +425,11 @@ class TfSparkLineElement extends LitElement {
this.requestUpdate(); this.requestUpdate();
} }
/**
* TODOC
* @param {*} line
* @returns
*/
render_line(line) { render_line(line) {
if (line?.values?.length >= 2) { if (line?.values?.length >= 2) {
let max = Math.max(this.max, ...line.values); let max = Math.max(this.max, ...line.values);
@ -353,6 +438,10 @@ class TfSparkLineElement extends LitElement {
} }
} }
/**
* TODOC
* @returns
*/
render() { render() {
let max = Math.round(10.0 * Math.max(...this.lines.map(line => line.values[line.values.length - 1]))) / 10.0; let max = Math.round(10.0 * Math.max(...this.lines.map(line => line.values[line.values.length - 1]))) / 10.0;
return html` return html`
@ -363,8 +452,10 @@ class TfSparkLineElement extends LitElement {
`; `;
} }
} }
customElements.define('tf-sparkline', TfSparkLineElement); customElements.define('tf-sparkline', TfSparkLineElement);
// TODOC
window.addEventListener("keydown", function(event) { window.addEventListener("keydown", function(event) {
if (event.keyCode == 83 && (event.altKey || event.ctrlKey)) { if (event.keyCode == 83 && (event.altKey || event.ctrlKey)) {
if (editing()) { if (editing()) {
@ -379,6 +470,12 @@ window.addEventListener("keydown", function(event) {
} }
}); });
/**
* TODOC
* @param {*} nodes
* @param {*} callback
* @returns
*/
function ensureLoaded(nodes, callback) { function ensureLoaded(nodes, callback) {
if (!nodes.length) { if (!nodes.length) {
callback(); callback();
@ -416,14 +513,26 @@ function ensureLoaded(nodes, callback) {
} }
} }
/**
* TODOC
* @returns
*/
function editing() { function editing() {
return document.getElementById("editPane").style.display != 'none'; return document.getElementById("editPane").style.display != 'none';
} }
/**
* TODOC
* @returns
*/
function is_edit_only() { function is_edit_only() {
return window.location.search == '?editonly=1' || window.innerWidth < 1024; return window.location.search == '?editonly=1' || window.innerWidth < 1024;
} }
/**
* TODOC
* @returns
*/
async function edit() { async function edit() {
if (editing()) { if (editing()) {
return; return;
@ -446,16 +555,30 @@ async function edit() {
} }
} }
/**
* TODOC
*/
function trace() { function trace() {
window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}`); window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}`);
} }
/**
* TODOC
* @param {*} name
* @returns
*/
function guessMode(name) { function guessMode(name) {
return name.endsWith(".js") ? "javascript" : return name.endsWith(".js") ? "javascript" :
name.endsWith(".html") ? "htmlmixed" : name.endsWith(".html") ? "htmlmixed" :
null; null;
} }
/**
* TODOC
* @param {*} name
* @param {*} id
* @returns
*/
function loadFile(name, id) { function loadFile(name, id) {
return fetch('/' + id + '/view').then(function(response) { return fetch('/' + id + '/view').then(function(response) {
if (!response.ok) { if (!response.ok) {
@ -472,6 +595,11 @@ function loadFile(name, id) {
}); });
} }
/**
* TODOC
* @param {*} path
* @returns
*/
async function load(path) { async function load(path) {
let response = await fetch((path || url()) + 'view'); let response = await fetch((path || url()) + 'view');
let json; let json;
@ -509,16 +637,28 @@ async function load(path) {
return Promise.all(promises); return Promise.all(promises);
} }
/**
* TODOC
*/
function closeEditor() { function closeEditor() {
window.localStorage.setItem('editing', '0'); window.localStorage.setItem('editing', '0');
document.getElementById("editPane").style.display = 'none'; document.getElementById("editPane").style.display = 'none';
document.getElementById('viewPane').style.display = 'flex'; document.getElementById('viewPane').style.display = 'flex';
} }
/**
* TODOC
* @returns
*/
function explodePath() { function explodePath() {
return /^\/~([^\/]+)\/([^\/]+)(.*)/.exec(window.location.pathname); return /^\/~([^\/]+)\/([^\/]+)(.*)/.exec(window.location.pathname);
} }
/**
* TODOC
* @param {*} save_to
* @returns
*/
function save(save_to) { function save(save_to) {
document.getElementById("save").disabled = true; document.getElementById("save").disabled = true;
if (gCurrentFile) { if (gCurrentFile) {
@ -603,6 +743,9 @@ function save(save_to) {
}); });
} }
/**
* TODOC
*/
function changeIcon() { function changeIcon() {
let value = prompt('Enter a new app icon emoji:'); let value = prompt('Enter a new app icon emoji:');
if (value !== undefined) { if (value !== undefined) {
@ -611,6 +754,9 @@ function changeIcon() {
} }
} }
/**
* TODOC
*/
function deleteApp() { function deleteApp() {
let name = document.getElementById("name"); let name = document.getElementById("name");
let path = name && name.value ? name.value : url(); let path = name && name.value ? name.value : url();
@ -627,6 +773,10 @@ function deleteApp() {
} }
} }
/**
* TODOC
* @returns
*/
function url() { function url() {
let hash = window.location.href.indexOf('#'); let hash = window.location.href.indexOf('#');
let question = window.location.href.indexOf('?'); let question = window.location.href.indexOf('?');
@ -642,20 +792,36 @@ function url() {
return end != -1 ? window.location.href.substring(0, end) : window.location.href; return end != -1 ? window.location.href.substring(0, end) : window.location.href;
} }
/**
* TODOC
* @returns
*/
function hash() { function hash() {
return window.location.hash != "#" ? window.location.hash : ""; return window.location.hash != "#" ? window.location.hash : "";
} }
/**
* TODOC
* @param {*} content
*/
function api_setDocument(content) { function api_setDocument(content) {
let iframe = document.getElementById("document"); let iframe = document.getElementById("document");
iframe.srcdoc = content; iframe.srcdoc = content;
} }
/**
* TODOC
* @param {*} message
*/
function api_postMessage(message) { function api_postMessage(message) {
let iframe = document.getElementById("document"); let iframe = document.getElementById("document");
iframe.contentWindow.postMessage(message, "*"); iframe.contentWindow.postMessage(message, "*");
} }
/**
* TODOC
* @param {*} error
*/
function api_error(error) { function api_error(error) {
if (error) { if (error) {
if (typeof(error) == 'string') { if (typeof(error) == 'string') {
@ -667,14 +833,30 @@ function api_error(error) {
console.log('error', error); console.log('error', error);
} }
/**
* TODOC
* @param {*} key
* @param {*} value
*/
function api_localStorageSet(key, value) { function api_localStorageSet(key, value) {
window.localStorage.setItem('app:' + key, value); window.localStorage.setItem('app:' + key, value);
} }
/**
* TODOC
* @param {*} key
* @returns
*/
function api_localStorageGet(key) { function api_localStorageGet(key) {
return window.localStorage.getItem('app:' + key); return window.localStorage.getItem('app:' + key);
} }
/**
* TODOC
* @param {*} permission
* @param {*} id
* @returns
*/
function api_requestPermission(permission, id) { function api_requestPermission(permission, id) {
let outer = document.createElement('div'); let outer = document.createElement('div');
outer.classList.add('permissions'); outer.classList.add('permissions');
@ -739,14 +921,25 @@ function api_requestPermission(permission, id) {
}); });
} }
/**
* TODOC
*/
function api_print() { function api_print() {
console.log('app>', ...arguments); console.log('app>', ...arguments);
} }
/**
* TODOC
* @param {*} hash
*/
function api_setHash(hash) { function api_setHash(hash) {
window.location.hash = hash; window.location.hash = hash;
} }
/**
* TODOC
* @param {*} message
*/
function _receive_websocket_message(message) { function _receive_websocket_message(message) {
if (message && message.action == "session") { if (message && message.action == "session") {
setStatusMessage("🟢 Executing...", kStatusColor); setStatusMessage("🟢 Executing...", kStatusColor);
@ -827,10 +1020,19 @@ function _receive_websocket_message(message) {
} }
} }
/**
* TODOC
* @param {*} message
* @param {*} color
*/
function setStatusMessage(message, color) { function setStatusMessage(message, color) {
document.getElementsByTagName('tf-navigation')[0].status = {message: message, color: color}; document.getElementsByTagName('tf-navigation')[0].status = {message: message, color: color};
} }
/**
* TODOC
* @param {*} value
*/
function send(value) { function send(value) {
try { try {
if (gSocket && gSocket.readyState == gSocket.OPEN) { if (gSocket && gSocket.readyState == gSocket.OPEN) {
@ -841,6 +1043,13 @@ function send(value) {
} }
} }
/**
* TODOC
* @param {*} sourceData
* @param {*} maxWidth
* @param {*} maxHeight
* @param {*} callback
*/
function fixImage(sourceData, maxWidth, maxHeight, callback) { function fixImage(sourceData, maxWidth, maxHeight, callback) {
let result = sourceData; let result = sourceData;
let image = new Image(); let image = new Image();
@ -864,16 +1073,26 @@ function fixImage(sourceData, maxWidth, maxHeight, callback) {
image.src = sourceData; image.src = sourceData;
} }
/**
* TODOC
* @param {*} image
*/
function sendImage(image) { function sendImage(image) {
fixImage(image, 320, 240, function(result) { fixImage(image, 320, 240, function(result) {
send({image: result}); send({image: result});
}); });
} }
/**
* TODOC
*/
function hashChange() { function hashChange() {
send({event: 'hashChange', hash: window.location.hash}); send({event: 'hashChange', hash: window.location.hash});
} }
/**
* TODOC
*/
function focus() { function focus() {
if (gSocket && gSocket.readyState == gSocket.CLOSED) { if (gSocket && gSocket.readyState == gSocket.CLOSED) {
connectSocket(); connectSocket();
@ -882,12 +1101,19 @@ function focus() {
} }
} }
/**
* TODOC
*/
function blur() { function blur() {
if (gSocket && gSocket.readyState == gSocket.OPEN) { if (gSocket && gSocket.readyState == gSocket.OPEN) {
send({event: "blur"}); send({event: "blur"});
} }
} }
/**
* TODOC
* @param {*} event
*/
function message(event) { function message(event) {
if (event.data && event.data.event == "resizeMe" && event.data.width && event.data.height) { if (event.data && event.data.event == "resizeMe" && event.data.width && event.data.height) {
let iframe = document.getElementById("iframe_" + event.data.name); let iframe = document.getElementById("iframe_" + event.data.name);
@ -916,6 +1142,10 @@ function message(event) {
} }
} }
/**
* TODOC
* @param {*} path
*/
function reconnect(path) { function reconnect(path) {
let oldSocket = gSocket; let oldSocket = gSocket;
gSocket = null gSocket = null
@ -928,6 +1158,10 @@ function reconnect(path) {
connectSocket(path); connectSocket(path);
} }
/**
* TODOC
* @param {*} path
*/
function connectSocket(path) { function connectSocket(path) {
if (!gSocket || gSocket.readyState != gSocket.OPEN) { if (!gSocket || gSocket.readyState != gSocket.OPEN) {
if (gSocket) { if (gSocket) {
@ -979,6 +1213,10 @@ function connectSocket(path) {
} }
} }
/**
* TODOC
* @param {*} name
*/
function openFile(name) { function openFile(name) {
let newDoc = (name && gFiles[name]) ? gFiles[name].doc : cm6.EditorState.create({doc: "", extensions: cm6.extensions}); let newDoc = (name && gFiles[name]) ? gFiles[name].doc : cm6.EditorState.create({doc: "", extensions: cm6.extensions});
let oldDoc = gEditor.state; let oldDoc = gEditor.state;
@ -995,6 +1233,9 @@ function openFile(name) {
gEditor.focus(); gEditor.focus();
} }
/**
* TODOC
*/
function updateFiles() { function updateFiles() {
let files = document.getElementsByTagName("tf-files-pane")[0]; let files = document.getElementsByTagName("tf-files-pane")[0];
if (files) { if (files) {
@ -1006,6 +1247,10 @@ function updateFiles() {
gEditor.focus(); gEditor.focus();
} }
/**
* TODOC
* @param {*} name
*/
function makeNewFile(name) { function makeNewFile(name) {
gFiles[name] = { gFiles[name] = {
doc: cm6.EditorState.create({extensions: cm6.extensions}), doc: cm6.EditorState.create({extensions: cm6.extensions}),
@ -1013,6 +1258,9 @@ function makeNewFile(name) {
openFile(name); openFile(name);
} }
/**
* TODOC
*/
function newFile() { function newFile() {
let name = prompt("Name of new file:", "file.js"); let name = prompt("Name of new file:", "file.js");
if (name && !gFiles[name]) { if (name && !gFiles[name]) {
@ -1020,6 +1268,9 @@ function newFile() {
} }
} }
/**
* TODOC
*/
function removeFile() { function removeFile() {
if (confirm("Remove " + gCurrentFile + "?")) { if (confirm("Remove " + gCurrentFile + "?")) {
delete gFiles[gCurrentFile]; delete gFiles[gCurrentFile];
@ -1027,6 +1278,9 @@ function removeFile() {
} }
} }
/**
* TODOC
*/
async function appExport() { async function appExport() {
let JsZip = (await import('/static/jszip.min.js')).default; let JsZip = (await import('/static/jszip.min.js')).default;
let owner = window.location.pathname.split('/')[1].replace('~', ''); let owner = window.location.pathname.split('/')[1].replace('~', '');
@ -1049,6 +1303,12 @@ async function appExport() {
a.click(); a.click();
} }
/**
* TODOC
* @param {*} name
* @param {*} file
* @returns
*/
async function save_file_to_blob_id(name, file) { async function save_file_to_blob_id(name, file) {
console.log(`Saving ${name}.`); console.log(`Saving ${name}.`);
let response = await fetch('/save', { let response = await fetch('/save', {
@ -1068,6 +1328,9 @@ async function save_file_to_blob_id(name, file) {
return blob_id; return blob_id;
} }
/**
* TODOC
*/
async function appImport() { async function appImport() {
let JsZip = (await import('/static/jszip.min.js')).default; let JsZip = (await import('/static/jszip.min.js')).default;
let input = document.createElement('input'); let input = document.createElement('input');
@ -1119,6 +1382,9 @@ async function appImport() {
} }
} }
/**
*
*/
async function sourcePretty() { async function sourcePretty() {
let prettier = (await import('/prettier/standalone.mjs')).default; let prettier = (await import('/prettier/standalone.mjs')).default;
let babel = (await import('/prettier/babel.mjs')).default; let babel = (await import('/prettier/babel.mjs')).default;
@ -1140,6 +1406,7 @@ async function sourcePretty() {
} }
} }
// TODOC
window.addEventListener("load", function() { window.addEventListener("load", function() {
window.addEventListener("hashchange", hashChange); window.addEventListener("hashchange", hashChange);
window.addEventListener("focus", focus); window.addEventListener("focus", focus);

View File

@ -91,6 +91,11 @@ let gGlobalSettings = {
let kPingInterval = 60 * 1000; let kPingInterval = 60 * 1000;
/**
* TODOC
* @param {*} out
* @param {*} error
*/
function printError(out, error) { function printError(out, error) {
if (error.stackTrace) { if (error.stackTrace) {
out.print(error.fileName + ":" + error.lineNumber + ": " + error.message); out.print(error.fileName + ":" + error.lineNumber + ": " + error.message);
@ -103,6 +108,12 @@ function printError(out, error) {
} }
} }
/**
* TODOC
* @param {*} handlers
* @param {*} argv
* @returns
*/
function invoke(handlers, argv) { function invoke(handlers, argv) {
let promises = []; let promises = [];
if (handlers) { if (handlers) {
@ -119,6 +130,12 @@ function invoke(handlers, argv) {
return Promise.all(promises); return Promise.all(promises);
} }
/**
* TODOC
* @param {*} eventName
* @param {*} argv
* @returns
*/
function broadcastEvent(eventName, argv) { function broadcastEvent(eventName, argv) {
let promises = []; let promises = [];
for (let process of Object.values(gProcesses)) { for (let process of Object.values(gProcesses)) {
@ -128,7 +145,11 @@ function broadcastEvent(eventName, argv) {
} }
return Promise.all(promises); return Promise.all(promises);
} }
/**
* TODOC
* @param {*} message
* @returns
*/
function broadcast(message) { function broadcast(message) {
let sender = this; let sender = this;
let promises = []; let promises = [];
@ -143,6 +164,12 @@ function broadcast(message) {
return Promise.all(promises); return Promise.all(promises);
} }
/**
* TODOC
* @param {*} caller
* @param {*} process
* @returns
*/
function getUser(caller, process) { function getUser(caller, process) {
return { return {
key: process.key, key: process.key,
@ -153,6 +180,12 @@ function getUser(caller, process) {
}; };
} }
/**
* TODOC
* @param {*} user
* @param {*} process
* @returns
*/
function getApps(user, process) { function getApps(user, process) {
if (process.credentials && if (process.credentials &&
process.credentials.session && process.credentials.session &&
@ -174,12 +207,26 @@ function getApps(user, process) {
return {}; return {};
} }
/**
* TODOC
* @param {*} from
* @param {*} to
* @param {*} message
* @returns
*/
function postMessageInternal(from, to, message) { function postMessageInternal(from, to, message) {
if (to.eventHandlers['message']) { if (to.eventHandlers['message']) {
return invoke(to.eventHandlers['message'], [getUser(from, from), message]); return invoke(to.eventHandlers['message'], [getUser(from, from), message]);
} }
} }
/**
* TODOC
* @param {*} blobId
* @param {*} session
* @param {*} options
* @returns
*/
async function getSessionProcessBlob(blobId, session, options) { async function getSessionProcessBlob(blobId, session, options) {
let actualOptions = {timeout: kPingInterval}; let actualOptions = {timeout: kPingInterval};
if (options) { if (options) {
@ -190,7 +237,15 @@ async function getSessionProcessBlob(blobId, session, options) {
return getProcessBlob(blobId, 'session_' + session, actualOptions); return getProcessBlob(blobId, 'session_' + session, actualOptions);
} }
/**
* TODOC
* @param {*} blobId
* @param {*} key
* @param {*} options
* @returns
*/
async function getProcessBlob(blobId, key, options) { async function getProcessBlob(blobId, key, options) {
// TODO(tasiaiso): break this down
let process = gProcesses[key]; let process = gProcesses[key];
if (!process if (!process
&& !(options && "create" in options && !options.create)) { && !(options && "create" in options && !options.create)) {
@ -535,6 +590,11 @@ async function getProcessBlob(blobId, key, options) {
return process; return process;
} }
/**
* TODOC
* @param {*} settings
* @returns
*/
function setGlobalSettings(settings) { function setGlobalSettings(settings) {
gGlobalSettings = settings; gGlobalSettings = settings;
try { try {
@ -544,6 +604,12 @@ function setGlobalSettings(settings) {
} }
} }
/**
* TODOC
* @param {*} data
* @param {*} bytes
* @returns
*/
function startsWithBytes(data, bytes) { function startsWithBytes(data, bytes) {
if (data.byteLength >= bytes.length) { if (data.byteLength >= bytes.length) {
let dataBytes = new Uint8Array(data.slice(0, bytes.length)); let dataBytes = new Uint8Array(data.slice(0, bytes.length));
@ -556,11 +622,21 @@ function startsWithBytes(data, bytes) {
} }
} }
/**
* TODOC
* @param {*} path
* @returns
*/
function guessTypeFromName(path) { function guessTypeFromName(path) {
let extension = path.split('.').pop(); let extension = path.split('.').pop();
return k_mime_types[extension]; return k_mime_types[extension];
} }
/**
* TODOC
* @param {*} data
* @returns
*/
function guessTypeFromMagicBytes(data) { function guessTypeFromMagicBytes(data) {
for (let magic of k_magic_bytes) { for (let magic of k_magic_bytes) {
if (startsWithBytes(data, magic.bytes)) { if (startsWithBytes(data, magic.bytes)) {
@ -569,6 +645,14 @@ function guessTypeFromMagicBytes(data) {
} }
} }
/**
* TODOC
* @param {*} response
* @param {*} data
* @param {*} type
* @param {*} headers
* @param {*} status_code
*/
function sendData(response, data, type, headers, status_code) { function sendData(response, data, type, headers, status_code) {
if (data) { if (data) {
response.writeHead(status_code ?? 200, Object.assign({"Content-Type": type || guessTypeFromMagicBytes(data) || "application/binary", "Content-Length": data.byteLength}, headers || {})); response.writeHead(status_code ?? 200, Object.assign({"Content-Type": type || guessTypeFromMagicBytes(data) || "application/binary", "Content-Length": data.byteLength}, headers || {}));
@ -579,6 +663,11 @@ function sendData(response, data, type, headers, status_code) {
} }
} }
/**
* TODOC
* @param {*} id
* @returns
*/
async function getBlobOrContent(id) { async function getBlobOrContent(id) {
if (!id) { if (!id) {
return; return;
@ -590,6 +679,18 @@ async function getBlobOrContent(id) {
} }
let g_handler_index = 0; let g_handler_index = 0;
/**
* TODOC
* @param {*} response
* @param {*} handler_blob_id
* @param {*} path
* @param {*} query
* @param {*} headers
* @param {*} packageOwner
* @param {*} packageName
* @returns
*/
async function useAppHandler(response, handler_blob_id, path, query, headers, packageOwner, packageName) { async function useAppHandler(response, handler_blob_id, path, query, headers, packageOwner, packageName) {
print('useAppHandler', packageOwner, packageName); print('useAppHandler', packageOwner, packageName);
let do_resolve; let do_resolve;
@ -623,7 +724,16 @@ async function useAppHandler(response, handler_blob_id, path, query, headers, pa
return result; return result;
} }
/**
* TODOC
* @param {*} request
* @param {*} response
* @param {*} blobId
* @param {*} uri
* @returns
*/
async function blobHandler(request, response, blobId, uri) { async function blobHandler(request, response, blobId, uri) {
// TODO(tasiaiso): break this down ?
for (let i in k_static_files) { for (let i in k_static_files) {
if (uri === k_static_files[i].uri && k_static_files[i].path) { if (uri === k_static_files[i].uri && k_static_files[i].path) {
let stat = await File.stat('core/' + k_static_files[i].path); let stat = await File.stat('core/' + k_static_files[i].path);
@ -851,6 +961,9 @@ ssb.addEventListener('connections', function() {
broadcastEvent('onConnectionsChanged', []); broadcastEvent('onConnectionsChanged', []);
}); });
/**
* TODOC
*/
async function loadSettings() { async function loadSettings() {
let data = {}; let data = {};
try { try {
@ -869,6 +982,9 @@ async function loadSettings() {
gGlobalSettings = data; gGlobalSettings = data;
} }
/**
* TODOC
*/
function sendStats() { function sendStats() {
let apps = Object.values(gProcesses).filter(process => process.app && process.stats).map(process => process.app); let apps = Object.values(gProcesses).filter(process => process.app && process.stats).map(process => process.app);
if (apps.length) { if (apps.length) {
@ -882,6 +998,11 @@ function sendStats() {
} }
} }
/**
* TODOC
* @param {*} process
* @param {*} enabled
*/
function enableStats(process, enabled) { function enableStats(process, enabled) {
process.stats = enabled; process.stats = enabled;
if (!gStatsTimer) { if (!gStatsTimer) {
@ -890,6 +1011,9 @@ function enableStats(process, enabled) {
} }
} }
/**
* TODOC
*/
loadSettings().then(function() { loadSettings().then(function() {
if (tildefriends.https_port && gGlobalSettings.http_redirect) { if (tildefriends.https_port && gGlobalSettings.http_redirect) {
httpd.set_http_redirect(gGlobalSettings.http_redirect); httpd.set_http_redirect(gGlobalSettings.http_redirect);
@ -955,6 +1079,14 @@ loadSettings().then(function() {
exit(1); exit(1);
}); });
/**
* TODOC
* @param {*} user
* @param {*} packageOwner
* @param {*} packageName
* @param {*} permission
* @param {*} allow
*/
function storePermission(user, packageOwner, packageName, permission, allow) { function storePermission(user, packageOwner, packageName, permission, allow) {
if (!gGlobalSettings.userPermissions) { if (!gGlobalSettings.userPermissions) {
gGlobalSettings.userPermissions = {}; gGlobalSettings.userPermissions = {};

View File

@ -1,3 +1,8 @@
/**
* TODOC
* @param {*} encoded
* @returns
*/
function decode(encoded) { function decode(encoded) {
let result = ""; let result = "";
for (let i = 0; i < encoded.length; i++) { for (let i = 0; i < encoded.length; i++) {
@ -14,6 +19,12 @@ function decode(encoded) {
return result; return result;
} }
/**
* TODOC
* @param {*} encoded
* @param {*} initial
* @returns
*/
function decodeForm(encoded, initial) { function decodeForm(encoded, initial) {
let result = initial || {}; let result = initial || {};
if (encoded) { if (encoded) {

View File

@ -1,3 +1,9 @@
/**
* TODOC
* TODO: document so we can make this improve
* @param {*} url
* @returns
*/
function parseUrl(url) { function parseUrl(url) {
// XXX: Hack. // XXX: Hack.
let match = url.match(new RegExp("(\\w+)://([^/:]+)(?::(\\d+))?(.*)")); let match = url.match(new RegExp("(\\w+)://([^/:]+)(?::(\\d+))?(.*)"));
@ -9,6 +15,11 @@ function parseUrl(url) {
}; };
} }
/**
* TODOC
* @param {*} data
* @returns
*/
function parseResponse(data) { function parseResponse(data) {
let firstLine; let firstLine;
let headers = {}; let headers = {};
@ -28,6 +39,13 @@ function parseResponse(data) {
return {body: data}; return {body: data};
} }
/**
* TODOC
* @param {*} url
* @param {*} options
* @param {*} allowed_hosts
* @returns
*/
export function fetch(url, options, allowed_hosts) { export function fetch(url, options, allowed_hosts) {
let parsed = parseUrl(url); let parsed = parseUrl(url);
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {

View File

@ -3,6 +3,10 @@ let g_api = {};
let g_next_id = 1; let g_next_id = 1;
let g_calls = {}; let g_calls = {};
/**
* TODOC
* @returns
*/
function get_is_browser() { function get_is_browser() {
try { return window !== undefined && console !== undefined; } catch { return false; } try { return window !== undefined && console !== undefined; } catch { return false; }
} }
@ -11,6 +15,13 @@ if (k_is_browser) {
print = console.log; print = console.log;
} }
/**
* TODOC
* @param {*} target
* @param {*} prop
* @param {*} receiver
* @returns
*/
function make_rpc(target, prop, receiver) { function make_rpc(target, prop, receiver) {
return function() { return function() {
let id = g_next_id++; let id = g_next_id++;
@ -29,6 +40,10 @@ function make_rpc(target, prop, receiver) {
} }
} }
/**
* TODOC
* @param {*} response
*/
function send(response) { function send(response) {
if (k_is_browser) { if (k_is_browser) {
window.parent.postMessage(response, '*'); window.parent.postMessage(response, '*');
@ -37,6 +52,10 @@ function send(response) {
} }
} }
/**
* TODOC
* @param {*} message
*/
function call_rpc(message) { function call_rpc(message) {
if (message && message.message === 'tfrpc') { if (message && message.message === 'tfrpc') {
let id = message.id; let id = message.id;
@ -85,6 +104,10 @@ if (k_is_browser) {
export let rpc = new Proxy({}, {get: make_rpc}); export let rpc = new Proxy({}, {get: make_rpc});
/**
* TODOC
* @param {*} method
*/
export function register(method) { export function register(method) {
g_api[method.name] = method; g_api[method.name] = method;
} }