@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
@@ -99,8 +99,7 @@ export type Classified =
99
99
  headers: string[];
100
100
  rowCount: number;
101
101
  getCell: (rowIndex: number, header: string) => any;
102
- // LuaTable record-arrays are historically tagged as "list", while
103
- // JS record-arrays are tagged as "table". Preserved for compatibility.
102
+ // Compatibility contract: LuaTable record-arrays use "list"; JS arrays use "table".
104
103
  dataType: "table" | "list";
105
104
  }
106
105
  | { kind: "scalarArray"; items: any[]; dataType: "list" };
@@ -138,7 +137,6 @@ export function classifyResult(result: any): Classified {
138
137
  const arrayLen = result.length;
139
138
  const hasStrKeys = keys.some((k) => typeof k === "string");
140
139
 
141
- // Pure array
142
140
  if (arrayLen > 0 && !hasStrKeys) {
143
141
  const elements: any[] = [];
144
142
  for (let i = 1; i <= arrayLen; i++) elements.push(result.rawGet(i));
@@ -162,7 +160,6 @@ export function classifyResult(result: any): Classified {
162
160
  return { kind: "scalarArray", items: elements, dataType: "list" };
163
161
  }
164
162
 
165
- // Has string keys (record or mixed) — single-row table
166
163
  const headers = keys.map(String);
167
164
  return {
168
165
  kind: "record",
@@ -267,9 +264,7 @@ export function renderResultToMarkdown(
267
264
  /**
268
265
  * Cell transformer for the clean-markdown (copy) path. Renders:
269
266
  * - `ref` columns as wiki links,
270
- * - scalar arrays as `<br/>`-joined lines (mirrors the HTML display
271
- * path, and relies on the markdown renderer now handling self-closing
272
- * `<br/>` inside GFM table cells),
267
+ * - scalar arrays as `<br/>`-joined lines inside GFM table cells,
273
268
  * - everything else via `defaultTransformer` (which Lua-encodes nested
274
269
  * tables and escapes pipes for scalars).
275
270
  */
@@ -0,0 +1,173 @@
1
+ import type { ASTCtx } from "./ast.ts";
2
+ import { evalExpression } from "./eval.ts";
3
+ import { parseExpressionString } from "./parse.ts";
4
+ import {
5
+ type ILuaFunction,
6
+ LuaEnv,
7
+ LuaRuntimeError,
8
+ LuaStackFrame,
9
+ LuaTable,
10
+ type LuaValue,
11
+ luaValueToJS,
12
+ singleResult,
13
+ } from "./runtime.ts";
14
+ import {
15
+ BUSY_LIMIT_DEFAULT_MS,
16
+ LuaBudgetStopped,
17
+ makeLuaBudget,
18
+ } from "./budget.ts";
19
+ import { isTaggedFloat } from "./numeric.ts";
20
+ import {
21
+ encodeRef,
22
+ getNameFromPath,
23
+ } from "@silverbulletmd/silverbullet/lib/ref";
24
+ import { resolveASTReference } from "../space_lua.ts";
25
+ import type { Client } from "../client.ts";
26
+ import { isViewValue } from "../navigator/view_value.ts";
27
+ import {
28
+ classifyResult,
29
+ renderResultToCleanMarkdown,
30
+ } from "./render_lua_markdown.ts";
31
+
32
+ /**
33
+ * Run a Space Lua computation and convert its result into something the
34
+ * LuaWidget renderer understands (a widget table, markdown string, or number).
35
+ * Shared by the `${...}` directive and Lua code widgets so the conversion +
36
+ * error formatting live in one place.
37
+ */
38
+ export async function renderLuaWidgetResult(
39
+ client: Client,
40
+ compute: (env: LuaEnv, sf: LuaStackFrame) => Promise<LuaValue> | LuaValue,
41
+ ctx: ASTCtx,
42
+ currentPageMeta?: { name: string } | undefined,
43
+ ): Promise<any> {
44
+ try {
45
+ const tl = new LuaEnv();
46
+ tl.setLocal(
47
+ "currentPage",
48
+ currentPageMeta ||
49
+ (client.ui.viewState.current
50
+ ? { name: getNameFromPath(client.ui.viewState.current.path) }
51
+ : undefined),
52
+ );
53
+ const sf = LuaStackFrame.createWithGlobalEnv(
54
+ client.clientSystem.spaceLuaEnv.env,
55
+ ctx,
56
+ );
57
+ sf.threadState.budget = makeLuaBudget({
58
+ busyLimitMs: BUSY_LIMIT_DEFAULT_MS,
59
+ onLimit: (b) => {
60
+ b.stopped = true;
61
+ },
62
+ });
63
+ const env = new LuaEnv(client.clientSystem.spaceLuaEnv.env);
64
+ env.setLocal("_CTX", tl);
65
+ const rawResult = singleResult(await compute(env, sf));
66
+ if (isTaggedFloat(rawResult) || typeof rawResult === "number") {
67
+ return rawResult;
68
+ }
69
+ if (rawResult instanceof LuaTable) {
70
+ if (rawResult.rawGet("_isWidget")) {
71
+ return luaValueToJS(rawResult, sf);
72
+ }
73
+ return rawResult;
74
+ }
75
+ return luaValueToJS(rawResult, sf);
76
+ } catch (e: any) {
77
+ if (e instanceof LuaBudgetStopped) {
78
+ return `**Lua timeout:** this widget took too long to render and was stopped. Reload the page to try again.`;
79
+ }
80
+ if (e instanceof LuaRuntimeError && e.sf?.astCtx) {
81
+ const source = resolveASTReference(e.sf.astCtx);
82
+ if (source) {
83
+ return `**Lua error:** ${e.message} (Origin: [[${encodeRef(source)}]])`;
84
+ }
85
+ }
86
+ return `**Lua error:** ${e.message}`;
87
+ }
88
+ }
89
+
90
+ /** Evaluate a `${...}`-style expression string and render it as a widget. */
91
+ export async function renderLuaExpression(
92
+ client: Client,
93
+ expressionText: string,
94
+ currentPageMeta?: { name: string } | undefined,
95
+ ): Promise<any> {
96
+ if (expressionText.trim().length === 0) {
97
+ return "**Error:** Empty Lua expression";
98
+ }
99
+ const expr = parseExpressionString(expressionText);
100
+ return renderLuaWidgetResult(
101
+ client,
102
+ (env, sf) => evalExpression(expr, env, sf),
103
+ expr.ctx,
104
+ currentPageMeta,
105
+ );
106
+ }
107
+
108
+ /** Call a stored Lua render function (e.g. a code widget) and render it. */
109
+ export async function renderLuaCallback(
110
+ client: Client,
111
+ fn: ILuaFunction,
112
+ args: LuaValue[],
113
+ currentPageMeta?: { name: string } | undefined,
114
+ ): Promise<any> {
115
+ return renderLuaWidgetResult(
116
+ client,
117
+ (_env, sf) => fn.call(sf, ...args),
118
+ {} as ASTCtx,
119
+ currentPageMeta,
120
+ );
121
+ }
122
+
123
+ export type PortableMarkdownResult =
124
+ | { ok: true; markdown: string }
125
+ | { ok: false; reason: string };
126
+
127
+ /**
128
+ * Evaluate a `${...}`-style expression and produce portable GFM markdown — the
129
+ * same clean rendering the Copy button uses — or report why it can't be baked.
130
+ * - nil/empty → ok with empty markdown
131
+ * - Lua error → not ok (the eval error string)
132
+ * - widget object: portable only if it exposes a `markdown` rendering;
133
+ * html-only widgets are not bakeable
134
+ * - scalars / tables / arrays / strings → clean GFM
135
+ */
136
+ export async function expressionToPortableMarkdown(
137
+ client: Client,
138
+ expressionText: string,
139
+ currentPageMeta?: { name: string } | undefined,
140
+ ): Promise<PortableMarkdownResult> {
141
+ const rawResult = await renderLuaExpression(
142
+ client,
143
+ expressionText,
144
+ currentPageMeta,
145
+ );
146
+ if (isViewValue(rawResult)) {
147
+ return { ok: false, reason: "A view has no portable Markdown rendering" };
148
+ }
149
+ if (rawResult === null || rawResult === undefined) {
150
+ return { ok: true, markdown: "" };
151
+ }
152
+ // renderLuaExpression returns eval failures as markdown error strings.
153
+ if (
154
+ typeof rawResult === "string" &&
155
+ (rawResult.startsWith("**Lua error:**") ||
156
+ rawResult.startsWith("**Error:**"))
157
+ ) {
158
+ return { ok: false, reason: rawResult };
159
+ }
160
+ // Widget objects: portable only when they expose a `markdown` rendering.
161
+ if (typeof rawResult === "object" && (rawResult as any)._isWidget) {
162
+ const md = (rawResult as any).markdown;
163
+ if (typeof md === "string") {
164
+ return { ok: true, markdown: md.trim() };
165
+ }
166
+ return { ok: false, reason: "html-only widget (no markdown rendering)" };
167
+ }
168
+ const markdown = await renderResultToCleanMarkdown(
169
+ rawResult,
170
+ classifyResult(rawResult),
171
+ );
172
+ return { ok: true, markdown };
173
+ }