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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +215 -0
  3. package/dist/api-client.d.ts +20 -0
  4. package/dist/api-client.js +264 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/api-types.d.ts +51 -0
  7. package/dist/api-types.js +2 -0
  8. package/dist/api-types.js.map +1 -0
  9. package/dist/auth-state.d.ts +2 -0
  10. package/dist/auth-state.js +113 -0
  11. package/dist/auth-state.js.map +1 -0
  12. package/dist/catalog.d.ts +46 -0
  13. package/dist/catalog.js +659 -0
  14. package/dist/catalog.js.map +1 -0
  15. package/dist/cli.d.ts +16 -0
  16. package/dist/cli.js +370 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/daemon-state.d.ts +17 -0
  19. package/dist/daemon-state.js +204 -0
  20. package/dist/daemon-state.js.map +1 -0
  21. package/dist/domain.d.ts +49 -0
  22. package/dist/domain.js +44 -0
  23. package/dist/domain.js.map +1 -0
  24. package/dist/fs-durability.d.ts +2 -0
  25. package/dist/fs-durability.js +35 -0
  26. package/dist/fs-durability.js.map +1 -0
  27. package/dist/package-info.d.ts +1 -0
  28. package/dist/package-info.js +17 -0
  29. package/dist/package-info.js.map +1 -0
  30. package/dist/server.d.ts +18 -0
  31. package/dist/server.js +702 -0
  32. package/dist/server.js.map +1 -0
  33. package/dist/sqlite-storage.d.ts +17 -0
  34. package/dist/sqlite-storage.js +342 -0
  35. package/dist/sqlite-storage.js.map +1 -0
  36. package/dist/storage.d.ts +12 -0
  37. package/dist/storage.js +2 -0
  38. package/dist/storage.js.map +1 -0
  39. package/dist/terminal-text.d.ts +9 -0
  40. package/dist/terminal-text.js +156 -0
  41. package/dist/terminal-text.js.map +1 -0
  42. package/dist/tui.d.ts +63 -0
  43. package/dist/tui.js +912 -0
  44. package/dist/tui.js.map +1 -0
  45. package/dist/web-client.d.ts +21 -0
  46. package/dist/web-client.js +337 -0
  47. package/dist/web-client.js.map +1 -0
  48. package/dist/web-styles.d.ts +1 -0
  49. package/dist/web-styles.js +249 -0
  50. package/dist/web-styles.js.map +1 -0
  51. package/package.json +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Oleksandr Besan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # mdmaid.desk
