@silverbulletmd/silverbullet 2.4.2 → 2.6.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.
Files changed (97) hide show
  1. package/README.md +19 -4
  2. package/client/asset_bundle/bundle.ts +3 -9
  3. package/client/data/datastore.ts +4 -5
  4. package/client/markdown_parser/constants.ts +5 -4
  5. package/client/plugos/hooks/code_widget.ts +3 -8
  6. package/client/plugos/hooks/command.ts +8 -8
  7. package/client/plugos/hooks/document_editor.ts +10 -15
  8. package/client/plugos/hooks/event.ts +33 -36
  9. package/client/plugos/hooks/mq.ts +17 -17
  10. package/client/plugos/hooks/plug_namespace.ts +3 -8
  11. package/client/plugos/hooks/slash_command.ts +13 -28
  12. package/client/plugos/hooks/syscall.ts +3 -3
  13. package/client/plugos/manifest_cache.ts +22 -15
  14. package/client/plugos/plug.ts +2 -6
  15. package/client/plugos/plug_compile.ts +79 -78
  16. package/client/plugos/protocol.ts +28 -28
  17. package/client/plugos/proxy_fetch.ts +7 -6
  18. package/client/plugos/sandboxes/web_worker_sandbox.ts +1 -1
  19. package/client/plugos/sandboxes/worker_sandbox.ts +18 -18
  20. package/client/plugos/syscalls/asset.ts +1 -3
  21. package/client/plugos/syscalls/code_widget.ts +1 -3
  22. package/client/plugos/syscalls/config.ts +1 -5
  23. package/client/plugos/syscalls/datastore.ts +1 -1
  24. package/client/plugos/syscalls/editor.ts +72 -69
  25. package/client/plugos/syscalls/event.ts +9 -12
  26. package/client/plugos/syscalls/fetch.ts +31 -23
  27. package/client/plugos/syscalls/index.ts +10 -1
  28. package/client/plugos/syscalls/jsonschema.ts +72 -32
  29. package/client/plugos/syscalls/language.ts +9 -5
  30. package/client/plugos/syscalls/markdown.ts +29 -7
  31. package/client/plugos/syscalls/mq.ts +4 -12
  32. package/client/plugos/syscalls/service_registry.ts +1 -4
  33. package/client/plugos/syscalls/shell.ts +2 -5
  34. package/client/plugos/syscalls/space.ts +1 -1
  35. package/client/plugos/syscalls/sync.ts +69 -60
  36. package/client/plugos/syscalls/system.ts +2 -3
  37. package/client/plugos/system.ts +6 -12
  38. package/client/plugos/worker_runtime.ts +12 -33
  39. package/client/space_lua/aggregates.ts +782 -0
  40. package/client/space_lua/ast.ts +42 -8
  41. package/client/space_lua/ast_narrow.ts +4 -2
  42. package/client/space_lua/eval.ts +886 -575
  43. package/client/space_lua/labels.ts +7 -12
  44. package/client/space_lua/liq_null.ts +6 -0
  45. package/client/space_lua/numeric.ts +5 -8
  46. package/client/space_lua/parse.ts +346 -120
  47. package/client/space_lua/query_collection.ts +926 -82
  48. package/client/space_lua/query_env.ts +26 -0
  49. package/client/space_lua/render_lua_markdown.ts +369 -0
  50. package/client/space_lua/rp.ts +5 -4
  51. package/client/space_lua/runtime.ts +288 -155
  52. package/client/space_lua/stdlib/format.ts +53 -39
  53. package/client/space_lua/stdlib/js.ts +3 -7
  54. package/client/space_lua/stdlib/load.ts +1 -3
  55. package/client/space_lua/stdlib/math.ts +84 -58
  56. package/client/space_lua/stdlib/net.ts +27 -17
  57. package/client/space_lua/stdlib/os.ts +81 -85
  58. package/client/space_lua/stdlib/pattern.ts +695 -0
  59. package/client/space_lua/stdlib/prng.ts +148 -0
  60. package/client/space_lua/stdlib/space_lua.ts +17 -23
  61. package/client/space_lua/stdlib/string.ts +102 -190
  62. package/client/space_lua/stdlib/string_pack.ts +490 -0
  63. package/client/space_lua/stdlib/table.ts +76 -16
  64. package/client/space_lua/stdlib.ts +53 -39
  65. package/client/space_lua/tonumber.ts +82 -42
  66. package/client/space_lua/util.ts +53 -15
  67. package/dist/plug-compile.js +55 -98
  68. package/package.json +27 -20
  69. package/plug-api/constants.ts +0 -32
  70. package/plug-api/lib/async.ts +20 -7
  71. package/plug-api/lib/crypto.ts +16 -17
  72. package/plug-api/lib/dates.ts +15 -7
  73. package/plug-api/lib/json.ts +11 -5
  74. package/plug-api/lib/limited_map.ts +1 -1
  75. package/plug-api/lib/native_fetch.ts +2 -0
  76. package/plug-api/lib/ref.ts +23 -23
  77. package/plug-api/lib/resolve.ts +7 -11
  78. package/plug-api/lib/tags.ts +13 -4
  79. package/plug-api/lib/transclusion.ts +10 -21
  80. package/plug-api/lib/tree.ts +165 -45
  81. package/plug-api/lib/yaml.ts +35 -25
  82. package/plug-api/syscalls/asset.ts +1 -1
  83. package/plug-api/syscalls/config.ts +1 -4
  84. package/plug-api/syscalls/editor.ts +15 -15
  85. package/plug-api/syscalls/jsonschema.ts +1 -3
  86. package/plug-api/syscalls/lua.ts +3 -9
  87. package/plug-api/syscalls/mq.ts +1 -4
  88. package/plug-api/syscalls/shell.ts +4 -1
  89. package/plug-api/syscalls/space.ts +3 -10
  90. package/plug-api/syscalls/system.ts +1 -4
  91. package/plug-api/syscalls/yaml.ts +2 -6
  92. package/plug-api/system_mock.ts +0 -1
  93. package/plug-api/types/client.ts +16 -1
  94. package/plug-api/types/event.ts +6 -4
  95. package/plug-api/types/manifest.ts +8 -9
  96. package/plugs/builtin_plugs.ts +2 -2
  97. package/client/plugos/sandboxes/deno_worker_sandbox.ts +0 -6
