@silverbulletmd/silverbullet 2.5.3 → 2.7.0

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 (96) hide show
  1. package/README.md +4 -6
  2. package/client/asset_bundle/bundle.ts +3 -9
  3. package/client/data/datastore.ts +4 -5
  4. package/client/markdown_parser/constants.ts +4 -2
  5. package/client/plugos/hooks/code_widget.ts +3 -5
  6. package/client/plugos/hooks/command.ts +54 -24
  7. package/client/plugos/hooks/document_editor.ts +10 -12
  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 -5
  11. package/client/plugos/hooks/slash_command.ts +15 -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 +7 -7
  15. package/client/plugos/plug_compile.ts +119 -67
  16. package/client/plugos/protocol.ts +28 -28
  17. package/client/plugos/proxy_fetch.ts +7 -6
  18. package/client/plugos/sandboxes/worker_sandbox.ts +26 -15
  19. package/client/plugos/syscalls/asset.ts +1 -3
  20. package/client/plugos/syscalls/code_widget.ts +1 -3
  21. package/client/plugos/syscalls/config.ts +10 -7
  22. package/client/plugos/syscalls/datastore.ts +1 -1
  23. package/client/plugos/syscalls/editor.ts +199 -60
  24. package/client/plugos/syscalls/event.ts +9 -12
  25. package/client/plugos/syscalls/fetch.ts +30 -22
  26. package/client/plugos/syscalls/index.ts +11 -2
  27. package/client/plugos/syscalls/jsonschema.ts +54 -32
  28. package/client/plugos/syscalls/language.ts +9 -5
  29. package/client/plugos/syscalls/markdown.ts +29 -7
  30. package/client/plugos/syscalls/mq.ts +3 -11
  31. package/client/plugos/syscalls/service_registry.ts +1 -4
  32. package/client/plugos/syscalls/shell.ts +2 -5
  33. package/client/plugos/syscalls/sync.ts +69 -60
  34. package/client/plugos/syscalls/system.ts +15 -3
  35. package/client/plugos/system.ts +18 -20
  36. package/client/plugos/types.ts +25 -0
  37. package/client/plugos/util.ts +20 -0
  38. package/client/plugos/worker_runtime.ts +4 -3
  39. package/client/space_lua/aggregates.ts +633 -60
  40. package/client/space_lua/ast.ts +21 -9
  41. package/client/space_lua/ast_narrow.ts +4 -2
  42. package/client/space_lua/eval.ts +842 -536
  43. package/client/space_lua/labels.ts +6 -11
  44. package/client/space_lua/numeric.ts +5 -8
  45. package/client/space_lua/parse.ts +290 -169
  46. package/client/space_lua/query_collection.ts +213 -149
  47. package/client/space_lua/render_lua_markdown.ts +369 -0
  48. package/client/space_lua/rp.ts +5 -4
  49. package/client/space_lua/runtime.ts +245 -142
  50. package/client/space_lua/sliq_null.ts +6 -0
  51. package/client/space_lua/stdlib/format.ts +34 -20
  52. package/client/space_lua/stdlib/js.ts +3 -7
  53. package/client/space_lua/stdlib/load.ts +1 -3
  54. package/client/space_lua/stdlib/math.ts +15 -14
  55. package/client/space_lua/stdlib/net.ts +25 -15
  56. package/client/space_lua/stdlib/os.ts +76 -85
  57. package/client/space_lua/stdlib/pattern.ts +28 -35
  58. package/client/space_lua/stdlib/prng.ts +15 -12
  59. package/client/space_lua/stdlib/space_lua.ts +16 -17
  60. package/client/space_lua/stdlib/string.ts +7 -17
  61. package/client/space_lua/stdlib/string_pack.ts +23 -19
  62. package/client/space_lua/stdlib/table.ts +5 -9
  63. package/client/space_lua/stdlib.ts +20 -30
  64. package/client/space_lua/tonumber.ts +79 -40
  65. package/client/space_lua/util.ts +14 -10
  66. package/dist/plug-compile.js +87 -42
  67. package/package.json +24 -22
  68. package/plug-api/constants.ts +20 -0
  69. package/plug-api/lib/async.ts +19 -6
  70. package/plug-api/lib/crypto.ts +5 -6
  71. package/plug-api/lib/dates.ts +15 -7
  72. package/plug-api/lib/json.ts +10 -4
  73. package/plug-api/lib/ref.ts +27 -20
  74. package/plug-api/lib/resolve.ts +7 -11
  75. package/plug-api/lib/shortcut.ts +16 -0
  76. package/plug-api/lib/tags.ts +13 -4
  77. package/plug-api/lib/transclusion.ts +6 -17
  78. package/plug-api/lib/tree.ts +146 -43
  79. package/plug-api/lib/yaml.ts +25 -15
  80. package/plug-api/syscalls/asset.ts +1 -1
  81. package/plug-api/syscalls/config.ts +38 -4
  82. package/plug-api/syscalls/editor.ts +169 -14
  83. package/plug-api/syscalls/index.ts +18 -0
  84. package/plug-api/syscalls/jsonschema.ts +1 -3
  85. package/plug-api/syscalls/lua.ts +3 -9
  86. package/plug-api/syscalls/mq.ts +1 -4
  87. package/plug-api/syscalls/shell.ts +4 -1
  88. package/plug-api/syscalls/space.ts +3 -10
  89. package/plug-api/syscalls/system.ts +16 -4
  90. package/plug-api/syscalls/yaml.ts +2 -6
  91. package/plug-api/types/client.ts +16 -1
  92. package/plug-api/types/event.ts +6 -4
  93. package/plug-api/types/manifest.ts +71 -9
  94. package/plugs/builtin_plugs.ts +3 -3
  95. package/client/plugos/sandboxes/web_worker_sandbox.ts +0 -17
  96. package/dist/worker_runtime_bundle.js +0 -233
