@silverbulletmd/silverbullet 2.4.1 → 2.5.3

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.
Files changed (57) hide show
  1. package/README.md +20 -4
  2. package/client/markdown_parser/constants.ts +2 -2
  3. package/client/plugos/hooks/code_widget.ts +0 -3
  4. package/client/plugos/hooks/document_editor.ts +0 -3
  5. package/client/plugos/hooks/event.ts +1 -1
  6. package/client/plugos/hooks/mq.ts +1 -1
  7. package/client/plugos/hooks/plug_namespace.ts +0 -3
  8. package/client/plugos/hooks/slash_command.ts +2 -2
  9. package/client/plugos/plug.ts +0 -1
  10. package/client/plugos/plug_compile.ts +28 -29
  11. package/client/plugos/proxy_fetch.ts +1 -1
  12. package/client/plugos/sandboxes/web_worker_sandbox.ts +1 -1
  13. package/client/plugos/sandboxes/worker_sandbox.ts +2 -3
  14. package/client/plugos/syscalls/editor.ts +12 -12
  15. package/client/plugos/syscalls/fetch.ts +1 -1
  16. package/client/plugos/syscalls/jsonschema.ts +1 -1
  17. package/client/plugos/syscalls/mq.ts +1 -1
  18. package/client/plugos/syscalls/space.ts +1 -1
  19. package/client/plugos/system.ts +2 -2
  20. package/client/plugos/worker_runtime.ts +8 -29
  21. package/client/space_lua/aggregates.ts +209 -0
  22. package/client/space_lua/ast.ts +24 -2
  23. package/client/space_lua/eval.ts +58 -53
  24. package/client/space_lua/labels.ts +1 -1
  25. package/client/space_lua/parse.ts +117 -12
  26. package/client/space_lua/query_collection.ts +850 -70
  27. package/client/space_lua/query_env.ts +26 -0
  28. package/client/space_lua/runtime.ts +47 -17
  29. package/client/space_lua/stdlib/format.ts +19 -19
  30. package/client/space_lua/stdlib/math.ts +73 -48
  31. package/client/space_lua/stdlib/net.ts +2 -2
  32. package/client/space_lua/stdlib/os.ts +5 -0
  33. package/client/space_lua/stdlib/pattern.ts +702 -0
  34. package/client/space_lua/stdlib/prng.ts +145 -0
  35. package/client/space_lua/stdlib/space_lua.ts +3 -8
  36. package/client/space_lua/stdlib/string.ts +103 -181
  37. package/client/space_lua/stdlib/string_pack.ts +486 -0
  38. package/client/space_lua/stdlib/table.ts +73 -9
  39. package/client/space_lua/stdlib.ts +38 -14
  40. package/client/space_lua/tonumber.ts +3 -2
  41. package/client/space_lua/util.ts +43 -9
  42. package/dist/plug-compile.js +23 -69
  43. package/dist/worker_runtime_bundle.js +233 -0
  44. package/package.json +16 -11
  45. package/plug-api/constants.ts +0 -32
  46. package/plug-api/lib/async.ts +2 -2
  47. package/plug-api/lib/crypto.ts +11 -11
  48. package/plug-api/lib/json.ts +1 -1
  49. package/plug-api/lib/limited_map.ts +1 -1
  50. package/plug-api/lib/native_fetch.ts +2 -0
  51. package/plug-api/lib/ref.ts +5 -5
  52. package/plug-api/lib/transclusion.ts +5 -5
  53. package/plug-api/lib/tree.ts +50 -2
  54. package/plug-api/lib/yaml.ts +10 -10
  55. package/plug-api/syscalls/editor.ts +1 -1
  56. package/plug-api/system_mock.ts +0 -1
  57. package/client/plugos/sandboxes/deno_worker_sandbox.ts +0 -6