@@ -3,23 +3,39 @@ import { readFile, writeFile, mkdtemp, rm, mkdir } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import * as YAML from "js-yaml";
5
5
 
6
- import { denoPlugin, esbuild } from "../../build_deps.ts";
6
+ import * as esbuild from "esbuild";
7
7
  import { bundleAssets } from "../asset_bundle/builder.ts";
8
8
  import type { Manifest } from "./types.ts";
9
- import { version } from "../../version.ts";
10
9
 
11
- // const workerRuntimeUrl = new URL(
12
- // "../lib/plugos/worker_runtime.ts",
13
- // import.meta.url,
14
- // );
15
- const workerRuntimeUrl =
16
- `https://deno.land/x/silverbullet@${version}/client/plugos/worker_runtime.ts`;
10
+ // When bundled by build_plug_compile.ts, this is replaced with the pre-bundled
11
+ // worker runtime JS. When running from source, it's undefined and esbuild
12
+ // resolves the .ts file directly (it handles TypeScript natively).
13
+ declare const __EMBEDDED_WORKER_RUNTIME_JS__: string | undefined;
14
+
15
+ const workerRuntimePlugin: esbuild.Plugin = {
16
+ name: "worker-runtime",
17
+ setup(build) {
18
+ if (typeof __EMBEDDED_WORKER_RUNTIME_JS__ !== "undefined") {
19
+ // Bundled CLI: serve pre-bundled JS from the embedded constant
20
+ build.onResolve({ filter: /^worker-runtime$/ }, () => ({
21
+ path: "worker-runtime",
22
+ namespace: "worker-runtime",
23
+ }));
24
+ build.onLoad({ filter: /.*/, namespace: "worker-runtime" }, () => ({
25
+ contents: __EMBEDDED_WORKER_RUNTIME_JS__,
26
+ loader: "js",
27
+ }));
28
+ } else {
29
+ // From source: point directly at the .ts file, esbuild handles it
30
+ build.onResolve({ filter: /^worker-runtime$/ }, () => ({
31
+ path: path.join(import.meta.dirname, "worker_runtime.ts"),
32
+ }));
33
+ }
34
+ },
35
+ };
17
36
 
18
37
  export type CompileOptions = {
19
38
  debug?: boolean;
20
- runtimeUrl?: string;
21
- // path to config file
22
- configPath?: string;
23
39
  // Print info on bundle size
24
40
  info?: boolean;
25
41
  };
