@silverbulletmd/silverbullet 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +18 -0
- package/README.md +98 -0
- package/client/asset_bundle/bundle.ts +95 -0
- package/client/data/datastore.ts +85 -0
- package/client/data/kv_primitives.ts +25 -0
- package/client/markdown_parser/constants.ts +13 -0
- package/client/plugos/event.ts +36 -0
- package/client/plugos/eventhook.ts +8 -0
- package/client/plugos/hooks/code_widget.ts +59 -0
- package/client/plugos/hooks/command.ts +104 -0
- package/client/plugos/hooks/document_editor.ts +77 -0
- package/client/plugos/hooks/event.ts +187 -0
- package/client/plugos/hooks/mq.ts +154 -0
- package/client/plugos/hooks/plug_namespace.ts +85 -0
- package/client/plugos/hooks/slash_command.ts +192 -0
- package/client/plugos/hooks/syscall.ts +66 -0
- package/client/plugos/manifest_cache.ts +67 -0
- package/client/plugos/plug.ts +99 -0
- package/client/plugos/plug_compile.ts +202 -0
- package/client/plugos/protocol.ts +40 -0
- package/client/plugos/proxy_fetch.ts +53 -0
- package/client/plugos/sandboxes/deno_worker_sandbox.ts +6 -0
- package/client/plugos/sandboxes/sandbox.ts +14 -0
- package/client/plugos/sandboxes/web_worker_sandbox.ts +17 -0
- package/client/plugos/sandboxes/worker_sandbox.ts +132 -0
- package/client/plugos/syscalls/asset.ts +35 -0
- package/client/plugos/syscalls/clientStore.ts +21 -0
- package/client/plugos/syscalls/client_code_widget.ts +12 -0
- package/client/plugos/syscalls/code_widget.ts +24 -0
- package/client/plugos/syscalls/config.ts +46 -0
- package/client/plugos/syscalls/datastore.ts +89 -0
- package/client/plugos/syscalls/editor.ts +673 -0
- package/client/plugos/syscalls/event.ts +36 -0
- package/client/plugos/syscalls/fetch.ts +128 -0
- package/client/plugos/syscalls/index.ts +102 -0
- package/client/plugos/syscalls/jsonschema.ts +69 -0
- package/client/plugos/syscalls/language.ts +23 -0
- package/client/plugos/syscalls/lua.ts +58 -0
- package/client/plugos/syscalls/markdown.ts +84 -0
- package/client/plugos/syscalls/mq.ts +52 -0
- package/client/plugos/syscalls/service_registry.ts +43 -0
- package/client/plugos/syscalls/shell.ts +39 -0
- package/client/plugos/syscalls/space.ts +139 -0
- package/client/plugos/syscalls/sync.ts +77 -0
- package/client/plugos/syscalls/system.ts +150 -0
- package/client/plugos/system.ts +201 -0
- package/client/plugos/types.ts +60 -0
- package/client/plugos/util.ts +14 -0
- package/client/plugos/worker_runtime.ts +195 -0
- package/client/space_lua/ast.ts +328 -0
- package/client/space_lua/ast_narrow.ts +81 -0
- package/client/space_lua/eval.ts +2478 -0
- package/client/space_lua/labels.ts +416 -0
- package/client/space_lua/numeric.ts +240 -0
- package/client/space_lua/parse.ts +1522 -0
- package/client/space_lua/query_collection.ts +232 -0
- package/client/space_lua/rp.ts +27 -0
- package/client/space_lua/runtime.ts +1702 -0
- package/client/space_lua/stdlib/crypto.ts +10 -0
- package/client/space_lua/stdlib/encoding.ts +19 -0
- package/client/space_lua/stdlib/format.ts +770 -0
- package/client/space_lua/stdlib/js.ts +73 -0
- package/client/space_lua/stdlib/load.ts +52 -0
- package/client/space_lua/stdlib/math.ts +193 -0
- package/client/space_lua/stdlib/net.ts +113 -0
- package/client/space_lua/stdlib/os.ts +368 -0
- package/client/space_lua/stdlib/space_lua.ts +153 -0
- package/client/space_lua/stdlib/string.ts +286 -0
- package/client/space_lua/stdlib/table.ts +401 -0
- package/client/space_lua/stdlib.ts +489 -0
- package/client/space_lua/tonumber.ts +501 -0
- package/client/space_lua/util.ts +96 -0
- package/dist/plug-compile.js +1513 -0
- package/package.json +120 -0
- package/plug-api/constants.ts +42 -0
- package/plug-api/lib/async.ts +162 -0
- package/plug-api/lib/crypto.ts +202 -0
- package/plug-api/lib/dates.ts +13 -0
- package/plug-api/lib/json.ts +136 -0
- package/plug-api/lib/limited_map.ts +72 -0
- package/plug-api/lib/memory_cache.ts +21 -0
- package/plug-api/lib/native_fetch.ts +6 -0
- package/plug-api/lib/ref.ts +275 -0
- package/plug-api/lib/resolve.ts +90 -0
- package/plug-api/lib/tags.ts +15 -0
- package/plug-api/lib/transclusion.ts +122 -0
- package/plug-api/lib/tree.ts +232 -0
- package/plug-api/lib/yaml.ts +284 -0
- package/plug-api/syscall.ts +15 -0
- package/plug-api/syscalls/asset.ts +36 -0
- package/plug-api/syscalls/client_store.ts +33 -0
- package/plug-api/syscalls/code_widget.ts +8 -0
- package/plug-api/syscalls/config.ts +58 -0
- package/plug-api/syscalls/datastore.ts +96 -0
- package/plug-api/syscalls/editor.ts +517 -0
- package/plug-api/syscalls/event.ts +47 -0
- package/plug-api/syscalls/index.ts +77 -0
- package/plug-api/syscalls/jsonschema.ts +25 -0
- package/plug-api/syscalls/language.ts +23 -0
- package/plug-api/syscalls/lua.ts +20 -0
- package/plug-api/syscalls/markdown.ts +38 -0
- package/plug-api/syscalls/mq.ts +79 -0
- package/plug-api/syscalls/shell.ts +14 -0
- package/plug-api/syscalls/space.ts +212 -0
- package/plug-api/syscalls/sync.ts +28 -0
- package/plug-api/syscalls/system.ts +102 -0
- package/plug-api/syscalls/yaml.ts +28 -0
- package/plug-api/syscalls.ts +21 -0
- package/plug-api/system_mock.ts +89 -0
- package/plug-api/types/client.ts +116 -0
- package/plug-api/types/config.ts +22 -0
- package/plug-api/types/datastore.ts +28 -0
- package/plug-api/types/event.ts +27 -0
- package/plug-api/types/index.ts +56 -0
- package/plug-api/types/manifest.ts +98 -0
- package/plug-api/types/namespace.ts +6 -0
- package/plugs/builtin_plugs.ts +14 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { SysCallMapping } from "../system.ts";
|
|
2
|
+
import type {
|
|
3
|
+
ProxyFetchRequest,
|
|
4
|
+
ProxyFetchRequest64,
|
|
5
|
+
ProxyFetchResponse,
|
|
6
|
+
ProxyFetchResponse64,
|
|
7
|
+
} from "../proxy_fetch.ts";
|
|
8
|
+
import type { Client } from "../../client.ts";
|
|
9
|
+
import {
|
|
10
|
+
base64Decode,
|
|
11
|
+
base64Encode,
|
|
12
|
+
} from "@silverbulletmd/silverbullet/lib/crypto";
|
|
13
|
+
import { fsEndpoint } from "../../spaces/constants.ts";
|
|
14
|
+
|
|
15
|
+
export function sandboxFetchSyscalls(
|
|
16
|
+
client: Client,
|
|
17
|
+
): SysCallMapping {
|
|
18
|
+
return {
|
|
19
|
+
// For use in Lua
|
|
20
|
+
"http.request": async (
|
|
21
|
+
_ctx,
|
|
22
|
+
url: string,
|
|
23
|
+
options: ProxyFetchRequest = {},
|
|
24
|
+
): Promise<ProxyFetchResponse> => {
|
|
25
|
+
console.warn("Deprecated: use net.proxyFetch() instead");
|
|
26
|
+
// JSONify any non-serializable body
|
|
27
|
+
if (
|
|
28
|
+
options?.body && typeof options.body !== "string" &&
|
|
29
|
+
!(options.body instanceof Uint8Array)
|
|
30
|
+
) {
|
|
31
|
+
options.body = JSON.stringify(options.body);
|
|
32
|
+
}
|
|
33
|
+
const fetchOptions = options
|
|
34
|
+
? {
|
|
35
|
+
method: options.method,
|
|
36
|
+
headers: {} as Record<string, string>,
|
|
37
|
+
body: options.body,
|
|
38
|
+
}
|
|
39
|
+
: {};
|
|
40
|
+
|
|
41
|
+
fetchOptions.headers = buildProxyHeaders(options?.headers);
|
|
42
|
+
|
|
43
|
+
const resp = await client.httpSpacePrimitives.authenticatedFetch(
|
|
44
|
+
buildProxyUrl(client, url),
|
|
45
|
+
fetchOptions,
|
|
46
|
+
);
|
|
47
|
+
// Do sensible things with the body based on the content type
|
|
48
|
+
let body: any;
|
|
49
|
+
const contentTypeHeader = options.responseEncoding ||
|
|
50
|
+
resp.headers.get("x-proxy-header-content-type");
|
|
51
|
+
const statusCode = +(resp.headers.get("x-proxy-status-code") || "200");
|
|
52
|
+
if (contentTypeHeader?.startsWith("application/json")) {
|
|
53
|
+
body = await resp.json();
|
|
54
|
+
} else if (
|
|
55
|
+
contentTypeHeader?.startsWith("application/xml") ||
|
|
56
|
+
contentTypeHeader?.startsWith("text/")
|
|
57
|
+
) {
|
|
58
|
+
body = await resp.text();
|
|
59
|
+
} else {
|
|
60
|
+
body = new Uint8Array(await resp.arrayBuffer());
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
ok: resp.ok,
|
|
64
|
+
status: statusCode,
|
|
65
|
+
headers: extractProxyHeaders(resp.headers),
|
|
66
|
+
body: body,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
"sandboxFetch.fetch": async (
|
|
70
|
+
_ctx,
|
|
71
|
+
url: string,
|
|
72
|
+
options?: ProxyFetchRequest64,
|
|
73
|
+
): Promise<ProxyFetchResponse64> => {
|
|
74
|
+
// console.log("Got sandbox fetch ", url, op);
|
|
75
|
+
const fetchOptions = options
|
|
76
|
+
? {
|
|
77
|
+
method: options.method,
|
|
78
|
+
headers: options.headers,
|
|
79
|
+
body: options.base64Body && base64Decode(options.base64Body),
|
|
80
|
+
}
|
|
81
|
+
: {};
|
|
82
|
+
fetchOptions.headers = buildProxyHeaders(options?.headers);
|
|
83
|
+
const resp = await client.httpSpacePrimitives.authenticatedFetch(
|
|
84
|
+
buildProxyUrl(client, url),
|
|
85
|
+
// Casting this to any because of weird Deno typing
|
|
86
|
+
fetchOptions as any,
|
|
87
|
+
);
|
|
88
|
+
const statusCode = +(resp.headers.get("x-proxy-status-code") || "200");
|
|
89
|
+
const body = await resp.arrayBuffer();
|
|
90
|
+
return {
|
|
91
|
+
ok: resp.ok,
|
|
92
|
+
status: statusCode,
|
|
93
|
+
headers: extractProxyHeaders(resp.headers),
|
|
94
|
+
base64Body: base64Encode(new Uint8Array(body)),
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function buildProxyUrl(client: Client, url: string) {
|
|
101
|
+
url = url.replace(/^https?:\/\//, "");
|
|
102
|
+
// Strip off the /.fs and replace with /.proxy
|
|
103
|
+
return client.httpSpacePrimitives.url.slice(0, -fsEndpoint.length) +
|
|
104
|
+
"/.proxy/" + url;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function buildProxyHeaders(headers?: Record<string, any>): Record<string, any> {
|
|
108
|
+
const newHeaders: Record<string, any> = { "X-Proxy-Request": "true" };
|
|
109
|
+
if (!headers) {
|
|
110
|
+
return newHeaders;
|
|
111
|
+
}
|
|
112
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
113
|
+
newHeaders[`X-Proxy-Header-${key}`] = value;
|
|
114
|
+
}
|
|
115
|
+
return newHeaders;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function extractProxyHeaders(
|
|
119
|
+
headers: Headers,
|
|
120
|
+
): Record<string, any> {
|
|
121
|
+
const newHeaders: Record<string, any> = {};
|
|
122
|
+
for (const [key, value] of headers.entries()) {
|
|
123
|
+
if (key.toLowerCase().startsWith("x-proxy-header-")) {
|
|
124
|
+
newHeaders[key.slice("x-proxy-header-".length)] = value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return newHeaders;
|
|
128
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { SysCallMapping } from "../system.ts";
|
|
2
|
+
import type {
|
|
3
|
+
LuaCollectionQuery,
|
|
4
|
+
LuaQueryCollection,
|
|
5
|
+
} from "../../space_lua/query_collection.ts";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
type ObjectIndex,
|
|
9
|
+
ObjectValidationError,
|
|
10
|
+
} from "../../data/object_index.ts";
|
|
11
|
+
import type { ObjectValue } from "@silverbulletmd/silverbullet/type/index";
|
|
12
|
+
import type { Client } from "../../client.ts";
|
|
13
|
+
import type { LuaTable } from "../../space_lua/runtime.ts";
|
|
14
|
+
|
|
15
|
+
export function indexSyscalls(
|
|
16
|
+
objectIndex: ObjectIndex,
|
|
17
|
+
client: Client,
|
|
18
|
+
): SysCallMapping {
|
|
19
|
+
return {
|
|
20
|
+
"index.tag": (_ctx, tagName: string): LuaQueryCollection => {
|
|
21
|
+
return objectIndex.tag(tagName);
|
|
22
|
+
},
|
|
23
|
+
"index.ensureFullIndex": (_ctx) => {
|
|
24
|
+
return objectIndex.ensureFullIndex(client.space);
|
|
25
|
+
},
|
|
26
|
+
"index.reindexSpace": () => {
|
|
27
|
+
return objectIndex.reindexSpace(client.space);
|
|
28
|
+
},
|
|
29
|
+
"index.indexObjects": (
|
|
30
|
+
_ctx,
|
|
31
|
+
page: string,
|
|
32
|
+
objects: ObjectValue[],
|
|
33
|
+
): Promise<void> => {
|
|
34
|
+
return objectIndex.indexObjects(page, objects);
|
|
35
|
+
},
|
|
36
|
+
"index.validateObjects": async (
|
|
37
|
+
_ctx,
|
|
38
|
+
page: string,
|
|
39
|
+
objects: ObjectValue[],
|
|
40
|
+
): Promise<{ error: string; object: ObjectValue } | null> => {
|
|
41
|
+
try {
|
|
42
|
+
await objectIndex.validateObjects(page, objects);
|
|
43
|
+
return null;
|
|
44
|
+
} catch (e: any) {
|
|
45
|
+
if (e instanceof ObjectValidationError) {
|
|
46
|
+
return {
|
|
47
|
+
error: e.message,
|
|
48
|
+
object: e.object,
|
|
49
|
+
};
|
|
50
|
+
} else {
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"index.getObjectByRef": (
|
|
56
|
+
_ctx,
|
|
57
|
+
page: string,
|
|
58
|
+
tag: string,
|
|
59
|
+
ref: string,
|
|
60
|
+
): Promise<ObjectValue | undefined> => {
|
|
61
|
+
return objectIndex.getObjectByRef(ref, page, tag);
|
|
62
|
+
},
|
|
63
|
+
"index.queryLuaObjects": (
|
|
64
|
+
_ctx,
|
|
65
|
+
tag: string,
|
|
66
|
+
query: LuaCollectionQuery,
|
|
67
|
+
scopedVariables?: Record<string, any>,
|
|
68
|
+
): Promise<ObjectValue[]> => {
|
|
69
|
+
return objectIndex.queryLuaObjects(
|
|
70
|
+
client.clientSystem.spaceLuaEnv.env,
|
|
71
|
+
tag,
|
|
72
|
+
query,
|
|
73
|
+
scopedVariables,
|
|
74
|
+
);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
"index.deleteObject": (
|
|
78
|
+
_ctx,
|
|
79
|
+
page: string,
|
|
80
|
+
tag: string,
|
|
81
|
+
ref: string,
|
|
82
|
+
): Promise<void> => {
|
|
83
|
+
return objectIndex.deleteObject(page, tag, ref);
|
|
84
|
+
},
|
|
85
|
+
"lua:index.defineTag": (_ctx, tagDef: LuaTable) => {
|
|
86
|
+
// Using 'lua:' prefix to _not_ convert tagDef to a JS version (but keep original LuaTable)
|
|
87
|
+
if (!tagDef.has("name")) {
|
|
88
|
+
throw new Error("A tag name is required");
|
|
89
|
+
}
|
|
90
|
+
const currentTag = client.config.get(["tags", tagDef.get("name")], null);
|
|
91
|
+
if (!currentTag) {
|
|
92
|
+
client.config.set(["tags", tagDef.get("name")], {
|
|
93
|
+
name: tagDef.get("name"),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
client.config.set(
|
|
97
|
+
["tags", tagDef.get("name"), "metatable"],
|
|
98
|
+
tagDef.get("metatable"),
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { SysCallMapping } from "../system.ts";
|
|
2
|
+
import { Ajv, type ValidateFunction } from "ajv";
|
|
3
|
+
|
|
4
|
+
const ajv = new Ajv();
|
|
5
|
+
|
|
6
|
+
ajv.addFormat("email", {
|
|
7
|
+
validate: (data: string) => {
|
|
8
|
+
// TODO: Implement email validation
|
|
9
|
+
return data.includes("@");
|
|
10
|
+
},
|
|
11
|
+
async: false,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
ajv.addFormat("page-ref", {
|
|
15
|
+
validate: (data: string) => {
|
|
16
|
+
return data.startsWith("[[") && data.endsWith("]]");
|
|
17
|
+
},
|
|
18
|
+
async: false,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const schemaCache = new Map<string, ValidateFunction>();
|
|
22
|
+
|
|
23
|
+
export function validateObject(schema: any, object: any): undefined | string {
|
|
24
|
+
try {
|
|
25
|
+
const schemaKey = JSON.stringify(schema);
|
|
26
|
+
if (!schemaCache.has(schemaKey)) {
|
|
27
|
+
const validate = ajv.compile(schema);
|
|
28
|
+
schemaCache.set(schemaKey, validate);
|
|
29
|
+
}
|
|
30
|
+
const validate = schemaCache.get(schemaKey)!;
|
|
31
|
+
if (validate(object)) {
|
|
32
|
+
return;
|
|
33
|
+
} else {
|
|
34
|
+
let text = ajv.errorsText(validate.errors);
|
|
35
|
+
text = text.replaceAll("/", ".");
|
|
36
|
+
text = text.replace(/^data[\.\s]/, "");
|
|
37
|
+
return text;
|
|
38
|
+
}
|
|
39
|
+
} catch (e: any) {
|
|
40
|
+
return e.message;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function validateSchema(schema: any): undefined | string {
|
|
45
|
+
const valid = ajv.validateSchema(schema);
|
|
46
|
+
if (valid) {
|
|
47
|
+
return;
|
|
48
|
+
} else {
|
|
49
|
+
return ajv.errorsText(ajv.errors);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function jsonschemaSyscalls(): SysCallMapping {
|
|
54
|
+
return {
|
|
55
|
+
"jsonschema.validateObject": (
|
|
56
|
+
_ctx,
|
|
57
|
+
schema: any,
|
|
58
|
+
object: any,
|
|
59
|
+
): undefined | string => {
|
|
60
|
+
return validateObject(schema, object);
|
|
61
|
+
},
|
|
62
|
+
"jsonschema.validateSchema": (
|
|
63
|
+
_ctx,
|
|
64
|
+
schema: any,
|
|
65
|
+
): undefined | string => {
|
|
66
|
+
return validateSchema(schema);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SysCallMapping } from "../system.ts";
|
|
2
|
+
import { parse } from "../../markdown_parser/parse_tree.ts";
|
|
3
|
+
import type { ParseTree } from "@silverbulletmd/silverbullet/lib/tree";
|
|
4
|
+
import { builtinLanguages, languageFor } from "../../languages.ts";
|
|
5
|
+
|
|
6
|
+
export function languageSyscalls(): SysCallMapping {
|
|
7
|
+
return {
|
|
8
|
+
"language.parseLanguage": (
|
|
9
|
+
_ctx,
|
|
10
|
+
language: string,
|
|
11
|
+
code: string,
|
|
12
|
+
): ParseTree => {
|
|
13
|
+
const lang = languageFor(language);
|
|
14
|
+
if (!lang) {
|
|
15
|
+
throw new Error(`Unknown language ${language}`);
|
|
16
|
+
}
|
|
17
|
+
return parse(lang, code);
|
|
18
|
+
},
|
|
19
|
+
"language.listLanguages": (): string[] => {
|
|
20
|
+
return Object.keys(builtinLanguages);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SysCallMapping } from "../system.ts";
|
|
2
|
+
import { evalExpression } from "../../space_lua/eval.ts";
|
|
3
|
+
import { parse, parseExpressionString } from "../../space_lua/parse.ts";
|
|
4
|
+
import {
|
|
5
|
+
LuaStackFrame,
|
|
6
|
+
luaToString,
|
|
7
|
+
luaValueToJS,
|
|
8
|
+
} from "../../space_lua/runtime.ts";
|
|
9
|
+
import { buildThreadLocalEnv } from "../../space_lua_api.ts";
|
|
10
|
+
import { isSendable } from "../util.ts";
|
|
11
|
+
import type { LuaBlock, LuaExpression } from "../../space_lua/ast.ts";
|
|
12
|
+
import type { ClientSystem } from "../../client_system.ts";
|
|
13
|
+
|
|
14
|
+
export function luaSyscalls(clientSystem: ClientSystem): SysCallMapping {
|
|
15
|
+
return {
|
|
16
|
+
"lua.parse": (_ctx, code: string): LuaBlock => {
|
|
17
|
+
return parse(code);
|
|
18
|
+
},
|
|
19
|
+
"lua.parseExpression": (_ctx, expression: string): LuaExpression => {
|
|
20
|
+
return parseExpressionString(expression);
|
|
21
|
+
},
|
|
22
|
+
/**
|
|
23
|
+
* Evaluates a Lua expression and returns the result as a JavaScript value
|
|
24
|
+
* @param _ctx
|
|
25
|
+
* @param expression
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
"lua.evalExpression": async (_ctx, expression: string) => {
|
|
29
|
+
try {
|
|
30
|
+
const ast = parseExpressionString(expression);
|
|
31
|
+
const env = await buildThreadLocalEnv(
|
|
32
|
+
clientSystem.system,
|
|
33
|
+
clientSystem.spaceLuaEnv.env,
|
|
34
|
+
);
|
|
35
|
+
const sf = new LuaStackFrame(env, null);
|
|
36
|
+
const luaResult = await evalExpression(
|
|
37
|
+
ast,
|
|
38
|
+
clientSystem.spaceLuaEnv.env,
|
|
39
|
+
sf,
|
|
40
|
+
);
|
|
41
|
+
const jsResult = luaValueToJS(luaResult, sf);
|
|
42
|
+
if (isSendable(jsResult)) {
|
|
43
|
+
return jsResult;
|
|
44
|
+
} else {
|
|
45
|
+
// This may evaluate to e.g. a function, which is not sendable, in this case we'll console.warn and return a stringified version of the result
|
|
46
|
+
console.warn(
|
|
47
|
+
"Lua eval result is not sendable, returning stringified version",
|
|
48
|
+
jsResult,
|
|
49
|
+
);
|
|
50
|
+
return luaToString(luaResult);
|
|
51
|
+
}
|
|
52
|
+
} catch (e: any) {
|
|
53
|
+
console.error("Lua eval error: ", e.message, e.sf?.astCtx);
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { SysCallMapping } from "../system.ts";
|
|
2
|
+
import { parse } from "../../markdown_parser/parse_tree.ts";
|
|
3
|
+
import {
|
|
4
|
+
type ParseTree,
|
|
5
|
+
renderToText,
|
|
6
|
+
} from "@silverbulletmd/silverbullet/lib/tree";
|
|
7
|
+
import { extendedMarkdownLanguage } from "../../markdown_parser/parser.ts";
|
|
8
|
+
import {
|
|
9
|
+
expandMarkdown,
|
|
10
|
+
type MarkdownExpandOptions,
|
|
11
|
+
} from "../../markdown_renderer/inline.ts";
|
|
12
|
+
import type { Client } from "../../client.ts";
|
|
13
|
+
import {
|
|
14
|
+
type MarkdownRenderOptions,
|
|
15
|
+
renderMarkdownToHtml,
|
|
16
|
+
} from "../../markdown_renderer/markdown_render.ts";
|
|
17
|
+
import {
|
|
18
|
+
jsonToMDTable,
|
|
19
|
+
refCellTransformer,
|
|
20
|
+
} from "../../markdown_renderer/result_render.ts";
|
|
21
|
+
|
|
22
|
+
export function markdownSyscalls(client: Client): SysCallMapping {
|
|
23
|
+
return {
|
|
24
|
+
"markdown.parseMarkdown": (_ctx, text: string): ParseTree => {
|
|
25
|
+
return parse(extendedMarkdownLanguage, text);
|
|
26
|
+
},
|
|
27
|
+
"markdown.renderParseTree": (_ctx, tree: ParseTree): string => {
|
|
28
|
+
return renderToText(tree);
|
|
29
|
+
},
|
|
30
|
+
"markdown.expandMarkdown": async (
|
|
31
|
+
_ctx,
|
|
32
|
+
treeOrText: ParseTree | string,
|
|
33
|
+
options?: MarkdownExpandOptions,
|
|
34
|
+
): Promise<ParseTree | string> => {
|
|
35
|
+
const outputString = typeof treeOrText === "string";
|
|
36
|
+
if (typeof treeOrText === "string") {
|
|
37
|
+
treeOrText = parse(extendedMarkdownLanguage, treeOrText);
|
|
38
|
+
}
|
|
39
|
+
const result = await expandMarkdownWithClient(
|
|
40
|
+
client,
|
|
41
|
+
treeOrText,
|
|
42
|
+
options,
|
|
43
|
+
);
|
|
44
|
+
if (outputString) {
|
|
45
|
+
return renderToText(result);
|
|
46
|
+
} else {
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"markdown.markdownToHtml": async (
|
|
51
|
+
_ctx,
|
|
52
|
+
text: string,
|
|
53
|
+
options: MarkdownRenderOptions = {},
|
|
54
|
+
) => {
|
|
55
|
+
let mdTree = parse(extendedMarkdownLanguage, text);
|
|
56
|
+
if (options.expand) {
|
|
57
|
+
mdTree = await expandMarkdownWithClient(client, mdTree);
|
|
58
|
+
}
|
|
59
|
+
return renderMarkdownToHtml(mdTree, options);
|
|
60
|
+
},
|
|
61
|
+
"markdown.objectsToTable": (
|
|
62
|
+
_ctx,
|
|
63
|
+
data: any[],
|
|
64
|
+
options: { renderCell?: (val: any, key: string) => Promise<any> | any } =
|
|
65
|
+
{},
|
|
66
|
+
) => {
|
|
67
|
+
return jsonToMDTable(data, options.renderCell || refCellTransformer);
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function expandMarkdownWithClient(
|
|
73
|
+
client: Client,
|
|
74
|
+
tree: ParseTree,
|
|
75
|
+
options?: MarkdownExpandOptions,
|
|
76
|
+
) {
|
|
77
|
+
return expandMarkdown(
|
|
78
|
+
client.space,
|
|
79
|
+
client.currentName(),
|
|
80
|
+
tree,
|
|
81
|
+
client.clientSystem.spaceLuaEnv,
|
|
82
|
+
options,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DataStoreMQ } from "../../data/mq.datastore.ts";
|
|
2
|
+
import type { MQListenerSpec } from "../hooks/mq.ts";
|
|
3
|
+
import type { SysCallMapping } from "../system.ts";
|
|
4
|
+
|
|
5
|
+
export type EventSubscription = MQListenerSpec & {
|
|
6
|
+
run: (...args: any[]) => Promise<any>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function mqSyscalls(
|
|
10
|
+
mq: DataStoreMQ,
|
|
11
|
+
): SysCallMapping {
|
|
12
|
+
return {
|
|
13
|
+
/**
|
|
14
|
+
* Define a Lua event listener
|
|
15
|
+
*/
|
|
16
|
+
"mq.subscribe": (
|
|
17
|
+
_ctx,
|
|
18
|
+
def: MQListenerSpec,
|
|
19
|
+
) => {
|
|
20
|
+
def.autoAck = def.autoAck != false;
|
|
21
|
+
// console.log("Registering Lua event listener: ", def.name);
|
|
22
|
+
client.config.insert([
|
|
23
|
+
"mqSubscriptions",
|
|
24
|
+
def.queue,
|
|
25
|
+
], def);
|
|
26
|
+
},
|
|
27
|
+
"mq.send": (_ctx, queue: string, body: any) => {
|
|
28
|
+
return mq.send(queue, body);
|
|
29
|
+
},
|
|
30
|
+
"mq.batchSend": (_ctx, queue: string, bodies: any[]) => {
|
|
31
|
+
return mq.batchSend(queue, bodies);
|
|
32
|
+
},
|
|
33
|
+
"mq.ack": (_ctx, queue: string, id: string) => {
|
|
34
|
+
return mq.ack(queue, id);
|
|
35
|
+
},
|
|
36
|
+
"mq.batchAck": (_ctx, queue: string, ids: string[]) => {
|
|
37
|
+
return mq.batchAck(queue, ids);
|
|
38
|
+
},
|
|
39
|
+
"mq.flushQueue": (_ctx, queue: string) => {
|
|
40
|
+
return mq.flushQueue(queue);
|
|
41
|
+
},
|
|
42
|
+
"mq.flushAllQueues": () => {
|
|
43
|
+
return mq.flushAllQueues();
|
|
44
|
+
},
|
|
45
|
+
"mq.getQueueStats": (_ctx, queue: string) => {
|
|
46
|
+
return mq.getQueueStats(queue);
|
|
47
|
+
},
|
|
48
|
+
"mq.awaitEmptyQueue": (_ctx, queue: string) => {
|
|
49
|
+
return mq.awaitEmptyQueue(queue);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ServiceMatch,
|
|
3
|
+
ServiceRegistry,
|
|
4
|
+
ServiceSpec,
|
|
5
|
+
} from "../../service_registry.ts";
|
|
6
|
+
import type { SysCallMapping } from "../system.ts";
|
|
7
|
+
|
|
8
|
+
export function serviceRegistrySyscalls(
|
|
9
|
+
serviceRegistry: ServiceRegistry,
|
|
10
|
+
): SysCallMapping {
|
|
11
|
+
return {
|
|
12
|
+
/**
|
|
13
|
+
* Define a Lua event listener
|
|
14
|
+
*/
|
|
15
|
+
"service.define": (
|
|
16
|
+
_ctx,
|
|
17
|
+
def: ServiceSpec,
|
|
18
|
+
) => {
|
|
19
|
+
return serviceRegistry.define(def);
|
|
20
|
+
},
|
|
21
|
+
"service.discover": (
|
|
22
|
+
_ctx,
|
|
23
|
+
selector: string,
|
|
24
|
+
data: any,
|
|
25
|
+
): Promise<ServiceMatch[]> => {
|
|
26
|
+
return serviceRegistry.discover(selector, data);
|
|
27
|
+
},
|
|
28
|
+
"service.invoke": (
|
|
29
|
+
_ctx,
|
|
30
|
+
service: ServiceMatch,
|
|
31
|
+
data: any,
|
|
32
|
+
): Promise<any> => {
|
|
33
|
+
return serviceRegistry.invoke(service, data);
|
|
34
|
+
},
|
|
35
|
+
"service.invokeBestMatch": (
|
|
36
|
+
_ctx,
|
|
37
|
+
selector: string,
|
|
38
|
+
data: any,
|
|
39
|
+
): Promise<any> => {
|
|
40
|
+
return serviceRegistry.invokeBestMatch(selector, data);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SysCallMapping } from "../system.ts";
|
|
2
|
+
import type { Client } from "../../client.ts";
|
|
3
|
+
import { fsEndpoint } from "../../spaces/constants.ts";
|
|
4
|
+
|
|
5
|
+
export function shellSyscalls(
|
|
6
|
+
client: Client,
|
|
7
|
+
): SysCallMapping {
|
|
8
|
+
return {
|
|
9
|
+
"shell.run": async (
|
|
10
|
+
_ctx,
|
|
11
|
+
cmd: string,
|
|
12
|
+
args: string[],
|
|
13
|
+
stdin?: string,
|
|
14
|
+
): Promise<{ stdout: string; stderr: string; code: number }> => {
|
|
15
|
+
if (!client.httpSpacePrimitives) {
|
|
16
|
+
throw new Error("Not supported in fully local mode");
|
|
17
|
+
}
|
|
18
|
+
const resp = client.httpSpacePrimitives.authenticatedFetch(
|
|
19
|
+
buildShellUrl(client),
|
|
20
|
+
{
|
|
21
|
+
method: "POST",
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
cmd,
|
|
24
|
+
args,
|
|
25
|
+
stdin,
|
|
26
|
+
}),
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
const { code, stderr, stdout } = await (await resp).json();
|
|
30
|
+
return { code, stderr, stdout };
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function buildShellUrl(client: Client) {
|
|
36
|
+
// Strip off the /.fs and replace with /.shell
|
|
37
|
+
return client.httpSpacePrimitives.url.slice(0, -fsEndpoint.length) +
|
|
38
|
+
"/.shell";
|
|
39
|
+
}
|