asljs-appbase 0.0.0-stage → 0.1.5
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.md +51 -0
- package/README.md +81 -2
- package/dist/browser-modules.d.ts +36 -0
- package/dist/browser-modules.js +148 -0
- package/dist/editor-app.d.ts +232 -0
- package/dist/editor-app.js +268 -0
- package/dist/files.d.ts +25 -0
- package/dist/files.js +48 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/markdown.d.ts +27 -0
- package/dist/markdown.js +84 -0
- package/dist/post-process.d.ts +50 -0
- package/dist/post-process.js +84 -0
- package/dist/server.d.ts +152 -0
- package/dist/server.js +354 -0
- package/dist/state-folder.d.ts +20 -0
- package/dist/state-folder.js +21 -0
- package/docs/appbase.md +193 -0
- package/package.json +72 -4
package/LICENSE.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Permissive No-Derivatives License 1.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexandrite Software Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software (the "Software") to:
|
|
7
|
+
|
|
8
|
+
1. Use the Software for any purpose, including commercial purposes.
|
|
9
|
+
2. Copy and redistribute the Software, including as part of another application,
|
|
10
|
+
library, or package.
|
|
11
|
+
3. Modify the Software for private or internal use.
|
|
12
|
+
|
|
13
|
+
Subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
## 1. No Distribution of Modified Versions
|
|
16
|
+
|
|
17
|
+
Modified versions of the Software, or substantial portions thereof, must not be
|
|
18
|
+
distributed without prior written permission from the copyright holder.
|
|
19
|
+
|
|
20
|
+
Routine build transformations, including minification, transpilation, and
|
|
21
|
+
bundling, are permitted for distribution, provided they do not intentionally
|
|
22
|
+
alter the Software's functionality.
|
|
23
|
+
|
|
24
|
+
## 2. Licence and Copyright Preservation
|
|
25
|
+
|
|
26
|
+
All distributed copies of the Software must retain this copyright notice and
|
|
27
|
+
licence.
|
|
28
|
+
|
|
29
|
+
The Software itself, including copies incorporated into other applications,
|
|
30
|
+
libraries, or packages, remains subject to this licence.
|
|
31
|
+
|
|
32
|
+
The Software must not be sublicensed or redistributed under a different licence.
|
|
33
|
+
|
|
34
|
+
## 3. Use in Other Software
|
|
35
|
+
|
|
36
|
+
Applications and libraries that merely use, import, link to, or bundle the
|
|
37
|
+
Software are not considered modified versions of the Software and may be
|
|
38
|
+
distributed under any licence.
|
|
39
|
+
|
|
40
|
+
Such use, incorporation, or bundling does not grant permission to relicense the
|
|
41
|
+
Software or distribute modified versions of it.
|
|
42
|
+
|
|
43
|
+
### 4. No Warranty
|
|
44
|
+
|
|
45
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
46
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
47
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
48
|
+
|
|
49
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR
|
|
50
|
+
OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS
|
|
51
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,82 @@
|
|
|
1
|
-
#
|
|
1
|
+
# appbase
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Part of [Alexandrite Software Library][#1] - a set of high-quality, performant
|
|
4
|
+
> JavaScript libraries and tools for everyday use.
|
|
5
|
+
|
|
6
|
+
The base the applications of this repository are built on: their configuration
|
|
7
|
+
files and state folders, the entry point of an executable, markdown, and serving
|
|
8
|
+
documents and editor applications in a browser.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
The applications - `rq`, `kb`, `part`, `cog`, `board`, `dash` and the tools -
|
|
13
|
+
share these parts:
|
|
14
|
+
|
|
15
|
+
- **Configuration** - read an application's `<app>.json`, and find the folder it
|
|
16
|
+
keeps its state in, `.<app>`.
|
|
17
|
+
- **Executables** - the logging options, errors and exit codes of a command
|
|
18
|
+
line, a web server or an MCP server.
|
|
19
|
+
- **Editor applications** - an application served as a plugin of the editor,
|
|
20
|
+
with a project per configuration file, alone or with the others.
|
|
21
|
+
- **Markdown** - parse a document, read a section, plain text and local links.
|
|
22
|
+
- **Files** - find the markdown files of a folder.
|
|
23
|
+
- **Post-processing** - remember the files a command wrote, and run the
|
|
24
|
+
project's formatter on them, named in the tool's configuration file.
|
|
25
|
+
- **Server** - serve a folder's data: its files as they are, markdown as its
|
|
26
|
+
text, and JSON values, on the first free port from 3000; the page renders
|
|
27
|
+
them.
|
|
28
|
+
|
|
29
|
+
## Scope
|
|
30
|
+
|
|
31
|
+
- Node.js, ES modules.
|
|
32
|
+
- The server is for local use: it serves every file inside its folder, and
|
|
33
|
+
renders nothing.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install asljs-appbase
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { getSection,
|
|
45
|
+
parseMarkdown,
|
|
46
|
+
plainText }
|
|
47
|
+
from 'asljs-appbase';
|
|
48
|
+
|
|
49
|
+
const root =
|
|
50
|
+
parseMarkdown('# R1 Export\n\n## Implementation\n\n- [T1](<tests/T1 PDF.md>)\n');
|
|
51
|
+
|
|
52
|
+
const items =
|
|
53
|
+
getSection(
|
|
54
|
+
root,
|
|
55
|
+
'Implementation')
|
|
56
|
+
?.map(plainText);
|
|
57
|
+
|
|
58
|
+
console.log(items);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Further reading
|
|
62
|
+
|
|
63
|
+
- [appbase][MD] - every export.
|
|
64
|
+
|
|
65
|
+
## Related packages
|
|
66
|
+
|
|
67
|
+
- `asljs-cmdbase` reads the configuration file and starts an executable; this
|
|
68
|
+
package re-exports it.
|
|
69
|
+
- `asljs-rq` manages requirements in markdown, and `asljs-rq-srv` shows them
|
|
70
|
+
with this package's server.
|
|
71
|
+
- `asljs-board` keeps a planning board in markdown, and `asljs-board-srv` shows
|
|
72
|
+
it with this package's server.
|
|
73
|
+
- `asljs-kb` manages a markdown knowledge base, and `asljs-kb-srv` shows it with
|
|
74
|
+
this package's server.
|
|
75
|
+
- `asljs-mcp` serves a tool's commands over MCP.
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
MIT
|
|
80
|
+
|
|
81
|
+
[#1]: https://github.com/AlexandriteSoftware/asljs
|
|
82
|
+
[MD]: docs/appbase.md
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** A package the browser page loads, and where its files are. */
|
|
2
|
+
export interface BrowserModule {
|
|
3
|
+
name: string;
|
|
4
|
+
/** The package folder on disk. */
|
|
5
|
+
root: string;
|
|
6
|
+
/** The ES module entry, relative to `root`, with forward slashes. */
|
|
7
|
+
entry: string;
|
|
8
|
+
/**
|
|
9
|
+
* The ES module of each subpath its `exports` names, e.g. `wiki` for
|
|
10
|
+
* `asljs-kb/wiki`, relative to `root`, with forward slashes.
|
|
11
|
+
*/
|
|
12
|
+
subpaths?: Readonly<Record<string, string>>;
|
|
13
|
+
}
|
|
14
|
+
/** The path the server serves `modules` under: `/modules/<name>/<file>`. */
|
|
15
|
+
export declare const MODULES_PREFIX = "/modules/";
|
|
16
|
+
/**
|
|
17
|
+
* Finds `name`, or each of the names, looked up from the folder `from`, and
|
|
18
|
+
* every package it depends on, at runtime, the way Node resolves them: in the
|
|
19
|
+
* `node_modules` folders above the folder of the package that depends on it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function findBrowserModules(name: string | readonly string[], from: string): BrowserModule[];
|
|
22
|
+
/**
|
|
23
|
+
* The import map that points each module name at its served entry, each
|
|
24
|
+
* subpath its `exports` names, as `asljs-kb/wiki`, at its module, and each
|
|
25
|
+
* `<name>/` at its folder, for a module that imports a file of a package, as
|
|
26
|
+
* lit imports `lit/decorators.js`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createImportMap(modules: readonly BrowserModule[], prefix: string): {
|
|
29
|
+
imports: Record<string, string>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The file of a module a request names, by the path after `MODULES_PREFIX`:
|
|
33
|
+
* `<name>/<file>` inside that module's folder, or `null` for an unknown module
|
|
34
|
+
* or a path that leaves its folder.
|
|
35
|
+
*/
|
|
36
|
+
export declare function findModuleFile(rest: string, modules: readonly BrowserModule[]): string | null;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/** The path the server serves `modules` under: `/modules/<name>/<file>`. */
|
|
4
|
+
export const MODULES_PREFIX = '/modules/';
|
|
5
|
+
/** Export conditions tried in order for a browser ES module entry. */
|
|
6
|
+
const CONDITIONS = ['browser',
|
|
7
|
+
'import',
|
|
8
|
+
'module',
|
|
9
|
+
'default'];
|
|
10
|
+
/**
|
|
11
|
+
* Finds `name`, or each of the names, looked up from the folder `from`, and
|
|
12
|
+
* every package it depends on, at runtime, the way Node resolves them: in the
|
|
13
|
+
* `node_modules` folders above the folder of the package that depends on it.
|
|
14
|
+
*/
|
|
15
|
+
export function findBrowserModules(name, from) {
|
|
16
|
+
const found = new Map();
|
|
17
|
+
const pending = (typeof name === 'string'
|
|
18
|
+
? [name]
|
|
19
|
+
: name)
|
|
20
|
+
.map(root => [root,
|
|
21
|
+
from]);
|
|
22
|
+
while (pending.length > 0) {
|
|
23
|
+
const [next, base] = pending.pop();
|
|
24
|
+
if (found.has(next)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const root = findPackageRoot(next, base);
|
|
28
|
+
if (!root) {
|
|
29
|
+
throw new Error(`Cannot find the package ${next} from ${base}.`);
|
|
30
|
+
}
|
|
31
|
+
const json = readPackageJson(root);
|
|
32
|
+
found.set(next, { name: next,
|
|
33
|
+
root,
|
|
34
|
+
entry: entryOf(json),
|
|
35
|
+
subpaths: subpathsOf(json) });
|
|
36
|
+
for (const dependency of Object.keys(json.dependencies ?? {})) {
|
|
37
|
+
pending.push([dependency,
|
|
38
|
+
root]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return [...found.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The import map that points each module name at its served entry, each
|
|
45
|
+
* subpath its `exports` names, as `asljs-kb/wiki`, at its module, and each
|
|
46
|
+
* `<name>/` at its folder, for a module that imports a file of a package, as
|
|
47
|
+
* lit imports `lit/decorators.js`.
|
|
48
|
+
*/
|
|
49
|
+
export function createImportMap(modules, prefix) {
|
|
50
|
+
return { imports: Object.fromEntries(modules.flatMap(module => [[module.name,
|
|
51
|
+
`${prefix}${module.name}/${module.entry}`],
|
|
52
|
+
...Object.entries(module.subpaths ?? {})
|
|
53
|
+
.map(([subpath, file]) => [`${module.name}/${subpath}`,
|
|
54
|
+
`${prefix}${module.name}/${file}`]),
|
|
55
|
+
[`${module.name}/`,
|
|
56
|
+
`${prefix}${module.name}/`]])) };
|
|
57
|
+
}
|
|
58
|
+
function findPackageRoot(name, from) {
|
|
59
|
+
let directory = path.resolve(from);
|
|
60
|
+
while (true) {
|
|
61
|
+
const candidate = path.join(directory, 'node_modules', name);
|
|
62
|
+
if (existsSync(path.join(candidate, 'package.json'))) {
|
|
63
|
+
return candidate;
|
|
64
|
+
}
|
|
65
|
+
const parent = path.dirname(directory);
|
|
66
|
+
if (parent === directory) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
directory = parent;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function readPackageJson(root) {
|
|
73
|
+
return JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
74
|
+
}
|
|
75
|
+
function entryOf(json) {
|
|
76
|
+
const exports = json.exports;
|
|
77
|
+
const main = typeof exports === 'object'
|
|
78
|
+
&& exports !== null
|
|
79
|
+
&& '.' in exports
|
|
80
|
+
? exports['.']
|
|
81
|
+
: exports;
|
|
82
|
+
const entry = pickCondition(main)
|
|
83
|
+
?? json.module
|
|
84
|
+
?? json.main
|
|
85
|
+
?? 'index.js';
|
|
86
|
+
return entry.replace(/^\.\//, '');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The module of each subpath of `exports` other than `.`, by the subpath
|
|
90
|
+
* without its `./`; a pattern subpath, with `*`, is left out.
|
|
91
|
+
*/
|
|
92
|
+
function subpathsOf(json) {
|
|
93
|
+
const exports = json.exports;
|
|
94
|
+
if (typeof exports
|
|
95
|
+
!== 'object'
|
|
96
|
+
|| exports === null) {
|
|
97
|
+
return {};
|
|
98
|
+
}
|
|
99
|
+
const found = {};
|
|
100
|
+
for (const [key, value] of Object.entries(exports)) {
|
|
101
|
+
const picked = pickCondition(value);
|
|
102
|
+
if (key.startsWith('./')
|
|
103
|
+
&& !key.includes('*')
|
|
104
|
+
&& picked !== null) {
|
|
105
|
+
found[key.slice(2)] =
|
|
106
|
+
picked.replace(/^\.\//, '');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return found;
|
|
110
|
+
}
|
|
111
|
+
function pickCondition(value) {
|
|
112
|
+
if (typeof value
|
|
113
|
+
=== 'string') {
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
if (typeof value
|
|
117
|
+
!== 'object'
|
|
118
|
+
|| value === null) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const conditions = value;
|
|
122
|
+
for (const condition of CONDITIONS) {
|
|
123
|
+
if (condition in conditions) {
|
|
124
|
+
const picked = pickCondition(conditions[condition]);
|
|
125
|
+
if (picked) {
|
|
126
|
+
return picked;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The file of a module a request names, by the path after `MODULES_PREFIX`:
|
|
134
|
+
* `<name>/<file>` inside that module's folder, or `null` for an unknown module
|
|
135
|
+
* or a path that leaves its folder.
|
|
136
|
+
*/
|
|
137
|
+
export function findModuleFile(rest, modules) {
|
|
138
|
+
for (const module of modules) {
|
|
139
|
+
if (!rest.startsWith(`${module.name}/`)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const target = path.resolve(module.root, rest.slice(module.name.length + 1));
|
|
143
|
+
return target.startsWith(module.root + path.sep)
|
|
144
|
+
? target
|
|
145
|
+
: null;
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { type CommandIo, type Config } from 'asljs-cmdbase';
|
|
2
|
+
import { type LoggerProvider } from 'asljs-logging';
|
|
3
|
+
import { type BrowserModule } from './browser-modules.js';
|
|
4
|
+
import { type RequestHandler } from './server.js';
|
|
5
|
+
/**
|
|
6
|
+
* A project of an application: a folder and the configuration file that
|
|
7
|
+
* configures the application in it, e.g. `apps/kb/kb.json`.
|
|
8
|
+
*/
|
|
9
|
+
export interface Project {
|
|
10
|
+
/**
|
|
11
|
+
* The folder relative to the folder the projects were looked for in, with
|
|
12
|
+
* `/` separators; `.` for that folder itself.
|
|
13
|
+
*/
|
|
14
|
+
id: string;
|
|
15
|
+
/**
|
|
16
|
+
* What the selector shows: the id, or the name of the folder for `.`.
|
|
17
|
+
*/
|
|
18
|
+
title: string;
|
|
19
|
+
/**
|
|
20
|
+
* The folder, by absolute path.
|
|
21
|
+
*/
|
|
22
|
+
folder: string;
|
|
23
|
+
/**
|
|
24
|
+
* The configuration file of the project.
|
|
25
|
+
*/
|
|
26
|
+
config: Config;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The projects of an application in `folder`, by its configuration file
|
|
30
|
+
* `name`, e.g. `kb.json`: the folder itself when it has the file; else every
|
|
31
|
+
* folder below it that has one, by id; else the folder itself, with the
|
|
32
|
+
* nearest file of a parent, or with none (`loadConfig`). The files are
|
|
33
|
+
* `files`, the files of `folder` as `listFiles` gives them, so that a server
|
|
34
|
+
* of several applications lists them once; `listFiles(folder)` when absent.
|
|
35
|
+
*
|
|
36
|
+
* With `required`, a project needs the file: when the folder, the folders
|
|
37
|
+
* below it and those above it have none, it throws, for an application whose
|
|
38
|
+
* projects cannot be told without it, e.g. which artefacts a part project
|
|
39
|
+
* supports.
|
|
40
|
+
*/
|
|
41
|
+
export declare function findProjects(folder: string, name: string, files?: readonly string[], options?: {
|
|
42
|
+
required?: boolean;
|
|
43
|
+
}): Promise<Project[]>;
|
|
44
|
+
/**
|
|
45
|
+
* The projects of an application in the folders of `context` by its
|
|
46
|
+
* configuration file `name`: `findProjects` of `cwd` and `files` alone, or of
|
|
47
|
+
* each of `folders` when there are several. Then the id of a project starts
|
|
48
|
+
* with the name of its folder, `docs/notes` for `notes` of `docs`, the name
|
|
49
|
+
* alone for the folder itself, and a name that two folders share gets `-2`,
|
|
50
|
+
* `-3` and so on after the first. With `required`, a folder without the file
|
|
51
|
+
* has no project, and an error is thrown only when no folder has one.
|
|
52
|
+
*/
|
|
53
|
+
export declare function findAppProjects(context: Pick<EditorAppContext, 'cwd' | 'files' | 'folders'>, name: string, options?: {
|
|
54
|
+
required?: boolean;
|
|
55
|
+
}): Promise<Project[]>;
|
|
56
|
+
/**
|
|
57
|
+
* A folder whose projects an application serves, and its files as `listFiles`
|
|
58
|
+
* gives them, when they are listed already.
|
|
59
|
+
*/
|
|
60
|
+
export interface WorkingFolder {
|
|
61
|
+
cwd: string;
|
|
62
|
+
files?: readonly string[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* What the `createApp` of an application server, e.g. `asljs-kb-srv`, makes
|
|
66
|
+
* its `EditorApp` with, whether it serves alone or in an aggregating server.
|
|
67
|
+
*/
|
|
68
|
+
export interface EditorAppContext {
|
|
69
|
+
/**
|
|
70
|
+
* The folder whose projects are served: `findProjects` of it.
|
|
71
|
+
*/
|
|
72
|
+
cwd: string;
|
|
73
|
+
/**
|
|
74
|
+
* The path the application is served at, ending with `/`: `/` alone,
|
|
75
|
+
* `/<id>/` in an aggregating server.
|
|
76
|
+
*/
|
|
77
|
+
base: string;
|
|
78
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
79
|
+
loggerProvider: LoggerProvider;
|
|
80
|
+
/**
|
|
81
|
+
* The files of `cwd`, as `listFiles` gives them, which `findProjects` looks
|
|
82
|
+
* for the configuration file in: an aggregating server lists them once for
|
|
83
|
+
* every application. Listed by each application when absent.
|
|
84
|
+
*/
|
|
85
|
+
files?: readonly string[];
|
|
86
|
+
/**
|
|
87
|
+
* The address the server listens on, when it is not a local one: the
|
|
88
|
+
* `host` of `createHandler`, which a `POST` must be sent to.
|
|
89
|
+
*/
|
|
90
|
+
host?: string;
|
|
91
|
+
/**
|
|
92
|
+
* The folders whose projects are served, when an aggregating server serves
|
|
93
|
+
* several, `cwd` and `files` being those of the first: `findAppProjects`
|
|
94
|
+
* finds the projects of them all.
|
|
95
|
+
*/
|
|
96
|
+
folders?: readonly WorkingFolder[];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* What a project handler is made with.
|
|
100
|
+
*/
|
|
101
|
+
export interface ProjectContext {
|
|
102
|
+
/**
|
|
103
|
+
* The path the project is served at, ending with `/`, e.g. `/kb/p/docs/`;
|
|
104
|
+
* the prefix of every link the project's pages and its plugin make.
|
|
105
|
+
*/
|
|
106
|
+
base: string;
|
|
107
|
+
/**
|
|
108
|
+
* Registers what `EditorApp.close` runs, such as stopping a background
|
|
109
|
+
* task the project started.
|
|
110
|
+
*/
|
|
111
|
+
onClose: (action: () => Promise<void>) => void;
|
|
112
|
+
}
|
|
113
|
+
export interface EditorAppOptions {
|
|
114
|
+
/**
|
|
115
|
+
* The application's id, e.g. `kb`: the path it is mounted at in an
|
|
116
|
+
* aggregating server, and the prefix of its documents' ids.
|
|
117
|
+
*/
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
/**
|
|
121
|
+
* The icon of the application as SVG, drawn in the text colour.
|
|
122
|
+
*/
|
|
123
|
+
icon: string;
|
|
124
|
+
/**
|
|
125
|
+
* The path the application is served at, ending with `/`; `/` by default.
|
|
126
|
+
*/
|
|
127
|
+
base?: string;
|
|
128
|
+
/**
|
|
129
|
+
* The projects, as `findProjects` gives them; the first is shown first.
|
|
130
|
+
*/
|
|
131
|
+
projects: readonly Project[];
|
|
132
|
+
/**
|
|
133
|
+
* The handler of a project, made when it is first requested.
|
|
134
|
+
*/
|
|
135
|
+
project: (project: Project, context: ProjectContext) => RequestHandler | Promise<RequestHandler>;
|
|
136
|
+
/**
|
|
137
|
+
* The plugin, by the path of its browser module, whose default export takes
|
|
138
|
+
* `{ id, base, project, model }` and returns the `EditorPlugin` of that
|
|
139
|
+
* project (see `asljs-ui-editor`). The plugin renders what the project's
|
|
140
|
+
* handler answers, which is data. The module's folder is served at
|
|
141
|
+
* `/_/plugin/`, its scripts and their source maps only, so that the module
|
|
142
|
+
* imports the modules beside it.
|
|
143
|
+
*/
|
|
144
|
+
plugin: string;
|
|
145
|
+
/**
|
|
146
|
+
* The packages the plugin and the pages import, served under
|
|
147
|
+
* `MODULES_PREFIX`; see `findBrowserModules`.
|
|
148
|
+
*/
|
|
149
|
+
modules: readonly BrowserModule[];
|
|
150
|
+
/**
|
|
151
|
+
* CSS of the plugin's panels and documents, added to the page.
|
|
152
|
+
*/
|
|
153
|
+
style?: string;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* What `/_/app.json` of an application says, with absolute paths.
|
|
157
|
+
*/
|
|
158
|
+
export interface EditorAppDescriptor {
|
|
159
|
+
id: string;
|
|
160
|
+
title: string;
|
|
161
|
+
icon: string;
|
|
162
|
+
/**
|
|
163
|
+
* The URL of the plugin module.
|
|
164
|
+
*/
|
|
165
|
+
plugin: string;
|
|
166
|
+
projects: {
|
|
167
|
+
id: string;
|
|
168
|
+
title: string;
|
|
169
|
+
base: string;
|
|
170
|
+
}[];
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* An application served as an editor plugin: its handler and what an
|
|
174
|
+
* aggregating page needs of it.
|
|
175
|
+
*/
|
|
176
|
+
export interface EditorApp {
|
|
177
|
+
id: string;
|
|
178
|
+
title: string;
|
|
179
|
+
base: string;
|
|
180
|
+
style: string;
|
|
181
|
+
modules: readonly BrowserModule[];
|
|
182
|
+
/**
|
|
183
|
+
* Answers the requests of the application, relative to `base`:
|
|
184
|
+
*
|
|
185
|
+
* - `/` - the editor with the application as its only plugin;
|
|
186
|
+
* - `/_/app.json` - `{ id, title, icon, plugin, projects }`, each project
|
|
187
|
+
* `{ id, title, base }`, with absolute paths;
|
|
188
|
+
* - `/_/plugin/...` - the plugin module and the modules beside it;
|
|
189
|
+
* - `/p/<project>/...` - the project, by its id, `~` for `.`;
|
|
190
|
+
* - `/modules/...` - the modules.
|
|
191
|
+
*/
|
|
192
|
+
handler: RequestHandler;
|
|
193
|
+
/**
|
|
194
|
+
* Runs what the projects registered with `onClose`.
|
|
195
|
+
*/
|
|
196
|
+
close: () => Promise<void>;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The segment of a project in its path: its id, `~` for `.`.
|
|
200
|
+
*/
|
|
201
|
+
export declare function projectSegment(id: string): string;
|
|
202
|
+
/**
|
|
203
|
+
* An application served as an editor plugin; see `EditorApp`.
|
|
204
|
+
*/
|
|
205
|
+
export declare function createEditorApp(options: EditorAppOptions): EditorApp;
|
|
206
|
+
/**
|
|
207
|
+
* A handler for several applications, each mounted at `/<id>/`, which is the
|
|
208
|
+
* `base` it was made with: `/` is the editor with every application as a
|
|
209
|
+
* plugin, and `/modules/...` the modules of them all.
|
|
210
|
+
*/
|
|
211
|
+
export declare function combineEditorApps(title: string, apps: readonly EditorApp[]): RequestHandler;
|
|
212
|
+
/**
|
|
213
|
+
* An editor page whose plugins are the applications of `apps`, the URLs of
|
|
214
|
+
* their `/_/app.json`; see `mountEditorApps` of `asljs-ui-editor`.
|
|
215
|
+
*/
|
|
216
|
+
export declare function editorPage(options: {
|
|
217
|
+
title: string;
|
|
218
|
+
apps: readonly string[];
|
|
219
|
+
modules: readonly BrowserModule[];
|
|
220
|
+
style?: string;
|
|
221
|
+
}): string;
|
|
222
|
+
/**
|
|
223
|
+
* Serves an editor application, as `<app>-srv` does: prints where it serves
|
|
224
|
+
* `cwd`, serves until SIGINT or SIGTERM, then closes the application.
|
|
225
|
+
*/
|
|
226
|
+
export declare function serveApp(app: EditorApp, options: {
|
|
227
|
+
io: CommandIo;
|
|
228
|
+
cwd: string;
|
|
229
|
+
port?: number;
|
|
230
|
+
host?: string;
|
|
231
|
+
loggerProvider: LoggerProvider;
|
|
232
|
+
}): Promise<void>;
|