@silverbulletmd/silverbullet 2.9.0 → 2.11.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 (123) hide show
  1. package/README.md +38 -25
  2. package/client/asset_bundle/bundle.ts +0 -1
  3. package/client/config.ts +343 -0
  4. package/client/markdown_parser/constants.ts +3 -1
  5. package/client/plugos/hooks/command.ts +0 -5
  6. package/client/plugos/hooks/event.ts +0 -6
  7. package/client/plugos/hooks/mq.ts +0 -3
  8. package/client/plugos/hooks/slash_command.ts +1 -7
  9. package/client/plugos/hooks/syscall.ts +24 -14
  10. package/client/plugos/manifest_cache.ts +0 -32
  11. package/client/plugos/plug.ts +0 -3
  12. package/client/plugos/plug_compile.ts +3 -13
  13. package/client/plugos/sandboxes/worker_sandbox.ts +19 -9
  14. package/client/plugos/syscalls/asset.ts +61 -23
  15. package/client/plugos/syscalls/clientStore.ts +32 -6
  16. package/client/plugos/syscalls/client_code_widget.ts +9 -4
  17. package/client/plugos/syscalls/code_widget.ts +26 -11
  18. package/client/plugos/syscalls/config.ts +146 -30
  19. package/client/plugos/syscalls/datastore.ts +146 -40
  20. package/client/plugos/syscalls/editor.ts +1518 -722
  21. package/client/plugos/syscalls/event.ts +44 -13
  22. package/client/plugos/syscalls/fetch.ts +120 -83
  23. package/client/plugos/syscalls/icon.ts +46 -0
  24. package/client/plugos/syscalls/index.ts +267 -121
  25. package/client/plugos/syscalls/jsonschema.ts +107 -9
  26. package/client/plugos/syscalls/language.ts +38 -12
  27. package/client/plugos/syscalls/markdown.ts +166 -50
  28. package/client/plugos/syscalls/mq.ts +92 -20
  29. package/client/plugos/syscalls/navigator.ts +143 -0
  30. package/client/plugos/syscalls/schema_introspection.ts +33 -0
  31. package/client/plugos/syscalls/search.ts +44 -0
  32. package/client/plugos/syscalls/service_registry.ts +74 -20
  33. package/client/plugos/syscalls/shell.ts +51 -21
  34. package/client/plugos/syscalls/space.ts +412 -113
  35. package/client/plugos/syscalls/sync.ts +103 -20
  36. package/client/plugos/syscalls/system.ts +274 -139
  37. package/client/plugos/system.ts +28 -10
  38. package/client/plugos/worker_runtime.ts +0 -2
  39. package/client/space_lua/aggregates.ts +0 -16
  40. package/client/space_lua/api_documentation.ts +107 -0
  41. package/client/space_lua/ast.ts +13 -5
  42. package/client/space_lua/ast_narrow.ts +0 -5
  43. package/client/space_lua/budget.ts +113 -0
  44. package/client/space_lua/budget_ui.ts +49 -0
  45. package/client/space_lua/eval.ts +125 -92
  46. package/client/space_lua/labels.ts +0 -4
  47. package/client/space_lua/numeric.ts +0 -5
  48. package/client/space_lua/parse.ts +243 -125
  49. package/client/space_lua/pretty_print.ts +128 -54
  50. package/client/space_lua/quarantine.ts +127 -0
  51. package/client/space_lua/query_collection.ts +7 -51
  52. package/client/space_lua/query_env.ts +0 -2
  53. package/client/space_lua/render_lua_markdown.ts +2 -7
  54. package/client/space_lua/render_widget.ts +173 -0
  55. package/client/space_lua/runtime.ts +133 -92
  56. package/client/space_lua/stdlib/crypto.ts +8 -3
  57. package/client/space_lua/stdlib/encoding.ts +27 -9
  58. package/client/space_lua/stdlib/format.ts +0 -12
  59. package/client/space_lua/stdlib/js.ts +136 -23
  60. package/client/space_lua/stdlib/load.ts +24 -16
  61. package/client/space_lua/stdlib/math.ts +331 -133
  62. package/client/space_lua/stdlib/net.ts +57 -13
  63. package/client/space_lua/stdlib/os.ts +111 -54
  64. package/client/space_lua/stdlib/pattern.ts +10 -15
  65. package/client/space_lua/stdlib/space_lua.ts +344 -21
  66. package/client/space_lua/stdlib/string.ts +282 -104
  67. package/client/space_lua/stdlib/string_pack.ts +58 -22
  68. package/client/space_lua/stdlib/table.ts +195 -45
  69. package/client/space_lua/stdlib.ts +354 -125
  70. package/client/space_lua/syscalls.ts +270 -0
  71. package/client/space_lua/tonumber.ts +0 -9
  72. package/dist/plug-compile.js +2 -3
  73. package/package.json +15 -5
  74. package/plug-api/lib/async.ts +1 -6
  75. package/plug-api/lib/collation.ts +22 -0
  76. package/plug-api/lib/crypto.ts +16 -15
  77. package/plug-api/lib/dates.ts +33 -0
  78. package/plug-api/lib/fuzzy.ts +282 -0
  79. package/plug-api/lib/json.ts +0 -6
  80. package/plug-api/lib/limited_map.ts +0 -2
  81. package/plug-api/lib/link_write.ts +27 -0
  82. package/plug-api/{ui → lib}/panel_styles.ts +4 -3
  83. package/plug-api/lib/ref.ts +124 -5
  84. package/plug-api/lib/resolve.ts +0 -1
  85. package/plug-api/lib/resolve_path.ts +290 -0
  86. package/plug-api/lib/shortcut.ts +17 -1
  87. package/plug-api/lib/tags.ts +0 -3
  88. package/plug-api/lib/transclusion.ts +28 -1
  89. package/plug-api/lib/tree.ts +0 -5
  90. package/plug-api/lib/yaml.ts +3 -42
  91. package/plug-api/syscall.ts +1 -5
  92. package/plug-api/syscalls/config.ts +7 -5
  93. package/plug-api/syscalls/editor.ts +70 -208
  94. package/plug-api/syscalls/icon.ts +18 -0
  95. package/plug-api/syscalls/index.ts +39 -5
  96. package/plug-api/syscalls/jsonschema.ts +9 -0
  97. package/plug-api/syscalls/lua.ts +7 -0
  98. package/plug-api/syscalls/search.ts +11 -0
  99. package/plug-api/syscalls/shell.ts +0 -1
  100. package/plug-api/syscalls/space.ts +122 -5
  101. package/plug-api/syscalls/sync.ts +23 -2
  102. package/plug-api/syscalls/system.ts +53 -0
  103. package/plug-api/syscalls.ts +2 -0
  104. package/plug-api/system_mock.ts +15 -2
  105. package/plug-api/types/client.ts +4 -3
  106. package/plug-api/types/datastore.ts +11 -2
  107. package/plug-api/types/index.ts +62 -1
  108. package/plug-api/types/manifest.ts +22 -4
  109. package/plug-api/types/profile.ts +13 -0
  110. package/plug-api/types/revisions.ts +67 -0
  111. package/plug-api/ui/cx.ts +1 -3
  112. package/plug-api/ui/description.ts +64 -0
  113. package/plug-api/ui/hover.ts +69 -0
  114. package/plug-api/ui/index.ts +61 -2
  115. package/plug-api/ui/scroll.ts +30 -0
  116. package/plug-api/ui/slugify.ts +44 -0
  117. package/plug-api/ui/tree_model.ts +263 -0
  118. package/plug-api/ui/tree_types.ts +66 -0
  119. package/plug-api/ui/use_fit_collapse.ts +67 -0
  120. package/plugs/builtin_plugs.ts +0 -1
  121. package/plugs/index/types.ts +9 -0
  122. package/client/plugos/syscalls/lua.ts +0 -81
  123. package/plug-api/lib/memory_cache.ts +0 -21