@@ -40,7 +56,7 @@ export async function compileManifest(
40
56
  // Assets
41
57
  const assetsBundle = await bundleAssets(
42
58
  path.resolve(rootPath),
43
- manifest.assets as string[] || [],
59
+ (manifest.assets as string[]) || [],
44
60
  );
45
61
  manifest.assets = assetsBundle.toJSON();
46
62
 
@@ -50,39 +66,35 @@ export async function compileManifest(
50
66
  }
51
67
 
52
68
  const jsFile = `
53
- import { setupMessageListener } from "${
54
- options.runtimeUrl || workerRuntimeUrl
55
- }";
69
+ import { setupMessageListener } from "worker-runtime";
56
70
 
57
71
  // Imports
58
- ${
59
- Object.entries(manifest.functions).map(([funcName, def]) => {
60
- if (!def.path) {
61
- return "";
62
- }
63
- let [filePath, jsFunctionName] = def.path.split(":");
64
- // Resolve path
65
- filePath = path.join(rootPath, filePath);
66
-
67
- return `import {${jsFunctionName} as ${funcName}} from "file://${
68
- // Replacing \ with / for Windows
69
- path.resolve(filePath).replaceAll(
70
- "\\",
71
- "\\\\",
72
- )}";\n`;
73
- }).join("")
74
- }
72
+ ${Object.entries(manifest.functions)
73
+ .map(([funcName, def]) => {
74
+ if (!def.path) {
75
+ return "";
76
+ }
77
+ let [filePath, jsFunctionName] = def.path.split(":");
78
+ // Resolve path
79
+ filePath = path.join(rootPath, filePath);
80
+
81
+ return `import {${jsFunctionName} as ${funcName}} from "${
82
+ // Replacing \ with / for Windows
83
+ path.resolve(filePath).replaceAll("\\", "\\\\")
84
+ }";\n`;
85
+ })
86
+ .join("")}
75
87
 
76
88
  // Function mapping
77
89
  const functionMapping = {
78
- ${
79
- Object.entries(manifest.functions).map(([funcName, def]) => {
80
- if (!def.path) {
81
- return "";
82
- }
83
- return ` ${funcName}: ${funcName},\n`;
84
- }).join("")
85
- }
90
+ ${Object.entries(manifest.functions)
91
+ .map(([funcName, def]) => {
92
+ if (!def.path) {
93
+ return "";
94
+ }
95
+ return ` ${funcName}: ${funcName},\n`;
96
+ })
97
+ .join("")}
86
98
  };
87
99
 
88
100
  // Manifest
@@ -111,12 +123,7 @@ setupMessageListener(functionMapping, manifest, self.postMessage);
111
123
  outfile: outFile,
112
124
  metafile: options.info,
113
125
  treeShaking: true,
114
- plugins: [
115
- denoPlugin({
116
- configPath: options.configPath &&
117
- path.resolve(process.cwd(), options.configPath),
118
- }),
119
- ],
126
+ plugins: [workerRuntimePlugin],
120
127
  });
121
128
 
122
129
  if (options.info) {
@@ -125,12 +132,12 @@ setupMessageListener(functionMapping, manifest, self.postMessage);
125
132
  }
126
133
 
127
134
  let jsCode = await readFile(outFile, "utf-8");
128
- jsCode = patchDenoLibJS(jsCode);
135
+ jsCode = patchBundledJS(jsCode);
129
136
  await writeFile(outFile, jsCode, "utf-8");
130
-
137
+
131
138
  // Clean up temp directory
132
139
  await rm(tempDir, { recursive: true, force: true });
133
-
140
+
134
141
  console.log(`Plug ${manifest.name} written to ${outFile}.`);
135
142
  return outFile;
136
143
  }
@@ -152,19 +159,17 @@ export async function compileManifests(
152
159
  await mkdir(dist, { recursive: true });
153
160
  const startTime = Date.now();
154
161
  // Build all plugs in parallel
155
- await Promise.all(manifestFiles.map(async (plugManifestPath) => {
156
- const manifestPath = plugManifestPath as string;
157
- try {
158
- await compileManifest(
159
- manifestPath,
160
- dist,
161
- options,
162
- );
163
- } catch (e: any) {
164
- console.error(`Error building ${manifestPath}:`, e.message);
165
- throw e;
166
- }
167
- }));
162
+ await Promise.all(
163
+ manifestFiles.map(async (plugManifestPath) => {
164
+ const manifestPath = plugManifestPath as string;
165
+ try {
166
+ await compileManifest(manifestPath, dist, options);
167
+ } catch (e: any) {
168
+ console.error(`Error building ${manifestPath}:`, e.message);
169
+ throw e;
170
+ }
171
+ }),
172
+ );
168
173
  console.log(`Done building plugs in ${Date.now() - startTime}ms`);
169
174
  building = false;
170
175
  }
@@ -172,31 +177,27 @@ export async function compileManifests(
172
177
  await buildAll();
173
178
  }
174
179
 
