diff --git a/common/syscalls/markdown.ts b/common/syscalls/markdown.ts index 57e472be..047bf00f 100644 --- a/common/syscalls/markdown.ts +++ b/common/syscalls/markdown.ts @@ -3,13 +3,13 @@ import {MarkdownTree, nodeAtPos, parse, render} from "../tree"; export function markdownSyscalls(): SysCallMapping { return { - parse(ctx, text: string): MarkdownTree { + "markdown.parse": (ctx, text: string): MarkdownTree => { return parse(text); }, - nodeAtPos(ctx, mdTree: MarkdownTree, pos: number): MarkdownTree | null { + "markdown.nodeAtPos": (ctx, mdTree: MarkdownTree, pos: number): MarkdownTree | null => { return nodeAtPos(mdTree, pos); }, - render(ctx, mdTree: MarkdownTree): string { + "markdown.render": (ctx, mdTree: MarkdownTree): string => { return render(mdTree); }, }; diff --git a/plugos-silverbullet-syscall/markdown.ts b/plugos-silverbullet-syscall/markdown.ts index 06d223f3..eaa05e15 100644 --- a/plugos-silverbullet-syscall/markdown.ts +++ b/plugos-silverbullet-syscall/markdown.ts @@ -8,7 +8,7 @@ export async function parse(text: string): Promise { export async function nodeAtPos( mdTree: MarkdownTree, pos: number -): Promise { +): Promise { return syscall("markdown.nodeAtPos", mdTree, pos); } diff --git a/plugos/bin/plugos-server.ts b/plugos/bin/plugos-server.ts index 93ef422a..8f9ab8ec 100755 --- a/plugos/bin/plugos-server.ts +++ b/plugos/bin/plugos-server.ts @@ -10,21 +10,17 @@ import {System} from "../system"; import {EndpointHook, EndpointHookT} from "../hooks/endpoint"; import {safeRun} from "../util"; import knex from "knex"; -import { - ensureTable, - storeReadSyscalls, - storeWriteSyscalls, -} from "../syscalls/store.knex_node"; +import {ensureTable, storeSyscalls} from "../syscalls/store.knex_node"; import {fetchSyscalls} from "../syscalls/fetch.node"; import {EventHook, EventHookT} from "../hooks/event"; import {eventSyscalls} from "../syscalls/event"; let args = yargs(hideBin(process.argv)) - .option("port", { - type: "number", - default: 1337, - }) - .parse(); + .option("port", { + type: "number", + default: 1337, + }) + .parse(); if (!args._.length) { console.error("Usage: plugos-server "); @@ -55,16 +51,11 @@ safeRun(async () => { system.addHook(new NodeCronHook()); let eventHook = new EventHook(); system.addHook(eventHook); - system.registerSyscalls("event", [], eventSyscalls(eventHook)); + system.registerSyscalls([], eventSyscalls(eventHook)); system.addHook(new EndpointHook(app, "")); - system.registerSyscalls("shell", [], shellSyscalls(".")); - system.registerSyscalls("fetch", [], fetchSyscalls()); - system.registerSyscalls( - "store", - [], - storeWriteSyscalls(db, "item"), - storeReadSyscalls(db, "item") - ); + system.registerSyscalls([], shellSyscalls(".")); + system.registerSyscalls([], fetchSyscalls()); + system.registerSyscalls([], storeSyscalls(db, "item")); app.listen(args.port, () => { console.log(`Plugbox server listening on port ${args.port}`); }); diff --git a/plugos/runtime.test.ts b/plugos/runtime.test.ts index e22a18f8..a38ac34c 100644 --- a/plugos/runtime.test.ts +++ b/plugos/runtime.test.ts @@ -1,10 +1,10 @@ -import { createSandbox } from "./environments/node_sandbox"; -import { expect, test } from "@jest/globals"; -import { System } from "./system"; +import {createSandbox} from "./environments/node_sandbox"; +import {expect, test} from "@jest/globals"; +import {System} from "./system"; test("Run a Node sandbox", async () => { let system = new System("server"); - system.registerSyscalls("", [], { + system.registerSyscalls([], { addNumbers: (ctx, a, b) => { return a + b; }, @@ -12,12 +12,12 @@ test("Run a Node sandbox", async () => { throw new Error("#fail"); }, }); - system.registerSyscalls("", ["restricted"], { + system.registerSyscalls(["restricted"], { restrictedSyscall: () => { return "restricted"; }, }); - system.registerSyscalls("", ["dangerous"], { + system.registerSyscalls(["dangerous"], { dangerousSyscall: () => { return "yay"; }, diff --git a/plugos/syscalls/event.ts b/plugos/syscalls/event.ts index 92aa88af..243d5e9a 100644 --- a/plugos/syscalls/event.ts +++ b/plugos/syscalls/event.ts @@ -1,9 +1,9 @@ -import { SysCallMapping } from "../system"; -import { EventHook } from "../hooks/event"; +import {SysCallMapping} from "../system"; +import {EventHook} from "../hooks/event"; export function eventSyscalls(eventHook: EventHook): SysCallMapping { return { - async dispatch(ctx, eventName: string, data: any) { + "event.dispatch": async(ctx, eventName: string, data: any) => { return eventHook.dispatchEvent(eventName, data); }, }; diff --git a/plugos/syscalls/fetch.node.ts b/plugos/syscalls/fetch.node.ts index b3f2d362..3ca4f700 100644 --- a/plugos/syscalls/fetch.node.ts +++ b/plugos/syscalls/fetch.node.ts @@ -1,13 +1,13 @@ -import fetch, { RequestInfo, RequestInit } from "node-fetch"; -import { SysCallMapping } from "../system"; +import fetch, {RequestInfo, RequestInit} from "node-fetch"; +import {SysCallMapping} from "../system"; export function fetchSyscalls(): SysCallMapping { return { - async json(ctx, url: RequestInfo, init: RequestInit) { + "fetch.json": async (ctx, url: RequestInfo, init: RequestInit) => { let resp = await fetch(url, init); return resp.json(); }, - async text(ctx, url: RequestInfo, init: RequestInit) { + "fetch.text": async(ctx, url: RequestInfo, init: RequestInit) => { let resp = await fetch(url, init); return resp.text(); }, diff --git a/plugos/syscalls/shell.node.ts b/plugos/syscalls/shell.node.ts index 3b3fd3a1..1bc8de25 100644 --- a/plugos/syscalls/shell.node.ts +++ b/plugos/syscalls/shell.node.ts @@ -1,12 +1,12 @@ -import { promisify } from "util"; -import { execFile } from "child_process"; -import type { SysCallMapping } from "../system"; +import {promisify} from "util"; +import {execFile} from "child_process"; +import type {SysCallMapping} from "../system"; const execFilePromise = promisify(execFile); export default function (cwd: string): SysCallMapping { return { - run: async ( + "shell.run": async ( ctx, cmd: string, args: string[] diff --git a/plugos/syscalls/store.dexie_browser.test.ts b/plugos/syscalls/store.dexie_browser.test.ts index b649106e..693a60bb 100644 --- a/plugos/syscalls/store.dexie_browser.test.ts +++ b/plugos/syscalls/store.dexie_browser.test.ts @@ -1,14 +1,14 @@ -import { createSandbox } from "../environments/node_sandbox"; -import { expect, test } from "@jest/globals"; -import { System } from "../system"; -import { storeSyscalls } from "./store.dexie_browser"; +import {createSandbox} from "../environments/node_sandbox"; +import {expect, test} from "@jest/globals"; +import {System} from "../system"; +import {storeSyscalls} from "./store.dexie_browser"; // For testing in node.js require("fake-indexeddb/auto"); test("Test store", async () => { let system = new System("server"); - system.registerSyscalls("store", [], storeSyscalls("test", "test")); + system.registerSyscalls([], storeSyscalls("test", "test")); let plug = await system.load( "test", { diff --git a/plugos/syscalls/store.dexie_browser.ts b/plugos/syscalls/store.dexie_browser.ts index 125ae1d4..466f6e96 100644 --- a/plugos/syscalls/store.dexie_browser.ts +++ b/plugos/syscalls/store.dexie_browser.ts @@ -1,5 +1,5 @@ import Dexie from "dexie"; -import { SysCallMapping } from "../system"; +import {SysCallMapping} from "../system"; export type KV = { key: string; @@ -17,26 +17,26 @@ export function storeSyscalls( const items = db.table(tableName); return { - async delete(ctx, key: string) { + "store.delete": async (ctx, key: string) => { await items.delete(key); }, - async deletePrefix(ctx, prefix: string) { + "store.deletePrefix": async (ctx, prefix: string) => { await items.where("key").startsWith(prefix).delete(); }, - async deleteAll() { + "store.deleteAll": async () => { await items.clear(); }, - async set(ctx, key: string, value: any) { + "store.set": async (ctx, key: string, value: any) => { await items.put({ key, value, }); }, - async batchSet(ctx, kvs: KV[]) { + "store.batchSet": async (ctx, kvs: KV[]) => { await items.bulkPut( kvs.map(({ key, value }) => ({ key, @@ -45,17 +45,17 @@ export function storeSyscalls( ); }, - async get(ctx, key: string): Promise { + "store.get": async (ctx, key: string): Promise => { let result = await items.get({ key, }); return result ? result.value : null; }, - async queryPrefix( + "store.queryPrefix": async ( ctx, keyPrefix: string - ): Promise<{ key: string; value: any }[]> { + ): Promise<{ key: string; value: any }[]> => { let results = await items.where("key").startsWith(keyPrefix).toArray(); return results.map((result) => ({ key: result.key, diff --git a/plugos/syscalls/store.knex_node.test.ts b/plugos/syscalls/store.knex_node.test.ts index 609be5e1..66df80cd 100644 --- a/plugos/syscalls/store.knex_node.test.ts +++ b/plugos/syscalls/store.knex_node.test.ts @@ -1,11 +1,7 @@ -import { createSandbox } from "../environments/node_sandbox"; -import { expect, test } from "@jest/globals"; -import { System } from "../system"; -import { - ensureTable, - storeReadSyscalls, - storeWriteSyscalls, -} from "./store.knex_node"; +import {createSandbox} from "../environments/node_sandbox"; +import {expect, test} from "@jest/globals"; +import {System} from "../system"; +import {ensureTable, storeSyscalls} from "./store.knex_node"; import knex from "knex"; import fs from "fs/promises"; @@ -19,12 +15,7 @@ test("Test store", async () => { }); await ensureTable(db, "test_table"); let system = new System("server"); - system.registerSyscalls( - "store", - [], - storeWriteSyscalls(db, "test_table"), - storeReadSyscalls(db, "test_table") - ); + system.registerSyscalls([], storeSyscalls(db, "test_table")); let plug = await system.load( "test", { diff --git a/plugos/syscalls/store.knex_node.ts b/plugos/syscalls/store.knex_node.ts index 5e4c448b..0afe388f 100644 --- a/plugos/syscalls/store.knex_node.ts +++ b/plugos/syscalls/store.knex_node.ts @@ -1,5 +1,5 @@ -import { Knex } from "knex"; -import { SysCallMapping } from "../system"; +import {Knex} from "knex"; +import {SysCallMapping} from "../system"; type Item = { page: string; @@ -23,21 +23,21 @@ export async function ensureTable(db: Knex, tableName: string) { } } -export function storeWriteSyscalls( +export function storeSyscalls( db: Knex, tableName: string ): SysCallMapping { const apiObj: SysCallMapping = { - delete: async (ctx, key: string) => { + "store.delete": async (ctx, key: string) => { await db(tableName).where({ key }).del(); }, - deletePrefix: async (ctx, prefix: string) => { + "store.deletePrefix": async (ctx, prefix: string) => { return db(tableName).andWhereLike("key", `${prefix}%`).del(); }, - deleteAll: async (ctx) => { + "store.deleteAll": async (ctx) => { await db(tableName).del(); }, - set: async (ctx, key: string, value: any) => { + "store.set": async (ctx, key: string, value: any) => { let changed = await db(tableName) .where({ key }) .update("value", JSON.stringify(value)); @@ -49,26 +49,17 @@ export function storeWriteSyscalls( } }, // TODO: Optimize - batchSet: async (ctx, kvs: KV[]) => { + "store.batchSet": async (ctx, kvs: KV[]) => { for (let { key, value } of kvs) { - await apiObj.set(ctx, key, value); + await apiObj["store.set"](ctx, key, value); } }, - batchDelete: async (ctx, keys: string[]) => { + "store.batchDelete": async (ctx, keys: string[]) => { for (let key of keys) { - await apiObj.delete(ctx, key); + await apiObj["store.delete"](ctx, key); } }, - }; - return apiObj; -} - -export function storeReadSyscalls( - db: Knex, - tableName: string -): SysCallMapping { - return { - get: async (ctx, key: string): Promise => { + "store.get": async (ctx, key: string): Promise => { let result = await db(tableName).where({ key }).select("value"); if (result.length) { return JSON.parse(result[0].value); @@ -76,7 +67,7 @@ export function storeReadSyscalls( return null; } }, - queryPrefix: async (ctx, prefix: string) => { + "store.queryPrefix": async (ctx, prefix: string) => { return ( await db(tableName) .andWhereLike("key", `${prefix}%`) @@ -87,4 +78,5 @@ export function storeReadSyscalls( })); }, }; + return apiObj; } diff --git a/plugos/system.ts b/plugos/system.ts index d479138d..ee405c89 100644 --- a/plugos/system.ts +++ b/plugos/system.ts @@ -1,7 +1,7 @@ -import { Hook, Manifest, RuntimeEnvironment } from "./types"; -import { EventEmitter } from "../common/event"; -import { SandboxFactory } from "./sandbox"; -import { Plug } from "./plug"; +import {Hook, Manifest, RuntimeEnvironment} from "./types"; +import {EventEmitter} from "../common/event"; +import {SandboxFactory} from "./sandbox"; +import {Plug} from "./plug"; export interface SysCallMapping { [key: string]: (ctx: SyscallContext, ...args: any) => Promise | any; @@ -29,31 +29,32 @@ type Syscall = { }; export class System extends EventEmitter> { + readonly runtimeEnv: RuntimeEnvironment; protected plugs = new Map>(); protected registeredSyscalls = new Map(); protected enabledHooks = new Set>(); - readonly runtimeEnv: RuntimeEnvironment; - constructor(env: RuntimeEnvironment) { super(); this.runtimeEnv = env; } + get loadedPlugs(): Map> { + return this.plugs; + } + addHook(feature: Hook) { this.enabledHooks.add(feature); feature.apply(this); } registerSyscalls( - namespace: string, requiredCapabilities: string[], ...registrationObjects: SysCallMapping[] ) { for (const registrationObject of registrationObjects) { for (let [name, callback] of Object.entries(registrationObject)) { - const callName = namespace ? `${namespace}.${name}` : name; - this.registeredSyscalls.set(callName, { + this.registeredSyscalls.set(name, { requiredPermissions: requiredCapabilities, callback, }); @@ -116,10 +117,6 @@ export class System extends EventEmitter> { this.plugs.delete(name); } - get loadedPlugs(): Map> { - return this.plugs; - } - toJSON(): SystemJSON { let plugJSON: { [key: string]: Manifest } = {}; for (let [name, plug] of this.plugs) { diff --git a/plugs/core/navigate.ts b/plugs/core/navigate.ts index 6192c73d..3ae68a3b 100644 --- a/plugs/core/navigate.ts +++ b/plugs/core/navigate.ts @@ -1,62 +1,54 @@ import {ClickEvent} from "../../webapp/app_event"; import {updateMaterializedQueriesCommand} from "./materialized_queries"; -import { - getSyntaxNodeAtPos, - getSyntaxNodeUnderCursor, - getText, - navigate as navigateTo, - openUrl, -} from "plugos-silverbullet-syscall/editor"; +import {getCursor, getText, navigate as navigateTo, openUrl,} from "plugos-silverbullet-syscall/editor"; import {taskToggleAtPos} from "../tasks/task"; import {nodeAtPos, parse} from "plugos-silverbullet-syscall/markdown"; +import type {MarkdownTree} from "../../common/tree"; const materializedQueryPrefix = /