@@ -11,6 +11,8 @@ export class Plug<HookT> {
11
11
 
12
12
  public manifest!: Manifest<HookT>;
13
13
  public assets?: AssetBundle;
14
+ // File path the plug was loaded from; also used as the manifest cache key.
15
+ public path!: string;
14
16
 
15
17
  constructor(
16
18
  readonly system: System<HookT>,
@@ -22,19 +24,17 @@ export class Plug<HookT> {
22
24
 
23
25
  static async createLazily<HookT>(
24
26
  system: System<HookT>,
25
- cacheKey: string,
27
+ path: string,
26
28
  cacheHash: number,
27
29
  sandboxFactory: SandboxFactory<HookT>,
28
30
  ): Promise<Plug<HookT>> {
29
- const plug = new Plug(
30
- system,
31
- sandboxFactory,
32
- );
31
+ const plug = new Plug(system, sandboxFactory);
32
+ plug.path = path;
33
33
 
34
34
  // Retrieve the manifest, which may either come from a cache or be loaded from the worker
35
35
  plug.manifest = await system.options.manifestCache!.getManifest(
36
36
  plug,
37
- cacheKey,
37
+ path,
38
38
  cacheHash,
39
39
  );
40
40
 
@@ -83,7 +83,7 @@ export class Plug<HookT> {
83
83
  }
84
84
  return plug.invoke(name, args);
85
85
  }
86
- if (!await this.canInvoke(name)) {
86
+ if (!(await this.canInvoke(name))) {
87
87
  throw new Error(
88
88
  `Function ${name} is not available in ${this.runtimeEnv}`,
89
89
  );
@@ -1,30 +1,44 @@
1
1
  import * as path from "node:path";
2
- import { readFile, writeFile, mkdtemp, rm, mkdir } from "node:fs/promises";
2
+ import {
3
+ copyFile,
4
+ mkdir,
5
+ mkdtemp,
6
+ readFile,
7
+ rm,
8
+ writeFile,
9
+ } from "node:fs/promises";
3
10
  import { tmpdir } from "node:os";
4
11
  import * as YAML from "js-yaml";
5
12
 
6
13
  import * as esbuild from "esbuild";
14
+ import * as sass from "sass";
7
15
  import { bundleAssets } from "../asset_bundle/builder.ts";
8
- import type { Manifest } from "./types.ts";
16
+ import type { BuildStep, Manifest } from "./types.ts";
9
17
 
10
- import { existsSync } from "node:fs";
11
-
12
- // Resolve the pre-built worker_runtime bundle path
13
- // When running from source: ../../dist/worker_runtime_bundle.js (from client/plugos/)
14
- // When bundled: ./worker_runtime_bundle.js (from dist/)
15
- const currentDir = import.meta.dirname;
16
- const bundledPath = path.join(currentDir, "worker_runtime_bundle.js");
17
- const sourcePath = path.join(currentDir, "../../dist/worker_runtime_bundle.js");
18
- const workerRuntimeBundlePath = existsSync(bundledPath)
19
- ? bundledPath
20
- : sourcePath;
18
+ // When bundled by build_plug_compile.ts, this is replaced with the pre-bundled
19
+ // worker runtime JS. When running from source, it's undefined and esbuild
20
+ // resolves the .ts file directly (it handles TypeScript natively).
21
+ declare const __EMBEDDED_WORKER_RUNTIME_JS__: string | undefined;
21
22
 
22
23
  const workerRuntimePlugin: esbuild.Plugin = {
23
24
  name: "worker-runtime",
24
25
  setup(build) {
25
- build.onResolve({ filter: /^worker-runtime$/ }, () => ({
26
- path: workerRuntimeBundlePath,
27
- }));
26
+ if (typeof __EMBEDDED_WORKER_RUNTIME_JS__ !== "undefined") {
27
+ // Bundled CLI: serve pre-bundled JS from the embedded constant
28
+ build.onResolve({ filter: /^worker-runtime$/ }, () => ({
29
+ path: "worker-runtime",
30
+ namespace: "worker-runtime",
31
+ }));
32
+ build.onLoad({ filter: /.*/, namespace: "worker-runtime" }, () => ({
33
+ contents: __EMBEDDED_WORKER_RUNTIME_JS__,
34
+ loader: "js",
35
+ }));
36
+ } else {
37
+ // From source: point directly at the .ts file, esbuild handles it
38
+ build.onResolve({ filter: /^worker-runtime$/ }, () => ({
39
+ path: path.join(import.meta.dirname, "worker_runtime.ts"),
40
+ }));
41
+ }
28
42
  },
29
43
  };
30
44
 
@@ -47,10 +61,19 @@ export async function compileManifest(
47
61
  throw new Error(`Missing 'name' in ${manifestPath}`);
48
62
  }
49
63
 
64
+ // Build steps (run before asset bundling so produced files can be picked
65
+ // up by the `assets` glob).
66
+ if (manifest.build) {
67
+ await Promise.all(
68
+ manifest.build.map((step) => runBuildStep(step, rootPath, options)),
69
+ );
70
+ delete manifest.build;
71
+ }
72
+
50
73
  // Assets
51
74
  const assetsBundle = await bundleAssets(
52
75
  path.resolve(rootPath),
53
- manifest.assets as string[] || [],
76
+ (manifest.assets as string[]) || [],
54
77
  );
55
78
  manifest.assets = assetsBundle.toJSON();
56
79
 
@@ -63,34 +86,32 @@ export async function compileManifest(
63
86
  import { setupMessageListener } from "worker-runtime";
64
87
 
65
88
  // Imports
66
- ${
67
- Object.entries(manifest.functions).map(([funcName, def]) => {
68
- if (!def.path) {
69
- return "";
70
- }
71
- let [filePath, jsFunctionName] = def.path.split(":");
72
- // Resolve path
73
- filePath = path.join(rootPath, filePath);
74
-
75
- return `import {${jsFunctionName} as ${funcName}} from "${
76
- // Replacing \ with / for Windows
77
- path.resolve(filePath).replaceAll(
78
- "\\",
79
- "\\\\",
80
- )}";\n`;
81
- }).join("")
82
- }
89
+ ${Object.entries(manifest.functions)
90
+ .map(([funcName, def]) => {
91
+ if (!def.path) {
92
+ return "";
93
+ }
94
+ let [filePath, jsFunctionName] = def.path.split(":");
95
+ // Resolve path
96
+ filePath = path.join(rootPath, filePath);
97
+
98
+ return `import {${jsFunctionName} as ${funcName}} from "${
99
+ // Replacing \ with / for Windows
100
+ path.resolve(filePath).replaceAll("\\", "\\\\")
101
+ }";\n`;
102
+ })
103
+ .join("")}
83
104
 
84
105
  // Function mapping
85
106
  const functionMapping = {
86
- ${
87
- Object.entries(manifest.functions).map(([funcName, def]) => {
88
- if (!def.path) {
89
- return "";
90
- }
91
- return ` ${funcName}: ${funcName},\n`;
92
- }).join("")
93
- }
107
+ ${Object.entries(manifest.functions)
108
+ .map(([funcName, def]) => {
109
+ if (!def.path) {
110
+ return "";
111
+ }
112
+ return ` ${funcName}: ${funcName},\n`;
113
+ })
114
+ .join("")}
94
115
  };
95
116
 
96
117
  // Manifest
@@ -130,10 +151,10 @@ setupMessageListener(functionMapping, manifest, self.postMessage);
130
151
  let jsCode = await readFile(outFile, "utf-8");
131
152
  jsCode = patchBundledJS(jsCode);
132
153
  await writeFile(outFile, jsCode, "utf-8");
133
-
154
+
134
155
  // Clean up temp directory
135
156
  await rm(tempDir, { recursive: true, force: true });
136
-
157
+
137
158
  console.log(`Plug ${manifest.name} written to ${outFile}.`);
138
159
  return outFile;
139
160
  }
@@ -155,19 +176,17 @@ export async function compileManifests(
155
176
  await mkdir(dist, { recursive: true });
156
177
  const startTime = Date.now();
157
178
  // Build all plugs in parallel
158
- await Promise.all(manifestFiles.map(async (plugManifestPath) => {
159
- const manifestPath = plugManifestPath as string;
160
- try {
161
- await compileManifest(
162
- manifestPath,
163
- dist,
164
- options,
165
- );
166
- } catch (e: any) {
167
- console.error(`Error building ${manifestPath}:`, e.message);
168
- throw e;
169
- }
170
- }));
179
+ await Promise.all(
180
+ manifestFiles.map(async (plugManifestPath) => {
181
+ const manifestPath = plugManifestPath as string;
182
+ try {
183
+ await compileManifest(manifestPath, dist, options);
184
+ } catch (e: any) {
185
+ console.error(`Error building ${manifestPath}:`, e.message);
186
+ throw e;
187
+ }
188
+ }),
189
+ );
171
190
  console.log(`Done building plugs in ${Date.now() - startTime}ms`);
172
191
  building = false;
173
192
  }
@@ -175,27 +194,60 @@ export async function compileManifests(
175
194
  await buildAll();
176
195
  }
177
196
 
197
+ async function runBuildStep(
198
+ step: BuildStep,
199
+ rootPath: string,
200
+ options: CompileOptions,
201
+ ) {
202
+ const type = step.type ?? "esbuild";
203
+ const inFile = path.resolve(rootPath, step.in);
204
+ const outFile = path.resolve(rootPath, step.out);
205
+ await mkdir(path.dirname(outFile), { recursive: true });
206
+ if (type === "esbuild") {
207
+ await esbuild.build({
208
+ entryPoints: [inFile],
209
+ bundle: true,
210
+ format: "iife",
211
+ platform: "browser",
212
+ minify: !options.debug,
213
+ outfile: outFile,
214
+ treeShaking: true,
215
+ });
216
+ } else if (type === "sass") {
217
+ const scss = await readFile(inFile, "utf-8");
218
+ const result = sass.compileString(scss, {
219
+ loadPaths: [path.dirname(inFile)],
220
+ style: options.debug ? "expanded" : "compressed",
221
+ });
222
+ await writeFile(outFile, result.css, "utf-8");
223
+ } else if (type === "copy") {
224
+ await copyFile(inFile, outFile);
225
+ } else {
226
+ throw new Error(`Unsupported build step type: ${type}`);
227
+ }
228
+ }
229
+
178
230
  export function patchBundledJS(code: string): string {
179
231
  // One bundled dependency has a lookbehind regex that WebKit can't parse; replace it with a no-op
180
232
  return code.replaceAll("/(?<=\\n)/", "/()/");
181
233
  }
182
234
 
183
235
  export async function plugCompileCommand(
184
- { dist, debug, info }: {
236
+ {
237
+ dist,
238
+ debug,
239
+ info,
240
+ }: {
185
241
  dist: string;
186
242
  debug: boolean;
187
243
  info: boolean;
188
244
  },
189
245
  ...manifestPaths: string[]
190
246
  ) {
191
- await compileManifests(
192
- manifestPaths,
193
- dist,
194
- {
195
- debug: debug,
196
- info: info,
197
- },
198
- );
199
- esbuild.stop();
247
+ await compileManifests(manifestPaths, dist, {
248
+ debug: debug,
249
+ info: info,
250
+ });
251
+ await esbuild.stop();
200
252
  process.exit(0);
201
253
  }
@@ -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 due to TypeScript fetch type limitations
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,
@@ -2,8 +2,9 @@ import type { Manifest } from "../types.ts";
2
2
  import type { ControllerMessage, WorkerMessage } from "../protocol.ts";
3
3
  import type { Plug } from "../plug.ts";
4
4
  import { AssetBundle, type AssetJson } from "../../asset_bundle/bundle.ts";
5
- import type { Sandbox } from "./sandbox.ts";
5
+ import type { Sandbox, SandboxFactory } from "./sandbox.ts";
6
6
  import { race, timeout } from "@silverbulletmd/silverbullet/lib/async";
7
+ import { fsEndpoint } from "../../spaces/constants.ts";
7
8
 
8
9
  /**
9
10
  * Represents a "safe" execution environment for plug code
@@ -22,7 +23,15 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
22
23
  readonly plug: Plug<HookT>,
23
24
  public workerUrl: URL,
24
25
  private workerOptions = {},
25
- ) {
26
+ ) {}
27
+
28
+ /** Factory producing a WorkerSandbox for a plug file at a local space path. */
29
+ static forPath<HookT>(path: string): SandboxFactory<HookT> {
30
+ return (plug) =>
31
+ new WorkerSandbox(
32
+ plug,
33
+ new URL(path, `${document.baseURI.slice(0, -1) + fsEndpoint}/`),
34
+ );
26
35
  }
27
36
 
28
37
  /**
@@ -43,7 +52,7 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
43
52
  return race([
44
53
  // We're adding a timeout of 5s here to handle the case where a plug blows up during initialization
45
54
  timeout(5000).catch((_) =>
46
- Promise.reject(new Error("Plug timed out during creation"))
55
+ Promise.reject(new Error("Plug timed out during creation")),
47
56
  ),
48
57
  new Promise((resolve) => {
49
58
  this.worker!.onmessage = (ev) => {
@@ -54,13 +63,13 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
54
63
 
55
64
  // Set assets in the plug
56
65
  this.plug.assets = new AssetBundle(
57
- this.manifest?.assets ? this.manifest.assets as AssetJson : {},
66
+ this.manifest?.assets ? (this.manifest.assets as AssetJson) : {},
58
67
  );
59
68
 
60
69
  return resolve();
61
70
  }
62
71
 
63
- this.onMessage(ev.data);
72
+ void this.onMessage(ev.data);
64
73
  };
65
74
  }),
66
75
  ]);
@@ -76,18 +85,20 @@ export class WorkerSandbox<HookT> implements Sandbox<HookT> {
76
85
  try {
77
86
  const result = await this.plug.syscall(data.name!, data.args!);
78
87
 
79
- this.worker && this.worker!.postMessage({
80
- type: "sysr",
81
- id: data.id,
82
- result: result,
83
- } as WorkerMessage);
88
+ this.worker &&
89
+ this.worker!.postMessage({
90
+ type: "sysr",
91
+ id: data.id,
92
+ result: result,
93
+ } as WorkerMessage);
84
94
  } catch (e: any) {
85
95
  // 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);
96
+ this.worker &&
97
+ this.worker!.postMessage({
98
+ type: "sysr",
99
+ id: data.id,
100
+ error: e.message,
101
+ } as WorkerMessage);
91
102
  }
92
103
  break;
93
104
  case "invr": {
@@ -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
  }
@@ -1,6 +1,7 @@
1
1
  import type { SysCallMapping } from "../system.ts";
2
2
  import type { Config } from "../../config.ts";
3
3
  import { LuaStackFrame, luaValueToJS } from "../../space_lua/runtime.ts";
4
+ import { stripFunctions } from "../util.ts";
4
5
 
5
6
  export function configSyscalls(config: Config): SysCallMapping {
6
7
  return {
@@ -23,11 +24,7 @@ export function configSyscalls(config: Config): SysCallMapping {
23
24
  keyOrValues = await luaValueToJS(keyOrValues, LuaStackFrame.lostFrame);
24
25
  config.set(keyOrValues as any, value);
25
26
  },
26
- "config.insert": (
27
- _ctx,
28
- key: string | string[],
29
- value: any,
30
- ) => {
27
+ "config.insert": (_ctx, key: string | string[], value: any) => {
31
28
  config.insert(key, value);
32
29
  },
33
30
  "config.has": (_ctx, path: string) => {
@@ -36,11 +33,17 @@ export function configSyscalls(config: Config): SysCallMapping {
36
33
  "config.define": (_ctx, key: string, schema: any) => {
37
34
  config.define(key, schema);
38
35
  },
36
+ "config.defineCategory": (_ctx, definition: any) => {
37
+ config.defineCategory(definition);
38
+ },
39
39
  "config.getValues": () => {
40
- return config.values;
40
+ return stripFunctions(config.values);
41
41
  },
42
42
  "config.getSchemas": () => {
43
- return config.schemas;
43
+ return stripFunctions(config.schemas);
44
+ },
45
+ "config.getCategories": () => {
46
+ return { ...config.categories };
44
47
  },
45
48
  };
46
49
  }
@@ -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
  };