175
- export function patchDenoLibJS(code: string): string {
176
- // The Deno std lib has one occurence of a regex that Webkit JS doesn't (yet parse), we'll strip it because it's likely never invoked anyway, YOLO
180
+ export function patchBundledJS(code: string): string {
181
+ // One bundled dependency has a lookbehind regex that WebKit can't parse; replace it with a no-op
177
182
  return code.replaceAll("/(?<=\\n)/", "/()/");
178
183
  }
179
184
 
180
185
  export async function plugCompileCommand(
181
- { dist, debug, info, config, runtimeUrl }: {
186
+ {
187
+ dist,
188
+ debug,
189
+ info,
190
+ }: {
182
191
  dist: string;
183
192
  debug: boolean;
184
193
  info: boolean;
185
- config?: string;
186
- runtimeUrl?: string;
187
194
  },
188
195
  ...manifestPaths: string[]
189
196
  ) {
190
- await compileManifests(
191
- manifestPaths,
192
- dist,
193
- {
194
- debug: debug,
195
- info: info,
196
- runtimeUrl,
197
- configPath: config,
198
- },
199
- );
200
- esbuild.stop();
197
+ await compileManifests(manifestPaths, dist, {
198
+ debug: debug,
199
+ info: info,
200
+ });
201
+ await esbuild.stop();
201
202
  process.exit(0);
202
203
  }
@@ -3,38 +3,38 @@ import type { Manifest } from "@silverbulletmd/silverbullet/type/manifest";
3
3
  // Messages received from the worker
4
4
  export type ControllerMessage =
5
5
  | {
6
- // Parsed manifest when worker is initialized
7
- type: "manifest";
8
- manifest: Manifest;
9
- }
6
+ // Parsed manifest when worker is initialized
7
+ type: "manifest";
8
+ manifest: Manifest;
9
+ }
10
10
  | {
11
- // Function invocation result
12
- type: "invr";
13
- id: number;
14
- error?: string;
15
- result?: any;
16
- }
11
+ // Function invocation result
12
+ type: "invr";
13
+ id: number;
14
+ error?: string;
15
+ result?: any;
16
+ }
17
17
  | {
18
- // Syscall
19
- type: "sys";
20
- id: number;
21
- name: string;
22
- args: any[];
23
- };
18
+ // Syscall
19
+ type: "sys";
20
+ id: number;
21
+ name: string;
22
+ args: any[];
23
+ };
24
24
 
25
25
  // Messages received inside the worker
26
26
  export type WorkerMessage =
27
27
  | {
28
- // Function invocation
29
- type: "inv";
30
- id: number;
31
- name: string;
32
- args: any[];
33
- }
28
+ // Function invocation
29
+ type: "inv";
30
+ id: number;
31
+ name: string;
32
+ args: any[];
33
+ }
34
34
  | {
35
- // Syscall result
36
- type: "sysr";
37
- id: number;
38
- result?: any;
39
- error?: any;
40
- };
35
+ // Syscall result
36
+ type: "sysr";
37
+ id: number;
38
+ result?: any;
39
+ error?: any;
40
+ };
@@ -35,12 +35,13 @@ export async function performLocalFetch(
35
35
  ): Promise<ProxyFetchResponse64> {
36
36
  const result = await fetch(
37
37
  url,
38
- req && {
39
- method: req.method,
40
- headers: req.headers,
41
- body: req.base64Body && base64Decode(req.base64Body),
42
- // Casting to "any" for now, since of weird Deno typing
43
- } as any,
38
+ req &&
39
+ ({
40
+ method: req.method,
41
+ headers: req.headers,
42
+ body: req.base64Body && base64Decode(req.base64Body),
43
+ // Casting to any due to TypeScript fetch type limitations
44
+ } as any),
44
45
  );
45
46
  return {
46
47
  ok: result.ok,
@@ -11,7 +11,7 @@ export function createWorkerSandboxFromLocalPath<HookT>(
11
11
  plug,
12
12
  new URL(
13
13
  name,
14
- document.baseURI.slice(0, -1) + fsEndpoint + "/", // We're NOT striping trailing '/', this used to be `location.origin`
14
+ `${document.baseURI.slice(0, -1) + fsEndpoint}/`, // We're NOT striping trailing '/', this used to be `location.origin`
15
15
  ),
16
16
  );
17
17
  }
@@ -22,8 +22,7 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
22
22
  readonly plug: Plug<HookT>,
23
23
  public workerUrl: URL,
24
24
  private workerOptions = {},
25
- ) {
26
- }
25
+ ) {}
27
26
 