@@ -1,4 +1,5 @@
1
1
  import {
2
+ getMetatable,
2
3
  type ILuaFunction,
3
4
  isILuaFunction,
4
5
  isLuaTable,
@@ -17,6 +18,7 @@ import {
17
18
  luaToString,
18
19
  luaTypeOf,
19
20
  type LuaValue,
21
+ singleResult,
20
22
  } from "./runtime.ts";
21
23
  import { stringApi } from "./stdlib/string.ts";
22
24
  import { tableApi } from "./stdlib/table.ts";
@@ -32,6 +34,7 @@ import { luaLoad } from "./stdlib/load.ts";
32
34
  import { cryptoApi } from "./stdlib/crypto.ts";
33
35
  import { netApi } from "./stdlib/net.ts";
34
36
  import { isTaggedFloat, makeLuaFloat } from "./numeric.ts";
37
+ import { isPromise } from "./rp.ts";
35
38
 
36
39
  const printFunction = new LuaBuiltinFunction(async (_sf, ...args) => {
37
40
  console.log(
@@ -121,23 +124,41 @@ export const eachFunction = new LuaBuiltinFunction(
121
124
  },
122
125
  );
123
126
 
124
- const unpackFunction = new LuaBuiltinFunction(async (sf, t: LuaTable) => {
125
- const values: LuaValue[] = [];
126
- for (let i = 1; i <= (t as any).length; i++) {
127
- values.push(await luaGet(t, i, sf.astCtx ?? null, sf));
128
- }
129
- return new LuaMultiRes(values);
130
- });
131
-
132
127
  const typeFunction = new LuaBuiltinFunction(
133
128
  (_sf, value: LuaValue): string | Promise<string> => {
134
129
  return luaTypeOf(value);
135
130
  },
136
131
  );
137
132
 
138
- const tostringFunction = new LuaBuiltinFunction((_sf, value: any) => {
139
- return luaToString(value);
140
- });
133
+ // tostring() checks `__tostring` metamethod first (with live SF), then
134
+ // falls back to the default `luaToString` representation.
135
+ const tostringFunction = new LuaBuiltinFunction(
136
+ (sf, value: any): string | Promise<string> => {
137
+ const mt = getMetatable(value, sf);
138
+ if (mt) {
139
+ const mm = mt.rawGet("__tostring");
140
+ if (mm !== undefined && mm !== null) {
141
+ const ctx = sf.astCtx ?? {};
142
+ const r = luaCall(mm, [value], ctx as any, sf);
143
+ const unwrap = (v: any): string => {
144
+ const s = singleResult(v);
145
+ if (typeof s !== "string") {
146
+ throw new LuaRuntimeError(
147
+ "'__tostring' must return a string",
148
+ sf,
149
+ );
150
+ }
151
+ return s;
152
+ };
153
+ if (isPromise(r)) {
154
+ return (r as Promise<any>).then(unwrap);
155
+ }
156
+ return unwrap(r);
157
+ }
158
+ }
159
+ return luaToString(value);
160
+ },
161
+ );
141
162
 
142
163
  const tonumberFunction = new LuaBuiltinFunction(
143
164
  (sf, value: LuaValue, base?: number) => {
@@ -255,7 +276,7 @@ const setmetatableFunction = new LuaBuiltinFunction(
255
276
 
256
277
  const rawlenFunction = new LuaBuiltinFunction(
257
278
  (_sf, value: LuaValue) => {
258
- return luaLen(value, _sf);
279
+ return luaLen(value, _sf, true);
259
280
  },
260
281
  );
261
282
 
@@ -429,7 +450,7 @@ const nextFunction = new LuaBuiltinFunction(
429
450
  const someFunction = new LuaBuiltinFunction(async (_sf, value: any) => {
430
451
  switch (await luaTypeOf(value)) {
431
452
  case "number":
432
- if (!isFinite(value)) return null;
453
+ if (!Number.isFinite(value)) return null;
433
454
  break;
434
455
  case "string":
435
456
  if (value.trim() === "") return null;
@@ -446,13 +467,16 @@ export function luaBuildStandardEnv() {
446
467
  const env = new LuaEnv();
447
468
  // _G global
448
469
  env.set("_G", env);
470
+ // Lua version string - for now it signals Lua 5.4 compatibility with
471
+ // selective 5.5 features; kept non-standard so callers can distinguish
472
+ // Space Lua from a plain Lua runtime.
473
+ env.set("_VERSION", "Lua 5.4+");
449
474
  // Top-level builtins
450
475
  env.set("print", printFunction);
451
476
  env.set("assert", assertFunction);
452
477
  env.set("type", typeFunction);
453
478
  env.set("tostring", tostringFunction);
454
479
  env.set("tonumber", tonumberFunction);
455
- env.set("unpack", unpackFunction);
456
480
  env.set("select", selectFunction);
457
481
  env.set("next", nextFunction);
458
482
  // Iterators
@@ -283,7 +283,7 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
283
283
  return { ok: false, value: 0 };
284
284
  }
285
285
 
286
- const result = sign * (hasExp ? val * Math.pow(10, exp) : val);
286
+ const result = sign * (hasExp ? val * 10 ** exp : val);
287
287
  return { ok: true, value: result };
288
288
  }
289
289
 
@@ -434,7 +434,7 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
434
434
  }
435
435
 
436
436
  const frac = fracVal === 0 ? 0 : (fracVal / fracScale);
437
- const result = sign * (intVal + frac) * Math.pow(2, expSign * exp);
437
+ const result = sign * (intVal + frac) * 2 ** (expSign * exp);
438
438
  return { ok: true, value: result };
439
439
  }
440
440
 
@@ -460,6 +460,7 @@ export function luaToNumberDetailed(
460
460
  }
461
461
 
462
462
  {
463
+ // biome-ignore lint/correctness/useParseIntRadix: local parseInt function, not global
463
464
  const parsed = parseInt(s);
464
465
  if (parsed.ok) {
465
466
  const v = parsed.value;
@@ -14,9 +14,8 @@ export function evalPromiseValues(vals: any[]): Promise<any[]> | any[] {
14
14
  }
15
15
  if (promises.length === 0) {
16
16
  return promiseResults;
17
- } else {
18
- return Promise.all(promises).then(() => promiseResults);
19
17
  }
18
+ return Promise.all(promises).then(() => promiseResults);
20
19
  }
21
20
 
22
21
  /**
@@ -36,18 +35,19 @@ async function getPivot(
36
35
  if (await compare(x, y) < 0) {
37
36
  if (await compare(y, z) < 0) {
38
37
  return y;
39
- } else if (await compare(z, x) < 0) {
38
+ }
39
+ if (await compare(z, x) < 0) {
40
40
  return x;
41
- } else {
42
- return z;
43
41
  }
44
- } else if (await compare(y, z) > 0) {
42
+ return z;
43
+ }
44
+ if (await compare(y, z) > 0) {
45
45
  return y;
46
- } else if (await compare(z, x) > 0) {
46
+ }
47
+ if (await compare(z, x) > 0) {
47
48
  return x;
48
- } else {
49
- return z;
50
49
  }
50
+ return z;
51
51
  }
52
52
 
53
53
  /**
@@ -94,3 +94,37 @@ export async function asyncQuickSort(
94
94
  }
95
95
  return arr;
96
96
  }
97
+
98
+ /**
99
+ * iterative async merge sort
100
+ * @param arr tagged array of { val, idx } elements
101
+ * @param compare async comparator returning <0, 0, or >0
102
+ */
103
+ export async function asyncMergeSort(
104
+ arr: { val: any; idx: number }[],
105
+ compare: (
106
+ a: { val: any; idx: number },
107
+ b: { val: any; idx: number },
108
+ ) => Promise<number>,
109
+ ): Promise<void> {
110
+ const n = arr.length;
111
+ if (n <= 1) return;
112
+ const work = new Array(n);
113
+
114
+ for (let size = 1; size < n; size *= 2) {
115
+ for (let left = 0; left < n; left += 2 * size) {
116
+ const mid = Math.min(left + size, n);
117
+ const right = Math.min(left + 2 * size, n);
118
+
119
+ let i = left, j = mid, k = left;
120
+ while (i < mid && j < right) {
121
+ const cmp = await compare(arr[i], arr[j]);
122
+ if (cmp <= 0) work[k++] = arr[i++];
123
+ else work[k++] = arr[j++];
124
+ }
125
+ while (i < mid) work[k++] = arr[i++];
126
+ while (j < right) work[k++] = arr[j++];
127
+ for (let m = left; m < right; m++) arr[m] = work[m];
128
+ }
129
+ }
130
+ }
@@ -4,64 +4,14 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // version.ts
7
- var version = "2.4.1";
7
+ var version = "2.5.3";
8
8
 
9
9
  // client/plugos/plug_compile.ts
10
10
  import * as path from "node:path";
11
11
  import { readFile as readFile2, writeFile, mkdtemp, rm, mkdir } from "node:fs/promises";
12
12
  import { tmpdir } from "node:os";
13
13
  import * as YAML from "js-yaml";
14
-
15
- // build_deps.ts
16
14
  import * as esbuild from "esbuild";
17
- import { readFileSync } from "node:fs";
18
- import { resolve, dirname } from "node:path";
19
- import { fileURLToPath } from "node:url";
20
- var __filename = fileURLToPath(import.meta.url);
21
- var __dirname = dirname(__filename);
22
- function denoPlugin(options) {
23
- const configPath = options?.configPath || resolve(__dirname, "deno.json");
24
- const denoConfig = JSON.parse(readFileSync(configPath, "utf-8"));
25
- const imports = denoConfig.imports || {};
26
- return {
27
- name: "deno-resolver",
28
- setup(build) {
29
- build.onResolve({ filter: /^file:\/\// }, (args) => {
30
- const filePath = args.path.replace(/^file:\/\//, "");
31
- return { path: filePath };
32
- });
33
- build.onResolve({ filter: /^@silverbulletmd\/silverbullet\// }, (args) => {
34
- const importPath = args.path;
35
- if (imports[importPath]) {
36
- const resolvedPath = resolve(__dirname, imports[importPath]);
37
- return { path: resolvedPath };
38
- }
39
- return null;
40
- });
41
- build.onResolve({ filter: /.*/ }, (args) => {
42
- if (args.path.startsWith(".") || args.path.startsWith("/")) {
43
- return null;
44
- }
45
- const importPath = args.path;
46
- if (imports[importPath]) {
47
- let mapped = imports[importPath];
48
- if (mapped.startsWith("npm:")) {
49
- return { path: mapped.replace(/^npm:/, ""), external: true };
50
- }
51
- if (mapped.startsWith("jsr:")) {
52
- return { path: args.path, external: true };
53
- }
54
- if (mapped.startsWith("http://") || mapped.startsWith("https://")) {
55
- return { path: args.path, external: true };
56
- }
57
- const resolvedPath = resolve(__dirname, mapped);
58
- return { path: resolvedPath };
59
- }
60
- return null;
61
- });
62
- }
63
- };
64
- }
65
15
 
66
16
  // client/asset_bundle/builder.ts
67
17
  import picomatch from "picomatch";
@@ -1365,7 +1315,19 @@ async function bundleAssets(rootPath, patterns) {
1365
1315
  }
1366
1316
 
1367
1317
  // client/plugos/plug_compile.ts
1368
- var workerRuntimeUrl = `https://deno.land/x/silverbullet@${version}/client/plugos/worker_runtime.ts`;
1318
+ import { existsSync } from "node:fs";
1319
+ var currentDir = import.meta.dirname;
1320
+ var bundledPath = path.join(currentDir, "worker_runtime_bundle.js");
1321
+ var sourcePath = path.join(currentDir, "../../dist/worker_runtime_bundle.js");
1322
+ var workerRuntimeBundlePath = existsSync(bundledPath) ? bundledPath : sourcePath;
1323
+ var workerRuntimePlugin = {
1324
+ name: "worker-runtime",
1325
+ setup(build2) {
1326
+ build2.onResolve({ filter: /^worker-runtime$/ }, () => ({
1327
+ path: workerRuntimeBundlePath
1328
+ }));
1329
+ }
1330
+ };
1369
1331
  async function compileManifest(manifestPath, destPath, options = {}) {
1370
1332
  const rootPath = path.dirname(manifestPath);
1371
1333
  const manifestContent = await readFile2(manifestPath, "utf-8");
@@ -1382,7 +1344,7 @@ async function compileManifest(manifestPath, destPath, options = {}) {
1382
1344
  manifest.functions = {};
1383
1345
  }
1384
1346
  const jsFile = `
1385
- import { setupMessageListener } from "${options.runtimeUrl || workerRuntimeUrl}";
1347
+ import { setupMessageListener } from "worker-runtime";
1386
1348
 
1387
1349
  // Imports
1388
1350
  ${Object.entries(manifest.functions).map(([funcName, def]) => {
@@ -1391,7 +1353,7 @@ ${Object.entries(manifest.functions).map(([funcName, def]) => {
1391
1353
  }
1392
1354
  let [filePath, jsFunctionName] = def.path.split(":");
1393
1355
  filePath = path.join(rootPath, filePath);
1394
- return `import {${jsFunctionName} as ${funcName}} from "file://${// Replacing \ with / for Windows
1356
+ return `import {${jsFunctionName} as ${funcName}} from "${// Replacing \ with / for Windows
1395
1357
  path.resolve(filePath).replaceAll(
1396
1358
  "\\",
1397
1359
  "\\\\"
@@ -1432,18 +1394,14 @@ setupMessageListener(functionMapping, manifest, self.postMessage);
1432
1394
  outfile: outFile,
1433
1395
  metafile: options.info,
1434
1396
  treeShaking: true,
1435
- plugins: [
1436
- denoPlugin({
1437
- configPath: options.configPath && path.resolve(process.cwd(), options.configPath)
1438
- })
1439
- ]
1397
+ plugins: [workerRuntimePlugin]
1440
1398
  });
1441
1399
  if (options.info) {
1442
1400
  const text = await esbuild.analyzeMetafile(result.metafile);
1443
1401
  console.log("Bundle info for", manifestPath, text);
1444
1402
  }
1445
1403
  let jsCode = await readFile2(outFile, "utf-8");
1446
- jsCode = patchDenoLibJS(jsCode);
1404
+ jsCode = patchBundledJS(jsCode);
1447
1405
  await writeFile(outFile, jsCode, "utf-8");
1448
1406
  await rm(tempDir, { recursive: true, force: true });
1449
1407
  console.log(`Plug ${manifest.name} written to ${outFile}.`);
@@ -1478,18 +1436,16 @@ async function compileManifests(manifestFiles, dist, options = {}) {
1478
1436
  }
1479
1437
  await buildAll();
1480
1438
  }
1481
- function patchDenoLibJS(code) {
1439
+ function patchBundledJS(code) {
1482
1440
  return code.replaceAll("/(?<=\\n)/", "/()/");
1483
1441
  }
1484
- async function plugCompileCommand({ dist, debug, info, config, runtimeUrl }, ...manifestPaths) {
1442
+ async function plugCompileCommand({ dist, debug, info }, ...manifestPaths) {
1485
1443
  await compileManifests(
1486
1444
  manifestPaths,
1487
1445
  dist,
1488
1446
  {
1489
1447
  debug,
1490
- info,
1491
- runtimeUrl,
1492
- configPath: config
1448
+ info
1493
1449
  }
1494
1450
  );
1495
1451
  esbuild.stop();
@@ -1498,14 +1454,12 @@ async function plugCompileCommand({ dist, debug, info, config, runtimeUrl }, ...
1498
1454
 
1499
1455
  // bin/plug-compile.ts
1500
1456
  var program = new Command();
1501
- program.name("plug-compile").description("Bundle (compile) one or more plug manifests").version(version).usage("<options> <manifest paths>").argument("<manifestPaths...>", "One or more .plug.yaml manifest files").option("--debug", "Do not minify code", false).option("--info", "Print out size info per function", false).option("-w, --watch", "Watch for changes and rebuild", false).option("--dist <path>", "Folder to put the resulting .plug.json file into", ".").option("-c, --config <path>", "Path to deno.json file to use").option("--runtimeUrl <url>", "URL to worker_runtime.ts to use").action(async (manifestPaths, options) => {
1457
+ program.name("plug-compile").description("Bundle (compile) one or more plug manifests").version(version).usage("<options> <manifest paths>").argument("<manifestPaths...>", "One or more .plug.yaml manifest files").option("--debug", "Do not minify code", false).option("--info", "Print out size info per function", false).option("-w, --watch", "Watch for changes and rebuild", false).option("--dist <path>", "Folder to put the resulting .plug.json file into", ".").action(async (manifestPaths, options) => {
1502
1458
  await plugCompileCommand(
1503
1459
  {
1504
1460
  dist: options.dist,
1505
1461
  debug: options.debug,
1506
- info: options.info,
1507
- config: options.config,
1508
- runtimeUrl: options.runtimeUrl
1462
+ info: options.info
1509
1463
  },
1510
1464
  ...manifestPaths
1511
1465
  );
@@ -0,0 +1,233 @@
1
+ // plug-api/lib/crypto.ts
2
+ function base64Decode(s) {
3
+ const binString = atob(s);
4
+ const len = binString.length;
5
+ const bytes = new Uint8Array(len);
6
+ for (let i = 0; i < len; i++) {
7
+ bytes[i] = binString.charCodeAt(i);
8
+ }
9
+ return bytes;
10
+ }
11
+ function base64Encode(buffer) {
12
+ if (typeof buffer === "string") {
13
+ buffer = new TextEncoder().encode(buffer);
14
+ }
15
+ let binary = "";
16
+ const len = buffer.byteLength;
17
+ for (let i = 0; i < len; i++) {
18
+ binary += String.fromCharCode(buffer[i]);
19
+ }
20
+ return btoa(binary);
21
+ }
22
+ var fixedCounter = new Uint8Array(16);
23
+
24
+ // client/lib/logger.ts
25
+ var Logger = class {
26
+ constructor(prefix = "", maxCaptureSize = 1e3) {
27
+ this.prefix = prefix;
28
+ this.maxCaptureSize = maxCaptureSize;
29
+ this.prefix = prefix;
30
+ this.originalConsole = {
31
+ log: console.log.bind(console),
32
+ info: console.info.bind(console),
33
+ warn: console.warn.bind(console),
34
+ error: console.error.bind(console),
35
+ debug: console.debug.bind(console)
36
+ };
37
+ this.patchConsole();
38
+ }
39
+ originalConsole;
40
+ logBuffer = [];
41
+ patchConsole() {
42
+ const createPatchedMethod = (level) => {
43
+ return (...args) => {
44
+ const prefixedArgs = this.prefix ? [this.prefix, ...args] : args;
45
+ this.originalConsole[level](...prefixedArgs);
46
+ this.captureLog(level, args);
47
+ };
48
+ };
49
+ console.log = createPatchedMethod("log");
50
+ console.info = createPatchedMethod("info");
51
+ console.warn = createPatchedMethod("warn");
52
+ console.error = createPatchedMethod("error");
53
+ console.debug = createPatchedMethod("debug");
54
+ }
55
+ captureLog(level, args) {
56
+ const entry = {
57
+ level,
58
+ timestamp: Date.now(),
59
+ message: args.map((arg) => {
60
+ if (typeof arg === "string") {
61
+ return arg;
62
+ }
63
+ try {
64
+ return JSON.stringify(arg);
65
+ } catch {
66
+ return String(arg);
67
+ }
68
+ }).join(" ")
69
+ };
70
+ this.logBuffer.push(entry);
71
+ if (this.logBuffer.length > this.maxCaptureSize) {
72
+ this.logBuffer.shift();
73
+ }
74
+ }
75
+ /**
76
+ * Posts all buffered logs to a server endpoint
77
+ */
78
+ async postToServer(logEndpoint, source) {
79
+ const logs = this.logBuffer;
80
+ if (logs.length > 0) {
81
+ const logCopy = [...this.logBuffer];
82
+ this.logBuffer = [];
83
+ try {
84
+ const resp = await fetch(logEndpoint, {
85
+ method: "POST",
86
+ headers: {
87
+ "Content-Type": "application/json"
88
+ },
89
+ body: JSON.stringify(logCopy.map((entry) => ({ ...entry, source })))
90
+ });
91
+ if (!resp.ok) {
92
+ throw new Error("Failed to post logs to server");
93
+ }
94
+ } catch (e) {
95
+ console.warn("Could not post logs to server", e.message);
96
+ this.logBuffer.unshift(...logCopy);
97
+ }
98
+ }
99
+ }
100
+ };
101
+ var globalLogger;
102
+ function initLogger(prefix = "") {
103
+ globalLogger = new Logger(prefix);
104
+ return globalLogger;
105
+ }
106
+
107
+ // client/plugos/worker_runtime.ts
108
+ var workerPostMessage = (_msg) => {
109
+ throw new Error("Not initialized yet");
110
+ };
111
+ var runningAsWebWorker = typeof window === "undefined" && // @ts-expect-error: globalThis
112
+ typeof globalThis.WebSocketPair === "undefined";
113
+ var pendingRequests = /* @__PURE__ */ new Map();
114
+ var syscallReqId = 0;
115
+ if (runningAsWebWorker) {
116
+ globalThis.syscall = async (name, ...args) => {
117
+ return await new Promise((resolve, reject) => {
118
+ syscallReqId++;
119
+ pendingRequests.set(syscallReqId, { resolve, reject });
120
+ workerPostMessage({
121
+ type: "sys",
122
+ id: syscallReqId,
123
+ name,
124
+ args
125
+ });
126
+ });
127
+ };
128
+ }
129
+ function setupMessageListener(functionMapping, manifest, postMessageFn) {
130
+ if (!runningAsWebWorker) {
131
+ return;
132
+ }
133
+ workerPostMessage = postMessageFn;
134
+ self.addEventListener("message", (event) => {
135
+ (async () => {
136
+ const data = event.data;
137
+ switch (data.type) {
138
+ case "inv":
139
+ {
140
+ const fn = functionMapping[data.name];
141
+ if (!fn) {
142
+ throw new Error(`Function not loaded: ${data.name}`);
143
+ }
144
+ try {
145
+ const result = await Promise.resolve(fn(...data.args || []));
146
+ workerPostMessage({
147
+ type: "invr",
148
+ id: data.id,
149
+ result
150
+ });
151
+ } catch (e) {
152
+ console.error(
153
+ "An exception was thrown as a result of invoking function",
154
+ data.name,
155
+ "error:",
156
+ e.message
157
+ );
158
+ workerPostMessage({
159
+ type: "invr",
160
+ id: data.id,
161
+ error: e.message
162
+ });
163
+ }
164
+ }
165
+ break;
166
+ case "sysr":
167
+ {
168
+ const syscallId = data.id;
169
+ const lookup = pendingRequests.get(syscallId);
170
+ if (!lookup) {
171
+ throw Error("Invalid request id");
172
+ }
173
+ pendingRequests.delete(syscallId);
174
+ if (data.error) {
175
+ lookup.reject(new Error(data.error));
176
+ } else {
177
+ lookup.resolve(data.result);
178
+ }
179
+ }
180
+ break;
181
+ }
182
+ })().catch(console.error);
183
+ });
184
+ workerPostMessage({
185
+ type: "manifest",
186
+ manifest
187
+ });
188
+ initLogger(`[${manifest.name} plug]`);
189
+ }
190
+ async function sandboxFetch(reqInfo, options) {
191
+ if (typeof reqInfo !== "string") {
192
+ const body = new Uint8Array(await reqInfo.arrayBuffer());
193
+ const encodedBody = body.length > 0 ? base64Encode(body) : void 0;
194
+ options = {
195
+ method: reqInfo.method,
196
+ headers: Object.fromEntries(reqInfo.headers.entries()),
197
+ base64Body: encodedBody
198
+ };
199
+ reqInfo = reqInfo.url;
200
+ }
201
+ return syscall("sandboxFetch.fetch", reqInfo, options);
202
+ }
203
+ globalThis.nativeFetch = globalThis.fetch;
204
+ function monkeyPatchFetch() {
205
+ globalThis.fetch = async (reqInfo, init) => {
206
+ const encodedBody = init?.body ? base64Encode(
207
+ new Uint8Array(await new Response(init.body).arrayBuffer())
208
+ ) : void 0;
209
+ const r = await sandboxFetch(
210
+ reqInfo,
211
+ init && {
212
+ method: init.method,
213
+ headers: init.headers,
214
+ base64Body: encodedBody
215
+ }
216
+ );
217
+ return new Response(
218
+ r.base64Body ? base64Decode(r.base64Body) : null,
219
+ {
220
+ status: r.status,
221
+ headers: r.headers
222
+ }
223
+ );
224
+ };
225
+ }
226
+ if (runningAsWebWorker) {
227
+ monkeyPatchFetch();
228
+ }
229
+ export {
230
+ monkeyPatchFetch,
231
+ sandboxFetch,
232
+ setupMessageListener
233
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silverbulletmd/silverbullet",
3
- "version": "2.4.1",
3
+ "version": "2.5.3",
4
4
  "type": "module",
5
5
  "description": "A self-hosted, web-based note taking app",
6
6
  "publishConfig": {
@@ -21,6 +21,7 @@
21
21
  "./lib/tags": "./plug-api/lib/tags.ts",
22
22
  "./lib/transclusion": "./plug-api/lib/transclusion.ts",
23
23
  "./lib/native_fetch": "./plug-api/lib/native_fetch.ts",
24
+ "./lib/query_expression": "./plug-api/lib/query_expression.ts",
24
25
  "./type/client": "./plug-api/types/client.ts",
25
26
  "./type/config": "./plug-api/types/config.ts",
26
27
  "./type/manifest": "./plug-api/types/manifest.ts",
@@ -46,16 +47,18 @@
46
47
  "!client/space_lua/**/*.bench.ts",
47
48
  "client/markdown_parser/constants.ts",
48
49
  "plugs/builtin_plugs.ts",
49
- "dist/plug-compile.js"
50
+ "dist/plug-compile.js",
51
+ "dist/worker_runtime_bundle.js"
50
52
  ],
51
53
  "scripts": {
52
- "build": "npm run build:plugs && npm run build:client",
54
+ "build": "tsx build_worker_runtime.ts && npm run build:plugs && npm run build:client",
53
55
  "build:plugs": "tsx build_plugs_libraries.ts",
54
56
  "build:client": "tsx build_client.ts",
55
- "build:plug-compile": "tsx build_plug_compile.ts",
57
+ "build:plug-compile": "tsx build_worker_runtime.ts && tsx build_plug_compile.ts",
56
58
  "prepublishOnly": "npm run build:plug-compile",
57
59
  "test": "vitest run",
58
60
  "check": "tsc --noEmit",
61
+ "lint": "biome lint .",
59
62
  "bench": "vitest bench"
60
63
  },
61
64
  "dependencies": {
@@ -83,38 +86,40 @@
83
86
  "@replit/codemirror-lang-nix": "6.0.1",
84
87
  "@replit/codemirror-vim": "6.3.0",
85
88
  "ajv": "8.17.1",
89
+ "commander": "^14.0.3",
86
90
  "crelt": "1.0.6",
91
+ "esbuild": "^0.27.3",
87
92
  "fast-diff": "1.3.0",
93
+ "fast-glob": "^3.3.3",
88
94
  "fuse.js": "7.1.0",
89
95
  "gitignore-parser": "0.0.2",
90
96
  "idb": "8.0.3",
91
- "js-yaml": "4.1.0",
97
+ "js-yaml": "^4.1.1",
92
98
  "mime": "4.1.0",
99
+ "picomatch": "^4.0.3",
93
100
  "preact": "10.28.2",
94
101
  "preact-feather": "4.2.1",
95
102
  "react-icons": "5.5.0",
103
+ "sass": "^1.97.3",
96
104
  "style-mod": "4.1.2",
97
105
  "turndown": "7.2.2"
98
106
  },
99
107
  "devDependencies": {
108
+ "@biomejs/biome": "2.4.6",
100
109
  "@preact/preset-vite": "^2.10.3",
101
110
  "@types/gitignore-parser": "^0.0.3",
102
111
  "@types/js-yaml": "^4.0.9",
103
112
  "@types/node": "^22.0.0",
104
113
  "@types/picomatch": "^4.0.2",
105
114
  "@types/turndown": "^5.0.6",
106
- "commander": "^14.0.3",
107
- "esbuild": "^0.27.3",
108
115
  "fake-indexeddb": "6.0.1",
109
- "fast-glob": "^3.3.0",
110
- "picomatch": "^4.0.0",
111
- "sass": "^1.97.3",
112
116
  "tsx": "^4.19.0",
113
117
  "typescript": "^5.9.3",
114
118
  "vite": "^7.3.1",
115
119
  "vitest": "^4.0.18"
116
120
  },
117
121
  "engines": {
118
- "node": ">=20.0.0"
122
+ "node": ">=24.13.0",
123
+ "npm": ">=10.0.0"
119
124
  }
120
125
  }