@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
@@ -18,7 +18,8 @@ function skipSpace(s: string, i: number): number {
18
18
  const n = s.length;
19
19
  while (i < n) {
20
20
  const c = s.charCodeAt(i);
21
- if (c === 32 || (c >= 9 && c <= 13)) { // SP, HT, LF, VT, FF, CR
21
+ if (c === 32 || (c >= 9 && c <= 13)) {
22
+ // SP, HT, LF, VT, FF, CR
22
23
  i++;
23
24
  } else {
24
25
  break;
@@ -28,21 +29,24 @@ function skipSpace(s: string, i: number): number {
28
29
  }
29
30
 
30
31
  function charToDigitBase(c: number, base: number): number {
31
- if (c >= 48 && c <= 57) { // '0'..'9'
32
+ if (c >= 48 && c <= 57) {
33
+ // '0'..'9'
32
34
  const v = c - 48;
33
35
  if (v < base) {
34
36
  return v;
35
37
  }
36
38
  return -1;
37
39
  }
38
- if (c >= 65 && c <= 90) { // 'A'..'Z'
40
+ if (c >= 65 && c <= 90) {
41
+ // 'A'..'Z'
39
42
  const v = 10 + (c - 65);
40
43
  if (v < base) {
41
44
  return v;
42
45
  }
43
46
  return -1;
44
47
  }
45
- if (c >= 97 && c <= 122) { // 'a'..'z'
48
+ if (c >= 97 && c <= 122) {
49
+ // 'a'..'z'
46
50
  const v = 10 + (c - 97);
47
51
  if (v < base) {
48
52
  return v;
@@ -64,10 +68,12 @@ function parseIntWithBase(
64
68
  }
65
69
 
66
70
  let sign = 1;
67
- if (s.charCodeAt(i) === 45) { // '-'
71
+ if (s.charCodeAt(i) === 45) {
72
+ // '-'
68
73
  sign = -1;
69
74
  i++;
70
- } else if (s.charCodeAt(i) === 43) { // '+'
75
+ } else if (s.charCodeAt(i) === 43) {
76
+ // '+'
71
77
  i++;
72
78
  }
73
79
 
@@ -80,7 +86,8 @@ function parseIntWithBase(
80
86
 
81
87
  while (i < n) {
82
88
  const c = s.charCodeAt(i);
83
- const isAlnum = (c >= 48 && c <= 57) || // '0'..'9'
89
+ const isAlnum =
90
+ (c >= 48 && c <= 57) || // '0'..'9'
84
91
  (c >= 65 && c <= 90) || // 'A'..'Z'
85
92
  (c >= 97 && c <= 122); // 'a'..'z'
86
93
 
@@ -119,10 +126,12 @@ function parseInt(s: string): { ok: boolean; value: number } {
119
126
  }
120
127
 
121
128
  let neg = false;
122
- if (s.charCodeAt(i) === 45) { // '-'
129
+ if (s.charCodeAt(i) === 45) {
130
+ // '-'
123
131
  neg = true;
124
132
  i++;
125
- } else if (s.charCodeAt(i) === 43) { // '+'
133
+ } else if (s.charCodeAt(i) === 43) {
134
+ // '+'
126
135
  i++;
127
136
  }
128
137
 
@@ -134,18 +143,23 @@ function parseInt(s: string): { ok: boolean; value: number } {
134
143
  let any = false;
135
144
 
136
145
  // hex?
137
- if (s.charCodeAt(i) === 48 && i + 1 < n) { // '0'
146
+ if (s.charCodeAt(i) === 48 && i + 1 < n) {
147
+ // '0'
138
148
  const x = s.charCodeAt(i + 1);
139
- if (x === 120 || x === 88) { // 'x' or 'X'
149
+ if (x === 120 || x === 88) {
150
+ // 'x' or 'X'
140
151
  i += 2;
141
152
  while (i < n) {
142
153
  const c = s.charCodeAt(i);
143
154
  let d = -1;
144
- if (c >= 48 && c <= 57) { // '0'..'9'
155
+ if (c >= 48 && c <= 57) {
156
+ // '0'..'9'
145
157
  d = c - 48; // '0'
146
- } else if (c >= 65 && c <= 70) { // 'A'..'F'
158
+ } else if (c >= 65 && c <= 70) {
159
+ // 'A'..'F'
147
160
  d = 10 + (c - 65);
148
- } else if (c >= 97 && c <= 102) { // 'a'..'f'
161
+ } else if (c >= 97 && c <= 102) {
162
+ // 'a'..'f'
149
163
  d = 10 + (c - 97);
150
164
  } else {
151
165
  d = -1;
@@ -168,7 +182,8 @@ function parseInt(s: string): { ok: boolean; value: number } {
168
182
  // decimal integer
169
183
  while (i < n) {
170
184
  const c = s.charCodeAt(i);
171
- if (c < 48 || c > 57) { // not '0'..'9'
185
+ if (c < 48 || c > 57) {
186
+ // not '0'..'9'
172
187
  break;
173
188
  }
174
189
  acc = acc * 10 + (c - 48);
@@ -193,10 +208,12 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
193
208
 
194
209
  let sign = 1;
195
210
  const c0 = s.charCodeAt(i);
196
- if (c0 === 45) { // '-'
211
+ if (c0 === 45) {
212
+ // '-'
197
213
  sign = -1;
198
214
  i++;
199
- } else if (c0 === 43) { // '+'
215
+ } else if (c0 === 43) {
216
+ // '+'
200
217
  i++;
201
218
  }
202
219
 
@@ -207,7 +224,8 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
207
224
  // integer part
208
225
  while (i < n) {
209
226
  const c = s.charCodeAt(i);
210
- if (c < 48 || c > 57) { // not '0'..'9'
227
+ if (c < 48 || c > 57) {
228
+ // not '0'..'9'
211
229
  break;
212
230
  }
213
231
  val = val * 10 + (c - 48);
@@ -217,12 +235,14 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
217
235
 
218
236
  // fractional part
219
237
  if (i < n) {
220
- if (s.charCodeAt(i) === 46) { // '.'
238
+ if (s.charCodeAt(i) === 46) {
239
+ // '.'
221
240
  i++;
222
241
  let scale = 1;
223
242
  while (i < n) {
224
243
  const c = s.charCodeAt(i);
225
- if (c < 48 || c > 57) { // not '0'..'9'
244
+ if (c < 48 || c > 57) {
245
+ // not '0'..'9'
226
246
  break;
227
247
  }
228
248
  scale *= 0.1;
@@ -238,7 +258,8 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
238
258
  let hasExp = false;
239
259
  if (i < n) {
240
260
  const ec = s.charCodeAt(i);
241
- if (ec === 101 || ec === 69) { // 'e' or 'E'
261
+ if (ec === 101 || ec === 69) {
262
+ // 'e' or 'E'
242
263
  hasExp = true;
243
264
  i++;
244
265
  if (i >= n) {
@@ -247,10 +268,12 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
247
268
  let expSign = 1;
248
269
  if (i < n) {
249
270
  const es = s.charCodeAt(i);
250
- if (es === 45) { // '-'
271
+ if (es === 45) {
272
+ // '-'
251
273
  expSign = -1;
252
274
  i++;
253
- } else if (es === 43) { // '+'
275
+ } else if (es === 43) {
276
+ // '+'
254
277
  i++;
255
278
  }
256
279
  }
@@ -260,7 +283,8 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
260
283
  let anyExp = false;
261
284
  while (i < n) {
262
285
  const c = s.charCodeAt(i);
263
- if (c < 48 || c > 57) { // not '0'..'9'
286
+ if (c < 48 || c > 57) {
287
+ // not '0'..'9'
264
288
  break;
265
289
  }
266
290
  exp = exp * 10 + (c - 48);
@@ -297,18 +321,22 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
297
321
 
298
322
  let sign = 1;
299
323
  const c0 = s.charCodeAt(i);
300
- if (c0 === 45) { // '-'
324
+ if (c0 === 45) {
325
+ // '-'
301
326
  sign = -1;
302
327
  i++;
303
- } else if (c0 === 43) { // '+'
328
+ } else if (c0 === 43) {
329
+ // '+'
304
330
  i++;
305
331
  }
306
332
 
307
- if (!(i + 1 < n && s.charCodeAt(i) === 48)) { // '0'
333
+ if (!(i + 1 < n && s.charCodeAt(i) === 48)) {
334
+ // '0'
308
335
  return { ok: false, value: 0 };
309
336
  }
310
337
  const x = s.charCodeAt(i + 1);
311
- if (!(x === 120 || x === 88)) { // 'x' or 'X'
338
+ if (!(x === 120 || x === 88)) {
339
+ // 'x' or 'X'
312
340
  return { ok: false, value: 0 };
313
341
  }
314
342
  i += 2;
@@ -323,11 +351,14 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
323
351
  while (i < n) {
324
352
  const c = s.charCodeAt(i);
325
353
  let d = -1;
326
- if (c >= 48 && c <= 57) { // '0'..'9'
354
+ if (c >= 48 && c <= 57) {
355
+ // '0'..'9'
327
356
  d = c - 48;
328
- } else if (c >= 65 && c <= 70) { // 'A'..'F'
357
+ } else if (c >= 65 && c <= 70) {
358
+ // 'A'..'F'
329
359
  d = 10 + (c - 65);
330
- } else if (c >= 97 && c <= 102) { // 'a'..'f'
360
+ } else if (c >= 97 && c <= 102) {
361
+ // 'a'..'f'
331
362
  d = 10 + (c - 97);
332
363
  } else {
333
364
  d = -1;
@@ -342,17 +373,21 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
342
373
 
343
374
  // optional fractional part
344
375
  if (i < n) {
345
- if (s.charCodeAt(i) === 46) { // '.'
376
+ if (s.charCodeAt(i) === 46) {
377
+ // '.'
346
378
  sawDot = true;
347
379
  i++;
348
380
  while (i < n) {
349
381
  const c = s.charCodeAt(i);
350
382
  let d = -1;
351
- if (c >= 48 && c <= 57) { // '0'..'9'
383
+ if (c >= 48 && c <= 57) {
384
+ // '0'..'9'
352
385
  d = c - 48;
353
- } else if (c >= 65 && c <= 70) { // 'A'..'F'
386
+ } else if (c >= 65 && c <= 70) {
387
+ // 'A'..'F'
354
388
  d = 10 + (c - 65);
355
- } else if (c >= 97 && c <= 102) { // 'a'..'f'
389
+ } else if (c >= 97 && c <= 102) {
390
+ // 'a'..'f'
356
391
  d = 10 + (c - 97);
357
392
  } else {
358
393
  d = -1;
@@ -376,14 +411,17 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
376
411
 
377
412
  if (i < n) {
378
413
  const ec = s.charCodeAt(i);
379
- if (ec === 112 || ec === 80) { // 'p' or 'P'
414
+ if (ec === 112 || ec === 80) {
415
+ // 'p' or 'P'
380
416
  i++;
381
417
  if (i < n) {
382
418
  const sc = s.charCodeAt(i);
383
- if (sc === 45) { // '-'
419
+ if (sc === 45) {
420
+ // '-'
384
421
  expSign = -1;
385
422
  i++;
386
- } else if (sc === 43) { // '+'
423
+ } else if (sc === 43) {
424
+ // '+'
387
425
  i++;
388
426
  }
389
427
  }
@@ -394,7 +432,8 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
394
432
  let anyExp = false;
395
433
  while (i < n) {
396
434
  const c = s.charCodeAt(i);
397
- if (c < 48 || c > 57) { // not '0'..'9'
435
+ if (c < 48 || c > 57) {
436
+ // not '0'..'9'
398
437
  break;
399
438
  }
400
439
  exp = exp * 10 + (c - 48);
@@ -433,7 +472,7 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
433
472
  return { ok: false, value: 0 };
434
473
  }
435
474
 
436
- const frac = fracVal === 0 ? 0 : (fracVal / fracScale);
475
+ const frac = fracVal === 0 ? 0 : fracVal / fracScale;
437
476
  const result = sign * (intVal + frac) * 2 ** (expSign * exp);
438
477
  return { ok: true, value: result };
439
478
  }
@@ -6,7 +6,7 @@ export function evalPromiseValues(vals: any[]): Promise<any[]> | any[] {
6
6
  for (let i = 0; i < vals.length; i++) {
7
7
  if (isPromise(vals[i])) {
8
8
  promises.push(
9
- (vals[i] as Promise<any>).then((v: any) => promiseResults[i] = v),
9
+ (vals[i] as Promise<any>).then((v: any) => (promiseResults[i] = v)),
10
10
  );
11
11
  } else {
12
12
  promiseResults[i] = vals[i];
@@ -32,19 +32,19 @@ async function getPivot(
32
32
  z: any,
33
33
  compare: (a: any, b: any) => Promise<number>,
34
34
  ) {
35
- if (await compare(x, y) < 0) {
36
- if (await compare(y, z) < 0) {
35
+ if ((await compare(x, y)) < 0) {
36
+ if ((await compare(y, z)) < 0) {
37
37
  return y;
38
38
  }
39
- if (await compare(z, x) < 0) {
39
+ if ((await compare(z, x)) < 0) {
40
40
  return x;
41
41
  }
42
42
  return z;
43
43
  }
44
- if (await compare(y, z) > 0) {
44
+ if ((await compare(y, z)) > 0) {
45
45
  return y;
46
46
  }
47
- if (await compare(z, x) > 0) {
47
+ if ((await compare(z, x)) > 0) {
48
48
  return x;
49
49
  }
50
50
  return z;
@@ -65,7 +65,9 @@ export async function asyncQuickSort(
65
65
  right = arr.length - 1,
66
66
  ) {
67
67
  if (left < right) {
68
- let i = left, j = right, tmp;
68
+ let i = left,
69
+ j = right,
70
+ tmp;
69
71
  const pivot = await getPivot(
70
72
  arr[i],
71
73
  arr[i + Math.floor((j - i) / 2)],
@@ -73,10 +75,10 @@ export async function asyncQuickSort(
73
75
  compare,
74
76
  );
75
77
  while (true) {
76
- while (await compare(arr[i], pivot) < 0) {
78
+ while ((await compare(arr[i], pivot)) < 0) {
77
79
  i++;
78
80
  }
79
- while (await compare(pivot, arr[j]) < 0) {
81
+ while ((await compare(pivot, arr[j])) < 0) {
80
82
  j--;
81
83
  }
82
84
  if (i >= j) {
@@ -116,7 +118,9 @@ export async function asyncMergeSort(
116
118
  const mid = Math.min(left + size, n);
117
119
  const right = Math.min(left + 2 * size, n);
118
120
 
119
- let i = left, j = mid, k = left;
121
+ let i = left,
122
+ j = mid,
123
+ k = left;
120
124
  while (i < mid && j < right) {
121
125
  const cmp = await compare(arr[i], arr[j]);
122
126
  if (cmp <= 0) work[k++] = arr[i++];
@@ -4,19 +4,26 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // version.ts
7
- var version = "2.5.3";
7
+ var version = "2.7.0";
8
8
 
9
9
  // client/plugos/plug_compile.ts
10
10
  import * as path from "node:path";
11
- import { readFile as readFile2, writeFile, mkdtemp, rm, mkdir } from "node:fs/promises";
11
+ import {
12
+ copyFile,
13
+ mkdir,
14
+ mkdtemp,
15
+ readFile as readFile2,
16
+ rm,
17
+ writeFile
18
+ } from "node:fs/promises";
12
19
  import { tmpdir } from "node:os";
13
20
  import * as YAML from "js-yaml";
14
21
  import * as esbuild from "esbuild";
22
+ import * as sass from "sass";
15
23
 
16
24
  // client/asset_bundle/builder.ts
17
- import picomatch from "picomatch";
18
25
  import { readFile, readdir } from "node:fs/promises";
19
- import { join } from "node:path";
26
+ import { join, matchesGlob } from "node:path";
20
27
 
21
28
  // node_modules/mime/dist/types/other.js
22
29
  var types = {
@@ -1300,10 +1307,9 @@ async function bundleAssets(rootPath, patterns) {
1300
1307
  if (patterns.length === 0) {
1301
1308
  return bundle;
1302
1309
  }
1303
- const isMatch = picomatch(patterns);
1304
1310
  for await (const file of walk(rootPath)) {
1305
1311
  const cleanPath = file.path.substring(rootPath.length + 1);
1306
- if (isMatch(cleanPath)) {
1312
+ if (patterns.some((p) => matchesGlob(cleanPath, p))) {
1307
1313
  bundle.writeFileSync(
1308
1314
  cleanPath,
1309
1315
  src_default.getType(cleanPath) || "application/octet-stream",
@@ -1315,17 +1321,23 @@ async function bundleAssets(rootPath, patterns) {
1315
1321
  }
1316
1322
 
1317
1323
  // client/plugos/plug_compile.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
1324
  var workerRuntimePlugin = {
1324
1325
  name: "worker-runtime",
1325
1326
  setup(build2) {
1326
- build2.onResolve({ filter: /^worker-runtime$/ }, () => ({
1327
- path: workerRuntimeBundlePath
1328
- }));
1327
+ if (true) {
1328
+ build2.onResolve({ filter: /^worker-runtime$/ }, () => ({
1329
+ path: "worker-runtime",
1330
+ namespace: "worker-runtime"
1331
+ }));
1332
+ build2.onLoad({ filter: /.*/, namespace: "worker-runtime" }, () => ({
1333
+ contents: '// plug-api/lib/crypto.ts\nfunction base64Decode(s) {\n const binString = atob(s);\n const len = binString.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binString.charCodeAt(i);\n }\n return bytes;\n}\nfunction base64Encode(buffer) {\n if (typeof buffer === "string") {\n buffer = new TextEncoder().encode(buffer);\n }\n let binary = "";\n const len = buffer.byteLength;\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(buffer[i]);\n }\n return btoa(binary);\n}\nvar fixedCounter = new Uint8Array(16);\n\n// client/lib/logger.ts\nvar Logger = class {\n constructor(prefix = "", maxCaptureSize = 1e3) {\n this.prefix = prefix;\n this.maxCaptureSize = maxCaptureSize;\n this.prefix = prefix;\n this.originalConsole = {\n log: console.log.bind(console),\n info: console.info.bind(console),\n warn: console.warn.bind(console),\n error: console.error.bind(console),\n debug: console.debug.bind(console)\n };\n this.patchConsole();\n }\n originalConsole;\n logBuffer = [];\n patchConsole() {\n const createPatchedMethod = (level) => {\n return (...args) => {\n const prefixedArgs = this.prefix ? [this.prefix, ...args] : args;\n this.originalConsole[level](...prefixedArgs);\n this.captureLog(level, args);\n };\n };\n console.log = createPatchedMethod("log");\n console.info = createPatchedMethod("info");\n console.warn = createPatchedMethod("warn");\n console.error = createPatchedMethod("error");\n console.debug = createPatchedMethod("debug");\n }\n captureLog(level, args) {\n const entry = {\n level,\n timestamp: Date.now(),\n message: args.map((arg) => {\n if (typeof arg === "string") {\n return arg;\n }\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n }).join(" ")\n };\n this.logBuffer.push(entry);\n if (this.logBuffer.length > this.maxCaptureSize) {\n this.logBuffer.shift();\n }\n }\n /**\n * Posts all buffered logs to a server endpoint\n */\n async postToServer(logEndpoint, source) {\n const logs = this.logBuffer;\n if (logs.length > 0) {\n const logCopy = [...this.logBuffer];\n this.logBuffer = [];\n try {\n const resp = await fetch(logEndpoint, {\n method: "POST",\n headers: {\n "Content-Type": "application/json"\n },\n body: JSON.stringify(logCopy.map((entry) => ({ ...entry, source })))\n });\n if (!resp.ok) {\n throw new Error("Failed to post logs to server");\n }\n } catch (e) {\n console.warn("Could not post logs to server", e.message);\n this.logBuffer.unshift(...logCopy);\n }\n }\n }\n};\nvar globalLogger;\nfunction initLogger(prefix = "") {\n globalLogger = new Logger(prefix);\n return globalLogger;\n}\n\n// client/plugos/worker_runtime.ts\nvar workerPostMessage = (_msg) => {\n throw new Error("Not initialized yet");\n};\nvar runningAsWebWorker = typeof window === "undefined" && // @ts-expect-error: globalThis\ntypeof globalThis.WebSocketPair === "undefined";\nvar pendingRequests = /* @__PURE__ */ new Map();\nvar syscallReqId = 0;\nif (runningAsWebWorker) {\n globalThis.syscall = async (name, ...args) => {\n return await new Promise((resolve, reject) => {\n syscallReqId++;\n pendingRequests.set(syscallReqId, { resolve, reject });\n workerPostMessage({\n type: "sys",\n id: syscallReqId,\n name,\n args\n });\n });\n };\n}\nfunction setupMessageListener(functionMapping, manifest, postMessageFn) {\n if (!runningAsWebWorker) {\n return;\n }\n workerPostMessage = postMessageFn;\n self.addEventListener("message", (event) => {\n (async () => {\n const data = event.data;\n switch (data.type) {\n case "inv":\n {\n const fn = functionMapping[data.name];\n if (!fn) {\n throw new Error(`Function not loaded: ${data.name}`);\n }\n try {\n const result = await Promise.resolve(fn(...data.args || []));\n workerPostMessage({\n type: "invr",\n id: data.id,\n result\n });\n } catch (e) {\n console.error(\n "An exception was thrown as a result of invoking function",\n data.name,\n "error:",\n e.message\n );\n workerPostMessage({\n type: "invr",\n id: data.id,\n error: e.message\n });\n }\n }\n break;\n case "sysr":\n {\n const syscallId = data.id;\n const lookup = pendingRequests.get(syscallId);\n if (!lookup) {\n throw Error("Invalid request id");\n }\n pendingRequests.delete(syscallId);\n if (data.error) {\n lookup.reject(new Error(data.error));\n } else {\n lookup.resolve(data.result);\n }\n }\n break;\n }\n })().catch(console.error);\n });\n workerPostMessage({\n type: "manifest",\n manifest\n });\n initLogger(`[${manifest.name} plug]`);\n}\nasync function sandboxFetch(reqInfo, options) {\n if (typeof reqInfo !== "string") {\n const body = new Uint8Array(await reqInfo.arrayBuffer());\n const encodedBody = body.length > 0 ? base64Encode(body) : void 0;\n options = {\n method: reqInfo.method,\n headers: Object.fromEntries(reqInfo.headers.entries()),\n base64Body: encodedBody\n };\n reqInfo = reqInfo.url;\n }\n return syscall("sandboxFetch.fetch", reqInfo, options);\n}\nglobalThis.nativeFetch = globalThis.fetch;\nfunction monkeyPatchFetch() {\n globalThis.fetch = async (reqInfo, init) => {\n const encodedBody = init?.body ? base64Encode(\n new Uint8Array(await new Response(init.body).arrayBuffer())\n ) : void 0;\n const r = await sandboxFetch(\n reqInfo,\n init && {\n method: init.method,\n headers: init.headers,\n base64Body: encodedBody\n }\n );\n return new Response(\n r.base64Body ? base64Decode(r.base64Body) : null,\n {\n status: r.status,\n headers: r.headers\n }\n );\n };\n}\nif (runningAsWebWorker) {\n monkeyPatchFetch();\n}\nexport {\n monkeyPatchFetch,\n sandboxFetch,\n setupMessageListener\n};\n',
1334
+ loader: "js"
1335
+ }));
1336
+ } else {
1337
+ build2.onResolve({ filter: /^worker-runtime$/ }, () => ({
1338
+ path: path.join(import.meta.dirname, "worker_runtime.ts")
1339
+ }));
1340
+ }
1329
1341
  }
1330
1342
  };
1331
1343
  async function compileManifest(manifestPath, destPath, options = {}) {
@@ -1335,6 +1347,12 @@ async function compileManifest(manifestPath, destPath, options = {}) {
1335
1347
  if (!manifest.name) {
1336
1348
  throw new Error(`Missing 'name' in ${manifestPath}`);
1337
1349
  }
1350
+ if (manifest.build) {
1351
+ await Promise.all(
1352
+ manifest.build.map((step) => runBuildStep(step, rootPath, options))
1353
+ );
1354
+ delete manifest.build;
1355
+ }
1338
1356
  const assetsBundle = await bundleAssets(
1339
1357
  path.resolve(rootPath),
1340
1358
  manifest.assets || []
@@ -1354,10 +1372,7 @@ ${Object.entries(manifest.functions).map(([funcName, def]) => {
1354
1372
  let [filePath, jsFunctionName] = def.path.split(":");
1355
1373
  filePath = path.join(rootPath, filePath);
1356
1374
  return `import {${jsFunctionName} as ${funcName}} from "${// Replacing \ with / for Windows
1357
- path.resolve(filePath).replaceAll(
1358
- "\\",
1359
- "\\\\"
1360
- )}";
1375
+ path.resolve(filePath).replaceAll("\\", "\\\\")}";
1361
1376
  `;
1362
1377
  }).join("")}
1363
1378
 
@@ -1418,43 +1433,73 @@ async function compileManifests(manifestFiles, dist, options = {}) {
1418
1433
  building = true;
1419
1434
  await mkdir(dist, { recursive: true });
1420
1435
  const startTime = Date.now();
1421
- await Promise.all(manifestFiles.map(async (plugManifestPath) => {
1422
- const manifestPath = plugManifestPath;
1423
- try {
1424
- await compileManifest(
1425
- manifestPath,
1426
- dist,
1427
- options
1428
- );
1429
- } catch (e) {
1430
- console.error(`Error building ${manifestPath}:`, e.message);
1431
- throw e;
1432
- }
1433
- }));
1436
+ await Promise.all(
1437
+ manifestFiles.map(async (plugManifestPath) => {
1438
+ const manifestPath = plugManifestPath;
1439
+ try {
1440
+ await compileManifest(manifestPath, dist, options);
1441
+ } catch (e) {
1442
+ console.error(`Error building ${manifestPath}:`, e.message);
1443
+ throw e;
1444
+ }
1445
+ })
1446
+ );
1434
1447
  console.log(`Done building plugs in ${Date.now() - startTime}ms`);
1435
1448
  building = false;
1436
1449
  }
1437
1450
  await buildAll();
1438
1451
  }
1452
+ async function runBuildStep(step, rootPath, options) {
1453
+ const type = step.type ?? "esbuild";
1454
+ const inFile = path.resolve(rootPath, step.in);
1455
+ const outFile = path.resolve(rootPath, step.out);
1456
+ await mkdir(path.dirname(outFile), { recursive: true });
1457
+ if (type === "esbuild") {
1458
+ await esbuild.build({
1459
+ entryPoints: [inFile],
1460
+ bundle: true,
1461
+ format: "iife",
1462
+ platform: "browser",
1463
+ minify: !options.debug,
1464
+ outfile: outFile,
1465
+ treeShaking: true
1466
+ });
1467
+ } else if (type === "sass") {
1468
+ const scss = await readFile2(inFile, "utf-8");
1469
+ const result = sass.compileString(scss, {
1470
+ loadPaths: [path.dirname(inFile)],
1471
+ style: options.debug ? "expanded" : "compressed"
1472
+ });
1473
+ await writeFile(outFile, result.css, "utf-8");
1474
+ } else if (type === "copy") {
1475
+ await copyFile(inFile, outFile);
1476
+ } else {
1477
+ throw new Error(`Unsupported build step type: ${type}`);
1478
+ }
1479
+ }
1439
1480
  function patchBundledJS(code) {
1440
1481
  return code.replaceAll("/(?<=\\n)/", "/()/");
1441
1482
  }
1442
- async function plugCompileCommand({ dist, debug, info }, ...manifestPaths) {
1443
- await compileManifests(
1444
- manifestPaths,
1445
- dist,
1446
- {
1447
- debug,
1448
- info
1449
- }
1450
- );
1451
- esbuild.stop();
1483
+ async function plugCompileCommand({
1484
+ dist,
1485
+ debug,
1486
+ info
1487
+ }, ...manifestPaths) {
1488
+ await compileManifests(manifestPaths, dist, {
1489
+ debug,
1490
+ info
1491
+ });
1492
+ await esbuild.stop();
1452
1493
  process.exit(0);
1453
1494
  }
1454
1495
 
1455
1496
  // bin/plug-compile.ts
1456
1497
  var program = new Command();
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) => {
1498
+ 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(
1499
+ "--dist <path>",
1500
+ "Folder to put the resulting .plug.json file into",
1501
+ "."
1502
+ ).action(async (manifestPaths, options) => {
1458
1503
  await plugCompileCommand(
1459
1504
  {
1460
1505
  dist: options.dist,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silverbulletmd/silverbullet",
3
- "version": "2.5.3",
3
+ "version": "2.7.0",
4
4
  "type": "module",
5
5
  "description": "A self-hosted, web-based note taking app",
6
6
  "publishConfig": {
@@ -47,45 +47,48 @@
47
47
  "!client/space_lua/**/*.bench.ts",
48
48
  "client/markdown_parser/constants.ts",
49
49
  "plugs/builtin_plugs.ts",
50
- "dist/plug-compile.js",
51
- "dist/worker_runtime_bundle.js"
50
+ "dist/plug-compile.js"
52
51
  ],
53
52
  "scripts": {
54
- "build": "tsx build_worker_runtime.ts && npm run build:plugs && npm run build:client",
55
- "build:plugs": "tsx build_plugs_libraries.ts",
56
- "build:client": "tsx build_client.ts",
57
- "build:plug-compile": "tsx build_worker_runtime.ts && tsx build_plug_compile.ts",
53
+ "build": "npm run build:plugs && npm run build:client",
54
+ "build:plugs": "tsx build/build_plugs.ts",
55
+ "build:client": "tsx build/build_client.ts",
56
+ "build:plug-compile": "tsx build/build_plug_compile.ts",
58
57
  "prepublishOnly": "npm run build:plug-compile",
59
58
  "test": "vitest run",
60
59
  "check": "tsc --noEmit",
61
60
  "lint": "biome lint .",
62
- "bench": "vitest bench"
61
+ "fmt": "biome format --write .",
62
+ "fmt:check": "biome format .",
63
+ "bench": "vitest bench",
64
+ "test:e2e": "npx playwright test",
65
+ "test:e2e:headed": "npx playwright test --headed"
63
66
  },
64
67
  "dependencies": {
65
- "@codemirror/autocomplete": "6.20.0",
66
- "@codemirror/commands": "6.10.1",
68
+ "@cfworker/json-schema": "^4.1.1",
69
+ "@codemirror/autocomplete": "6.20.1",
70
+ "@codemirror/commands": "6.10.3",
67
71
  "@codemirror/lang-css": "6.3.1",
68
72
  "@codemirror/lang-html": "6.4.11",
69
- "@codemirror/lang-javascript": "6.2.4",
73
+ "@codemirror/lang-javascript": "6.2.5",
70
74
  "@codemirror/lang-markdown": "6.5.0",
71
- "@codemirror/language": "6.12.1",
75
+ "@codemirror/language": "6.12.3",
72
76
  "@codemirror/legacy-modes": "6.5.2",
73
- "@codemirror/lint": "6.9.2",
77
+ "@codemirror/lint": "6.9.5",
74
78
  "@codemirror/search": "6.6.0",
75
- "@codemirror/state": "6.5.4",
76
- "@codemirror/view": "6.39.11",
79
+ "@codemirror/state": "6.6.0",
80
+ "@codemirror/view": "6.41.0",
77
81
  "@joplin/turndown-plugin-gfm": "1.0.64",
78
- "@lezer/common": "1.5.0",
79
- "@lezer/css": "1.3.0",
82
+ "@lezer/common": "1.5.1",
83
+ "@lezer/css": "1.3.3",
80
84
  "@lezer/highlight": "1.2.3",
81
85
  "@lezer/html": "1.3.13",
82
86
  "@lezer/javascript": "1.5.4",
83
- "@lezer/lr": "1.4.7",
87
+ "@lezer/lr": "1.4.8",
84
88
  "@lezer/markdown": "1.6.3",
85
89
  "@msgpack/msgpack": "3.1.3",
86
90
  "@replit/codemirror-lang-nix": "6.0.1",
87
91
  "@replit/codemirror-vim": "6.3.0",
88
- "ajv": "8.17.1",
89
92
  "commander": "^14.0.3",
90
93
  "crelt": "1.0.6",
91
94
  "esbuild": "^0.27.3",
@@ -96,21 +99,20 @@
96
99
  "idb": "8.0.3",
97
100
  "js-yaml": "^4.1.1",
98
101
  "mime": "4.1.0",
99
- "picomatch": "^4.0.3",
100
102
  "preact": "10.28.2",
101
103
  "preact-feather": "4.2.1",
102
104
  "react-icons": "5.5.0",
103
105
  "sass": "^1.97.3",
104
- "style-mod": "4.1.2",
106
+ "style-mod": "4.1.3",
105
107
  "turndown": "7.2.2"
106
108
  },
107
109
  "devDependencies": {
108
110
  "@biomejs/biome": "2.4.6",
111
+ "@playwright/test": "^1.58.2",
109
112
  "@preact/preset-vite": "^2.10.3",
110
113
  "@types/gitignore-parser": "^0.0.3",
111
114
  "@types/js-yaml": "^4.0.9",
112
115
  "@types/node": "^22.0.0",
113
- "@types/picomatch": "^4.0.2",
114
116
  "@types/turndown": "^5.0.6",
115
117
  "fake-indexeddb": "6.0.1",
116
118
  "tsx": "^4.19.0",