@@ -1,8 +1,13 @@
1
- import type { SysCallMapping } from "../system.ts";
2
1
  import type { Client } from "../../client.ts";
2
+ import type { SysCallMapping } from "../system.ts";
3
3
 
4
4
  export function syncSyscalls(client: Client): SysCallMapping {
5
5
  const syncTimeoutMs = 30000;
6
+ // Deferring indexing only pays off while the sync engine is actually
7
+ // delivering files. Once it has gone this long without reporting progress
8
+ // there is nothing left to yield to, and continuing to defer would stall
9
+ // the initial index forever.
10
+ const syncStallMs = 5000;
6
11
 
7
12
  function waitForServiceWorkerActivation(path?: string): Promise<any> {
8
13
  return new Promise<any>((resolve, reject) => {
@@ -60,27 +65,105 @@ export function syncSyscalls(client: Client): SysCallMapping {
60
65
  }
61
66
 
62
67
  return {
63
- "sync.hasInitialSyncCompleted": (): boolean => {
64
- return client.fullSyncCompleted;
68
+ "sync.hasInitialSyncCompleted": {
69
+ callback: (): boolean => {
70
+ return client.fullSyncCompleted;
71
+ },
72
+ description:
73
+ "Checks whether the initial client synchronization has completed.",
74
+ returns: [
75
+ { type: "boolean", description: "Whether initial sync is complete." },
76
+ ],
65
77
  },
66
- "sync.performFileSync": async (_ctx, path: string): Promise<void> => {
67
- await client.postServiceWorkerMessage({
68
- type: "perform-file-sync",
69
- path,
70
- });
71
- // postServiceWorkerMessage returns silently if no SW, so only wait if SW is active
72
- const registration = await navigator.serviceWorker.getRegistration();
73
- if (registration?.active) {
74
- return waitForServiceWorkerActivation(path);
75
- }
78
+ "sync.areFilesReadyToIndex": {
79
+ callback: (_ctx, paths: string[]): boolean[] => {
80
+ const allReady =
81
+ !!client.bootConfig.disableServiceWorker ||
82
+ client.fullSyncCompleted ||
83
+ client.fullIndexCompleted ||
84
+ (client.serverPingMs !== undefined && client.serverPingMs < 25) ||
85
+ Date.now() - client.lastSyncProgressAt > syncStallMs;
86
+ return paths.map((path) => allReady || client.syncedPaths.has(path));
87
+ },
88
+ description:
89
+ "For each file, whether indexing it now would read it locally or cheaply (true), or race the initial sync and expensively re-download it (false).",
90
+ parameters: [
91
+ {
92
+ name: "paths",
93
+ type: "string[]",
94
+ description: "Space-relative file paths.",
95
+ },
96
+ ],
97
+ returns: [
98
+ {
99
+ type: "boolean[]",
100
+ description: "Per-path readiness, in input order.",
101
+ },
102
+ ],
76
103
  },
77
- "sync.performSpaceSync": async (): Promise<number> => {
78
- await client.postServiceWorkerMessage({ type: "perform-space-sync" });
79
- const registration = await navigator.serviceWorker.getRegistration();
80
- if (registration?.active) {
81
- return waitForServiceWorkerActivation();
82
- }
83
- return 0;
104
+ "sync.performFileSync": {
105
+ callback: async (
106
+ _ctx,
107
+ path: string,
108
+ remoteLastModified?: number,
109
+ remoteRevisionHash?: string,
110
+ ): Promise<void> => {
111
+ await client.postServiceWorkerMessage({
112
+ type: "perform-file-sync",
113
+ path,
114
+ remoteLastModified,
115
+ remoteRevisionHash,
116
+ });
117
+ // postServiceWorkerMessage returns silently if no SW, so only wait if SW is active
118
+ const registration = await navigator.serviceWorker?.getRegistration();
119
+ if (registration?.active) {
120
+ return waitForServiceWorkerActivation(path);
121
+ }
122
+ },
123
+ description:
124
+ "Prioritizes a file for immediate synchronization and waits for completion.",
125
+ parameters: [
126
+ {
127
+ name: "path",
128
+ type: "string",
129
+ description: "Space-relative file path.",
130
+ },
131
+ {
132
+ name: "remoteLastModified",
133
+ type: "number",
134
+ optional: true,
135
+ description:
136
+ "lastModified of the remote change event, used for echo suppression.",
137
+ },
138
+ {
139
+ name: "remoteRevisionHash",
140
+ type: "string",
141
+ optional: true,
142
+ description:
143
+ "Content revision the remote change event reported, which tells a same-millisecond change from an echo.",
144
+ },
145
+ ],
146
+ examples: [{ code: 'sync.performFileSync("notes/important.md")' }],
147
+ },
148
+ "sync.performSpaceSync": {
149
+ callback: async (): Promise<number> => {
150
+ await client.postServiceWorkerMessage({ type: "perform-space-sync" });
151
+ const registration = await navigator.serviceWorker?.getRegistration();
152
+ if (registration?.active) {
153
+ return waitForServiceWorkerActivation();
154
+ }
155
+ return 0;
156
+ },
157
+ description:
158
+ "Starts an immediate full-space synchronization and waits for completion.",
159
+ returns: [
160
+ {
161
+ type: "number",
162
+ description:
163
+ "Number of sync operations, or zero without an active worker.",
164
+ },
165
+ ],
166
+ examples: [{ code: "local changes = sync.performSpaceSync()" }],
84
167
  },
85
168
  };
86
169
  }
@@ -1,161 +1,296 @@
1
1
  import type { SysCallMapping } from "../system.ts";
2
2
  import type { Client } from "../../client.ts";
3
- import { publicVersion } from "../../../public_version.ts";
3
+ import { version as publicVersion } from "../../../version.json";
4
4
  import type { CommandDef } from "@silverbulletmd/silverbullet/type/manifest";
5
5
  import type { SyscallMeta } from "@silverbulletmd/silverbullet/type/index";
6
+ import { loadAccounts, loadProfile } from "../../accounts.ts";
7
+ import type {
8
+ Account,
9
+ ClientProfile,
10
+ } from "../../../plug-api/types/profile.ts";
6
11
 
7
12
  export function systemSyscalls(
8
13
  client: Client,
9
14
  readOnlyMode: boolean,
10
15
  ): SysCallMapping {
11
16
  const api: SysCallMapping = {
12
- "system.invokeFunction": (
13
- _ctx,
14
- fullName: string, // plug.function
15
- ...args: any[]
16
- ) => {
17
- const [plugName, functionName] = fullName.split(".");
18
- if (!plugName || !functionName) {
19
- throw Error(`Invalid function name ${fullName}`);
20
- }
21
- const plug = client.clientSystem.system.loadedPlugs.get(plugName);
22
- if (!plug) {
23
- throw Error(`Plug ${plugName} not found`);
24
- }
25
- const functionDef = plug.manifest!.functions[functionName];
26
- if (!functionDef) {
27
- throw Error(`Function ${functionName} not found`);
28
- }
29
- return plug.invoke(functionName, args);
30
- },
31
- "system.invokeFunctionOnServer": (
32
- ctx,
33
- fullName: string, // plug.function
34
- ...args: any[]
35
- ) => {
36
- console.warn(
37
- "Calling deprecated system.invokeFunctionOnServer, use system.invokeFunction instead",
38
- );
39
- return api["system.invokeFunction"](ctx, fullName, ...args);
40
- },
41
- "system.serverSyscall": (_ctx, name: string, ...args: any[]) => {
42
- console.warn(
43
- "Calling deprecated system.serverSyscall, use syscall instead",
44
- );
45
- return client.clientSystem.localSyscall(name, args);
46
- },
47
- "system.invokeCommand": (_ctx, name: string, args?: string[]) => {
48
- console.warn("Deprecated, use editor.invokeCommand instead");
49
- return client.runCommandByName(name, args);
50
- },
51
- "system.listCommands": (): { [key: string]: CommandDef } => {
52
- const commandHook = client.clientSystem.commandHook;
53
- const allCommands: { [key: string]: CommandDef } = {};
54
- for (const [cmd, def] of commandHook.buildAllCommands()) {
55
- allCommands[cmd] = {
56
- name: def.name,
57
- contexts: def.contexts,
58
- priority: def.priority,
59
- key: def.key,
60
- mac: def.mac,
61
- hide: def.hide,
62
- requireMode: def.requireMode,
63
- requireEditor: def.requireEditor,
64
- menu: def.menu,
65
- menuMac: def.menuMac,
66
- menuWindows: def.menuWindows,
67
- menuLinux: def.menuLinux,
68
- };
69
- }
70
- return allCommands;
71
- },
72
- "system.listSyscalls": (): SyscallMeta[] => {
73
- const syscalls: SyscallMeta[] = [];
74
- for (const [name, info] of client.clientSystem.system
75
- .registeredSyscalls) {
76
- syscalls.push({
77
- name,
78
- requiredPermissions: info.requiredPermissions,
79
- argCount: Math.max(0, info.callback.length - 1),
80
- });
81
- }
82
- return syscalls;
83
- },
84
- "system.reloadPlugs": () => {
85
- if (!client) {
86
- throw new Error("Not supported");
87
- }
88
- return client.loadPlugs();
89
- },
90
- "system.loadPlug": async (_ctx, path: string) => {
91
- const meta = await client.space.spacePrimitives.getFileMeta(path);
92
- await client.clientSystem.loadPlugFromPath(path, meta.lastModified);
93
- await client.dispatchAppEvent("plugs:loaded");
94
- },
95
- "system.unloadPlug": (_ctx, path: string) => {
96
- return client.clientSystem.system.unloadByPath(path);
97
- },
98
- "system.reloadConfig": (): Record<string, any> => {
99
- console.warn("system.reloadConfig is deprecated, it's now a no-op");
100
- return client.config.values;
101
- },
102
- "system.loadSpaceScripts": async () => {
103
- console.warn("DEPRECATED: used system.loadScripts instead");
104
- await client.clientSystem.loadLuaScripts();
105
- },
106
- "system.loadScripts": async () => {
107
- await client.clientSystem.loadLuaScripts();
108
- },
109
- "system.loadSpaceStyles": async () => {
110
- if (!client) {
111
- throw new Error("Not supported on server");
112
- }
113
- await client.loadCustomStyles();
114
- },
115
- "system.wipeClient": async (_ctx, logout = false) => {
116
- await client.wipeClient();
117
- if (logout) {
118
- location.href = ".logout";
119
- } else {
120
- alert("Client wiped, feel free to navigate elsewhere");
121
- }
17
+ "system.invokeFunction": {
18
+ callback: (
19
+ _ctx,
20
+ fullName: string, // plug.function
21
+ ...args: any[]
22
+ ) => {
23
+ const [plugName, functionName] = fullName.split(".");
24
+ if (!plugName || !functionName) {
25
+ throw Error(`Invalid function name ${fullName}`);
26
+ }
27
+ const plug = client.clientSystem.system.loadedPlugs.get(plugName);
28
+ if (!plug) {
29
+ throw Error(`Plug ${plugName} not found`);
30
+ }
31
+ const functionDef = plug.manifest!.functions[functionName];
32
+ if (!functionDef) {
33
+ throw Error(`Function ${functionName} not found`);
34
+ }
35
+ return plug.invoke(functionName, args);
36
+ },
37
+ description: "Invokes a loaded plug function by its plug-qualified name.",
38
+ signatures: ["system.invokeFunction(name, ...)"],
39
+ },
40
+ "system.invokeFunctionOnServer": {
41
+ callback: (
42
+ ctx,
43
+ fullName: string, // plug.function
44
+ ...args: any[]
45
+ ) => {
46
+ console.warn(
47
+ "Calling deprecated system.invokeFunctionOnServer, use system.invokeFunction instead",
48
+ );
49
+ const registration = api["system.invokeFunction"];
50
+ const invokeFunction =
51
+ typeof registration === "function"
52
+ ? registration
53
+ : registration.callback;
54
+ return invokeFunction(ctx, fullName, ...args);
55
+ },
56
+ description: "Deprecated alias for system.invokeFunction.",
57
+ deprecated: "Use system.invokeFunction instead.",
58
+ signatures: ["system.invokeFunctionOnServer(name, ...)"],
59
+ },
60
+ "system.serverSyscall": {
61
+ callback: (_ctx, name: string, ...args: any[]) => {
62
+ console.warn(
63
+ "Calling deprecated system.serverSyscall, use syscall instead",
64
+ );
65
+ return client.clientSystem.localSyscall(name, args);
66
+ },
67
+ description: "Deprecated helper for invoking a named syscall.",
68
+ deprecated: "Invoke the target syscall directly instead.",
69
+ signatures: ["system.serverSyscall(name, ...)"],
70
+ },
71
+ "system.invokeCommand": {
72
+ callback: (_ctx, name: string, args?: string[]) => {
73
+ console.warn("Deprecated, use editor.invokeCommand instead");
74
+ return client.runCommandByName(name, args);
75
+ },
76
+ description: "Deprecated alias for editor.invokeCommand.",
77
+ deprecated: "Use editor.invokeCommand instead.",
78
+ signatures: ["system.invokeCommand(name, args?)"],
79
+ },
80
+ "system.listCommands": {
81
+ callback: (): { [key: string]: CommandDef } => {
82
+ const commandHook = client.clientSystem.commandHook;
83
+ const allCommands: { [key: string]: CommandDef } = {};
84
+ for (const [cmd, def] of commandHook.buildAllCommands()) {
85
+ allCommands[cmd] = {
86
+ name: def.name,
87
+ contexts: def.contexts,
88
+ priority: def.priority,
89
+ key: def.key,
90
+ mac: def.mac,
91
+ hide: def.hide,
92
+ requireMode: def.requireMode,
93
+ requireEditor: def.requireEditor,
94
+ menu: def.menu,
95
+ menuMac: def.menuMac,
96
+ menuWindows: def.menuWindows,
97
+ menuLinux: def.menuLinux,
98
+ };
99
+ }
100
+ return allCommands;
101
+ },
102
+ description:
103
+ "Returns a map of every currently available command definition.",
104
+ },
105
+ "system.listPaletteCommands": {
106
+ callback: () => client.listPaletteCommands(),
107
+ description: `Returns the commands the command palette would show right now: context- and mode-filtered, hidden ones dropped, each with its prettified key hint and the time it was last run on this client.`,
108
+ signatures: ["system.listPaletteCommands()"],
109
+ },
110
+ "system.runPaletteCommand": {
111
+ callback: async (_ctx, name: string) => {
112
+ await client.registerCommandRun(name);
113
+ try {
114
+ return await client.runCommandByName(name);
115
+ } catch (e: any) {
116
+ client.reportError(e, "Command invocation");
117
+ return false;
118
+ }
119
+ },
120
+ description: `Runs a command as if it had been picked from the command palette: records it as the most recently run, then invokes it and returns its result. A command that throws is reported to the user and answered as false, which in this protocol means "do not move focus on my behalf".`,
121
+ parameters: [
122
+ { name: "name", type: "string", description: "Command name." },
123
+ ],
124
+ returns: [{ description: "Whatever the command returned." }],
125
+ },
126
+ "system.listSyscalls": {
127
+ callback: (): SyscallMeta[] => {
128
+ const syscalls: SyscallMeta[] = [];
129
+ for (const [name, info] of client.clientSystem.system
130
+ .registeredSyscalls) {
131
+ const { callback, requiredPermissions, ...metadata } = info;
132
+ syscalls.push({
133
+ name,
134
+ requiredPermissions,
135
+ argCount: Math.max(0, callback.length - 1),
136
+ ...metadata,
137
+ });
138
+ }
139
+ return syscalls;
140
+ },
141
+ description:
142
+ "Lists registered syscalls with permissions, argument counts, and documentation metadata.",
143
+ },
144
+ "system.reloadPlugs": {
145
+ callback: () => {
146
+ if (!client) {
147
+ throw new Error("Not supported");
148
+ }
149
+ return client.loadPlugs();
150
+ },
151
+ description: "Reloads every plug available to the client.",
152
+ },
153
+ "system.reboot": {
154
+ callback: async () => {
155
+ await client.save(true);
156
+ await client.eventedSpacePrimitives.fetchFileListWhenIdle();
157
+ await client.mq.awaitEmptyQueue("indexQueue");
158
+ await client.clientSystem.reloadState();
159
+ },
160
+ description:
161
+ "Saves the current editor buffer, detects on-disk changes, waits for indexing, and reloads configuration, scripts, styles, and client state. Because the buffer is saved first, an external edit to the currently open page can be overwritten; edit that page through the editor or navigate away first.",
162
+ },
163
+ "system.loadPlug": {
164
+ callback: async (_ctx, path: string) => {
165
+ const meta = await client.space.spacePrimitives.getFileMeta(path);
166
+ await client.clientSystem.loadPlugFromPath(path, meta.lastModified);
167
+ await client.dispatchAppEvent("plugs:loaded");
168
+ },
169
+ description: "Loads or reloads one plug from a space file path.",
170
+ signatures: ["system.loadPlug(path)"],
171
+ },
172
+ "system.unloadPlug": {
173
+ callback: (_ctx, path: string) =>
174
+ client.clientSystem.system.unloadByPath(path),
175
+ description: "Unloads the plug loaded from a space file path.",
176
+ signatures: ["system.unloadPlug(path)"],
177
+ },
178
+ "system.reloadConfig": {
179
+ callback: (): Record<string, any> => {
180
+ console.warn("system.reloadConfig is deprecated, it's now a no-op");
181
+ return client.config.values;
182
+ },
183
+ description: "Deprecated no-op that returns the current configuration.",
184
+ deprecated:
185
+ "Configuration reloads automatically; use system.reboot when needed.",
186
+ },
187
+ "system.loadSpaceScripts": {
188
+ callback: async () => {
189
+ console.warn("DEPRECATED: used system.loadScripts instead");
190
+ await client.clientSystem.loadLuaScripts();
191
+ },
192
+ description: "Deprecated alias for system.loadScripts.",
193
+ deprecated: "Use system.loadScripts instead.",
194
+ },
195
+ "system.loadScripts": {
196
+ callback: async () => {
197
+ await client.clientSystem.loadLuaScripts();
198
+ },
199
+ description: "Reloads Space Lua scripts and configuration.",
200
+ },
201
+ "system.loadSpaceStyles": {
202
+ callback: async () => {
203
+ if (!client) {
204
+ throw new Error("Not supported on server");
205
+ }
206
+ await client.loadCustomStyles();
207
+ },
208
+ description: "Reloads custom Space Style definitions.",
209
+ },
210
+ "system.wipeClient": {
211
+ callback: async (_ctx, logout = false) => {
212
+ await client.wipeClient();
213
+ if (logout) {
214
+ location.href = ".logout";
215
+ } else {
216
+ alert("Client wiped, feel free to navigate elsewhere");
217
+ }
218
+ },
219
+ description:
220
+ "Wipes local client state, cached files, databases, and optionally the login session.",
221
+ signatures: ["system.wipeClient(logout?)"],
122
222
  },
123
223
  // DEPRECATED
124
- "system.cleanDatabases": (): boolean => {
125
- console.warn(
126
- "system.cleanDatabses is deprecated, use Client: Wipe instead",
127
- );
128
- return false;
224
+ "system.cleanDatabases": {
225
+ callback: (): boolean => {
226
+ console.warn(
227
+ "system.cleanDatabses is deprecated, use Client: Wipe instead",
228
+ );
229
+ return false;
230
+ },
231
+ description: "Deprecated no-op retained for compatibility.",
232
+ deprecated: "Use system.wipeClient or the Client: Wipe command instead.",
129
233
  },
130
- "system.getMode": () => {
131
- return readOnlyMode ? "ro" : "rw";
234
+ "system.getMode": {
235
+ callback: () => (readOnlyMode ? "ro" : "rw"),
236
+ description: "Returns rw for read-write mode or ro for read-only mode.",
132
237
  },
133
- "system.getURLPrefix": () => {
134
- const url = new URL(document.baseURI);
135
-
136
- return url.pathname;
238
+ "system.getURLPrefix": {
239
+ callback: () => {
240
+ const url = new URL(document.baseURI);
241
+ return url.pathname;
242
+ },
243
+ description:
244
+ "Returns the configured URL path prefix for this SilverBullet instance.",
245
+ },
246
+ "system.getBaseURI": {
247
+ callback: () => document.baseURI,
248
+ description:
249
+ "Returns the browser base URI for this SilverBullet instance.",
137
250
  },
138
- "system.getBaseURI": () => {
139
- return document.baseURI;
251
+ "system.getVersion": {
252
+ callback: () => publicVersion,
253
+ description: "Returns the running SilverBullet version.",
140
254
  },
141
- "system.getVersion": () => {
142
- return publicVersion;
255
+ "system.getProfile": {
256
+ callback: (): Promise<ClientProfile> => loadProfile(client),
257
+ description:
258
+ 'The current user\'s identity. `username` is "me" when the server has no account for this session.',
259
+ signatures: ["system.getProfile()"],
143
260
  },
144
- "system.getConfig": (_ctx, key: string, defaultValue: any = undefined) => {
145
- return client.config.get(key, defaultValue);
261
+ "system.listAccounts": {
262
+ callback: (): Promise<Account[]> => loadAccounts(client),
263
+ description:
264
+ "Every account with access to this space, with the current user marked.",
265
+ signatures: ["system.listAccounts()"],
266
+ },
267
+ "system.getConfig": {
268
+ callback: (_ctx, key: string, defaultValue: any = undefined) =>
269
+ client.config.get(key, defaultValue),
270
+ description: "Returns a configuration value, with an optional default.",
271
+ signatures: ["system.getConfig(key, defaultValue?)"],
146
272
  },
147
273
  // DEPRECATED
148
- "system.getEnv": () => {
149
- console.warn(
150
- "system.getEnv is deprecated, you can assume the env to always be the client",
151
- );
152
- return null;
153
- },
154
- "system.getSpaceConfig": (_ctx, key, defaultValue?) => {
155
- console.warn(
156
- "system.getSpaceConfig is deprecated, use system.getConfig instead",
157
- );
158
- return client.config.get(key, defaultValue);
274
+ "system.getEnv": {
275
+ callback: () => {
276
+ console.warn(
277
+ "system.getEnv is deprecated, you can assume the env to always be the client",
278
+ );
279
+ return null;
280
+ },
281
+ description: "Deprecated environment probe that always returns nil.",
282
+ deprecated: "The environment is always the client.",
283
+ },
284
+ "system.getSpaceConfig": {
285
+ callback: (_ctx, key, defaultValue?) => {
286
+ console.warn(
287
+ "system.getSpaceConfig is deprecated, use system.getConfig instead",
288
+ );
289
+ return client.config.get(key, defaultValue);
290
+ },
291
+ description: "Deprecated alias for system.getConfig.",
292
+ deprecated: "Use system.getConfig instead.",
293
+ signatures: ["system.getSpaceConfig(key, defaultValue?)"],
159
294
  },
160
295
  };
161
296
  return api;