@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,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
jsToLuaValue,
|
|
3
|
+
LuaBuiltinFunction,
|
|
4
|
+
LuaTable,
|
|
5
|
+
luaValueToJS,
|
|
6
|
+
} from "../runtime.ts";
|
|
7
|
+
|
|
8
|
+
export const jsApi = new LuaTable({
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new instance of a JavaScript class.
|
|
11
|
+
* @param constructorFn - The constructor function.
|
|
12
|
+
* @param args - The arguments to pass to the constructor.
|
|
13
|
+
* @returns The new instance.
|
|
14
|
+
*/
|
|
15
|
+
new: new LuaBuiltinFunction(
|
|
16
|
+
(sf, constructorFn: any, ...args) => {
|
|
17
|
+
return new constructorFn(
|
|
18
|
+
...args.map((v) => luaValueToJS(v, sf)),
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
),
|
|
22
|
+
/**
|
|
23
|
+
* Imports a JavaScript module.
|
|
24
|
+
* @param url - The URL of the module to import.
|
|
25
|
+
* @returns The imported module.
|
|
26
|
+
*/
|
|
27
|
+
import: new LuaBuiltinFunction(async (_sf, url) => {
|
|
28
|
+
let m = await import(url);
|
|
29
|
+
// Unwrap default if it exists
|
|
30
|
+
if (Object.keys(m).length === 1 && m.default) {
|
|
31
|
+
m = m.default;
|
|
32
|
+
}
|
|
33
|
+
return m;
|
|
34
|
+
}),
|
|
35
|
+
eachIterable: new LuaBuiltinFunction((_sf, val) => {
|
|
36
|
+
const iterator = val[Symbol.asyncIterator]();
|
|
37
|
+
return async () => {
|
|
38
|
+
const result = await iterator.next();
|
|
39
|
+
if (result.done) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
return result.value;
|
|
43
|
+
};
|
|
44
|
+
}),
|
|
45
|
+
/**
|
|
46
|
+
* Converts a JavaScript value to a Lua value.
|
|
47
|
+
* @param val - The JavaScript value to convert.
|
|
48
|
+
* @returns The Lua value.
|
|
49
|
+
*/
|
|
50
|
+
tolua: new LuaBuiltinFunction((_sf, val) => jsToLuaValue(val)),
|
|
51
|
+
/**
|
|
52
|
+
* Converts a Lua value to a JavaScript value.
|
|
53
|
+
* @param val - The Lua value to convert.
|
|
54
|
+
* @returns The JavaScript value.
|
|
55
|
+
*/
|
|
56
|
+
tojs: new LuaBuiltinFunction((sf, val) => luaValueToJS(val, sf)),
|
|
57
|
+
/**
|
|
58
|
+
* Logs a message to the console.
|
|
59
|
+
* @param args - The arguments to log.
|
|
60
|
+
*/
|
|
61
|
+
log: new LuaBuiltinFunction((_sf, ...args) => {
|
|
62
|
+
console.log(...args);
|
|
63
|
+
}),
|
|
64
|
+
/**
|
|
65
|
+
* Converts a Lua value to a JSON string.
|
|
66
|
+
* @param val - The Lua value to convert.
|
|
67
|
+
* @returns The JSON string.
|
|
68
|
+
*/
|
|
69
|
+
stringify: new LuaBuiltinFunction((_sf, val) => JSON.stringify(val)),
|
|
70
|
+
|
|
71
|
+
// Expose the global window object
|
|
72
|
+
window: globalThis,
|
|
73
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LuaBuiltinFunction,
|
|
3
|
+
type LuaEnv,
|
|
4
|
+
LuaMultiRes,
|
|
5
|
+
type LuaStackFrame,
|
|
6
|
+
type LuaValue,
|
|
7
|
+
} from "../runtime.ts";
|
|
8
|
+
import { parse } from "../parse.ts";
|
|
9
|
+
import { evalStatement } from "../eval.ts";
|
|
10
|
+
|
|
11
|
+
// Returns a function (callable chunk) or (nil, "error message") pair.
|
|
12
|
+
export function luaLoad(code: LuaValue, sf: LuaStackFrame): LuaValue {
|
|
13
|
+
const s = typeof code === "string" ? code : String(code);
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const block = parse(s, sf.astCtx || {});
|
|
17
|
+
const globalEnvMaybe = sf.threadLocal.get("_GLOBAL");
|
|
18
|
+
|
|
19
|
+
// Be vocal when no _GLOBAL is set
|
|
20
|
+
if (!globalEnvMaybe) {
|
|
21
|
+
console.warn(
|
|
22
|
+
"load() called without _GLOBAL in thread-local environment",
|
|
23
|
+
);
|
|
24
|
+
return new LuaMultiRes([null, "Global environment not set"]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const globalEnv: LuaEnv = globalEnvMaybe as LuaEnv;
|
|
28
|
+
|
|
29
|
+
const runner = new LuaBuiltinFunction(async (innerSf: LuaStackFrame) => {
|
|
30
|
+
const res = await evalStatement(block, globalEnv, innerSf, true);
|
|
31
|
+
if (res === undefined) {
|
|
32
|
+
return null;
|
|
33
|
+
} else {
|
|
34
|
+
if (res && typeof res === "object" && (res as any).ctrl === "return") {
|
|
35
|
+
return new LuaMultiRes((res as any).values);
|
|
36
|
+
}
|
|
37
|
+
if (res && typeof res === "object" && (res as any).ctrl === "break") {
|
|
38
|
+
throw new Error("break outside loop");
|
|
39
|
+
}
|
|
40
|
+
if (res && typeof res === "object" && (res as any).ctrl === "goto") {
|
|
41
|
+
throw new Error("unexpected goto signal");
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return runner;
|
|
48
|
+
} catch (e: any) {
|
|
49
|
+
const msg = e && typeof e.message === "string" ? e.message : String(e);
|
|
50
|
+
return new LuaMultiRes([null, msg]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LuaBuiltinFunction,
|
|
3
|
+
LuaMultiRes,
|
|
4
|
+
LuaRuntimeError,
|
|
5
|
+
LuaTable,
|
|
6
|
+
} from "../runtime.ts";
|
|
7
|
+
import { isNegativeZero, isTaggedFloat } from "../numeric.ts";
|
|
8
|
+
|
|
9
|
+
// Fast unwrap: avoids function call overhead for the common plain-number case
|
|
10
|
+
function untagNumber(x: any): number {
|
|
11
|
+
if (typeof x === "number") return x;
|
|
12
|
+
if (isTaggedFloat(x)) return x.value;
|
|
13
|
+
return Number(x);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const mathApi = new LuaTable({
|
|
17
|
+
// math constants
|
|
18
|
+
huge: 1 / 0,
|
|
19
|
+
pi: Math.PI,
|
|
20
|
+
|
|
21
|
+
// math.type(x) => "integer" | "float" | nil
|
|
22
|
+
type: new LuaBuiltinFunction((_sf, x?: any) => {
|
|
23
|
+
if (x === undefined) {
|
|
24
|
+
throw new LuaRuntimeError(
|
|
25
|
+
"bad argument #1 to 'math.type' (value expected)",
|
|
26
|
+
_sf,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
if (isTaggedFloat(x)) {
|
|
30
|
+
return "float";
|
|
31
|
+
}
|
|
32
|
+
if (typeof x === "number") {
|
|
33
|
+
if (!Number.isFinite(x) || isNegativeZero(x)) {
|
|
34
|
+
return "float";
|
|
35
|
+
}
|
|
36
|
+
return Number.isInteger(x) ? "integer" : "float";
|
|
37
|
+
}
|
|
38
|
+
if (typeof x === "bigint") {
|
|
39
|
+
return "integer";
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}),
|
|
43
|
+
/**
|
|
44
|
+
* When called without arguments, returns a pseudo-random float with
|
|
45
|
+
* uniform distribution in the range [0,1). When called with two
|
|
46
|
+
* integers m and n, math.random returns a pseudo-random integer
|
|
47
|
+
* with uniform distribution in the range [m, n]. The call
|
|
48
|
+
* math.random(n), for a positive n, is equivalent to
|
|
49
|
+
* math.random(1,n). The call math.random(0) produces an integer
|
|
50
|
+
* with all bits (pseudo)random.
|
|
51
|
+
*/
|
|
52
|
+
random: new LuaBuiltinFunction((_sf, m?: number, n?: number) => {
|
|
53
|
+
if (m !== undefined) m = untagNumber(m);
|
|
54
|
+
if (n !== undefined) n = untagNumber(n);
|
|
55
|
+
|
|
56
|
+
if (m === undefined && n === undefined) {
|
|
57
|
+
return Math.random();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!Number.isInteger(m)) {
|
|
61
|
+
throw new LuaRuntimeError(
|
|
62
|
+
"bad argument #1 to 'math.random' (integer expected)",
|
|
63
|
+
_sf,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (n === undefined) {
|
|
68
|
+
if (m! == 0) {
|
|
69
|
+
const high = Math.floor(Math.random() * 0x100000000);
|
|
70
|
+
const low = Math.floor(Math.random() * 0x100000000);
|
|
71
|
+
let result = (BigInt(high) << 32n) | BigInt(low);
|
|
72
|
+
if (result & (1n << 63n)) {
|
|
73
|
+
result -= 1n << 64n;
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
if (m! < 1) {
|
|
78
|
+
throw new LuaRuntimeError(
|
|
79
|
+
"bad argument #1 to 'math.random' (interval is empty)",
|
|
80
|
+
_sf,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return Math.floor(Math.random() * m!) + 1;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!Number.isInteger(n!)) {
|
|
87
|
+
throw new LuaRuntimeError(
|
|
88
|
+
"bad argument #2 to 'math.random' (integer expected)",
|
|
89
|
+
_sf,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (n! < m!) {
|
|
94
|
+
throw new LuaRuntimeError(
|
|
95
|
+
"bad argument #1 to 'math.random' (interval is empty)",
|
|
96
|
+
_sf,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return Math.floor(Math.random() * (n! - m! + 1)) + m!;
|
|
100
|
+
}),
|
|
101
|
+
|
|
102
|
+
// Basic functions
|
|
103
|
+
abs: new LuaBuiltinFunction((_sf, x: number) => Math.abs(untagNumber(x))),
|
|
104
|
+
ceil: new LuaBuiltinFunction((_sf, x: number) => Math.ceil(untagNumber(x))),
|
|
105
|
+
floor: new LuaBuiltinFunction((_sf, x: number) => Math.floor(untagNumber(x))),
|
|
106
|
+
max: new LuaBuiltinFunction((_sf, ...args: number[]) =>
|
|
107
|
+
Math.max(...args.map(untagNumber))
|
|
108
|
+
),
|
|
109
|
+
min: new LuaBuiltinFunction((_sf, ...args: number[]) =>
|
|
110
|
+
Math.min(...args.map(untagNumber))
|
|
111
|
+
),
|
|
112
|
+
|
|
113
|
+
// Rounding and remainder
|
|
114
|
+
fmod: new LuaBuiltinFunction((_sf, x: number, y: number) =>
|
|
115
|
+
untagNumber(x) % untagNumber(y)
|
|
116
|
+
),
|
|
117
|
+
modf: new LuaBuiltinFunction((_sf, x: number) => {
|
|
118
|
+
const xn = untagNumber(x);
|
|
119
|
+
const int = Math.trunc(xn);
|
|
120
|
+
const frac = xn - int;
|
|
121
|
+
return new LuaMultiRes([int, frac]);
|
|
122
|
+
}),
|
|
123
|
+
|
|
124
|
+
// Power and logarithms
|
|
125
|
+
exp: new LuaBuiltinFunction((_sf, x: number) => Math.exp(untagNumber(x))),
|
|
126
|
+
log: new LuaBuiltinFunction((_sf, x: number, base?: number) => {
|
|
127
|
+
if (base === undefined) {
|
|
128
|
+
return Math.log(untagNumber(x));
|
|
129
|
+
}
|
|
130
|
+
return Math.log(untagNumber(x)) / Math.log(untagNumber(base));
|
|
131
|
+
}),
|
|
132
|
+
pow: new LuaBuiltinFunction((_sf, x: number, y: number) =>
|
|
133
|
+
Math.pow(untagNumber(x), untagNumber(y))
|
|
134
|
+
),
|
|
135
|
+
sqrt: new LuaBuiltinFunction((_sf, x: number) => Math.sqrt(untagNumber(x))),
|
|
136
|
+
|
|
137
|
+
// Trigonometric functions
|
|
138
|
+
cos: new LuaBuiltinFunction((_sf, x: number) => Math.cos(untagNumber(x))),
|
|
139
|
+
sin: new LuaBuiltinFunction((_sf, x: number) => Math.sin(untagNumber(x))),
|
|
140
|
+
tan: new LuaBuiltinFunction((_sf, x: number) => Math.tan(untagNumber(x))),
|
|
141
|
+
acos: new LuaBuiltinFunction((_sf, x: number) => Math.acos(untagNumber(x))),
|
|
142
|
+
asin: new LuaBuiltinFunction((_sf, x: number) => Math.asin(untagNumber(x))),
|
|
143
|
+
atan: new LuaBuiltinFunction((_sf, y: number, x?: number) => {
|
|
144
|
+
if (x === undefined) {
|
|
145
|
+
return Math.atan(untagNumber(y));
|
|
146
|
+
}
|
|
147
|
+
return Math.atan2(untagNumber(y), untagNumber(x));
|
|
148
|
+
}),
|
|
149
|
+
|
|
150
|
+
// Hyperbolic functions
|
|
151
|
+
cosh: new LuaBuiltinFunction((_sf, x: number) => Math.cosh(untagNumber(x))),
|
|
152
|
+
sinh: new LuaBuiltinFunction((_sf, x: number) => Math.sinh(untagNumber(x))),
|
|
153
|
+
tanh: new LuaBuiltinFunction((_sf, x: number) => Math.tanh(untagNumber(x))),
|
|
154
|
+
|
|
155
|
+
// Additional utility
|
|
156
|
+
deg: new LuaBuiltinFunction((_sf, x: number) =>
|
|
157
|
+
untagNumber(x) * 180 / Math.PI
|
|
158
|
+
),
|
|
159
|
+
rad: new LuaBuiltinFunction((_sf, x: number) =>
|
|
160
|
+
untagNumber(x) * Math.PI / 180
|
|
161
|
+
),
|
|
162
|
+
ult: new LuaBuiltinFunction((_sf, m: number, n: number) => {
|
|
163
|
+
return (untagNumber(m) >>> 0) < (untagNumber(n) >>> 0);
|
|
164
|
+
}),
|
|
165
|
+
|
|
166
|
+
// Keep the cosineSimilarity utility function
|
|
167
|
+
cosineSimilarity: new LuaBuiltinFunction(
|
|
168
|
+
(sf, vecA: LuaTable | number[], vecB: LuaTable | number[]) => {
|
|
169
|
+
if (vecA instanceof LuaTable) {
|
|
170
|
+
vecA = vecA.toJSArray();
|
|
171
|
+
}
|
|
172
|
+
if (vecB instanceof LuaTable) {
|
|
173
|
+
vecB = vecB.toJSArray();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (vecA.length !== vecB.length) {
|
|
177
|
+
throw new LuaRuntimeError("Vectors must be of the same length", sf);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let dotProduct = 0;
|
|
181
|
+
let normA = 0;
|
|
182
|
+
let normB = 0;
|
|
183
|
+
|
|
184
|
+
for (let i = 0; i < vecA.length; i++) {
|
|
185
|
+
dotProduct += vecA[i] * vecB[i];
|
|
186
|
+
normA += vecA[i] ** 2;
|
|
187
|
+
normB += vecB[i] ** 2;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
191
|
+
},
|
|
192
|
+
),
|
|
193
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { Client } from "../../client.ts";
|
|
2
|
+
import type {
|
|
3
|
+
ProxyFetchRequest,
|
|
4
|
+
ProxyFetchResponse,
|
|
5
|
+
} from "../../plugos/proxy_fetch.ts";
|
|
6
|
+
import { fsEndpoint } from "../../spaces/constants.ts";
|
|
7
|
+
import { LuaNativeJSFunction, LuaTable } from "../runtime.ts";
|
|
8
|
+
|
|
9
|
+
export const netApi = new LuaTable({
|
|
10
|
+
proxyFetch: new LuaNativeJSFunction(
|
|
11
|
+
async (
|
|
12
|
+
url: string,
|
|
13
|
+
options: ProxyFetchRequest = {},
|
|
14
|
+
): Promise<ProxyFetchResponse> => {
|
|
15
|
+
// JSONify any non-serializable body
|
|
16
|
+
if (
|
|
17
|
+
options?.body && typeof options.body !== "string" &&
|
|
18
|
+
!(options.body instanceof Uint8Array)
|
|
19
|
+
) {
|
|
20
|
+
options.body = JSON.stringify(options.body);
|
|
21
|
+
}
|
|
22
|
+
const fetchOptions = options
|
|
23
|
+
? {
|
|
24
|
+
method: options.method,
|
|
25
|
+
headers: {} as Record<string, string>,
|
|
26
|
+
body: options.body,
|
|
27
|
+
}
|
|
28
|
+
: {};
|
|
29
|
+
fetchOptions.headers = buildProxyHeaders(options.headers);
|
|
30
|
+
const resp = await client.httpSpacePrimitives.authenticatedFetch(
|
|
31
|
+
buildProxyUrl(client, url),
|
|
32
|
+
fetchOptions,
|
|
33
|
+
);
|
|
34
|
+
if (resp.status !== 200) {
|
|
35
|
+
return {
|
|
36
|
+
ok: false,
|
|
37
|
+
status: resp.status,
|
|
38
|
+
headers: extractProxyHeaders(resp.headers),
|
|
39
|
+
body: await resp.text(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Do sensible things with the body based on the content type
|
|
43
|
+
let body: any;
|
|
44
|
+
const contentTypeHeader = options.responseEncoding ||
|
|
45
|
+
resp.headers.get("x-proxy-header-content-type");
|
|
46
|
+
const statusCode = +(resp.headers.get("x-proxy-status-code") || "200");
|
|
47
|
+
if (contentTypeHeader?.startsWith("application/json")) {
|
|
48
|
+
body = await resp.json();
|
|
49
|
+
} else if (
|
|
50
|
+
contentTypeHeader?.startsWith("application/xml") ||
|
|
51
|
+
contentTypeHeader?.startsWith("text/")
|
|
52
|
+
) {
|
|
53
|
+
body = await resp.text();
|
|
54
|
+
} else {
|
|
55
|
+
body = new Uint8Array(await resp.arrayBuffer());
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
ok: resp.ok,
|
|
59
|
+
status: statusCode,
|
|
60
|
+
headers: extractProxyHeaders(resp.headers),
|
|
61
|
+
body: body,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
),
|
|
65
|
+
readURI: new LuaNativeJSFunction(
|
|
66
|
+
(uri: string, options: { uri?: string; encoding?: string } = {}) => {
|
|
67
|
+
options.uri = uri;
|
|
68
|
+
return client.clientSystem.serviceRegistry.invokeBestMatch(
|
|
69
|
+
"net.readURI:" + uri,
|
|
70
|
+
options,
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
),
|
|
74
|
+
writeURI: new LuaNativeJSFunction(
|
|
75
|
+
(uri: string, content: string | Uint8Array) => {
|
|
76
|
+
return client.clientSystem.serviceRegistry.invokeBestMatch(
|
|
77
|
+
"net.writeURI:" + uri,
|
|
78
|
+
{ uri, content },
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Utility functions
|
|
85
|
+
function buildProxyUrl(client: Client, url: string) {
|
|
86
|
+
url = url.replace(/^https?:\/\//, "");
|
|
87
|
+
// Strip off the /.fs and replace with /.proxy
|
|
88
|
+
return client.httpSpacePrimitives.url.slice(0, -fsEndpoint.length) +
|
|
89
|
+
"/.proxy/" + url;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function buildProxyHeaders(headers?: Record<string, any>): Record<string, any> {
|
|
93
|
+
const newHeaders: Record<string, any> = { "X-Proxy-Request": "true" };
|
|
94
|
+
if (!headers) {
|
|
95
|
+
return newHeaders;
|
|
96
|
+
}
|
|
97
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
98
|
+
newHeaders[`X-Proxy-Header-${key}`] = value;
|
|
99
|
+
}
|
|
100
|
+
return newHeaders;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function extractProxyHeaders(
|
|
104
|
+
headers: Headers,
|
|
105
|
+
): Record<string, any> {
|
|
106
|
+
const newHeaders: Record<string, any> = {};
|
|
107
|
+
for (const [key, value] of headers.entries()) {
|
|
108
|
+
if (key.toLowerCase().startsWith("x-proxy-header-")) {
|
|
109
|
+
newHeaders[key.slice("x-proxy-header-".length)] = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return newHeaders;
|
|
113
|
+
}
|