@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
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { Path, Ref } from "@silverbulletmd/silverbullet/lib/ref";
|
|
3
2
|
import type {
|
|
4
3
|
DocumentMeta,
|
|
5
4
|
FileMeta,
|
|
6
5
|
PageMeta,
|
|
7
6
|
} from "../../plug-api/types/index.ts";
|
|
8
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
FileRevisions,
|
|
9
|
+
SpaceLog,
|
|
10
|
+
} from "../../plug-api/types/revisions.ts";
|
|
11
|
+
import type { PathLookup } from "../lib/resolve_path.ts";
|
|
12
|
+
import { syscall } from "../syscall.ts";
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Exposes the space with its pages, documents and plugs.
|
|
@@ -134,8 +138,6 @@ export function deleteDocument(name: string): Promise<void> {
|
|
|
134
138
|
return syscall("space.deleteDocument", name);
|
|
135
139
|
}
|
|
136
140
|
|
|
137
|
-
// Lower level-file operations
|
|
138
|
-
|
|
139
141
|
/**
|
|
140
142
|
* List all files in the space (pages, documents and plugs).
|
|
141
143
|
* @returns a list of all files in the space represented as FileMeta objects
|
|
@@ -203,3 +205,118 @@ export function deleteFile(name: string): Promise<void> {
|
|
|
203
205
|
export function fileExists(name: string): Promise<boolean> {
|
|
204
206
|
return syscall("space.fileExists", name);
|
|
205
207
|
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Every basename carried by more than one file, with the files that carry it.
|
|
211
|
+
* Small under the bare-iff-unique invariant; pair with `collisionIndex` and
|
|
212
|
+
* `writeLinkPath` from `lib/resolve_path` to decide link write formats.
|
|
213
|
+
*/
|
|
214
|
+
export function collidingBasenames(): Promise<Record<string, Path[]>> {
|
|
215
|
+
return syscall("space.collidingBasenames");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Looks up a batch of paths at once: for each, whether that exact path exists
|
|
220
|
+
* and which files share its basename. Pair with `lookupIndex` and `resolvePath`
|
|
221
|
+
* from `lib/resolve_path` to resolve them.
|
|
222
|
+
*/
|
|
223
|
+
export function lookupPaths(
|
|
224
|
+
paths: string[],
|
|
225
|
+
): Promise<Record<string, PathLookup>> {
|
|
226
|
+
return syscall("space.lookupPaths", paths);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Lists the revision history of a file.
|
|
231
|
+
* @param path the path of the file to list revisions for
|
|
232
|
+
* @param before list revisions older than this revision id
|
|
233
|
+
*/
|
|
234
|
+
export function listRevisions(
|
|
235
|
+
path: string,
|
|
236
|
+
before?: string,
|
|
237
|
+
): Promise<FileRevisions> {
|
|
238
|
+
return syscall("space.listRevisions", path, before);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Reads the text of a file as it was at a given revision, or at that
|
|
243
|
+
* revision's parent.
|
|
244
|
+
* @param path the path of the file to read
|
|
245
|
+
* @param rev the revision id to read
|
|
246
|
+
* @param parent read the file as of the revision's parent instead (e.g. the
|
|
247
|
+
* version immediately before a deletion commit)
|
|
248
|
+
*/
|
|
249
|
+
export function getRevision(
|
|
250
|
+
path: string,
|
|
251
|
+
rev: string,
|
|
252
|
+
parent?: boolean,
|
|
253
|
+
): Promise<string> {
|
|
254
|
+
return syscall("space.getRevision", path, rev, parent);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Reads a unified diff of a revision's own change (vs its parent; a root
|
|
259
|
+
* commit reads as fully added).
|
|
260
|
+
* @param path the path of the file to diff
|
|
261
|
+
* @param rev the revision id to diff; omitted, diffs the uncommitted change
|
|
262
|
+
*/
|
|
263
|
+
export function getRevisionDiff(path: string, rev?: string): Promise<string> {
|
|
264
|
+
return syscall("space.getRevisionDiff", path, rev);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Lists the space-wide commit log.
|
|
269
|
+
* @param before list commits older than this revision id
|
|
270
|
+
* @param q match commits whose message or author contains this phrase
|
|
271
|
+
*/
|
|
272
|
+
export function getSpaceLog(before?: string, q?: string): Promise<SpaceLog> {
|
|
273
|
+
return syscall("space.getSpaceLog", before, q);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Commits everything outstanding as a revision now, rather than waiting for
|
|
278
|
+
* the automatic commit.
|
|
279
|
+
* @returns false if there was nothing to commit
|
|
280
|
+
*/
|
|
281
|
+
export function createRevisionSnapshot(): Promise<boolean> {
|
|
282
|
+
return syscall("space.createRevisionSnapshot");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function getGitSyncStatus(): Promise<
|
|
286
|
+
import("../types/revisions.ts").GitSyncSnapshot
|
|
287
|
+
> {
|
|
288
|
+
return syscall("space.getGitSyncStatus");
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function getGitConflicts(): Promise<
|
|
292
|
+
import("../types/revisions.ts").GitConflicts
|
|
293
|
+
> {
|
|
294
|
+
return syscall("space.getGitConflicts");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function syncGitNow(): Promise<void> {
|
|
298
|
+
return syscall("space.syncGitNow");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function resolveGitConflict(
|
|
302
|
+
id: string,
|
|
303
|
+
generation: string,
|
|
304
|
+
contentRevision: string,
|
|
305
|
+
action: import("../types/revisions.ts").GitConflictAction,
|
|
306
|
+
): Promise<import("../types/revisions.ts").GitConflicts> {
|
|
307
|
+
return syscall(
|
|
308
|
+
"space.resolveGitConflict",
|
|
309
|
+
id,
|
|
310
|
+
generation,
|
|
311
|
+
contentRevision,
|
|
312
|
+
action,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function getGitConflictVersion(
|
|
317
|
+
id: string,
|
|
318
|
+
generation: string,
|
|
319
|
+
side: "local" | "remote",
|
|
320
|
+
): Promise<Uint8Array> {
|
|
321
|
+
return syscall("space.getGitConflictVersion", id, generation, side);
|
|
322
|
+
}
|
|
@@ -12,12 +12,33 @@ export function hasInitialSyncCompleted(): Promise<boolean> {
|
|
|
12
12
|
return syscall("sync.hasInitialSyncCompleted");
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* For each file, whether indexing it now would read it locally or cheaply
|
|
17
|
+
* (true), or race the initial sync and expensively re-download it (false).
|
|
18
|
+
* Always all-true outside a fresh install's initial index window.
|
|
19
|
+
* @param paths the space-relative file paths
|
|
20
|
+
*/
|
|
21
|
+
export function areFilesReadyToIndex(paths: string[]): Promise<boolean[]> {
|
|
22
|
+
return syscall("sync.areFilesReadyToIndex", paths);
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
/**
|
|
16
26
|
* Syncs a file immediately. Sync would happen automatically, but this prioritizes the file.
|
|
17
27
|
* @param path the path to the file to sync
|
|
28
|
+
* @param remoteLastModified lastModified of the remote change event, used for echo suppression
|
|
29
|
+
* @param remoteRevisionHash content revision the remote change event reported, which tells a same-millisecond change from an echo
|
|
18
30
|
*/
|
|
19
|
-
export function performFileSync(
|
|
20
|
-
|
|
31
|
+
export function performFileSync(
|
|
32
|
+
path: string,
|
|
33
|
+
remoteLastModified?: number,
|
|
34
|
+
remoteRevisionHash?: string,
|
|
35
|
+
): Promise<void> {
|
|
36
|
+
return syscall(
|
|
37
|
+
"sync.performFileSync",
|
|
38
|
+
path,
|
|
39
|
+
remoteLastModified,
|
|
40
|
+
remoteRevisionHash,
|
|
41
|
+
);
|
|
21
42
|
}
|
|
22
43
|
|
|
23
44
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { syscall } from "../syscall.ts";
|
|
2
2
|
import type { CommandDef } from "../types/manifest.ts";
|
|
3
3
|
import type { SyscallMeta } from "@silverbulletmd/silverbullet/type/index";
|
|
4
|
+
import type { Account, ClientProfile } from "../types/profile.ts";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* System level syscalls
|
|
@@ -35,6 +36,34 @@ export function listCommands(): Promise<Record<string, CommandDef>> {
|
|
|
35
36
|
return syscall("system.listCommands");
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Lists the commands the command palette would show right now: context- and
|
|
41
|
+
* mode-filtered, hidden ones dropped, each with its prettified key hint and
|
|
42
|
+
* the time it was last run on this client.
|
|
43
|
+
* Note: only available on the client
|
|
44
|
+
*/
|
|
45
|
+
export function listPaletteCommands(): Promise<
|
|
46
|
+
{
|
|
47
|
+
name: string;
|
|
48
|
+
priority: number;
|
|
49
|
+
lastRun?: number;
|
|
50
|
+
hint?: string;
|
|
51
|
+
}[]
|
|
52
|
+
> {
|
|
53
|
+
return syscall("system.listPaletteCommands");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Runs a command as if it had been picked from the command palette: records
|
|
58
|
+
* it as the most recently run (which is what orders the palette), then
|
|
59
|
+
* invokes it.
|
|
60
|
+
* Note: only available on the client
|
|
61
|
+
* @returns whatever the command returned
|
|
62
|
+
*/
|
|
63
|
+
export function runPaletteCommand(name: string): Promise<any> {
|
|
64
|
+
return syscall("system.runPaletteCommand", name);
|
|
65
|
+
}
|
|
66
|
+
|
|
38
67
|
/**
|
|
39
68
|
* Lists all syscalls available
|
|
40
69
|
* @returns a list of all available syscalls
|
|
@@ -101,6 +130,23 @@ export function getVersion(): Promise<string> {
|
|
|
101
130
|
return syscall("system.getVersion");
|
|
102
131
|
}
|
|
103
132
|
|
|
133
|
+
/**
|
|
134
|
+
* The current user's identity. `username` falls back to "me" when the
|
|
135
|
+
* deployment has no accounts.
|
|
136
|
+
*/
|
|
137
|
+
export function getProfile(): Promise<ClientProfile> {
|
|
138
|
+
return syscall("system.getProfile");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Every account with access to this space. `username` falls back to "me" for a
|
|
143
|
+
* deployment without accounts, and exactly one entry is marked `me` whenever
|
|
144
|
+
* the current user is known.
|
|
145
|
+
*/
|
|
146
|
+
export function listAccounts(): Promise<Account[]> {
|
|
147
|
+
return syscall("system.listAccounts");
|
|
148
|
+
}
|
|
149
|
+
|
|
104
150
|
export function getConfig<T = any>(
|
|
105
151
|
key: string,
|
|
106
152
|
defaultValue: any = undefined,
|
package/plug-api/syscalls.ts
CHANGED
|
@@ -14,6 +14,8 @@ export * as datastore from "./syscalls/datastore.ts";
|
|
|
14
14
|
export * as jsonschema from "./syscalls/jsonschema.ts";
|
|
15
15
|
export * as lua from "./syscalls/lua.ts";
|
|
16
16
|
export * as config from "./syscalls/config.ts";
|
|
17
|
+
export * as search from "./syscalls/search.ts";
|
|
18
|
+
export * as icon from "./syscalls/icon.ts";
|
|
17
19
|
|
|
18
20
|
// Not technically syscalls, but we want to export them for convenience
|
|
19
21
|
export * as index from "./syscalls/index.ts";
|
package/plug-api/system_mock.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { MemoryKvPrimitives } from "../client/data/memory_kv_primitives.ts";
|
|
|
4
4
|
import { DataStoreMQ } from "../client/data/mq.datastore.ts";
|
|
5
5
|
import { ObjectIndex } from "../client/data/object_index.ts";
|
|
6
6
|
import { EventHook } from "../client/plugos/hooks/event.ts";
|
|
7
|
+
import { configSyscalls } from "../client/plugos/syscalls/config.ts";
|
|
7
8
|
import {
|
|
8
9
|
dataStoreReadSyscalls,
|
|
9
10
|
dataStoreWriteSyscalls,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
spaceReadSyscalls,
|
|
20
21
|
spaceWriteSyscalls,
|
|
21
22
|
} from "../client/plugos/syscalls/space.ts";
|
|
23
|
+
import { syncSyscalls } from "../client/plugos/syscalls/sync.ts";
|
|
22
24
|
import { systemSyscalls } from "../client/plugos/syscalls/system.ts";
|
|
23
25
|
import { System } from "../client/plugos/system.ts";
|
|
24
26
|
import { Space } from "../client/space.ts";
|
|
@@ -45,6 +47,13 @@ export function createMockSystem() {
|
|
|
45
47
|
space,
|
|
46
48
|
config,
|
|
47
49
|
eventedSpacePrimitives: spacePrimitives,
|
|
50
|
+
// Sync/index state consulted by sync syscalls; defaults simulate a
|
|
51
|
+
// steady-state client (everything synced).
|
|
52
|
+
bootConfig: {},
|
|
53
|
+
fullSyncCompleted: true,
|
|
54
|
+
fullIndexCompleted: true,
|
|
55
|
+
syncedPaths: new Set<string>(),
|
|
56
|
+
serverPingMs: undefined,
|
|
48
57
|
};
|
|
49
58
|
|
|
50
59
|
const objectIndex = new ObjectIndex(ds, config, eventHook, mq);
|
|
@@ -64,11 +73,13 @@ export function createMockSystem() {
|
|
|
64
73
|
languageSyscalls(),
|
|
65
74
|
jsonschemaSyscalls(),
|
|
66
75
|
indexSyscalls(objectIndex, clientMock),
|
|
76
|
+
configSyscalls(config),
|
|
67
77
|
luaSyscalls(system, () => clientSystemMock.spaceLuaEnv.env),
|
|
68
78
|
mqSyscalls(mq),
|
|
69
79
|
dataStoreReadSyscalls(ds, clientSystemMock),
|
|
70
80
|
dataStoreWriteSyscalls(ds),
|
|
71
81
|
systemSyscalls(clientMock, false),
|
|
82
|
+
syncSyscalls(clientMock),
|
|
72
83
|
);
|
|
73
84
|
|
|
74
85
|
globalThis.syscall = (name: string, ...args: any): Promise<any> => {
|
|
@@ -77,6 +88,7 @@ export function createMockSystem() {
|
|
|
77
88
|
|
|
78
89
|
return {
|
|
79
90
|
system,
|
|
91
|
+
objectIndex,
|
|
80
92
|
eventHook,
|
|
81
93
|
config,
|
|
82
94
|
kv,
|
|
@@ -84,5 +96,6 @@ export function createMockSystem() {
|
|
|
84
96
|
mq,
|
|
85
97
|
ds,
|
|
86
98
|
space,
|
|
99
|
+
clientMock,
|
|
87
100
|
};
|
|
88
101
|
}
|
package/plug-api/types/client.ts
CHANGED
|
@@ -33,7 +33,10 @@ export type Notification = {
|
|
|
33
33
|
persistent?: boolean;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
// A plain number is a flex-grow ratio (or, for the modal slot, a pixel
|
|
37
|
+
// inset); a string is a raw CSS `flex` shorthand, e.g. "0 0 260px" for a
|
|
38
|
+
// fixed-width sidebar.
|
|
39
|
+
export type PanelMode = number | string;
|
|
37
40
|
|
|
38
41
|
export type CodeWidgetContent = {
|
|
39
42
|
html?: string;
|
|
@@ -43,7 +46,6 @@ export type CodeWidgetContent = {
|
|
|
43
46
|
url?: string;
|
|
44
47
|
};
|
|
45
48
|
|
|
46
|
-
// Document editors stuff
|
|
47
49
|
export type DocumentEditorCallback = () => Promise<DocumentEditorContent>;
|
|
48
50
|
export type DocumentEditorContent = {
|
|
49
51
|
html: string;
|
|
@@ -136,7 +138,6 @@ export type SlashCompletions = {
|
|
|
136
138
|
options: SlashCompletionOption[];
|
|
137
139
|
};
|
|
138
140
|
|
|
139
|
-
// Code widget stuff
|
|
140
141
|
export type CodeWidgetCallback = (
|
|
141
142
|
bodyText: string,
|
|
142
143
|
pageName: string,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// Message Queue related types
|
|
2
1
|
export type MQMessage = {
|
|
3
2
|
id: string;
|
|
4
3
|
queue: string;
|
|
@@ -13,9 +12,10 @@ export type MQStats = {
|
|
|
13
12
|
export type MQSubscribeOptions = {
|
|
14
13
|
batchSize?: number;
|
|
15
14
|
pollInterval?: number;
|
|
15
|
+
/** How often a running callback refreshes its messages' processing lease. */
|
|
16
|
+
leaseRenewIntervalMs?: number;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
|
-
// KV types
|
|
19
19
|
export type KvKey = string[];
|
|
20
20
|
|
|
21
21
|
export type KV<T = any> = {
|
|
@@ -26,3 +26,12 @@ export type KV<T = any> = {
|
|
|
26
26
|
export type KvQuery = {
|
|
27
27
|
prefix?: KvKey;
|
|
28
28
|
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Body of an `indexQueue` message: a plain path, or a path a producer has
|
|
32
|
+
* already cleared the index for (a full reindex empties the index wholesale
|
|
33
|
+
* before queueing). Shared by the producers (`client/data/object_index.ts`)
|
|
34
|
+
* and the consumer (`plugs/index/queue.ts`) so the two ends of the queue
|
|
35
|
+
* cannot drift.
|
|
36
|
+
*/
|
|
37
|
+
export type IndexQueueBody = string | { path: string; cleared?: boolean };
|
package/plug-api/types/index.ts
CHANGED
|
@@ -14,6 +14,16 @@ export type PageDecoration = {
|
|
|
14
14
|
cssClasses?: string[];
|
|
15
15
|
hide?: boolean;
|
|
16
16
|
renderWidgets?: boolean; // Defaults to true
|
|
17
|
+
/** A Feather name ("star"), a namespaced one ("feather:star"), or literal
|
|
18
|
+
* SVG markup, shown alongside the page in the top bar, navigation, links,
|
|
19
|
+
* and completion. */
|
|
20
|
+
icon?: string;
|
|
21
|
+
tree?: PageTreeDecoration;
|
|
22
|
+
};
|
|
23
|
+
export type PageTreeDecoration = {
|
|
24
|
+
/** Floats the page above its lower-priority siblings (default 0). */
|
|
25
|
+
priority?: number;
|
|
26
|
+
hide?: boolean;
|
|
17
27
|
};
|
|
18
28
|
export type PageMeta = ObjectValue<
|
|
19
29
|
{
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type ClientProfile = {
|
|
2
|
+
username: string;
|
|
3
|
+
fullName?: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/** One account with access to the space. `username` is absent where the
|
|
7
|
+
* deployment keeps no accounts at all, and exactly one entry is marked `me`
|
|
8
|
+
* whenever the current user is known. */
|
|
9
|
+
export type Account = {
|
|
10
|
+
username: string | null;
|
|
11
|
+
fullName?: string;
|
|
12
|
+
me: boolean;
|
|
13
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type RevisionEntry = {
|
|
2
|
+
rev: string;
|
|
3
|
+
timestamp: number;
|
|
4
|
+
author: string;
|
|
5
|
+
message: string;
|
|
6
|
+
added?: number;
|
|
7
|
+
removed?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type FileRevisions = {
|
|
11
|
+
mode: "managed" | "unmanaged" | "disabled";
|
|
12
|
+
uncommitted: boolean;
|
|
13
|
+
revisions: RevisionEntry[];
|
|
14
|
+
more: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type FileStatus = "added" | "modified" | "deleted" | "renamed";
|
|
18
|
+
|
|
19
|
+
export type LogFile = { path: string; status: FileStatus };
|
|
20
|
+
|
|
21
|
+
export type LogCommit = RevisionEntry & { files: LogFile[] };
|
|
22
|
+
|
|
23
|
+
export type SpaceLog = {
|
|
24
|
+
mode: "managed" | "unmanaged" | "disabled";
|
|
25
|
+
commits: LogCommit[];
|
|
26
|
+
more: boolean;
|
|
27
|
+
/** What differs from HEAD right now -- what a snapshot would capture. */
|
|
28
|
+
uncommitted: LogFile[];
|
|
29
|
+
sync?: SyncState | null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** Mirrors the server's `SyncState` (`revisions::engine`), which serializes
|
|
33
|
+
* with `#[serde(tag = "state", rename_all = "camelCase")]` -- that renames
|
|
34
|
+
* variant names but not their fields, so `Paused`'s field stays `reason`,
|
|
35
|
+
* not `message`. `message` is absent on the `/.events` frame, which any
|
|
36
|
+
* Read-level visitor receives; `/.revisions/` and the admin route carry it. */
|
|
37
|
+
export type SyncState =
|
|
38
|
+
| { state: "idle" }
|
|
39
|
+
| { state: "syncing" }
|
|
40
|
+
| { state: "conflicted"; paths: string[] }
|
|
41
|
+
| { state: "paused"; reason: string }
|
|
42
|
+
| { state: "error"; kind: string; message?: string };
|
|
43
|
+
|
|
44
|
+
export type GitSyncSnapshot = {
|
|
45
|
+
sync: SyncState;
|
|
46
|
+
lastAttempt: number | null;
|
|
47
|
+
lastSuccess: number | null;
|
|
48
|
+
version: number;
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
paused: boolean;
|
|
51
|
+
dirty?: boolean;
|
|
52
|
+
pending: number | null;
|
|
53
|
+
incoming: number | null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type GitConflict = {
|
|
57
|
+
id: string;
|
|
58
|
+
path: string;
|
|
59
|
+
kind: "text" | "binary" | "deleteModify" | "unsupported";
|
|
60
|
+
local: boolean;
|
|
61
|
+
remote: boolean;
|
|
62
|
+
contentRevision: string;
|
|
63
|
+
canResolve?: boolean;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type GitConflicts = { generation: string; conflicts: GitConflict[] };
|
|
67
|
+
export type GitConflictAction = "local" | "remote" | "edited" | "delete";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type StructuredDescription = {
|
|
2
|
+
label?: string;
|
|
3
|
+
text: string;
|
|
4
|
+
highlights?: [number, number][];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type Description = string | StructuredDescription;
|
|
8
|
+
|
|
9
|
+
export function normalizeDescription(value: unknown): Description | undefined {
|
|
10
|
+
if (typeof value === "string") return value;
|
|
11
|
+
if (
|
|
12
|
+
!value ||
|
|
13
|
+
typeof value !== "object" ||
|
|
14
|
+
!("text" in value) ||
|
|
15
|
+
typeof value.text !== "string"
|
|
16
|
+
)
|
|
17
|
+
return undefined;
|
|
18
|
+
const text = value.text;
|
|
19
|
+
const boundary = (offset: number) =>
|
|
20
|
+
!(
|
|
21
|
+
offset > 0 &&
|
|
22
|
+
offset < text.length &&
|
|
23
|
+
/[\uD800-\uDBFF]/.test(text[offset - 1]) &&
|
|
24
|
+
/[\uDC00-\uDFFF]/.test(text[offset])
|
|
25
|
+
);
|
|
26
|
+
const ranges =
|
|
27
|
+
"highlights" in value && Array.isArray(value.highlights)
|
|
28
|
+
? value.highlights
|
|
29
|
+
: [];
|
|
30
|
+
const valid = ranges
|
|
31
|
+
.filter(
|
|
32
|
+
(range): range is [number, number] =>
|
|
33
|
+
Array.isArray(range) &&
|
|
34
|
+
range.length === 2 &&
|
|
35
|
+
range.every(Number.isInteger) &&
|
|
36
|
+
range[0] >= 0 &&
|
|
37
|
+
range[1] <= text.length &&
|
|
38
|
+
range[0] < range[1] &&
|
|
39
|
+
boundary(range[0]) &&
|
|
40
|
+
boundary(range[1]),
|
|
41
|
+
)
|
|
42
|
+
.sort((a, b) => a[0] - b[0]);
|
|
43
|
+
const highlights: [number, number][] = [];
|
|
44
|
+
for (const [start, end] of valid) {
|
|
45
|
+
const previous = highlights.at(-1);
|
|
46
|
+
if (previous && start <= previous[1])
|
|
47
|
+
previous[1] = Math.max(previous[1], end);
|
|
48
|
+
else highlights.push([start, end]);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
text,
|
|
52
|
+
...("label" in value && typeof value.label === "string"
|
|
53
|
+
? { label: value.label }
|
|
54
|
+
: {}),
|
|
55
|
+
highlights,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function descriptionText(description?: Description): string {
|
|
60
|
+
if (typeof description === "string") return description;
|
|
61
|
+
return description
|
|
62
|
+
? [description.label, description.text].filter(Boolean).join(" ")
|
|
63
|
+
: "";
|
|
64
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useEffect, useState } from "preact/hooks";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tracks hover outside parent state. Individual subscriptions re-render only
|
|
5
|
+
* the two affected rows instead of the entire expanded list.
|
|
6
|
+
*/
|
|
7
|
+
export class HoverTracker {
|
|
8
|
+
private key: unknown = undefined;
|
|
9
|
+
private subscribers = new Set<(key: unknown) => void>();
|
|
10
|
+
/** Where the pointer was last seen -- see `resolveHover`. */
|
|
11
|
+
private x = -1;
|
|
12
|
+
private y = -1;
|
|
13
|
+
|
|
14
|
+
get(): unknown {
|
|
15
|
+
return this.key;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
set(key: unknown): void {
|
|
19
|
+
if (this.key === key) return;
|
|
20
|
+
this.key = key;
|
|
21
|
+
for (const notify of this.subscribers) notify(key);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A pointer event over the row container: remembers where, and over what.
|
|
26
|
+
* Any `MouseEvent` will do -- a drop is the other event that moves the
|
|
27
|
+
* pointer somewhere the tracker has to hear about (see `onDrop`), and its
|
|
28
|
+
* coordinates are the last ones a drag leaves behind.
|
|
29
|
+
*/
|
|
30
|
+
track(event: MouseEvent, rowAt: (node: Element | null) => unknown): void {
|
|
31
|
+
this.x = event.clientX;
|
|
32
|
+
this.y = event.clientY;
|
|
33
|
+
this.set(rowAt(event.target as Element | null));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
elementUnderPointer(): Element | null {
|
|
37
|
+
if (this.x < 0 && this.y < 0) return null;
|
|
38
|
+
return document.elementFromPoint(this.x, this.y);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
subscribe(notify: (key: unknown) => void): () => void {
|
|
42
|
+
this.subscribers.add(notify);
|
|
43
|
+
return () => {
|
|
44
|
+
this.subscribers.delete(notify);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Re-answers "what is the pointer over" without the pointer having moved --
|
|
51
|
+
* after a refresh replaced the rows, or after the keyboard scrolled different
|
|
52
|
+
* ones underneath it. Identity, never position: the row that was under the
|
|
53
|
+
* pointer may be gone, and the one now in its slot was never pointed at.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveHover(
|
|
56
|
+
tracker: HoverTracker,
|
|
57
|
+
rowAt: (node: Element | null) => unknown,
|
|
58
|
+
): void {
|
|
59
|
+
tracker.set(rowAt(tracker.elementUnderPointer()));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function useHovered(tracker: HoverTracker, key: unknown): boolean {
|
|
63
|
+
const [hovered, setHovered] = useState(() => tracker.get() === key);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
setHovered(tracker.get() === key);
|
|
66
|
+
return tracker.subscribe((current) => setHovered(current === key));
|
|
67
|
+
}, [tracker, key]);
|
|
68
|
+
return hovered;
|
|
69
|
+
}
|
package/plug-api/ui/index.ts
CHANGED
|
@@ -18,5 +18,61 @@ export { UrlPrefixInput } from "./url_prefix_input.tsx";
|
|
|
18
18
|
export type { UrlPrefixInputProps } from "./url_prefix_input.tsx";
|
|
19
19
|
export { normalizePrefix, prefixFromName, slugify } from "./slugify.ts";
|
|
20
20
|
export { cx } from "./cx.ts";
|
|
21
|
-
export { panelStyles } from "
|
|
22
|
-
export type { PanelStylesOptions } from "
|
|
21
|
+
export { panelStyles } from "../lib/panel_styles.ts";
|
|
22
|
+
export type { PanelStylesOptions } from "../lib/panel_styles.ts";
|
|
23
|
+
export { Icon } from "./icon.tsx";
|
|
24
|
+
export type { IconProps } from "./icon.tsx";
|
|
25
|
+
export { SegmentedControl } from "./segmented_control.tsx";
|
|
26
|
+
export type {
|
|
27
|
+
SegmentedControlProps,
|
|
28
|
+
SegmentItem,
|
|
29
|
+
} from "./segmented_control.tsx";
|
|
30
|
+
export { useFitCollapse } from "./use_fit_collapse.ts";
|
|
31
|
+
export type { FitLevel } from "./use_fit_collapse.ts";
|
|
32
|
+
export { ResizeHandle } from "./resize_handle.tsx";
|
|
33
|
+
export type { ResizeHandleProps } from "./resize_handle.tsx";
|
|
34
|
+
export { RowActions } from "./row_actions.tsx";
|
|
35
|
+
export type { RowActionsProps } from "./row_actions.tsx";
|
|
36
|
+
export { RowText } from "./row_text.tsx";
|
|
37
|
+
export type { Description, StructuredDescription } from "./description.ts";
|
|
38
|
+
export { highlightMatches } from "./highlight.tsx";
|
|
39
|
+
export { HoverTracker, resolveHover, useHovered } from "./hover.ts";
|
|
40
|
+
export { revealInClosest, revealInContainer } from "./scroll.ts";
|
|
41
|
+
export { TreeView } from "./tree_view.tsx";
|
|
42
|
+
export type { TreeViewProps } from "./tree_view.tsx";
|
|
43
|
+
export {
|
|
44
|
+
allFolderPaths,
|
|
45
|
+
allNodes,
|
|
46
|
+
ancestorPaths,
|
|
47
|
+
buildTree,
|
|
48
|
+
computeTreeDisplay,
|
|
49
|
+
findNode,
|
|
50
|
+
flattenVisible,
|
|
51
|
+
nodeObject,
|
|
52
|
+
planMove,
|
|
53
|
+
pruneTree,
|
|
54
|
+
withExpanded,
|
|
55
|
+
} from "./tree_model.ts";
|
|
56
|
+
export type {
|
|
57
|
+
MovePlan,
|
|
58
|
+
TreeDisplay,
|
|
59
|
+
TreeNode,
|
|
60
|
+
VisibleRow,
|
|
61
|
+
} from "./tree_model.ts";
|
|
62
|
+
export type {
|
|
63
|
+
ActionMeta,
|
|
64
|
+
Decoration,
|
|
65
|
+
Row,
|
|
66
|
+
RowState,
|
|
67
|
+
RowStates,
|
|
68
|
+
} from "./tree_types.ts";
|
|
69
|
+
|
|
70
|
+
export { Sliders as SlidersIcon } from "preact-feather";
|
|
71
|
+
export { SectionNav } from "./section_nav.tsx";
|
|
72
|
+
export type { SectionItem, SectionNavProps } from "./section_nav.tsx";
|
|
73
|
+
export { Field, CheckboxField } from "./field.tsx";
|
|
74
|
+
export type { FieldProps, CheckboxFieldProps } from "./field.tsx";
|
|
75
|
+
export { PasswordInput } from "./password_input.tsx";
|
|
76
|
+
export type { PasswordInputProps } from "./password_input.tsx";
|
|
77
|
+
export { ButtonLink } from "./button.tsx";
|
|
78
|
+
export type { ButtonLinkProps } from "./button.tsx";
|