28
27
  /**
29
28
  * Should only invoked lazily (either by invoke, or by a ManifestCache to load the manifest)
@@ -43,7 +42,7 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
43
42
  return race([
44
43
  // We're adding a timeout of 5s here to handle the case where a plug blows up during initialization
45
44
  timeout(5000).catch((_) =>
46
- Promise.reject(new Error("Plug timed out during creation"))
45
+ Promise.reject(new Error("Plug timed out during creation")),
47
46
  ),
48
47
  new Promise((resolve) => {
49
48
  this.worker!.onmessage = (ev) => {
@@ -54,13 +53,13 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
54
53
 
55
54
  // Set assets in the plug
56
55
  this.plug.assets = new AssetBundle(
57
- this.manifest?.assets ? this.manifest.assets as AssetJson : {},
56
+ this.manifest?.assets ? (this.manifest.assets as AssetJson) : {},
58
57
  );
59
58
 
60
59
  return resolve();
61
60
  }
62
61
 
63
- this.onMessage(ev.data);
62
+ void this.onMessage(ev.data);
64
63
  };
65
64
  }),
66
65
  ]);
@@ -76,28 +75,29 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
76
75
  try {
77
76
  const result = await this.plug.syscall(data.name!, data.args!);
78
77
 
79
- this.worker && this.worker!.postMessage({
80
- type: "sysr",
81
- id: data.id,
82
- result: result,
83
- } as WorkerMessage);
78
+ this.worker &&
79
+ this.worker!.postMessage({
80
+ type: "sysr",
81
+ id: data.id,
82
+ result: result,
83
+ } as WorkerMessage);
84
84
  } catch (e: any) {
85
85
  // console.error("Syscall fail", e);
86
- this.worker && this.worker!.postMessage({
87
- type: "sysr",
88
- id: data.id,
89
- error: e.message,
90
- } as WorkerMessage);
86
+ this.worker &&
87
+ this.worker!.postMessage({
88
+ type: "sysr",
89
+ id: data.id,
90
+ error: e.message,
91
+ } as WorkerMessage);
91
92
  }
92
93
  break;
93
94
  case "invr": {
94
95
  const resultCbs = this.outstandingInvocations.get(data.id!);
95
96
  this.outstandingInvocations.delete(data.id!);
96
97
  if (data.error) {
97
- resultCbs &&
98
- resultCbs.reject(new Error(data.error));
98
+ resultCbs?.reject(new Error(data.error));
99
99
  } else {
100
- resultCbs && resultCbs.resolve(data.result);
100
+ resultCbs?.resolve(data.result);
101
101
  }
102
102
  break;
103
103
  }
@@ -4,9 +4,7 @@ import type { FileMeta } from "../../../plug-api/types/index.ts";
4
4
  export default function assetSyscalls(system: System<any>): SysCallMapping {
5
5
  return {
6
6
  "asset.readAsset": (_ctx, plugName: string, name: string): string => {
7
- return system.loadedPlugs.get(plugName)!.assets!.readFileAsDataUrl(
8
- name,
9
- );
7
+ return system.loadedPlugs.get(plugName)!.assets!.readFileAsDataUrl(name);
10
8
  },
11
9
  "asset.listFiles": (_ctx, plugName: string): FileMeta[] => {
12
10
  const assets = system.loadedPlugs.get(plugName)!.assets!;
@@ -12,9 +12,7 @@ export function codeWidgetSyscalls(
12
12
  body: string,
13
13
  pageName: string,
14
14
  ): Promise<CodeWidgetContent | null> => {
15
- const langCallback = codeWidgetHook.codeWidgetCallbacks.get(
16
- lang,
17
- );
15
+ const langCallback = codeWidgetHook.codeWidgetCallbacks.get(lang);
18
16
  if (!langCallback) {
19
17
  throw new Error(`Code widget ${lang} not found`);
20
18
  }
@@ -23,11 +23,7 @@ export function configSyscalls(config: Config): SysCallMapping {
23
23
  keyOrValues = await luaValueToJS(keyOrValues, LuaStackFrame.lostFrame);
24
24
  config.set(keyOrValues as any, value);
25
25
  },
26
- "config.insert": (
27
- _ctx,
28
- key: string | string[],
29
- value: any,
30
- ) => {
26
+ "config.insert": (_ctx, key: string | string[], value: any) => {
31
27
  config.insert(key, value);
32
28
  },
33
29
  "config.has": (_ctx, path: string) => {
@@ -61,7 +61,7 @@ export function dataStoreReadSyscalls(
61
61
  }
62
62
  }
63
63
  return (await queryLua<any>(ds.kv, prefix, query, env, sf)).map((item) =>
64
- luaValueToJS(item, sf)
64
+ luaValueToJS(item, sf),
65
65
  );
66
66
  },
67
67
  };