mdmaid-desk 0.1.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/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/api-client.d.ts +20 -0
- package/dist/api-client.js +264 -0
- package/dist/api-client.js.map +1 -0
- package/dist/api-types.d.ts +51 -0
- package/dist/api-types.js +2 -0
- package/dist/api-types.js.map +1 -0
- package/dist/auth-state.d.ts +2 -0
- package/dist/auth-state.js +113 -0
- package/dist/auth-state.js.map +1 -0
- package/dist/catalog.d.ts +46 -0
- package/dist/catalog.js +659 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.js +370 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon-state.d.ts +17 -0
- package/dist/daemon-state.js +204 -0
- package/dist/daemon-state.js.map +1 -0
- package/dist/domain.d.ts +49 -0
- package/dist/domain.js +44 -0
- package/dist/domain.js.map +1 -0
- package/dist/fs-durability.d.ts +2 -0
- package/dist/fs-durability.js +35 -0
- package/dist/fs-durability.js.map +1 -0
- package/dist/package-info.d.ts +1 -0
- package/dist/package-info.js +17 -0
- package/dist/package-info.js.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.js +702 -0
- package/dist/server.js.map +1 -0
- package/dist/sqlite-storage.d.ts +17 -0
- package/dist/sqlite-storage.js +342 -0
- package/dist/sqlite-storage.js.map +1 -0
- package/dist/storage.d.ts +12 -0
- package/dist/storage.js +2 -0
- package/dist/storage.js.map +1 -0
- package/dist/terminal-text.d.ts +9 -0
- package/dist/terminal-text.js +156 -0
- package/dist/terminal-text.js.map +1 -0
- package/dist/tui.d.ts +63 -0
- package/dist/tui.js +912 -0
- package/dist/tui.js.map +1 -0
- package/dist/web-client.d.ts +21 -0
- package/dist/web-client.js +337 -0
- package/dist/web-client.js.map +1 -0
- package/dist/web-styles.d.ts +1 -0
- package/dist/web-styles.js +249 -0
- package/dist/web-styles.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { chmod, link, lstat, mkdir, open, unlink, } from "node:fs/promises";
|
|
4
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
5
|
+
import { syncDirectory } from "./fs-durability.js";
|
|
6
|
+
const MAX_AUTH_TOKEN_BYTES = 128;
|
|
7
|
+
const AUTH_TOKEN_PATTERN = /^[A-Za-z0-9_-]{43}$/;
|
|
8
|
+
export function authTokenPath(statePath) {
|
|
9
|
+
return join(dirname(resolve(statePath)), "auth-token");
|
|
10
|
+
}
|
|
11
|
+
export async function readOrCreateAuthToken(statePath) {
|
|
12
|
+
const destination = authTokenPath(statePath);
|
|
13
|
+
const existing = await readAuthToken(destination);
|
|
14
|
+
if (existing !== undefined) {
|
|
15
|
+
return existing;
|
|
16
|
+
}
|
|
17
|
+
const directory = dirname(destination);
|
|
18
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
19
|
+
await chmod(directory, 0o700);
|
|
20
|
+
const token = randomBytes(32).toString("base64url");
|
|
21
|
+
const temporary = join(directory, `.${basename(destination)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
|
|
22
|
+
let temporaryExists = false;
|
|
23
|
+
try {
|
|
24
|
+
const handle = await open(temporary, constants.O_CREAT |
|
|
25
|
+
constants.O_EXCL |
|
|
26
|
+
constants.O_WRONLY |
|
|
27
|
+
constants.O_NOFOLLOW, 0o600);
|
|
28
|
+
temporaryExists = true;
|
|
29
|
+
try {
|
|
30
|
+
await handle.writeFile(`${token}\n`, "utf8");
|
|
31
|
+
await handle.sync();
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await handle.close();
|
|
35
|
+
}
|
|
36
|
+
await chmod(temporary, 0o600);
|
|
37
|
+
try {
|
|
38
|
+
await link(temporary, destination);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (!isNodeError(error) || error.code !== "EEXIST") {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
const concurrent = await readAuthToken(destination);
|
|
45
|
+
if (concurrent === undefined) {
|
|
46
|
+
throw new Error("Authentication token disappeared during creation");
|
|
47
|
+
}
|
|
48
|
+
return concurrent;
|
|
49
|
+
}
|
|
50
|
+
await syncDirectory(directory);
|
|
51
|
+
return token;
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
if (temporaryExists) {
|
|
55
|
+
await unlinkIfPresent(temporary);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function readAuthToken(path) {
|
|
60
|
+
let info;
|
|
61
|
+
try {
|
|
62
|
+
info = await lstat(path);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
if (info.isSymbolicLink() || !info.isFile()) {
|
|
71
|
+
throw new Error("Auth token must be a regular, non-symlink file");
|
|
72
|
+
}
|
|
73
|
+
if ((info.mode & 0o077) !== 0) {
|
|
74
|
+
throw new Error("Auth token must have user-only permissions");
|
|
75
|
+
}
|
|
76
|
+
if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
|
|
77
|
+
throw new Error("Auth token must be owned by the current user");
|
|
78
|
+
}
|
|
79
|
+
if (info.size === 0 || info.size > MAX_AUTH_TOKEN_BYTES) {
|
|
80
|
+
throw new Error("Invalid auth token");
|
|
81
|
+
}
|
|
82
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
83
|
+
let raw;
|
|
84
|
+
try {
|
|
85
|
+
const opened = await handle.stat();
|
|
86
|
+
if (opened.dev !== info.dev || opened.ino !== info.ino) {
|
|
87
|
+
throw new Error("Auth token changed while opening");
|
|
88
|
+
}
|
|
89
|
+
raw = await handle.readFile("utf8");
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
await handle.close();
|
|
93
|
+
}
|
|
94
|
+
const token = raw.endsWith("\n") ? raw.slice(0, -1) : raw;
|
|
95
|
+
if (!AUTH_TOKEN_PATTERN.test(token)) {
|
|
96
|
+
throw new Error("Invalid auth token");
|
|
97
|
+
}
|
|
98
|
+
return token;
|
|
99
|
+
}
|
|
100
|
+
async function unlinkIfPresent(path) {
|
|
101
|
+
try {
|
|
102
|
+
await unlink(path);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
if (!isNodeError(error) || error.code !== "ENOENT") {
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function isNodeError(error) {
|
|
111
|
+
return error instanceof Error && "code" in error;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=auth-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-state.js","sourceRoot":"","sources":["../src/auth-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Attention, type Document, type DocumentFilters, type DocumentKind, type Workspace } from "./domain.js";
|
|
2
|
+
export type { Attention, Document, DocumentFilters, DocumentKind, ReadingStatus, Workspace, } from "./domain.js";
|
|
3
|
+
export declare const CATALOG_SCHEMA_VERSION = 1;
|
|
4
|
+
export interface CatalogOptions {
|
|
5
|
+
maxDocumentBytes?: number;
|
|
6
|
+
legacyStatePath?: string | false;
|
|
7
|
+
}
|
|
8
|
+
export interface AddWorkspaceInput {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
root: string;
|
|
12
|
+
artifactRoots: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface RegisterDocumentInput {
|
|
15
|
+
workspaceId: string;
|
|
16
|
+
taskId?: string;
|
|
17
|
+
producer?: string;
|
|
18
|
+
kind: DocumentKind;
|
|
19
|
+
title: string;
|
|
20
|
+
path: string;
|
|
21
|
+
attention: Attention;
|
|
22
|
+
tags?: string[];
|
|
23
|
+
}
|
|
24
|
+
export declare class Catalog {
|
|
25
|
+
#private;
|
|
26
|
+
private constructor();
|
|
27
|
+
static open(databasePath: string, options?: CatalogOptions): Promise<Catalog>;
|
|
28
|
+
close(): void;
|
|
29
|
+
listWorkspaces(): Workspace[];
|
|
30
|
+
listDocuments(filters?: DocumentFilters): Document[];
|
|
31
|
+
getDocument(id: string): Document | undefined;
|
|
32
|
+
readDocument(id: string): Promise<{
|
|
33
|
+
content: string;
|
|
34
|
+
document: Document;
|
|
35
|
+
}>;
|
|
36
|
+
addWorkspace(input: AddWorkspaceInput): Promise<Workspace>;
|
|
37
|
+
registerDocument(input: RegisterDocumentInput): Promise<Document>;
|
|
38
|
+
markDocumentOpened(id: string): Promise<Document>;
|
|
39
|
+
markDocumentRead(id: string): Promise<Document>;
|
|
40
|
+
markDocumentUnread(id: string): Promise<Document>;
|
|
41
|
+
setDocumentTags(id: string, tags: string[]): Promise<Document>;
|
|
42
|
+
archiveDocument(id: string): Promise<Document>;
|
|
43
|
+
restoreDocument(id: string): Promise<Document>;
|
|
44
|
+
markDocumentMissing(id: string): Promise<Document>;
|
|
45
|
+
markDocumentPresent(id: string): Promise<Document>;
|
|
46
|
+
}
|