@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.
Files changed (2) hide show
  1. package/README.md +25 -231
  2. package/package.json +9 -9
package/README.md CHANGED
@@ -1,251 +1,45 @@
1
1
  # @omnitron-dev/titan-lumen
2
2
 
3
- Lumen's Titan integration provides document reads, search, theorem graphs and
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
- ## Integrating with an existing Titan application
5
+ ## Capabilities
9
6
 
10
- Register `LumenModule.forRoot({ docsDir: '/absolute/docs' })` in the application's
11
- modules, or use `LumenModule.forRootAsync({ useFactory, inject })` for configuration
12
- provided by DI. Resolve `LumenService` and expose it on the application's
13
- Netron peer using `peer.exposeService(app.resolve(LumenService))`. The application owns its
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
- The equivalent explicit composition is:
12
+ ## Quick start
13
+
14
+ ```sh
15
+ pnpm add @omnitron-dev/titan-lumen
16
+ ```
18
17
 
19
18
  ```ts
20
- import { LumenService } from '@omnitron-dev/titan-lumen';
19
+ import { LumenModule } from '@omnitron-dev/titan-lumen';
21
20
 
22
- const documents = new LumenService({
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
- Configure authentication on the host Netron before opening its listeners. Use the
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
- ```ts
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
- An unavailable database or missing migration is an error for enabled authoring,
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
- Editors first call `getEditableDocument('guides/start.pdx')`, then send its exact
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
- ```ts
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
- Paths include their `.pdx`, `.md` or `.mdx` extension and must be canonical relative
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
- ```ts
154
- import { HttpNativeServer } from '@omnitron-dev/titan/netron/transport/http';
155
- import { LumenMcpAdapter } from '@omnitron-dev/titan-lumen';
156
-
157
- let mcp: LumenMcpAdapter;
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
- The adapter publishes `search_corpus`, `get_document`, `lumen_inspect_ast` and
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.6",
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.6",
21
- "@omnitron-dev/lumen-ast": "0.4.6",
22
- "@omnitron-dev/titan-database": "0.4.6",
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.6",
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.6"
29
+ "@omnitron-dev/titan": "0.4.9"
30
30
  },
31
31
  "devDependencies": {
32
- "@omnitron-dev/testing": "0.4.6",
32
+ "@omnitron-dev/testing": "0.4.9",
33
33
  "better-sqlite3": "^13.0.3",
34
- "@omnitron-dev/titan": "0.4.6",
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": "3a912fa181e97ddd238a28bb355cd7445c1b7364",
49
+ "gitHead": "c6005ff1d0cde480cfa6b0bc346c9b53b2e638bf",
50
50
  "scripts": {
51
51
  "build": "../../scripts/build-package.sh -p ./tsconfig.json",
52
52
  "typecheck": "tsc --noEmit",