@omnitron-dev/titan-lumen 0.4.6 → 0.4.9
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 +25 -231
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,251 +1,45 @@
|
|
|
1
1
|
# @omnitron-dev/titan-lumen
|
|
2
2
|
|
|
3
|
-
Lumen
|
|
4
|
-
controlled authoring through Netron. The AST compiler remains in
|
|
5
|
-
`@omnitron-dev/lumen-ast`; transport authentication and invocation isolation
|
|
6
|
-
belong to Titan's Netron core.
|
|
3
|
+
Lumen document services for Titan applications. The module exposes authorized reads, search, theorem graphs and optional durable authoring through the application's existing Netron peer.
|
|
7
4
|
|
|
8
|
-
##
|
|
5
|
+
## Capabilities
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
listeners and authentication adapter; Lumen does not need a second HTTP auth
|
|
15
|
-
middleware.
|
|
7
|
+
- Document reads and search projected for the admitted caller.
|
|
8
|
+
- Symbol contracts and theorem graphs.
|
|
9
|
+
- Explicitly authorized playground execution.
|
|
10
|
+
- Revision-checked editing backed by the application's database.
|
|
16
11
|
|
|
17
|
-
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pnpm add @omnitron-dev/titan-lumen
|
|
16
|
+
```
|
|
18
17
|
|
|
19
18
|
```ts
|
|
20
|
-
import {
|
|
19
|
+
import { LumenModule } from '@omnitron-dev/titan-lumen';
|
|
21
20
|
|
|
22
|
-
const documents =
|
|
21
|
+
export const documents = LumenModule.forRoot({
|
|
23
22
|
docsDir: '/absolute/docs',
|
|
24
23
|
enablePlayground: false,
|
|
25
24
|
});
|
|
26
|
-
await netron.peer.exposeService(documents);
|
|
27
25
|
```
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
same application authentication/session provider as other Titan services. Never
|
|
31
|
-
accept a role list or `valid: true` in a request as proof of identity.
|
|
32
|
-
|
|
33
|
-
## Published RPC surface
|
|
34
|
-
|
|
35
|
-
The service name is `Lumen`. `LumenServiceContract` describes its network methods:
|
|
36
|
-
|
|
37
|
-
| Method | Result | Authorization |
|
|
38
|
-
| --- | --- | --- |
|
|
39
|
-
| `search(query, options?)` | Ranked document hits | Public projection or verified caller's document access |
|
|
40
|
-
| `getDocument(path)` | Authorized Markdown or `null` | Document and node access |
|
|
41
|
-
| `getEditableDocument(path)` | Whole document, revision, hash and access or `null` | `lumen.documents.write` and access to every section |
|
|
42
|
-
| `getSymbolContract(symbol)` | Symbol contract or `null` | Configured source access, internal by default |
|
|
43
|
-
| `getTheoremGraph()` | Theorem nodes and edges | Authorized document projection |
|
|
44
|
-
| `executePlayground(code)` | Execution result or error | `lumen.playground.execute` |
|
|
45
|
-
| `saveLiveEdit(payload)` | Revision or conflict | `lumen.documents.write` |
|
|
46
|
-
|
|
47
|
-
Grant mutation permissions through the host application's role/permission system.
|
|
48
|
-
They are independent: an editor can receive document write access without code
|
|
49
|
-
execution access. The same requirements apply to HTTP and WebSocket; missing
|
|
50
|
-
identity returns 401 and insufficient permissions return 403.
|
|
51
|
-
|
|
52
|
-
Netron supplies the admitted identity through `getCurrentInvocationContext()`.
|
|
53
|
-
`session` is not part of the wire contract. Extra arguments cannot impersonate an
|
|
54
|
-
administrator. Search filters cannot override the verified caller's roles.
|
|
55
|
-
`getOptions()` and `getAccessFilterService()` are internal service APIs and are
|
|
56
|
-
not published RPC methods.
|
|
57
|
-
|
|
58
|
-
Direct in-process reads outside an admitted Netron invocation are anonymous.
|
|
59
|
-
Mutations require the corresponding admitted service method and a verified
|
|
60
|
-
identity. There is one service and one contract; there are no session arguments,
|
|
61
|
-
controller wrappers or alternate service tokens. Titan resolves the service and
|
|
62
|
-
its `AccessFilterService` and `LiveEditService` collaborators by their classes.
|
|
63
|
-
`LUMEN_OPTIONS_TOKEN` is the configuration token.
|
|
64
|
-
|
|
65
|
-
An empty corpus returns empty results. A missing configured corpus reports an
|
|
66
|
-
error on document, search and graph reads; it never substitutes demonstration
|
|
67
|
-
documents or symbol contracts.
|
|
68
|
-
|
|
69
|
-
## Durable authoring
|
|
70
|
-
|
|
71
|
-
Without `liveEdit`, Lumen reads the filesystem and refuses edits. Enable authoring
|
|
72
|
-
with `liveEdit: { corpusId: 'product-docs', connectionName: 'default' }` and the
|
|
73
|
-
application's `TitanDatabaseModule`. Both synchronous and asynchronous Lumen
|
|
74
|
-
module providers resolve that module's `DATABASE_MANAGER`; they do not create
|
|
75
|
-
another pool. The connection must use PostgreSQL or file-backed SQLite with its
|
|
76
|
-
native driver installed. Choose a stable `corpusId` shared by every instance that
|
|
77
|
-
serves the same corpus. Different corpus IDs have independent document identities.
|
|
78
|
-
|
|
79
|
-
Apply the exported migration through the application's explicit migration workflow
|
|
80
|
-
before enabling authoring. Runtime dependency injection never creates tables:
|
|
27
|
+
Add the module to an existing Titan application. Resolve `LumenService` and expose it with `peer.exposeService(app.resolve(LumenService))` on that application's Netron peer. The host owns its listeners and authentication provider. `LumenServiceContract` describes the published `Lumen` service; no separate controller or request-supplied session is needed.
|
|
81
28
|
|
|
82
|
-
|
|
83
|
-
import { MigrationRunner } from '@omnitron-dev/titan-database/migration';
|
|
84
|
-
import { lumenAuthoringMigration, type LumenAuthoringDatabase } from '@omnitron-dev/titan-lumen';
|
|
85
|
-
|
|
86
|
-
const db = await databaseManager.getConnection<LumenAuthoringDatabase>('default');
|
|
87
|
-
await new MigrationRunner(db, [lumenAuthoringMigration], {
|
|
88
|
-
useTransactions: true,
|
|
89
|
-
enforceChecksums: true,
|
|
90
|
-
}).up();
|
|
91
|
-
```
|
|
29
|
+
An empty corpus returns empty results. A missing configured corpus is an error. Direct in-process reads outside an admitted invocation are anonymous.
|
|
92
30
|
|
|
93
|
-
|
|
94
|
-
including document reads, search and graph operations. No in-memory store or
|
|
95
|
-
stale filesystem substitute is used.
|
|
31
|
+
## Authorization and editing
|
|
96
32
|
|
|
97
|
-
|
|
98
|
-
`revision` and SHA-256 `hash` as `baseRevision` and `baseHash` with each edit:
|
|
33
|
+
Netron supplies the verified invocation identity. `getEditableDocument` and `saveLiveEdit` require `lumen.documents.write`; `executePlayground` independently requires `lumen.playground.execute`. Caller-supplied roles or extra arguments cannot grant those permissions.
|
|
99
34
|
|
|
100
|
-
|
|
101
|
-
const document = await lumen.getEditableDocument('guides/start.pdx');
|
|
102
|
-
if (document) {
|
|
103
|
-
const saved = await lumen.saveLiveEdit({
|
|
104
|
-
docId: document.docId,
|
|
105
|
-
baseRevision: document.revision,
|
|
106
|
-
baseHash: document.hash,
|
|
107
|
-
mode: 'replace',
|
|
108
|
-
patch: updatedMarkdown,
|
|
109
|
-
});
|
|
110
|
-
if (saved.conflict) {
|
|
111
|
-
// Reload the current revision and let the editor reconcile its changes.
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
```
|
|
35
|
+
Without `liveEdit`, the service reads files and refuses edits. Durable authoring uses `liveEdit: { corpusId, connectionName }`, the existing `TitanDatabaseModule`, and PostgreSQL or file-backed SQLite. Apply `lumenAuthoringMigration` through the application's migration workflow before enabling it. An unavailable store or missing schema is an error, not a fallback to stale files.
|
|
115
36
|
|
|
116
|
-
|
|
117
|
-
paths. A disk document starts at revision zero. Its first successful edit stores
|
|
118
|
-
that exact seed, provenance and hash as history revision zero and the edit as
|
|
119
|
-
revision one, in the same transaction. The database then owns that path: later
|
|
120
|
-
filesystem changes cannot replace it. A new document uses revision zero and the
|
|
121
|
-
SHA-256 of the empty string as its base. `append`, `replace` and one-based
|
|
122
|
-
`line-range` edits preserve submitted whitespace.
|
|
123
|
-
|
|
124
|
-
Current content and append-only revision history commit atomically. A database
|
|
125
|
-
compare-and-swap checks both revision and hash. Competing editors receive a
|
|
126
|
-
conflict; SQLite snapshot conflicts and PostgreSQL serialization/deadlock errors
|
|
127
|
-
use TitanDatabase's bounded whole-transaction retry. Connection failures are
|
|
128
|
-
reported. Success and `live-edit` notifications occur only after commit. The
|
|
129
|
-
author comes from the verified Netron invocation; client `author` and `access`
|
|
130
|
-
fields are rejected. Existing content is authorized before conflict details are
|
|
131
|
-
returned; every section of edited content is authorized before commit. Reads and
|
|
132
|
-
edits verify stored revision numbers, UTF-8 byte lengths and content hashes;
|
|
133
|
-
corruption is an explicit error.
|
|
134
|
-
|
|
135
|
-
Accepted documents are never evicted. Writes default to 256 KiB per patch and
|
|
136
|
-
2 MiB per document, configurable up to 8 MiB. `readCorpus` checks entry and byte
|
|
137
|
-
metadata in one consistent database snapshot before reading content, then the
|
|
138
|
-
service merges unowned filesystem documents within the remaining corpus budget.
|
|
139
|
-
Document reads, search and graph therefore share the same durable source.
|
|
140
|
-
Internal `getHistory` requires an authenticated actor and access to both the
|
|
141
|
-
current document and each returned revision; it defaults to 50 versions and
|
|
142
|
-
8 MiB per page, with hard bounds of 100 versions and 64 MiB. History is not an
|
|
143
|
-
additional public RPC.
|
|
144
|
-
|
|
145
|
-
## MCP on the existing Netron HTTP host
|
|
146
|
-
|
|
147
|
-
`LumenMcpAdapter` uses the official MCP SDK for protocol negotiation, schemas and
|
|
148
|
-
errors. It translates tool/resource calls into the host's native Netron HTTP
|
|
149
|
-
entry point in process. Authorization headers and the host-supplied connection
|
|
150
|
-
address enter the same authentication, permission and rate-limit path as RPC.
|
|
151
|
-
The adapter has no listener, authentication callback or mutable caller session.
|
|
37
|
+
`getEditableDocument` returns the original source, revision and hash only when the caller can edit the whole document. Pass that source to Prism's `ResearchEditor.initialSource`, then save snapshot `getSource()` with `baseRevision` and `baseHash`. `saveLiveEdit` reports a conflict when those no longer match. Projected Markdown is for reading or export, not overwriting the original.
|
|
152
38
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const http = new HttpNativeServer({
|
|
159
|
-
host: '127.0.0.1',
|
|
160
|
-
port: 8081,
|
|
161
|
-
customRoutes: [async (request, { remoteAddress }) =>
|
|
162
|
-
new URL(request.url).pathname === '/mcp'
|
|
163
|
-
? mcp.handleRequest(request, remoteAddress)
|
|
164
|
-
: null],
|
|
165
|
-
});
|
|
166
|
-
http.setPeer(netron.peer);
|
|
167
|
-
mcp = new LumenMcpAdapter({
|
|
168
|
-
http,
|
|
169
|
-
resources: ['guides/start.pdx'],
|
|
170
|
-
allowedHostnames: ['localhost', '127.0.0.1', '[::1]'],
|
|
171
|
-
allowedOriginHostnames: ['localhost', '127.0.0.1', '[::1]'],
|
|
172
|
-
});
|
|
173
|
-
await http.listen();
|
|
174
|
-
```
|
|
39
|
+
## Documentation
|
|
40
|
+
|
|
41
|
+
[Public API](src/index.ts) · [Package exports](package.json) · [Lumen](../lumen/README.md) · [Prism authoring](../prism/README.md#research-documents-and-authoring)
|
|
42
|
+
|
|
43
|
+
## License
|
|
175
44
|
|
|
176
|
-
|
|
177
|
-
`lumen://corpus/{path}` resources. Resource lists contain only documents readable
|
|
178
|
-
by the caller; every read re-enters the service, so no independent content store
|
|
179
|
-
can bypass document access. Tool schemas reject undeclared role/session fields.
|
|
180
|
-
|
|
181
|
-
The endpoint uses stateless Streamable HTTP with JSON responses. POST is the
|
|
182
|
-
only accepted method; it does not open persistent SSE sessions. The default
|
|
183
|
-
body limit is 1 MiB. Configure host/origin hostname allowlists for the actual
|
|
184
|
-
deployment; they default to loopback names. Set `rpcPath` when the host changes
|
|
185
|
-
its native invocation route. The host owns TLS, authentication and shutdown.
|
|
186
|
-
See the [official TypeScript MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk).
|
|
187
|
-
|
|
188
|
-
## Qualification status
|
|
189
|
-
|
|
190
|
-
Server playground calls use the shared Lumen WASM interpreter in a fresh Node
|
|
191
|
-
Worker with an empty environment. Netron checks `lumen.playground.execute`
|
|
192
|
-
before admitting a call. At most four workers run per service; excess calls
|
|
193
|
-
receive 429, and capacity is released only after worker termination. The outer
|
|
194
|
-
five-second timer includes initialization. Execution, memory, source and result
|
|
195
|
-
limits are enforced by `@omnitron-dev/lumen-ast/execution`; no `node:vm` or host
|
|
196
|
-
JavaScript fallback is used. Keep `enablePlayground: false` when execution is
|
|
197
|
-
unnecessary; public read access never grants execution permission.
|
|
198
|
-
|
|
199
|
-
The 0.4.0 audit is in progress. Do not infer that a test with a PDF header,
|
|
200
|
-
hydration flag or mock request establishes production readiness. The repository's
|
|
201
|
-
`audit/LUMEN-0.4.0.md` records release qualification work. Durable authoring is
|
|
202
|
-
covered by real SQLite and PostgreSQL transactions, independent connection races, commit failure,
|
|
203
|
-
restart, native RPC and shared document/search/graph tests. The isolated execution engine has
|
|
204
|
-
local negative tests through actual Netron, including memory exhaustion,
|
|
205
|
-
constructor escapes and concurrent admission. Browser and final package checks
|
|
206
|
-
remain part of the release gate. Nothing in this package's audit
|
|
207
|
-
activates changes on running Omnitron controllers or applications.
|
|
208
|
-
|
|
209
|
-
## Corpus bounds and source visibility
|
|
210
|
-
|
|
211
|
-
Filesystem documents use canonical relative paths. Symlinks, hidden paths,
|
|
212
|
-
`node_modules` and generated `dist` trees are excluded. A missing document is
|
|
213
|
-
`null`; a missing configured directory, invalid UTF-8 or failed read is an error.
|
|
214
|
-
Search and theorem graphs consume the same complete, deterministic inventory.
|
|
215
|
-
The default inventory budget is 10,000 entries, 64 MiB and 32 directory levels;
|
|
216
|
-
`corpusLimits` configures these bounds. Documents are limited to 5 MiB and source
|
|
217
|
-
files to 2 MiB. Exceeding a bound fails the request rather than returning a
|
|
218
|
-
successful partial corpus. Search accepts limits from 0 to 100 and queries of
|
|
219
|
-
at most 4 KiB.
|
|
220
|
-
|
|
221
|
-
Each service admits at most four concurrent corpus reads, independently of its
|
|
222
|
-
four playground workers. Read admission covers the complete operation through
|
|
223
|
-
authorization and projection; excess calls receive 429 and can retry after the
|
|
224
|
-
current operations finish. An overload is an error, not an empty search result.
|
|
225
|
-
|
|
226
|
-
## PostgreSQL qualification
|
|
227
|
-
|
|
228
|
-
The dedicated `test:postgres` target exercises the built package on a real
|
|
229
|
-
PostgreSQL 16 container through TitanDatabase and Kysera. Build the SDK first,
|
|
230
|
-
then set `LUMEN_POSTGRES_DATA_ROOT` to an existing absolute directory reserved
|
|
231
|
-
for disposable test data. On this development Mac, use the mounted AGI workspace.
|
|
232
|
-
The regular unit target excludes this container suite; the explicit PostgreSQL
|
|
233
|
-
target fails if Docker, PostgreSQL or test storage is unavailable.
|
|
234
|
-
|
|
235
|
-
The suite creates its own Docker network, loopback port and data directory.
|
|
236
|
-
The existing DockerTestManager enforces 1 CPU, 512 MiB of memory and 128 processes
|
|
237
|
-
from container creation; tests inspect the actual Docker configuration. Cleanup
|
|
238
|
-
owns only these resources, and the global orphan reaper is disabled for this run.
|
|
239
|
-
No configured application database is used.
|
|
240
|
-
|
|
241
|
-
Qualification covers migration and checksum enforcement, races between eight
|
|
242
|
-
independent PostgreSQL connections, rollback when a deferred constraint rejects
|
|
243
|
-
COMMIT, canonical transaction retry after SQLSTATE `40001`, and history/source
|
|
244
|
-
hashes after restarting the isolated PostgreSQL server. PostgreSQL durability
|
|
245
|
-
settings remain enabled throughout the run.
|
|
246
|
-
|
|
247
|
-
`sourceAccess` and `knowledgeBaseAccess` default to `internal`, independently of
|
|
248
|
-
public Markdown. Set either to `public` only when that entire configured source
|
|
249
|
-
is intended for anonymous readers. Per-entry and section restrictions still
|
|
250
|
-
apply to knowledge-base search results. A failed KB query or source scan is
|
|
251
|
-
reported explicitly; it does not silently fall back to a different corpus.
|
|
45
|
+
[MIT](../../LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omnitron-dev/titan-lumen",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"description": "Titan backend integration module for Lumen documentation and knowledge portal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@omnitron-dev/kb": "0.4.
|
|
21
|
-
"@omnitron-dev/lumen-ast": "0.4.
|
|
22
|
-
"@omnitron-dev/titan-database": "0.4.
|
|
20
|
+
"@omnitron-dev/kb": "0.4.9",
|
|
21
|
+
"@omnitron-dev/lumen-ast": "0.4.9",
|
|
22
|
+
"@omnitron-dev/titan-database": "0.4.9",
|
|
23
23
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
24
24
|
"@modelcontextprotocol/server": "^2.4.0",
|
|
25
|
-
"@omnitron-dev/netron-protocol": "0.4.
|
|
25
|
+
"@omnitron-dev/netron-protocol": "0.4.9",
|
|
26
26
|
"zod": "^4.6.7"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@omnitron-dev/titan": "0.4.
|
|
29
|
+
"@omnitron-dev/titan": "0.4.9"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@omnitron-dev/testing": "0.4.
|
|
32
|
+
"@omnitron-dev/testing": "0.4.9",
|
|
33
33
|
"better-sqlite3": "^13.0.3",
|
|
34
|
-
"@omnitron-dev/titan": "0.4.
|
|
34
|
+
"@omnitron-dev/titan": "0.4.9",
|
|
35
35
|
"@types/node": "26.6.6",
|
|
36
36
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
37
37
|
"vitest": "^5.0.5",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"url": "git+https://github.com/omnitron-dev/omni.git",
|
|
47
47
|
"directory": "packages/titan-lumen"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "c6005ff1d0cde480cfa6b0bc346c9b53b2e638bf",
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "../../scripts/build-package.sh -p ./tsconfig.json",
|
|
52
52
|
"typecheck": "tsc --noEmit",
|