2
+
3
+ `mdmaid.desk` is a persistent local document inbox and reading workspace for
4
+ Markdown artifacts produced by harnesses, editors, and scripts.
5
+
6
+ The repository name is `mdmaid.desk`; its initial executable is
7
+ `mdmaid-desk`.
8
+
9
+ ## Status
10
+
11
+ The repository contains the first usable shared-service vertical slice:
12
+
13
+ - persistent workspace metadata;
14
+ - Markdown document registration;
15
+ - idempotent updates by canonical path;
16
+ - workspace and artifact-root containment;
17
+ - symlink-escape protection;
18
+ - document size limits;
19
+ - revision-aware Unread, Reading, and Done state;
20
+ - tags, archive, and missing-document state;
21
+ - transactional SQLite migrations and one-time JSON catalog import;
22
+ - user-only catalog permissions;
23
+ - authenticated loopback HTTP API and stable document/workspace routes;
24
+ - sanitized `mdmaid` HTML and terminal rendering;
25
+ - responsive browser queue, project/status filters, search, reader, and actions;
26
+ - terminal-native queue, filters, search, reader, and lifecycle actions;
27
+ - Server-Sent Event refreshes for both clients;
28
+ - atomic, user-only daemon discovery state so the TUI reuses a running service;
29
+ - memorable `http://mdmaid.desk.localhost:43127/` browser origin;
30
+ - `workspace`, `register`, `list`, `web`, and `tui` commands.
31
+
32
+ Background `daemon ensure/status/stop`, directory watching, stdin-managed
33
+ enqueue, comments, and editing remain planned milestones. `web` currently runs
34
+ the persistent service in the foreground; `tui` attaches to it when present and
35
+ uses an embedded loopback service otherwise.
36
+
37
+ ## Responsibility
38
+
39
+ `mdmaid.desk` owns:
40
+
41
+ - the persistent local daemon;
42
+ - workspace and document catalogs;
43
+ - artifact-directory discovery;
44
+ - stable document URLs;
45
+ - the browser document library;
46
+ - local CLI and API access;
47
+ - attention metadata;
48
+ - presentation security boundaries.
49
+
50
+ It does not own:
51
+
52
+ - agent workflow state;
53
+ - task approvals;
54
+ - model or provider routing;
55
+ - Markdown rendering internals;
56
+ - editor-specific keymaps.
57
+
58
+ `mdmaid` remains the rendering engine. `agentctl` is a configurator only.
59
+ Harnesses and tools register documents directly through generic CLI/API
60
+ interfaces. `mdmaid.nvim` may become an optional client.
61
+
62
+ ## Development
63
+
64
+ mdmaid.desk requires Node.js 22 or newer.
65
+
66
+ ```bash
67
+ npm install
68
+ npm test
69
+ ```
70
+
71
+ Build:
72
+
73
+ ```bash
74
+ npm run build
75
+ ```
76
+
77
+ Run the CLI from the build:
78
+
79
+ ```bash
80
+ node dist/cli.js --help
81
+ ```
82
+
83
+ ## Installation
84
+
85
+ After the first public release, install the canonical npm package globally:
86
+
87
+ ```bash
88
+ npm install --global mdmaid-desk
89
+ mdmaid-desk --version
90
+ mdmaid-desk web
91
+ ```
92
+
93
+ In another terminal, open the same catalog through the terminal client:
94
+
95
+ ```bash
96
+ mdmaid-desk tui
97
+ ```
98
+
99
+ Homebrew is the planned first-class macOS installation and service path. Its
100
+ formula will consume this same npm release so the two installers share one
101
+ version and artifact lineage. See [Releasing and distribution](docs/RELEASING.md)
102
+ for the rollout and one-time npm bootstrap.
103
+
104
+ ## Current CLI
105
+
106
+ Register a workspace:
107
+
108
+ ```bash
109
+ node dist/cli.js workspace add /path/to/repository \
110
+ --id example \
111
+ --name "Example"
112
+ ```
113
+
114
+ Register a document:
115
+
116
+ ```bash
117
+ node dist/cli.js register /path/to/repository/docs/plan.md \
118
+ --workspace example \
119
+ --task PROJECT-123 \
120
+ --kind plan \
121
+ --attention approval
122
+ ```
123
+
124
+ List documents:
125
+
126
+ ```bash
127
+ node dist/cli.js list --workspace example
128
+ node dist/cli.js list --task PROJECT-123
129
+ ```
130
+
131
+ Run the browser workspace as a foreground local service:
132
+
133
+ ```bash
134
+ node dist/cli.js web
135
+ ```
136
+
137
+ The command binds only to loopback on the stable port `43127` and prints an
138
+ authenticated URL such as:
139
+
140
+ ```text
141
+ http://mdmaid.desk.localhost:43127/?token=...
142
+ ```
143
+
144
+ No proxy, certificate, DNS, or `/etc/hosts` setup is required. After the first
145
+ authenticated open, the browser redirects to the clean URL, which can be
146
+ bookmarked. The service publishes a user-only `daemon.json` for local clients
147
+ and keeps its persistent random authentication token in a user-only
148
+ `auth-token` file, so browser sessions survive service restarts. Stop the
149
+ foreground service with `Ctrl-C`.
150
+
151
+ Use `--port` to select another loopback port. An advanced `--public-url` option
152
+ accepts HTTP or HTTPS `.localhost` origins; a direct HTTP origin must use the
153
+ same port as the service.
154
+
155
+ See [Local browser URL](docs/LOCAL_WEB.md) for details.
156
+
157
+ Run the terminal workspace:
158
+
159
+ ```bash
160
+ node dist/cli.js tui
161
+ ```
162
+
163
+ The TUI reuses the running web daemon when available, so both clients share
164
+ catalog events and reading state. Keys are shown in its footer; the main flow
165
+ uses `j`/`k`, `Enter`, `/`, `m`, `u`, `a`, `b`, and `q`.
166
+
167
+ The default state directory is:
168
+
169
+ ```text
170
+ ${XDG_STATE_HOME:-~/.local/state}/mdmaid.desk/
171
+ auth-token
172
+ catalog.sqlite3
173
+ daemon.json # present while the web service is running
174
+ ```
175
+
176
+ ## Target Interaction
177
+
178
+ ```mermaid
179
+ flowchart LR
180
+ A[Harnesses and tools] -->|register document| S[mdmaid.desk]
181
+ CFG[agentctl] -.->|optional configuration| A
182
+ N[mdmaid.nvim] -->|register or open| S
183
+ X[Scripts] -->|register| S
184
+ S --> CAT[(Catalog)]
185
+ S --> M[mdmaid renderer]
186
+ S --> W[Web workspace]
187
+ S --> T[TUI workspace]
188
+ W --> H[Human]
189
+ T --> H
190
+ H -->|reading status and tags| S
191
+ ```
192
+
193
+ Document registration and presentation never imply workflow approval.
194
+
195
+ ## Documentation
196
+
197
+ - [Architecture and roadmap](docs/ARCHITECTURE.md)
198
+ - [Releasing and distribution](docs/RELEASING.md)
199
+ - [Security policy](SECURITY.md)
200
+ - [Contributing](CONTRIBUTING.md)
201
+ - [MIT license](LICENSE)
202
+
203
+ ## Naming
204
+
205
+ Current naming:
206
+
207
+ ```text
208
+ Product/UI: mdmaid.desk
209
+ Repository: mdmaid.desk
210
+ Package: mdmaid-desk
211
+ CLI: mdmaid-desk
212
+ ```
213
+
214
+ A future `mdmaid desk ...` umbrella command may delegate to this package, but
215
+ the repositories and release cycles remain separate.
@@ -0,0 +1,20 @@
1
+ import type { DocumentAction, HealthData, PublicDocument, PublicWorkspace, TerminalRenderPreferences, TerminalRender, WebRender } from "./api-types.js";
2
+ export interface CatalogEvent {
3
+ action: string;
4
+ documentId: string;
5
+ }
6
+ export interface CatalogSubscriptionOptions {
7
+ signal?: AbortSignal;
8
+ onReady?: () => void;
9
+ }
10
+ export declare class DeskApiClient {
11
+ #private;
12
+ constructor(baseUrl: string, token: string);
13
+ health(signal?: AbortSignal): Promise<HealthData>;
14
+ listDocuments(): Promise<PublicDocument[]>;
15
+ listWorkspaces(): Promise<PublicWorkspace[]>;
16
+ renderDocument(id: string, target: "terminal", width?: number, preferences?: TerminalRenderPreferences): Promise<TerminalRender>;
17
+ renderDocument(id: string, target: "web", width?: number): Promise<WebRender>;
18
+ act(id: string, action: DocumentAction): Promise<PublicDocument>;
19
+ subscribeCatalog(listener: (event: CatalogEvent) => void, options?: CatalogSubscriptionOptions): Promise<void>;
20
+ }
@@ -0,0 +1,264 @@
1
+ import { ATTENTION_STATES, DOCUMENT_KINDS, } from "./domain.js";
2
+ export class DeskApiClient {
3
+ #baseUrl;
4
+ #token;
5
+ constructor(baseUrl, token) {
6
+ const parsed = new URL(baseUrl);
7
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
8
+ throw new Error("daemon URL must use HTTP or HTTPS");
9
+ }
10
+ if (parsed.username || parsed.password || parsed.search || parsed.hash) {
11
+ throw new Error("daemon URL must not contain credentials, query, or fragment");
12
+ }
13
+ if (typeof token !== "string" || token.length < 8) {
14
+ throw new Error("daemon token must contain at least 8 characters");
15
+ }
16
+ this.#baseUrl = parsed.href.replace(/\/$/, "");
17
+ this.#token = token;
18
+ }
19
+ async health(signal) {
20
+ const value = await this.#request("/api/v1/health", {
21
+ authenticated: false,
22
+ ...(signal === undefined ? {} : { signal }),
23
+ });
24
+ if (!isHealth(value)) {
25
+ throw new Error("Daemon returned an invalid health response");
26
+ }
27
+ return value;
28
+ }
29
+ async listDocuments() {
30
+ const value = await this.#request("/api/v1/documents");
31
+ if (!Array.isArray(value) || !value.every(isPublicDocument)) {
32
+ throw new Error("Daemon returned an invalid document list");
33
+ }
34
+ return value;
35
+ }
36
+ async listWorkspaces() {
37
+ const value = await this.#request("/api/v1/workspaces");
38
+ if (!Array.isArray(value) || !value.every(isPublicWorkspace)) {
39
+ throw new Error("Daemon returned an invalid workspace list");
40
+ }
41
+ return value;
42
+ }
43
+ async renderDocument(id, target, width = 100, preferences = {}) {
44
+ assertDocumentId(id);
45
+ if (!Number.isSafeInteger(width) || width < 20 || width > 1_000) {
46
+ throw new Error("render width must be an integer between 20 and 1000");
47
+ }
48
+ const query = new URLSearchParams({ target });
49
+ if (target === "terminal") {
50
+ query.set("width", String(width));
51
+ if (preferences.color !== undefined) {
52
+ query.set("color", String(preferences.color));
53
+ }
54
+ if (preferences.unicode !== undefined) {
55
+ query.set("unicode", String(preferences.unicode));
56
+ }
57
+ }
58
+ const value = await this.#request(`/api/v1/documents/${encodeURIComponent(id)}/render?${query.toString()}`);
59
+ if (target === "terminal" && isTerminalRender(value)) {
60
+ return value;
61
+ }
62
+ if (target === "web" && isWebRender(value)) {
63
+ return value;
64
+ }
65
+ throw new Error("Daemon returned an invalid render response");
66
+ }
67
+ async act(id, action) {
68
+ assertDocumentId(id);
69
+ const value = await this.#request(`/api/v1/documents/${encodeURIComponent(id)}/${action}`, { method: "POST" });
70
+ if (!isPublicDocument(value)) {
71
+ throw new Error("Daemon returned an invalid document response");
72
+ }
73
+ return value;
74
+ }
75
+ async subscribeCatalog(listener, options = {}) {
76
+ try {
77
+ const response = await fetch(`${this.#baseUrl}/api/v1/events`, {
78
+ headers: { authorization: `Bearer ${this.#token}` },
79
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
80
+ });
81
+ if (!response.ok) {
82
+ let body;
83
+ try {
84
+ body = await response.json();
85
+ }
86
+ catch {
87
+ throw new Error(`Daemon event stream failed (${response.status})`);
88
+ }
89
+ if (isErrorEnvelope(body)) {
90
+ throw new Error(body.error.message);
91
+ }
92
+ throw new Error(`Daemon event stream failed (${response.status})`);
93
+ }
94
+ if (!response.body) {
95
+ throw new Error("Daemon returned an empty event stream");
96
+ }
97
+ const reader = response.body.getReader();
98
+ const decoder = new TextDecoder();
99
+ let buffer = "";
100
+ while (true) {
101
+ const chunk = await reader.read();
102
+ if (chunk.done) {
103
+ break;
104
+ }
105
+ buffer += decoder.decode(chunk.value, { stream: true }).replaceAll("\r\n", "\n");
106
+ let boundary = buffer.indexOf("\n\n");
107
+ while (boundary >= 0) {
108
+ const block = buffer.slice(0, boundary);
109
+ buffer = buffer.slice(boundary + 2);
110
+ dispatchEventBlock(block, listener, options.onReady);
111
+ boundary = buffer.indexOf("\n\n");
112
+ }
113
+ }
114
+ }
115
+ catch (error) {
116
+ if (options.signal?.aborted) {
117
+ return;
118
+ }
119
+ throw error;
120
+ }
121
+ }
122
+ async #request(path, options = {}) {
123
+ const authenticated = options.authenticated ?? true;
124
+ const response = await fetch(`${this.#baseUrl}${path}`, {
125
+ method: options.method ?? "GET",
126
+ ...(authenticated
127
+ ? { headers: { authorization: `Bearer ${this.#token}` } }
128
+ : {}),
129
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
130
+ });
131
+ let body;
132
+ try {
133
+ body = await response.json();
134
+ }
135
+ catch {
136
+ throw new Error(`Daemon returned a non-JSON response (${response.status})`);
137
+ }
138
+ if (!response.ok) {
139
+ if (isErrorEnvelope(body)) {
140
+ throw new Error(body.error.message);
141
+ }
142
+ throw new Error(`Daemon request failed (${response.status})`);
143
+ }
144
+ if (!isRecord(body) || !("data" in body)) {
145
+ throw new Error("Daemon returned an invalid response envelope");
146
+ }
147
+ return body.data;
148
+ }
149
+ }
150
+ function isHealth(value) {
151
+ return (isRecord(value) &&
152
+ value.service === "mdmaid.desk" &&
153
+ value.status === "ok" &&
154
+ typeof value.version === "number");
155
+ }
156
+ function isPublicWorkspace(value) {
157
+ return (isRecord(value) &&
158
+ typeof value.id === "string" &&
159
+ typeof value.name === "string" &&
160
+ typeof value.documentCount === "number" &&
161
+ typeof value.route === "string");
162
+ }
163
+ function isPublicDocument(value) {
164
+ if (!isRecord(value)) {
165
+ return false;
166
+ }
167
+ return (typeof value.id === "string" &&
168
+ typeof value.workspaceId === "string" &&
169
+ optionalString(value.taskId) &&
170
+ optionalString(value.producer) &&
171
+ typeof value.kind === "string" &&
172
+ DOCUMENT_KINDS.includes(value.kind) &&
173
+ typeof value.title === "string" &&
174
+ typeof value.attention === "string" &&
175
+ ATTENTION_STATES.includes(value.attention) &&
176
+ Array.isArray(value.tags) &&
177
+ value.tags.every((tag) => typeof tag === "string") &&
178
+ isInteger(value.revision) &&
179
+ nullableInteger(value.openedRevision) &&
180
+ nullableInteger(value.completedRevision) &&
181
+ (value.status === "unread" ||
182
+ value.status === "reading" ||
183
+ value.status === "done") &&
184
+ nullableString(value.archivedAt) &&
185
+ nullableString(value.missingAt) &&
186
+ typeof value.createdAt === "string" &&
187
+ typeof value.updatedAt === "string" &&
188
+ typeof value.route === "string");
189
+ }
190
+ function isWebRender(value) {
191
+ return (isRecord(value) &&
192
+ value.target === "web" &&
193
+ typeof value.content === "string" &&
194
+ isPublicDocument(value.document));
195
+ }
196
+ function isTerminalRender(value) {
197
+ return (isRecord(value) &&
198
+ value.target === "terminal" &&
199
+ typeof value.content === "string" &&
200
+ typeof value.backend === "string" &&
201
+ Array.isArray(value.warnings) &&
202
+ value.warnings.every((warning) => typeof warning === "string") &&
203
+ isPublicDocument(value.document));
204
+ }
205
+ function isErrorEnvelope(value) {
206
+ return (isRecord(value) &&
207
+ isRecord(value.error) &&
208
+ typeof value.error.code === "string" &&
209
+ typeof value.error.message === "string");
210
+ }
211
+ function dispatchEventBlock(block, listener, onReady) {
212
+ let type = "message";
213
+ const data = [];
214
+ for (const line of block.split("\n")) {
215
+ if (line.startsWith("event:")) {
216
+ type = line.slice("event:".length).trim();
217
+ }
218
+ else if (line.startsWith("data:")) {
219
+ data.push(line.slice("data:".length).trimStart());
220
+ }
221
+ }
222
+ if (type === "ready") {
223
+ onReady?.();
224
+ return;
225
+ }
226
+ if (type !== "catalog") {
227
+ return;
228
+ }
229
+ let value;
230
+ try {
231
+ value = JSON.parse(data.join("\n"));
232
+ }
233
+ catch {
234
+ throw new Error("Daemon returned an invalid catalog event");
235
+ }
236
+ if (!isRecord(value) ||
237
+ typeof value.action !== "string" ||
238
+ typeof value.documentId !== "string" ||
239
+ !/^doc-[a-f0-9]{20}$/.test(value.documentId)) {
240
+ throw new Error("Daemon returned an invalid catalog event");
241
+ }
242
+ listener({ action: value.action, documentId: value.documentId });
243
+ }
244
+ function optionalString(value) {
245
+ return value === undefined || typeof value === "string";
246
+ }
247
+ function nullableString(value) {
248
+ return value === null || typeof value === "string";
249
+ }
250
+ function isInteger(value) {
251
+ return typeof value === "number" && Number.isSafeInteger(value);
252
+ }
253
+ function nullableInteger(value) {
254
+ return value === null || isInteger(value);
255
+ }
256
+ function isRecord(value) {
257
+ return typeof value === "object" && value !== null && !Array.isArray(value);
258
+ }
259
+ function assertDocumentId(id) {
260
+ if (!/^doc-[a-f0-9]{20}$/.test(id)) {
261
+ throw new Error("invalid document id");
262
+ }
263
+ }
264
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { Attention, DocumentKind, ReadingStatus } from "./domain.js";
2
+ export type { Attention, DocumentKind, ReadingStatus };
3
+ export interface PublicDocument {
4
+ id: string;
5
+ workspaceId: string;
6
+ taskId?: string;
7
+ producer?: string;
8
+ kind: DocumentKind;
9
+ title: string;
10
+ attention: Attention;
11
+ tags: string[];
12
+ revision: number;
13
+ openedRevision: number | null;
14
+ completedRevision: number | null;
15
+ status: ReadingStatus;
16
+ archivedAt: string | null;
17
+ missingAt: string | null;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ route: string;
21
+ }
22
+ export interface PublicWorkspace {
23
+ id: string;
24
+ name: string;
25
+ documentCount: number;
26
+ route: string;
27
+ }
28
+ export interface HealthData {
29
+ service: "mdmaid.desk";
30
+ status: "ok";
31
+ version: number;
32
+ }
33
+ export type RenderTarget = "web" | "terminal";
34
+ export interface TerminalRenderPreferences {
35
+ color?: boolean;
36
+ unicode?: boolean;
37
+ }
38
+ export interface WebRender {
39
+ document: PublicDocument;
40
+ target: "web";
41
+ content: string;
42
+ }
43
+ export interface TerminalRender {
44
+ document: PublicDocument;
45
+ target: "terminal";
46
+ content: string;
47
+ backend: string;
48
+ warnings: string[];
49
+ }
50
+ export type DocumentRender = WebRender | TerminalRender;
51
+ export type DocumentAction = "opened" | "read" | "unread" | "archive" | "restore" | "missing" | "present";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=api-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-types.js","sourceRoot":"","sources":["../src/api-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare function authTokenPath(statePath: string): string;
2
+ export declare function readOrCreateAuthToken(statePath: string): Promise<string>;