@silverbulletmd/silverbullet 2.10.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.
- package/README.md +4 -4
- package/client/asset_bundle/bundle.ts +0 -1
- package/client/config.ts +343 -0
- package/client/markdown_parser/constants.ts +3 -1
- package/client/plugos/hooks/command.ts +0 -5
- package/client/plugos/hooks/event.ts +0 -6
- package/client/plugos/hooks/mq.ts +0 -3
- package/client/plugos/hooks/slash_command.ts +1 -7
- package/client/plugos/hooks/syscall.ts +0 -4
- package/client/plugos/manifest_cache.ts +0 -32
- package/client/plugos/plug.ts +0 -3
- package/client/plugos/plug_compile.ts +3 -13
- package/client/plugos/sandboxes/worker_sandbox.ts +19 -9
- package/client/plugos/syscalls/editor.ts +128 -53
- package/client/plugos/syscalls/event.ts +0 -2
- package/client/plugos/syscalls/fetch.ts +0 -4
- package/client/plugos/syscalls/icon.ts +46 -0
- package/client/plugos/syscalls/index.ts +33 -13
- package/client/plugos/syscalls/jsonschema.ts +0 -1
- package/client/plugos/syscalls/mq.ts +0 -1
- package/client/plugos/syscalls/navigator.ts +143 -0
- package/client/plugos/syscalls/search.ts +44 -0
- package/client/plugos/syscalls/shell.ts +0 -1
- package/client/plugos/syscalls/space.ts +250 -7
- package/client/plugos/syscalls/sync.ts +56 -4
- package/client/plugos/syscalls/system.ts +38 -0
- package/client/plugos/system.ts +7 -5
- package/client/plugos/worker_runtime.ts +0 -2
- package/client/space_lua/aggregates.ts +0 -16
- package/client/space_lua/ast.ts +0 -5
- package/client/space_lua/ast_narrow.ts +0 -5
- package/client/space_lua/budget.ts +113 -0
- package/client/space_lua/budget_ui.ts +49 -0
- package/client/space_lua/eval.ts +113 -88
- package/client/space_lua/labels.ts +0 -4
- package/client/space_lua/numeric.ts +0 -5
- package/client/space_lua/parse.ts +0 -17
- package/client/space_lua/quarantine.ts +127 -0
- package/client/space_lua/query_collection.ts +3 -47
- package/client/space_lua/query_env.ts +0 -2
- package/client/space_lua/render_lua_markdown.ts +2 -7
- package/client/space_lua/render_widget.ts +18 -1
- package/client/space_lua/runtime.ts +50 -70
- package/client/space_lua/stdlib/format.ts +0 -12
- package/client/space_lua/stdlib/js.ts +0 -2
- package/client/space_lua/stdlib/load.ts +0 -1
- package/client/space_lua/stdlib/math.ts +0 -7
- package/client/space_lua/stdlib/net.ts +0 -4
- package/client/space_lua/stdlib/os.ts +0 -10
- package/client/space_lua/stdlib/pattern.ts +10 -15
- package/client/space_lua/stdlib/space_lua.ts +1 -2
- package/client/space_lua/stdlib/string_pack.ts +0 -3
- package/client/space_lua/stdlib/table.ts +0 -5
- package/client/space_lua/stdlib.ts +18 -31
- package/client/space_lua/tonumber.ts +0 -9
- package/dist/plug-compile.js +2 -3
- package/package.json +13 -3
- package/plug-api/lib/async.ts +1 -6
- package/plug-api/lib/collation.ts +22 -0
- package/plug-api/lib/crypto.ts +16 -15
- package/plug-api/lib/dates.ts +33 -0
- package/plug-api/lib/fuzzy.ts +282 -0
- package/plug-api/lib/json.ts +0 -6
- package/plug-api/lib/limited_map.ts +0 -2
- package/plug-api/lib/link_write.ts +27 -0
- package/plug-api/lib/ref.ts +28 -5
- package/plug-api/lib/resolve.ts +0 -1
- package/plug-api/lib/resolve_path.ts +290 -0
- package/plug-api/lib/shortcut.ts +15 -0
- package/plug-api/lib/tags.ts +0 -3
- package/plug-api/lib/transclusion.ts +28 -1
- package/plug-api/lib/tree.ts +0 -5
- package/plug-api/lib/yaml.ts +3 -42
- package/plug-api/syscall.ts +1 -5
- package/plug-api/syscalls/config.ts +2 -2
- package/plug-api/syscalls/editor.ts +59 -213
- package/plug-api/syscalls/icon.ts +18 -0
- package/plug-api/syscalls/index.ts +22 -4
- package/plug-api/syscalls/search.ts +11 -0
- package/plug-api/syscalls/space.ts +122 -5
- package/plug-api/syscalls/sync.ts +23 -2
- package/plug-api/syscalls/system.ts +46 -0
- package/plug-api/syscalls.ts +2 -0
- package/plug-api/system_mock.ts +13 -0
- package/plug-api/types/client.ts +4 -3
- package/plug-api/types/datastore.ts +11 -2
- package/plug-api/types/index.ts +10 -0
- package/plug-api/types/profile.ts +13 -0
- package/plug-api/types/revisions.ts +67 -0
- package/plug-api/ui/description.ts +64 -0
- package/plug-api/ui/hover.ts +69 -0
- package/plug-api/ui/index.ts +58 -2
- package/plug-api/ui/scroll.ts +30 -0
- package/plug-api/ui/tree_model.ts +263 -0
- package/plug-api/ui/tree_types.ts +66 -0
- package/plug-api/ui/use_fit_collapse.ts +67 -0
- package/plugs/builtin_plugs.ts +0 -1
- package/plugs/index/types.ts +9 -0
- package/plug-api/lib/memory_cache.ts +0 -21
- /package/plug-api/{ui → lib}/panel_styles.ts +0 -0
|
@@ -147,7 +147,6 @@ function buildSpecMap(d: Date, utc: boolean): Record<string, () => string> {
|
|
|
147
147
|
const dow = () => wd(d, utc);
|
|
148
148
|
|
|
149
149
|
return {
|
|
150
|
-
// Date
|
|
151
150
|
Y: () => yr(d, utc).toString(),
|
|
152
151
|
y: () => pad2(yr(d, utc) % 100),
|
|
153
152
|
C: () => pad2(Math.floor(yr(d, utc) / 100)),
|
|
@@ -156,14 +155,12 @@ function buildSpecMap(d: Date, utc: boolean): Record<string, () => string> {
|
|
|
156
155
|
e: () => da(d, utc).toString().padStart(2, " "),
|
|
157
156
|
j: () => pad3(dayOfYear(d, utc)),
|
|
158
157
|
|
|
159
|
-
// Time
|
|
160
158
|
H: () => pad2(h()),
|
|
161
159
|
I: () => pad2(h12()),
|
|
162
160
|
M: () => pad2(mi(d, utc)),
|
|
163
161
|
S: () => pad2(sc(d, utc)),
|
|
164
162
|
p: () => (h() >= 12 ? "PM" : "AM"),
|
|
165
163
|
|
|
166
|
-
// Weekday
|
|
167
164
|
A: () =>
|
|
168
165
|
d.toLocaleString("en-US", {
|
|
169
166
|
weekday: "long",
|
|
@@ -177,7 +174,6 @@ function buildSpecMap(d: Date, utc: boolean): Record<string, () => string> {
|
|
|
177
174
|
w: () => dow().toString(),
|
|
178
175
|
u: () => (dow() === 0 ? 7 : dow()).toString(),
|
|
179
176
|
|
|
180
|
-
// Month name
|
|
181
177
|
b: () =>
|
|
182
178
|
d.toLocaleString("en-US", {
|
|
183
179
|
month: "short",
|
|
@@ -194,14 +190,12 @@ function buildSpecMap(d: Date, utc: boolean): Record<string, () => string> {
|
|
|
194
190
|
...(utc ? { timeZone: "UTC" } : {}),
|
|
195
191
|
}),
|
|
196
192
|
|
|
197
|
-
// Week number
|
|
198
193
|
U: () => pad2(weekNumber(d, utc, 0, false)),
|
|
199
194
|
W: () => pad2(weekNumber(d, utc, 1, false)),
|
|
200
195
|
V: () => pad2(weekNumber(d, utc, 1, true)),
|
|
201
196
|
G: () => isoWeekYear(d, utc).toString(),
|
|
202
197
|
g: () => pad2(isoWeekYear(d, utc) % 100),
|
|
203
198
|
|
|
204
|
-
// Composite specifiers
|
|
205
199
|
c: () =>
|
|
206
200
|
d.toLocaleString("en-US", {
|
|
207
201
|
...(utc ? { timeZone: "UTC" } : {}),
|
|
@@ -225,14 +219,11 @@ function buildSpecMap(d: Date, utc: boolean): Record<string, () => string> {
|
|
|
225
219
|
h() >= 12 ? "PM" : "AM"
|
|
226
220
|
}`,
|
|
227
221
|
|
|
228
|
-
// Epoch
|
|
229
222
|
s: () => Math.floor(d.getTime() / 1000).toString(),
|
|
230
223
|
|
|
231
|
-
// Whitespace
|
|
232
224
|
n: () => "\n",
|
|
233
225
|
t: () => "\t",
|
|
234
226
|
|
|
235
|
-
// Timezone
|
|
236
227
|
Z: () => {
|
|
237
228
|
if (utc) return "UTC";
|
|
238
229
|
const match = d.toTimeString().match(/\((.*)\)/);
|
|
@@ -246,7 +237,6 @@ function buildSpecMap(d: Date, utc: boolean): Record<string, () => string> {
|
|
|
246
237
|
return `${sign}${pad2(Math.floor(abs / 60))}${pad2(abs % 60)}`;
|
|
247
238
|
},
|
|
248
239
|
|
|
249
|
-
// Literal
|
|
250
240
|
"%": () => "%",
|
|
251
241
|
};
|
|
252
242
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// Lua Optimized Pattern Matching Engine Implementation
|
|
2
|
-
|
|
3
1
|
const CH_ESC = 37; // '%'
|
|
4
2
|
const CH_OPEN = 40; // '('
|
|
5
3
|
const CH_CLOSE = 41; // ')'
|
|
@@ -40,21 +38,21 @@ interface Capture {
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
export interface MatchState {
|
|
43
|
-
src: string;
|
|
44
|
-
s:
|
|
41
|
+
src: string;
|
|
42
|
+
s: Uint16Array;
|
|
45
43
|
slen: number;
|
|
46
|
-
p:
|
|
44
|
+
p: Uint16Array;
|
|
47
45
|
plen: number;
|
|
48
46
|
level: number;
|
|
49
47
|
capture: Capture[]; // pre-allocated, length `MAX_CAPTURES`
|
|
50
48
|
matchdepth: number;
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
function
|
|
51
|
+
function toCodeUnits(s: string): Uint16Array {
|
|
54
52
|
const len = s.length;
|
|
55
|
-
const arr = new
|
|
53
|
+
const arr = new Uint16Array(len);
|
|
56
54
|
for (let i = 0; i < len; i++) {
|
|
57
|
-
arr[i] = s.charCodeAt(i)
|
|
55
|
+
arr[i] = s.charCodeAt(i);
|
|
58
56
|
}
|
|
59
57
|
return arr;
|
|
60
58
|
}
|
|
@@ -108,7 +106,7 @@ function matchClass(c: number, cl: number): boolean {
|
|
|
108
106
|
return cl >= 97 && cl <= 122 ? res : !res;
|
|
109
107
|
}
|
|
110
108
|
|
|
111
|
-
function classEnd(p:
|
|
109
|
+
function classEnd(p: Uint16Array, plen: number, pi: number): number {
|
|
112
110
|
const ch = p[pi];
|
|
113
111
|
pi++;
|
|
114
112
|
if (ch === CH_ESC) {
|
|
@@ -138,7 +136,7 @@ function classEnd(p: Uint8Array, plen: number, pi: number): number {
|
|
|
138
136
|
|
|
139
137
|
function matchBracketClass(
|
|
140
138
|
c: number,
|
|
141
|
-
p:
|
|
139
|
+
p: Uint16Array,
|
|
142
140
|
pi: number,
|
|
143
141
|
ec: number,
|
|
144
142
|
): boolean {
|
|
@@ -404,8 +402,8 @@ function match(ms: MatchState, si: number, pi: number): number {
|
|
|
404
402
|
}
|
|
405
403
|
|
|
406
404
|
function createMatchState(s: string, p: string): MatchState {
|
|
407
|
-
const sb =
|
|
408
|
-
const pb =
|
|
405
|
+
const sb = toCodeUnits(s);
|
|
406
|
+
const pb = toCodeUnits(p);
|
|
409
407
|
const capture: Capture[] = new Array(MAX_CAPTURES);
|
|
410
408
|
for (let i = 0; i < MAX_CAPTURES; i++) {
|
|
411
409
|
capture[i] = { init: 0, len: 0 };
|
|
@@ -434,8 +432,6 @@ function noSpecials(p: string): boolean {
|
|
|
434
432
|
return true;
|
|
435
433
|
}
|
|
436
434
|
|
|
437
|
-
// Public API
|
|
438
|
-
|
|
439
435
|
export type CaptureResult = { s: string } | { position: number };
|
|
440
436
|
|
|
441
437
|
interface RawCapture {
|
|
@@ -615,7 +611,6 @@ function expandReplacementString(
|
|
|
615
611
|
throw new Error("invalid use of '%' in replacement string");
|
|
616
612
|
}
|
|
617
613
|
} else {
|
|
618
|
-
// Collect consecutive literal characters
|
|
619
614
|
let j = i + 1;
|
|
620
615
|
while (j < repl.length && repl.charCodeAt(j) !== CH_ESC) j++;
|
|
621
616
|
parts.push(repl.substring(i, j));
|
|
@@ -180,7 +180,6 @@ export async function interpolateLuaString(
|
|
|
180
180
|
|
|
181
181
|
result += template.slice(currentIndex, startIndex);
|
|
182
182
|
|
|
183
|
-
// Find matching closing brace by counting nesting
|
|
184
183
|
let nestLevel = 1;
|
|
185
184
|
let endIndex = startIndex + 2;
|
|
186
185
|
while (nestLevel > 0 && endIndex < template.length) {
|
|
@@ -519,7 +518,7 @@ export const spaceluaApi = new LuaTable({
|
|
|
519
518
|
*/
|
|
520
519
|
baseUrl: new LuaBuiltinFunction({
|
|
521
520
|
callback: () => {
|
|
522
|
-
//
|
|
521
|
+
// The origin contract excludes a trailing slash.
|
|
523
522
|
return document.baseURI.replace(/\/*$/, "");
|
|
524
523
|
},
|
|
525
524
|
description:
|
|
@@ -145,7 +145,6 @@ function getOption(
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
// Compute alignment padding
|
|
149
148
|
function getDetails(
|
|
150
149
|
fmt: string,
|
|
151
150
|
pos: number,
|
|
@@ -264,7 +263,6 @@ export const strPackFn = new LuaBuiltinFunction({
|
|
|
264
263
|
let opt: ParsedOption;
|
|
265
264
|
[opt, pos] = getDetails(fmt, pos, h, totalsize);
|
|
266
265
|
|
|
267
|
-
// alignment padding
|
|
268
266
|
if (opt.ntoalign > 0) {
|
|
269
267
|
parts.push(new Uint8Array(opt.ntoalign));
|
|
270
268
|
totalsize += opt.ntoalign;
|
|
@@ -349,7 +347,6 @@ export const strPackFn = new LuaBuiltinFunction({
|
|
|
349
347
|
}
|
|
350
348
|
}
|
|
351
349
|
|
|
352
|
-
// Concatenate all parts into one binary string (latin-1 encoding)
|
|
353
350
|
let total = 0;
|
|
354
351
|
for (const p of parts) total += p.length;
|
|
355
352
|
const out = new Uint8Array(total);
|
|
@@ -274,12 +274,10 @@ export const tableApi = new LuaTable({
|
|
|
274
274
|
t: number,
|
|
275
275
|
a2?: LuaTable | any[],
|
|
276
276
|
) => {
|
|
277
|
-
// a2 defaults to a1
|
|
278
277
|
if (a2 === undefined || a2 === null) {
|
|
279
278
|
a2 = a1;
|
|
280
279
|
}
|
|
281
280
|
|
|
282
|
-
// Empty range: nothing to do, return destination
|
|
283
281
|
if (e < f) {
|
|
284
282
|
return a2;
|
|
285
283
|
}
|
|
@@ -422,7 +420,6 @@ export const tableApi = new LuaTable({
|
|
|
422
420
|
return false;
|
|
423
421
|
}
|
|
424
422
|
if (tbl instanceof LuaTable) {
|
|
425
|
-
// Iterate over the table
|
|
426
423
|
for (const key of tbl.keys()) {
|
|
427
424
|
if (luaEquals(tbl.get(key), value)) {
|
|
428
425
|
return true;
|
|
@@ -459,9 +456,7 @@ export const tableApi = new LuaTable({
|
|
|
459
456
|
tbl: LuaTable | Record<string, any>,
|
|
460
457
|
...keys: LuaValue[]
|
|
461
458
|
) => {
|
|
462
|
-
// Normalize arguments
|
|
463
459
|
if (Array.isArray(keys[0])) {
|
|
464
|
-
// First argument is key array, let's unpack
|
|
465
460
|
keys = keys[0];
|
|
466
461
|
} else if (keys[0] instanceof LuaTable) {
|
|
467
462
|
keys = keys[0].toJSArray();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LuaBudgetStopped } from "./budget.ts";
|
|
1
2
|
import {
|
|
2
3
|
getMetatable,
|
|
3
4
|
type ILuaFunction,
|
|
@@ -101,7 +102,6 @@ const ipairsFunction = new LuaBuiltinFunction({
|
|
|
101
102
|
|
|
102
103
|
const pairsFunction = new LuaBuiltinFunction({
|
|
103
104
|
callback: (sf, t: LuaTable | any[] | Record<string, any>) => {
|
|
104
|
-
// Respect `__pairs` metamethod for Lua tables
|
|
105
105
|
if (isLuaTable(t)) {
|
|
106
106
|
const mt = (t as any).metatable as LuaTable | null | undefined;
|
|
107
107
|
if (mt) {
|
|
@@ -295,27 +295,24 @@ async function pcallBoundary(
|
|
|
295
295
|
const msg = errMsgOf(e);
|
|
296
296
|
try {
|
|
297
297
|
await luaCloseFromMark(sf, mark, msg);
|
|
298
|
-
return { ok: false, message: msg };
|
|
299
298
|
} catch (closeErr: any) {
|
|
300
|
-
|
|
299
|
+
if (!(e instanceof LuaBudgetStopped)) {
|
|
300
|
+
return { ok: false, message: errMsgOf(closeErr) };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// A user-initiated stop is not a recoverable Lua error.
|
|
304
|
+
if (e instanceof LuaBudgetStopped) {
|
|
305
|
+
throw e;
|
|
301
306
|
}
|
|
307
|
+
return { ok: false, message: msg };
|
|
302
308
|
}
|
|
303
309
|
}
|
|
304
310
|
|
|
305
311
|
const pcallFunction = new LuaBuiltinFunction({
|
|
306
312
|
callback: async (sf, fn: ILuaFunction, ...args) => {
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
// after that.
|
|
311
|
-
//
|
|
312
|
-
// The protected call boundary must be established *before*
|
|
313
|
-
// evaluating the function and its arguments. Otherwise, any
|
|
314
|
-
// `<close>` locals created while evaluating `pcall`'s arguments
|
|
315
|
-
// will be wrongly treated as "inside" the protected call, and
|
|
316
|
-
// `pcall` may end up closing them (or affecting close ordering).
|
|
317
|
-
//
|
|
318
|
-
// `threadState` is read-only on the stack frame; do not reassign!
|
|
313
|
+
// Snapshot the close stack before evaluating the function and arguments,
|
|
314
|
+
// so argument-owned <close> locals stay outside the protected boundary.
|
|
315
|
+
// Do not reassign the frame’s read-only threadState.
|
|
319
316
|
const res = await pcallBoundary(sf, fn, args);
|
|
320
317
|
if (res.ok) {
|
|
321
318
|
return new LuaMultiRes([true, ...res.values]);
|
|
@@ -345,7 +342,6 @@ const xpcallFunction = new LuaBuiltinFunction({
|
|
|
345
342
|
errorHandler: ILuaFunction,
|
|
346
343
|
...args
|
|
347
344
|
) => {
|
|
348
|
-
// Same semantic as `pcall` (see comments there)
|
|
349
345
|
const res = await pcallBoundary(sf, fn, args);
|
|
350
346
|
if (res.ok) {
|
|
351
347
|
return new LuaMultiRes([true, ...res.values]);
|
|
@@ -505,6 +501,12 @@ const dofileFunction = new LuaBuiltinFunction({
|
|
|
505
501
|
const env = new LuaEnv(global);
|
|
506
502
|
await evalStatement(parsedExpr, env, sf.withCtx(parsedExpr.ctx));
|
|
507
503
|
} catch (e: any) {
|
|
504
|
+
// A user-initiated stop must keep its identity so an enclosing
|
|
505
|
+
// pcall/xpcall still recognizes and rethrows it, rather than being
|
|
506
|
+
// rewrapped into a recoverable LuaRuntimeError.
|
|
507
|
+
if (e instanceof LuaBudgetStopped) {
|
|
508
|
+
throw e;
|
|
509
|
+
}
|
|
508
510
|
throw new LuaRuntimeError(
|
|
509
511
|
`Error evaluating "${filename}": ${e.message}`,
|
|
510
512
|
sf,
|
|
@@ -582,30 +584,24 @@ const nextFunction = new LuaBuiltinFunction({
|
|
|
582
584
|
index: number | null = null,
|
|
583
585
|
) => {
|
|
584
586
|
if (!table) {
|
|
585
|
-
// When nil value
|
|
586
587
|
return null;
|
|
587
588
|
}
|
|
588
589
|
const keys = luaKeys(table);
|
|
589
590
|
|
|
590
|
-
// Empty table -> null return value
|
|
591
591
|
if (keys.length === 0) {
|
|
592
592
|
return null;
|
|
593
593
|
}
|
|
594
594
|
|
|
595
595
|
if (index === null) {
|
|
596
|
-
// Return the first key, value
|
|
597
596
|
const key = keys[0];
|
|
598
597
|
return new LuaMultiRes([key, luaGet(table, key, sf.astCtx ?? null, sf)]);
|
|
599
598
|
}
|
|
600
|
-
// Find index in the key list
|
|
601
599
|
const idx = keys.indexOf(index);
|
|
602
600
|
if (idx === -1) {
|
|
603
|
-
// Not found
|
|
604
601
|
throw new LuaRuntimeError("invalid key to 'next': key not found", sf);
|
|
605
602
|
}
|
|
606
603
|
const key = keys[idx + 1];
|
|
607
604
|
if (key === undefined) {
|
|
608
|
-
// When called with the last key, should return nil
|
|
609
605
|
return null;
|
|
610
606
|
}
|
|
611
607
|
return new LuaMultiRes([key, luaGet(table, key, sf.astCtx ?? null, sf)]);
|
|
@@ -622,7 +618,6 @@ const nextFunction = new LuaBuiltinFunction({
|
|
|
622
618
|
],
|
|
623
619
|
});
|
|
624
620
|
|
|
625
|
-
// Non-standard, but useful
|
|
626
621
|
const someFunction = new LuaBuiltinFunction({
|
|
627
622
|
callback: async (_sf, value: any) => {
|
|
628
623
|
switch (await luaTypeOf(value)) {
|
|
@@ -691,13 +686,11 @@ function annotateBuiltinApi(
|
|
|
691
686
|
|
|
692
687
|
export function luaBuildStandardEnv() {
|
|
693
688
|
const env = new LuaEnv();
|
|
694
|
-
// _G global
|
|
695
689
|
env.set("_G", env);
|
|
696
690
|
// Lua version string - for now it signals Lua 5.4 compatibility with
|
|
697
691
|
// selective 5.5 features; kept non-standard so callers can distinguish
|
|
698
692
|
// Space Lua from a plain Lua runtime.
|
|
699
693
|
env.set("_VERSION", "Lua 5.4+");
|
|
700
|
-
// Top-level builtins
|
|
701
694
|
env.set("print", printFunction);
|
|
702
695
|
env.set("assert", assertFunction);
|
|
703
696
|
env.set("type", typeFunction);
|
|
@@ -705,10 +698,8 @@ export function luaBuildStandardEnv() {
|
|
|
705
698
|
env.set("tonumber", tonumberFunction);
|
|
706
699
|
env.set("select", selectFunction);
|
|
707
700
|
env.set("next", nextFunction);
|
|
708
|
-
// Iterators
|
|
709
701
|
env.set("pairs", pairsFunction);
|
|
710
702
|
env.set("ipairs", ipairsFunction);
|
|
711
|
-
// meta table stuff
|
|
712
703
|
env.set("setmetatable", setmetatableFunction);
|
|
713
704
|
env.set("getmetatable", getmetatableFunction);
|
|
714
705
|
env.set("rawlen", rawlenFunction);
|
|
@@ -716,19 +707,15 @@ export function luaBuildStandardEnv() {
|
|
|
716
707
|
env.set("rawget", rawgetFunction);
|
|
717
708
|
env.set("rawequal", rawequalFunction);
|
|
718
709
|
env.set("dofile", dofileFunction);
|
|
719
|
-
// Error handling
|
|
720
710
|
env.set("error", errorFunction);
|
|
721
711
|
env.set("pcall", pcallFunction);
|
|
722
712
|
env.set("xpcall", xpcallFunction);
|
|
723
|
-
// Evaluation
|
|
724
713
|
env.set("load", loadFunction);
|
|
725
|
-
// APIs
|
|
726
714
|
env.set("string", stringApi);
|
|
727
715
|
env.set("table", tableApi);
|
|
728
716
|
env.set("os", osApi);
|
|
729
717
|
env.set("js", jsApi);
|
|
730
718
|
env.set("math", mathApi);
|
|
731
|
-
// Non-standard
|
|
732
719
|
env.set("each", eachFunction);
|
|
733
720
|
env.set("spacelua", spaceluaApi);
|
|
734
721
|
env.set("encoding", encodingApi);
|
|
@@ -142,7 +142,6 @@ function parseInt(s: string): { ok: boolean; value: number } {
|
|
|
142
142
|
let acc = 0;
|
|
143
143
|
let any = false;
|
|
144
144
|
|
|
145
|
-
// hex?
|
|
146
145
|
if (s.charCodeAt(i) === 48 && i + 1 < n) {
|
|
147
146
|
// '0'
|
|
148
147
|
const x = s.charCodeAt(i + 1);
|
|
@@ -179,7 +178,6 @@ function parseInt(s: string): { ok: boolean; value: number } {
|
|
|
179
178
|
}
|
|
180
179
|
}
|
|
181
180
|
|
|
182
|
-
// decimal integer
|
|
183
181
|
while (i < n) {
|
|
184
182
|
const c = s.charCodeAt(i);
|
|
185
183
|
if (c < 48 || c > 57) {
|
|
@@ -221,7 +219,6 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
|
|
|
221
219
|
let fracAny = false;
|
|
222
220
|
let val = 0;
|
|
223
221
|
|
|
224
|
-
// integer part
|
|
225
222
|
while (i < n) {
|
|
226
223
|
const c = s.charCodeAt(i);
|
|
227
224
|
if (c < 48 || c > 57) {
|
|
@@ -233,7 +230,6 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
|
|
|
233
230
|
i++;
|
|
234
231
|
}
|
|
235
232
|
|
|
236
|
-
// fractional part
|
|
237
233
|
if (i < n) {
|
|
238
234
|
if (s.charCodeAt(i) === 46) {
|
|
239
235
|
// '.'
|
|
@@ -253,7 +249,6 @@ function parseDecFloat(s: string): { ok: boolean; value: number } {
|
|
|
253
249
|
}
|
|
254
250
|
}
|
|
255
251
|
|
|
256
|
-
// exponent
|
|
257
252
|
let exp = 0;
|
|
258
253
|
let hasExp = false;
|
|
259
254
|
if (i < n) {
|
|
@@ -347,7 +342,6 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
|
|
|
347
342
|
let anyHex = false;
|
|
348
343
|
let sawDot = false;
|
|
349
344
|
|
|
350
|
-
// integer hex digits
|
|
351
345
|
while (i < n) {
|
|
352
346
|
const c = s.charCodeAt(i);
|
|
353
347
|
let d = -1;
|
|
@@ -371,7 +365,6 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
|
|
|
371
365
|
i++;
|
|
372
366
|
}
|
|
373
367
|
|
|
374
|
-
// optional fractional part
|
|
375
368
|
if (i < n) {
|
|
376
369
|
if (s.charCodeAt(i) === 46) {
|
|
377
370
|
// '.'
|
|
@@ -444,7 +437,6 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
|
|
|
444
437
|
return { ok: false, value: 0 };
|
|
445
438
|
}
|
|
446
439
|
} else {
|
|
447
|
-
// no exponent marker
|
|
448
440
|
if (!sawDot) {
|
|
449
441
|
// without dot we must reject so parseInt can claim it as integer
|
|
450
442
|
return { ok: false, value: 0 };
|
|
@@ -456,7 +448,6 @@ function parseHexFloat(s: string): { ok: boolean; value: number } {
|
|
|
456
448
|
exp = 0; // implicit p0
|
|
457
449
|
}
|
|
458
450
|
} else {
|
|
459
|
-
// end of string
|
|
460
451
|
if (!sawDot) {
|
|
461
452
|
return { ok: false, value: 0 };
|
|
462
453
|
}
|
package/dist/plug-compile.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
6
|
// version.ts
|
|
7
|
-
var version = "2.
|
|
7
|
+
var version = "2.11.0";
|
|
8
8
|
|
|
9
9
|
// client/plugos/plug_compile.ts
|
|
10
10
|
import * as path from "node:path";
|
|
@@ -1371,8 +1371,7 @@ ${Object.entries(manifest.functions).map(([funcName, def]) => {
|
|
|
1371
1371
|
}
|
|
1372
1372
|
let [filePath, jsFunctionName] = def.path.split(":");
|
|
1373
1373
|
filePath = path.join(rootPath, filePath);
|
|
1374
|
-
return `import {${jsFunctionName} as ${funcName}} from "${
|
|
1375
|
-
path.resolve(filePath).replaceAll("\\", "\\\\")}";
|
|
1374
|
+
return `import {${jsFunctionName} as ${funcName}} from "${path.resolve(filePath).replaceAll("\\", "\\\\")}";
|
|
1376
1375
|
`;
|
|
1377
1376
|
}).join("")}
|
|
1378
1377
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silverbulletmd/silverbullet",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A self-hosted, web-based note taking app",
|
|
6
6
|
"publishConfig": {
|
|
@@ -15,20 +15,26 @@
|
|
|
15
15
|
"./lib/tree": "./plug-api/lib/tree.ts",
|
|
16
16
|
"./lib/ref": "./plug-api/lib/ref.ts",
|
|
17
17
|
"./lib/resolve": "./plug-api/lib/resolve.ts",
|
|
18
|
+
"./lib/resolve_path": "./plug-api/lib/resolve_path.ts",
|
|
19
|
+
"./lib/link_write": "./plug-api/lib/link_write.ts",
|
|
18
20
|
"./lib/dates": "./plug-api/lib/dates.ts",
|
|
21
|
+
"./lib/fuzzy": "./plug-api/lib/fuzzy.ts",
|
|
19
22
|
"./lib/async": "./plug-api/lib/async.ts",
|
|
20
23
|
"./lib/crypto": "./plug-api/lib/crypto.ts",
|
|
21
24
|
"./lib/limited_map": "./plug-api/lib/limited_map.ts",
|
|
22
25
|
"./lib/tags": "./plug-api/lib/tags.ts",
|
|
26
|
+
"./lib/collation": "./plug-api/lib/collation.ts",
|
|
23
27
|
"./lib/transclusion": "./plug-api/lib/transclusion.ts",
|
|
24
28
|
"./lib/native_fetch": "./plug-api/lib/native_fetch.ts",
|
|
25
29
|
"./lib/query_expression": "./plug-api/lib/query_expression.ts",
|
|
30
|
+
"./lib/panel_styles": "./plug-api/lib/panel_styles.ts",
|
|
26
31
|
"./type/client": "./plug-api/types/client.ts",
|
|
27
32
|
"./type/config": "./plug-api/types/config.ts",
|
|
28
33
|
"./type/manifest": "./plug-api/types/manifest.ts",
|
|
29
34
|
"./type/namespace": "./plug-api/types/namespace.ts",
|
|
30
35
|
"./type/datastore": "./plug-api/types/datastore.ts",
|
|
31
36
|
"./type/event": "./plug-api/types/event.ts",
|
|
37
|
+
"./type/revisions": "./plug-api/types/revisions.ts",
|
|
32
38
|
"./type/index": "./plug-api/types/index.ts"
|
|
33
39
|
},
|
|
34
40
|
"bin": {
|
|
@@ -41,6 +47,7 @@
|
|
|
41
47
|
"client/plugos/**/*.ts",
|
|
42
48
|
"!client/plugos/**/*.test.ts",
|
|
43
49
|
"client/asset_bundle/bundle.ts",
|
|
50
|
+
"client/config.ts",
|
|
44
51
|
"client/data/kv_primitives.ts",
|
|
45
52
|
"client/data/datastore.ts",
|
|
46
53
|
"client/space_lua/**/*.ts",
|
|
@@ -48,6 +55,7 @@
|
|
|
48
55
|
"!client/space_lua/**/*.bench.ts",
|
|
49
56
|
"client/markdown_parser/constants.ts",
|
|
50
57
|
"plugs/builtin_plugs.ts",
|
|
58
|
+
"plugs/index/types.ts",
|
|
51
59
|
"dist/plug-compile.js"
|
|
52
60
|
],
|
|
53
61
|
"scripts": {
|
|
@@ -55,9 +63,10 @@
|
|
|
55
63
|
"build:plugs": "tsx build/build_plugs.ts",
|
|
56
64
|
"build:client": "tsx build/build_client.ts",
|
|
57
65
|
"build:plug-compile": "tsx build/build_plug_compile.ts",
|
|
66
|
+
"prebuild:client": "node build/patch_codemirror_view.mjs",
|
|
58
67
|
"prepublishOnly": "npm run build:plug-compile",
|
|
59
68
|
"test": "vitest run",
|
|
60
|
-
"check": "tsc --noEmit",
|
|
69
|
+
"check": "tsc --noEmit && tsc -p tsconfig.e2e.json",
|
|
61
70
|
"lint": "biome lint .",
|
|
62
71
|
"fmt": "biome format --write .",
|
|
63
72
|
"fmt:check": "biome format .",
|
|
@@ -92,8 +101,10 @@
|
|
|
92
101
|
"@lezer/lr": "1.4.8",
|
|
93
102
|
"@lezer/markdown": "1.6.3",
|
|
94
103
|
"@msgpack/msgpack": "3.1.3",
|
|
104
|
+
"@noble/hashes": "2.0.1",
|
|
95
105
|
"@replit/codemirror-lang-nix": "6.0.1",
|
|
96
106
|
"@replit/codemirror-vim": "6.3.0",
|
|
107
|
+
"@types/js-yaml": "^4.0.9",
|
|
97
108
|
"commander": "^14.0.3",
|
|
98
109
|
"crelt": "1.0.6",
|
|
99
110
|
"d3-force": "^3.0.0",
|
|
@@ -118,7 +129,6 @@
|
|
|
118
129
|
"@preact/preset-vite": "^2.10.3",
|
|
119
130
|
"@types/d3-force": "^3.0.10",
|
|
120
131
|
"@types/gitignore-parser": "^0.0.3",
|
|
121
|
-
"@types/js-yaml": "^4.0.9",
|
|
122
132
|
"@types/node": "^22.0.0",
|
|
123
133
|
"@types/turndown": "^5.0.6",
|
|
124
134
|
"fake-indexeddb": "6.0.1",
|
package/plug-api/lib/async.ts
CHANGED
|
@@ -11,7 +11,6 @@ export function throttle(
|
|
|
11
11
|
}, limit);
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
|
-
// Immediately execute any pending call and cancel the timer
|
|
15
14
|
throttled.flush = () => {
|
|
16
15
|
if (timer) {
|
|
17
16
|
clearTimeout(timer);
|
|
@@ -91,7 +90,7 @@ export class PromiseQueue {
|
|
|
91
90
|
reject(error);
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
void this.process();
|
|
93
|
+
void this.process();
|
|
95
94
|
}
|
|
96
95
|
}
|
|
97
96
|
|
|
@@ -108,17 +107,13 @@ export async function batchRequests<I, O>(
|
|
|
108
107
|
batchSize: number,
|
|
109
108
|
): Promise<O[]> {
|
|
110
109
|
const results: O[] = [];
|
|
111
|
-
// Split values into batches of batchSize
|
|
112
110
|
const batches: I[][] = [];
|
|
113
111
|
for (let i = 0; i < values.length; i += batchSize) {
|
|
114
112
|
batches.push(values.slice(i, i + batchSize));
|
|
115
113
|
}
|
|
116
|
-
// Run fn on them in parallel
|
|
117
114
|
const batchResults = await Promise.all(batches.map(fn));
|
|
118
|
-
// Flatten the results
|
|
119
115
|
for (const batchResult of batchResults) {
|
|
120
116
|
if (Array.isArray(batchResult)) {
|
|
121
|
-
// If fn returns an array, collect them
|
|
122
117
|
results.push(...batchResult);
|
|
123
118
|
}
|
|
124
119
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { QueryCollationConfig } from "../types/config.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compares two values the same way the query engine's `order by` does:
|
|
5
|
+
* codepoint order by default, or `Intl.Collator` order when the space's
|
|
6
|
+
* `queryCollation` config turns it on and both sides are strings.
|
|
7
|
+
*/
|
|
8
|
+
export function compareCollated(
|
|
9
|
+
// deno-lint-ignore no-explicit-any
|
|
10
|
+
a: any,
|
|
11
|
+
// deno-lint-ignore no-explicit-any
|
|
12
|
+
b: any,
|
|
13
|
+
collation: QueryCollationConfig | undefined,
|
|
14
|
+
collator: Intl.Collator,
|
|
15
|
+
): number {
|
|
16
|
+
if (collation?.enabled && typeof a === "string" && typeof b === "string") {
|
|
17
|
+
return collator.compare(a, b);
|
|
18
|
+
}
|
|
19
|
+
if (a < b) return -1;
|
|
20
|
+
if (a > b) return 1;
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
package/plug-api/lib/crypto.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
+
|
|
1
3
|
export function base64Decode(s: string): Uint8Array {
|
|
2
4
|
const binString = atob(s);
|
|
3
5
|
const len = binString.length;
|
|
@@ -32,31 +34,33 @@ export function base64DecodeDataUrl(dataUrl: string): Uint8Array {
|
|
|
32
34
|
return base64Decode(b64Encoded);
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
/**
|
|
36
|
-
* Perform sha256 hash using the browser's crypto APIs
|
|
37
|
-
* Note: this will only work over HTTPS
|
|
38
|
-
* @param message
|
|
39
|
-
*/
|
|
40
37
|
export async function hashSHA256(
|
|
41
38
|
message: string | Uint8Array,
|
|
42
39
|
): Promise<string> {
|
|
43
|
-
// Transform the string into an ArrayBuffer
|
|
44
40
|
const encoder = new TextEncoder();
|
|
45
41
|
const data: Uint8Array =
|
|
46
42
|
typeof message === "string" ? encoder.encode(message) : message;
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
data as BufferSource,
|
|
52
|
-
);
|
|
44
|
+
const hashBuffer = globalThis.crypto.subtle
|
|
45
|
+
? await globalThis.crypto.subtle.digest("SHA-256", data as BufferSource)
|
|
46
|
+
: sha256(data);
|
|
53
47
|
|
|
54
|
-
// Transform the hash into a hex string
|
|
55
48
|
return Array.from(new Uint8Array(hashBuffer))
|
|
56
49
|
.map((b) => b.toString(16).padStart(2, "0"))
|
|
57
50
|
.join("");
|
|
58
51
|
}
|
|
59
52
|
|
|
53
|
+
export function randomUUID(): string {
|
|
54
|
+
if (globalThis.crypto.randomUUID) return globalThis.crypto.randomUUID();
|
|
55
|
+
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16));
|
|
56
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
57
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
58
|
+
const hex = Array.from(bytes, (byte) =>
|
|
59
|
+
byte.toString(16).padStart(2, "0"),
|
|
60
|
+
).join("");
|
|
61
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
/**
|
|
61
65
|
* To avoid database clashes based on space folder path name, base URLs and encryption keys we derive
|
|
62
66
|
* a database name from a hash of all these combined together
|
|
@@ -117,7 +121,6 @@ export async function encryptAesGcm(
|
|
|
117
121
|
);
|
|
118
122
|
const encrypted = new Uint8Array(encryptedBuffer);
|
|
119
123
|
|
|
120
|
-
// Prepend IV to ciphertext
|
|
121
124
|
const result = new Uint8Array(iv.length + encrypted.length);
|
|
122
125
|
result.set(iv, 0);
|
|
123
126
|
result.set(encrypted, iv.length);
|
|
@@ -143,10 +146,8 @@ export async function deriveCTRKeyFromPassword(
|
|
|
143
146
|
password: string,
|
|
144
147
|
salt: Uint8Array,
|
|
145
148
|
): Promise<CryptoKey> {
|
|
146
|
-
// Encode password to ArrayBuffer
|
|
147
149
|
const passwordBytes = new TextEncoder().encode(password);
|
|
148
150
|
|
|
149
|
-
// Import password as a CryptoKey
|
|
150
151
|
const baseKey = await globalThis.crypto.subtle.importKey(
|
|
151
152
|
"raw",
|
|
152
153
|
passwordBytes,
|