asljs-appbase 0.0.0-stage → 0.1.4

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.
@@ -0,0 +1,182 @@
1
+ # appbase
2
+
3
+ The exports of `asljs-appbase`, by module.
4
+
5
+ ## Logging
6
+
7
+ The functions that run something take an optional `Logger` of `asljs-logging`
8
+ from their caller, and log nothing without one: they never create a provider.
9
+ What they log is listed with each of them.
10
+
11
+ Asking an AI agent and running commands are in `asljs-agents`, and the MCP
12
+ server core in `asljs-mcp`.
13
+
14
+ ## Markdown
15
+
16
+ - `parseMarkdown(text)` - the mdast tree.
17
+ - `findSectionHeading(root, name)`, `getSection(root, name)` - a level 2
18
+ section: its heading, or its nodes up to the next level 1 or 2 heading.
19
+ - `plainText(node)` - the text of a node.
20
+ - `splitLocalUrl(url)` - a local link target split into a decoded path and its
21
+ `#` fragment; `null` for a URL with a scheme.
22
+ - `formatUrl(url)` - a link target in angle brackets when it has spaces or
23
+ parentheses.
24
+
25
+ ## Files
26
+
27
+ - `findMarkdownFiles(folder, { skip })` - the `.md` files of a folder and its
28
+ subfolders, any case of the extension, by absolute path, sorted, as the
29
+ `LocationResolver` of `asljs-locator` finds them, skipping folders whose name
30
+ starts with `.`, `node_modules`, and the `skip` names.
31
+ - `listFiles(folder)` - every file of a folder and its subfolders, relative to
32
+ it with `/` separators, sorted, as the `LocationResolver` of `asljs-locator`
33
+ finds them; what `.gitignore` files ignore, `.git` and `node_modules` are left
34
+ out.
35
+ - `toDisplayPath(folder, file)` - a path relative to `folder` with `/`
36
+ separators.
37
+
38
+ ## Post-processing
39
+
40
+ - `writeMarkdown(file, text)` - writes a markdown file and remembers it.
41
+ - `takeWritten()` - the files written since the last call, and forgets them.
42
+ - `findConfig(folder, name)` - the nearest configuration file `name`, e.g.
43
+ `rq.json`, of `folder` or a parent; an error when it is not valid JSON or its
44
+ `markdownPostProcessing` is not a string.
45
+ - `postProcess(io, files, name)` - runs the `markdownPostProcessing` command of
46
+ the nearest `name` with the files that still exist, relative to the
47
+ configuration file's folder, where it runs. Returns 1 and writes the output to
48
+ `io.stderr` when the command fails, 0 otherwise. The command line and its exit
49
+ code go to `io.logger` at `debug`.
50
+
51
+ ## Configuration and executables
52
+
53
+ The configuration readers, `loadConfig` and the `config*` functions, and the
54
+ entry point of an executable, `runMain`, `commandLine` and the helpers beside
55
+ them, are in [asljs-cmdbase][CMB], and this package re-exports them. The rules
56
+ of the configuration file are in [Configuration][CFG] at the repository root.
57
+ `findConfig` is `loadConfig` with the check of `markdownPostProcessing`.
58
+
59
+ ## State folder
60
+
61
+ - `stateFolder(folder, app, config, given?)` - where application `app` keeps
62
+ what it stores between runs for the project in `folder`: `given`, a command
63
+ line's `{ option, variable, env, cwd }`, the option, else the variable, e.g.
64
+ `KB_STATE_DIR`, both against `cwd`; else `stateDir` of `config`, against the
65
+ folder of the file; else `.<app>` in `folder`, e.g. `.kb`. A service passes no
66
+ `given`: its projects are configured by their own files.
67
+
68
+ ## Server
69
+
70
+ A server sends data, never a rendering of it: rendering is the page's, e.g. the
71
+ plugin of an editor application. It serves a markdown file as its text, and JSON
72
+ values; the only HTML it sends is `index`, a page that loads its data.
73
+
74
+ - `startServer({ folder, index?, json?, port?, host?, post?, allow?, modules?,
75
+ logger? })` - serves `/` with `index()`, made again on every request, and not
76
+ found without it; a path of `json` with its value; and any file of `folder` as
77
+ it is, a `.md` file as `text/markdown`. Nothing outside `folder`, or that
78
+ `allow(relative)` refuses, is served. The files of each of `modules` are
79
+ served under `MODULES_PREFIX`, `/modules/<name>/<file>`, and nothing outside
80
+ their folders. It listens on `host`, `127.0.0.1` by default, on `port`, or
81
+ without one on the first free port from `DEFAULT_PORT`, 3000, up to 3099.
82
+ `logger` is told that it listens, with its URL, at `information`, each request
83
+ at `trace`, and a request that failed at `error`. A `POST` is answered by
84
+ `post(url, body)` with the parsed JSON body; it returns a `PostReply`, `{
85
+ status, body }`, sent back as JSON. Without `post` a `POST` is not found. Only
86
+ a `POST` with `Content-Type: application/json`, sent to a local name
87
+ (`localhost`, `127.0.0.1`, `[::1]` or `host`) and, when it has an `Origin`,
88
+ from the server's own pages is answered; any other gets 403, a body that is
89
+ not JSON 400, and one over 10 MB 413.
90
+ - `json` of `startServer`, by path, gives values sent as JSON, e.g.
91
+ `/_/data.json`, made from the request URL with its query; a value made with
92
+ `jsonReply(status, body)` is sent with that status, e.g. 422. `methods`, e.g.
93
+ `[ 'GET', 'HEAD' ]`, refuses any other method with 405, and `moduleTypes`,
94
+ e.g. `[ '.js', '.mjs', '.map' ]`, limits the module files served by their
95
+ extensions.
96
+ - `createHandler(options)` - the `RequestHandler` of `startServer` without
97
+ listening: `(request, response, url)`, whose `url` path is relative to where
98
+ it is mounted. `serve(handler, { port?, host?, logger? })` listens with any
99
+ handler, as `startServer` does; `send(response, status, type, body)` answers.
100
+ - `mountHandlers(mounts, fallback?)` - passes a request for `/<name>/...` to
101
+ `mounts[name]` with the path relative to it, redirects `/<name>` to
102
+ `/<name>/`, and passes any other request to `fallback`, or answers 404.
103
+ - `untilStopped(server, signals?)` - resolves once the server has closed; the
104
+ first of `signals`, `SIGINT` and `SIGTERM` by default, closes it and its open
105
+ connections. A command that serves awaits it, so that it releases what the
106
+ server used, such as its logger provider, only after the server.
107
+ - `serverUrl(server)` - its address, e.g. `http://127.0.0.1:3000/`, an IPv6
108
+ address in brackets.
109
+ - `page(title, body, style?)` - an HTML page with the shared style and `style`,
110
+ e.g. the editor page, or a page printed to PDF.
111
+ - `scriptJson(value)` - JSON that is safe inside a `<script>` element.
112
+ - `versionConflict()` - the 409 reply to a save of a document that changed since
113
+ its editor read it.
114
+ - `escapeHtml(text)` - the text with `&`, `<`, `>` and `"` escaped.
115
+
116
+ ## Editor applications
117
+
118
+ An application served as a plugin of the editor of `asljs-ui-editor`, with a
119
+ selector of its projects; one server can serve one application, or several.
120
+
121
+ - `findProjects(folder, name, files?)` - the projects of an application by its
122
+ configuration file `name`, e.g. `kb.json`: `folder` itself when it has the
123
+ file; else every folder below it that has one, by id; else `folder` itself
124
+ with the nearest file of a parent, or none. It looks for the file in `files`,
125
+ the files of `folder` as `listFiles` gives them, so that a server of several
126
+ applications lists them once; it lists them itself without. A `Project` is `{
127
+ id, title, folder, config }`; `id` is the folder relative to `folder`, `.` for
128
+ itself.
129
+ - `createEditorApp({ id, title, icon, base?, projects, project, plugin, modules,
130
+ style? })` - an `EditorApp`, whose `handler` answers, relative to `base`, `/`
131
+ with the editor whose only plugin is the application, `/_/app.json` with an
132
+ `EditorAppDescriptor` - `{ id, title, icon, plugin, projects }`, each project
133
+ `{ id, title, base }` - `/_/plugin/...` with the folder of `plugin`, the path
134
+ of the plugin's browser module, its scripts and source maps only, so that it
135
+ imports the modules beside it, `plugin` being `/_/plugin/<file>` in the
136
+ descriptor; `/modules/...` with the modules, and `/p/<project>/...` with the
137
+ handler of that project, `~` naming `.`. `project(project, { base, onClose })`
138
+ makes that handler when the project is first requested; it answers data, which
139
+ the plugin renders. `base` is where it is served, e.g. `/kb/p/docs/`, the
140
+ prefix of the URLs its plugin reads, and `onClose` registers what `close()` of
141
+ the application runs. `projectSegment(id)` is the segment of a project in a
142
+ path.
143
+ - `EditorAppContext` - `{ cwd, base, env, loggerProvider, files?, host? }`, what
144
+ the `createApp` of an application server makes its `EditorApp` with, alone or
145
+ in an aggregating server; `files`, the files of `cwd` an aggregating server
146
+ listed once, go to `findProjects`, and `host`, the address the server listens
147
+ on, to the `host` of each project's handler.
148
+ - `combineEditorApps(title, apps)` - a handler that mounts each application at
149
+ `/<id>/`, the `base` it was made with, and answers `/` with the editor whose
150
+ plugins are all of them and `/modules/...` with the modules of them all.
151
+ - `editorPage({ title, apps, modules, style? })` - the editor page: the import
152
+ map of `modules`, an `asljs-editor` and `mountEditorApps` of the applications
153
+ whose `/_/app.json` URLs are `apps`, and `style`; the editor adds its own
154
+ style, `EDITOR_STYLE` of `asljs-ui-editor`, when it mounts.
155
+ - `serveApp(app, { io, cwd, port?, host?, loggerProvider })` - serves an
156
+ `EditorApp`, prints `Serving <cwd> at <url>`, waits until SIGINT or SIGTERM,
157
+ and closes the application.
158
+
159
+ ## Browser modules
160
+
161
+ A page served by `startServer` can import installed packages, such as
162
+ `asljs-ui-diagram`, without a bundler.
163
+
164
+ - `findBrowserModules(name, from)` - the package `name`, or each package of an
165
+ array of names, looked up from the folder `from`, and every package it depends
166
+ on at runtime, each a `BrowserModule`: its `name`, its folder `root`, and its
167
+ ES module `entry`, picked from the `browser`, `import`, `module` and `default`
168
+ conditions of `exports`, else `module`, else `main`, else `index.js`, and its
169
+ `subpaths`, the module of each other subpath of `exports`, e.g. `wiki` of
170
+ `asljs-kb/wiki`, a pattern with `*` left out. It throws for a package it
171
+ cannot find.
172
+ - `createImportMap(modules, prefix)` - the import map that points each name at
173
+ `<prefix><name>/<entry>`, each `<name>/<subpath>` at its module, and `<name>/`
174
+ at `<prefix><name>/`, for a module that imports a file of a package, as lit
175
+ imports `lit/decorators.js`. Pass it to `startServer` as `modules` and put the
176
+ map, with `MODULES_PREFIX`, in a `<script type="importmap">` of the page.
177
+ - `findModuleFile(rest, modules)` - the file of a module that a path after
178
+ `MODULES_PREFIX` names, or `null` for an unknown module or a path that leaves
179
+ its folder.
180
+
181
+ [CFG]: ../../../docs/Configuration.md
182
+ [CMB]: ../../cmdbase/docs/cmdbase.md
package/package.json CHANGED
@@ -1,6 +1,64 @@
1
1
  {
2
2
  "name": "asljs-appbase",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.4",
4
+ "description": "The base of the applications: configuration files and state folders, the entry point of an executable, markdown, the document server and editor applications.",
5
+ "type": "module",
6
+ "asljs": {
7
+ "type": "lib"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist/**",
19
+ "docs/**",
20
+ "README.md",
21
+ "LICENSE.md"
22
+ ],
23
+ "scripts": {
24
+ "flint": "toolkit flint",
25
+ "clean": "toolkit clean",
26
+ "build": "npm run codegen --if-present && tsc -p tsconfig.build.json",
27
+ "build:dist": "npm run codegen --if-present && tsc -p tsconfig.dist.json",
28
+ "typecheck": "npm run codegen --if-present && tsc -p tsconfig.build.json --noEmit",
29
+ "guard:clean-git": "toolkit ensure-clean-working-directory",
30
+ "prepack": "npm run clean && npm run build:dist && npm run build && npm run test && npm run guard:clean-git",
31
+ "postpublish": "toolkit tag-release-revision",
32
+ "test": "node --test --enable-source-maps \"build/**/*.test.js\"",
33
+ "test:watch": "node --watch --test \"build/**/*.test.js\"",
34
+ "coverage": "npm run build && node --test --experimental-test-coverage --enable-source-maps --test-coverage-exclude=\"**/*.test.js\" \"build/**/*.test.js\"",
35
+ "release:patch": "toolkit release-patch",
36
+ "all": "npm run clean && npm run build:dist && npm run flint && npm run typecheck && npm run build && npm run test"
37
+ },
38
+ "keywords": [
39
+ "markdown",
40
+ "cli"
41
+ ],
42
+ "homepage": "https://github.com/AlexandriteSoftware/asljs#readme",
43
+ "bugs": {
44
+ "url": "https://github.com/AlexandriteSoftware/asljs/issues"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/AlexandriteSoftware/asljs.git"
49
+ },
50
+ "author": "\"Alex Netkachov\" <alex.netkachov@gmail.com>",
51
+ "license": "SEE LICENSE IN LICENSE.md",
52
+ "dependencies": {
53
+ "asljs-agents": "^0.1.0",
54
+ "asljs-cmdbase": "^0.1.0",
55
+ "asljs-locator": "^0.1.0",
56
+ "asljs-logging": "^0.1.2",
57
+ "remark-parse": "^11.0.0",
58
+ "unified": "^11.0.5"
59
+ },
60
+ "devDependencies": {
61
+ "asljs-tmpdir": "^0.1.13",
62
+ "asljs-toolkit": "^0.1.0"
63
+ }
64
+ }