@tinyviber/a2h 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 (162) hide show
  1. package/README.md +229 -0
  2. package/bin/a2h.js +7 -0
  3. package/dist/actions/engine.d.ts +40 -0
  4. package/dist/actions/engine.d.ts.map +1 -0
  5. package/dist/actions/engine.js +227 -0
  6. package/dist/actions/engine.js.map +1 -0
  7. package/dist/actions/policy.d.ts +8 -0
  8. package/dist/actions/policy.d.ts.map +1 -0
  9. package/dist/actions/policy.js +55 -0
  10. package/dist/actions/policy.js.map +1 -0
  11. package/dist/cli/index.d.ts +2 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +258 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/init.d.ts +8 -0
  16. package/dist/cli/init.d.ts.map +1 -0
  17. package/dist/cli/init.js +69 -0
  18. package/dist/cli/init.js.map +1 -0
  19. package/dist/index.d.ts +26 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +66 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/ir/build.d.ts +8 -0
  24. package/dist/ir/build.d.ts.map +1 -0
  25. package/dist/ir/build.js +397 -0
  26. package/dist/ir/build.js.map +1 -0
  27. package/dist/ir/enrich.d.ts +21 -0
  28. package/dist/ir/enrich.d.ts.map +1 -0
  29. package/dist/ir/enrich.js +177 -0
  30. package/dist/ir/enrich.js.map +1 -0
  31. package/dist/ir/identity.d.ts +3 -0
  32. package/dist/ir/identity.d.ts.map +1 -0
  33. package/dist/ir/identity.js +91 -0
  34. package/dist/ir/identity.js.map +1 -0
  35. package/dist/ir/scoring.d.ts +7 -0
  36. package/dist/ir/scoring.d.ts.map +1 -0
  37. package/dist/ir/scoring.js +88 -0
  38. package/dist/ir/scoring.js.map +1 -0
  39. package/dist/parsers/code.d.ts +3 -0
  40. package/dist/parsers/code.d.ts.map +1 -0
  41. package/dist/parsers/code.js +17 -0
  42. package/dist/parsers/code.js.map +1 -0
  43. package/dist/parsers/diff.d.ts +11 -0
  44. package/dist/parsers/diff.d.ts.map +1 -0
  45. package/dist/parsers/diff.js +125 -0
  46. package/dist/parsers/diff.js.map +1 -0
  47. package/dist/parsers/json.d.ts +3 -0
  48. package/dist/parsers/json.d.ts.map +1 -0
  49. package/dist/parsers/json.js +16 -0
  50. package/dist/parsers/json.js.map +1 -0
  51. package/dist/parsers/log.d.ts +3 -0
  52. package/dist/parsers/log.d.ts.map +1 -0
  53. package/dist/parsers/log.js +105 -0
  54. package/dist/parsers/log.js.map +1 -0
  55. package/dist/parsers/markdown.d.ts +15 -0
  56. package/dist/parsers/markdown.d.ts.map +1 -0
  57. package/dist/parsers/markdown.js +89 -0
  58. package/dist/parsers/markdown.js.map +1 -0
  59. package/dist/parsers/text.d.ts +24 -0
  60. package/dist/parsers/text.d.ts.map +1 -0
  61. package/dist/parsers/text.js +98 -0
  62. package/dist/parsers/text.js.map +1 -0
  63. package/dist/presentation/blocks.d.ts +14 -0
  64. package/dist/presentation/blocks.d.ts.map +1 -0
  65. package/dist/presentation/blocks.js +87 -0
  66. package/dist/presentation/blocks.js.map +1 -0
  67. package/dist/presentation/present.d.ts +12 -0
  68. package/dist/presentation/present.d.ts.map +1 -0
  69. package/dist/presentation/present.js +115 -0
  70. package/dist/presentation/present.js.map +1 -0
  71. package/dist/providers/mock.d.ts +3 -0
  72. package/dist/providers/mock.d.ts.map +1 -0
  73. package/dist/providers/mock.js +171 -0
  74. package/dist/providers/mock.js.map +1 -0
  75. package/dist/providers/registry.d.ts +12 -0
  76. package/dist/providers/registry.d.ts.map +1 -0
  77. package/dist/providers/registry.js +20 -0
  78. package/dist/providers/registry.js.map +1 -0
  79. package/dist/providers/types.d.ts +64 -0
  80. package/dist/providers/types.d.ts.map +1 -0
  81. package/dist/providers/types.js +40 -0
  82. package/dist/providers/types.js.map +1 -0
  83. package/dist/renderer/assets/index.html +41 -0
  84. package/dist/renderer/assets/js/actions.js +205 -0
  85. package/dist/renderer/assets/js/api.js +75 -0
  86. package/dist/renderer/assets/js/artifacts.js +422 -0
  87. package/dist/renderer/assets/js/blocks.js +301 -0
  88. package/dist/renderer/assets/js/bus.js +21 -0
  89. package/dist/renderer/assets/js/cards.js +137 -0
  90. package/dist/renderer/assets/js/dom.js +61 -0
  91. package/dist/renderer/assets/js/format.js +118 -0
  92. package/dist/renderer/assets/js/main.js +125 -0
  93. package/dist/renderer/assets/js/nav.js +80 -0
  94. package/dist/renderer/assets/js/router.js +64 -0
  95. package/dist/renderer/assets/js/store.js +69 -0
  96. package/dist/renderer/assets/js/views.js +356 -0
  97. package/dist/renderer/assets/styles.css +856 -0
  98. package/dist/renderer/content.d.ts +11 -0
  99. package/dist/renderer/content.d.ts.map +1 -0
  100. package/dist/renderer/content.js +114 -0
  101. package/dist/renderer/content.js.map +1 -0
  102. package/dist/scanner/classify.d.ts +17 -0
  103. package/dist/scanner/classify.d.ts.map +1 -0
  104. package/dist/scanner/classify.js +117 -0
  105. package/dist/scanner/classify.js.map +1 -0
  106. package/dist/scanner/git.d.ts +3 -0
  107. package/dist/scanner/git.d.ts.map +1 -0
  108. package/dist/scanner/git.js +43 -0
  109. package/dist/scanner/git.js.map +1 -0
  110. package/dist/scanner/ignore.d.ts +22 -0
  111. package/dist/scanner/ignore.d.ts.map +1 -0
  112. package/dist/scanner/ignore.js +57 -0
  113. package/dist/scanner/ignore.js.map +1 -0
  114. package/dist/scanner/scan.d.ts +8 -0
  115. package/dist/scanner/scan.d.ts.map +1 -0
  116. package/dist/scanner/scan.js +108 -0
  117. package/dist/scanner/scan.js.map +1 -0
  118. package/dist/security/boundary.d.ts +19 -0
  119. package/dist/security/boundary.d.ts.map +1 -0
  120. package/dist/security/boundary.js +59 -0
  121. package/dist/security/boundary.js.map +1 -0
  122. package/dist/security/urlPolicy.d.ts +4 -0
  123. package/dist/security/urlPolicy.d.ts.map +1 -0
  124. package/dist/security/urlPolicy.js +56 -0
  125. package/dist/security/urlPolicy.js.map +1 -0
  126. package/dist/security/workspaceRead.d.ts +25 -0
  127. package/dist/security/workspaceRead.d.ts.map +1 -0
  128. package/dist/security/workspaceRead.js +103 -0
  129. package/dist/security/workspaceRead.js.map +1 -0
  130. package/dist/semantics/load.d.ts +11 -0
  131. package/dist/semantics/load.d.ts.map +1 -0
  132. package/dist/semantics/load.js +537 -0
  133. package/dist/semantics/load.js.map +1 -0
  134. package/dist/semantics/resolve.d.ts +37 -0
  135. package/dist/semantics/resolve.d.ts.map +1 -0
  136. package/dist/semantics/resolve.js +211 -0
  137. package/dist/semantics/resolve.js.map +1 -0
  138. package/dist/semantics/types.d.ts +158 -0
  139. package/dist/semantics/types.d.ts.map +1 -0
  140. package/dist/semantics/types.js +3 -0
  141. package/dist/semantics/types.js.map +1 -0
  142. package/dist/server/server.d.ts +17 -0
  143. package/dist/server/server.d.ts.map +1 -0
  144. package/dist/server/server.js +510 -0
  145. package/dist/server/server.js.map +1 -0
  146. package/dist/server/workspace.d.ts +53 -0
  147. package/dist/server/workspace.d.ts.map +1 -0
  148. package/dist/server/workspace.js +211 -0
  149. package/dist/server/workspace.js.map +1 -0
  150. package/dist/types.d.ts +570 -0
  151. package/dist/types.d.ts.map +1 -0
  152. package/dist/types.js +19 -0
  153. package/dist/types.js.map +1 -0
  154. package/dist/util/path.d.ts +11 -0
  155. package/dist/util/path.d.ts.map +1 -0
  156. package/dist/util/path.js +35 -0
  157. package/dist/util/path.js.map +1 -0
  158. package/dist/util/safeRead.d.ts +38 -0
  159. package/dist/util/safeRead.d.ts.map +1 -0
  160. package/dist/util/safeRead.js +117 -0
  161. package/dist/util/safeRead.js.map +1 -0
  162. package/package.json +40 -0
@@ -0,0 +1,510 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findAssetsDir = findAssetsDir;
4
+ exports.createA2hServer = createA2hServer;
5
+ const node_fs_1 = require("node:fs");
6
+ const node_crypto_1 = require("node:crypto");
7
+ const node_http_1 = require("node:http");
8
+ const node_path_1 = require("node:path");
9
+ const boundary_1 = require("../security/boundary");
10
+ const safeRead_1 = require("../util/safeRead");
11
+ // ---------------------------------------------------------------------------
12
+ // The local server.
13
+ //
14
+ // Security posture (this is a local-first tool, so the threat model is "the
15
+ // workspace content is untrusted, and so is every other page the human has
16
+ // open in a browser"):
17
+ //
18
+ // * The server binds to 127.0.0.1 by default.
19
+ // * Repository content is never executed. Markdown HTML is escaped, code is
20
+ // sent as text, and raw file serving is restricted to *inline-safe image
21
+ // types only* — so a `.html` or `.js` file in the workspace can never be
22
+ // served as an executable same-origin document.
23
+ // * Sensitive files and symlinks are never served as bytes.
24
+ // * Actions can only reference ids declared in the workspace manifest, and
25
+ // go through the ActionEngine's confirmation boundary.
26
+ //
27
+ // The last point is the one that grows teeth later. Today the executor is a
28
+ // mock, so the worst a forged request achieves is a simulated run in someone
29
+ // else's tab. The moment a real provider is registered behind `/api/action`,
30
+ // this endpoint *is* a local control API, and the browser is the delivery
31
+ // mechanism. So the mutation guard is built now, while it is still cheap:
32
+ //
33
+ // * Host must name this machine. A hostile page can point a name it controls
34
+ // at 127.0.0.1 (DNS rebinding) and the browser will happily treat us as
35
+ // same-origin; requiring the Host header to be local breaks that.
36
+ // * Content-Type must be application/json, which forces a cross-origin
37
+ // caller into a preflight we never answer.
38
+ // * A session token, minted per process and handed out only to the page we
39
+ // serve, must be presented. A cross-origin page cannot read it.
40
+ //
41
+ // Any one of the three is bypassable in isolation; together they are not.
42
+ // ---------------------------------------------------------------------------
43
+ /** Hostnames a request to this server may legitimately carry. */
44
+ const LOCAL_HOSTNAMES = new Set(['127.0.0.1', 'localhost', '::1']);
45
+ /** A bind address that means "listen everywhere" — the host check is skipped. */
46
+ const WILDCARD_HOSTS = new Set(['0.0.0.0', '::', '']);
47
+ const CONTENT_TYPES = {
48
+ '.html': 'text/html; charset=utf-8',
49
+ '.css': 'text/css; charset=utf-8',
50
+ '.js': 'text/javascript; charset=utf-8',
51
+ '.mjs': 'text/javascript; charset=utf-8',
52
+ '.json': 'application/json; charset=utf-8',
53
+ '.svg': 'image/svg+xml',
54
+ '.png': 'image/png',
55
+ '.jpg': 'image/jpeg',
56
+ '.jpeg': 'image/jpeg',
57
+ '.gif': 'image/gif',
58
+ '.webp': 'image/webp',
59
+ '.bmp': 'image/bmp',
60
+ '.ico': 'image/x-icon',
61
+ '.avif': 'image/avif',
62
+ '.tif': 'image/tiff',
63
+ '.tiff': 'image/tiff',
64
+ '.woff2': 'font/woff2',
65
+ '.map': 'application/json; charset=utf-8',
66
+ };
67
+ /**
68
+ * Types that may be served from a workspace path. Images are safe to inline:
69
+ * none of them can execute script in the document context. SVG is allowed but
70
+ * always carries a restrictive CSP. Everything else (html, js, css, svg-as-doc,
71
+ * json, and all binaries) is refused.
72
+ */
73
+ const INLINE_SAFE_EXTS = new Set([
74
+ '.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.ico', '.avif', '.tif', '.tiff', '.svg',
75
+ ]);
76
+ const ASSET_EXTS = new Set(['.html', '.css', '.js', '.mjs', '.svg', '.png', '.json', '.map', '.woff2']);
77
+ // Restrictive CSP: no external scripts/images/connections, no inline script.
78
+ const PAGE_CSP = "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; " +
79
+ "script-src 'self'; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'none'";
80
+ const SVG_CSP = "default-src 'none'; style-src 'unsafe-inline'";
81
+ const MAX_ACTION_BODY_BYTES = 64 * 1024;
82
+ /** How long the session token is, in bytes, before hex encoding. */
83
+ const TOKEN_BYTES = 24;
84
+ /** Methods that change something. Every one of them goes through the guard. */
85
+ const MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
86
+ function findAssetsDir() {
87
+ // Compiled layout: dist/server/server.js -> dist/renderer/assets
88
+ return (0, node_path_1.join)(__dirname, '..', 'renderer', 'assets');
89
+ }
90
+ function createA2hServer(options) {
91
+ const { workspace } = options;
92
+ const host = options.host ?? '127.0.0.1';
93
+ const assetsDir = (0, node_path_1.resolve)(options.assetsDir ?? findAssetsDir());
94
+ // Minted once per process. Not persisted: restarting the server invalidates
95
+ // every tab, which is the right trade for a token that only ever needs to
96
+ // outlive a browsing session.
97
+ const sessionToken = options.sessionToken ?? (0, node_crypto_1.randomBytes)(TOKEN_BYTES).toString('hex');
98
+ const hostCheckEnabled = !WILDCARD_HOSTS.has(host);
99
+ const shell = buildShell(assetsDir, sessionToken);
100
+ // SSE subscribers for watch mode and action results.
101
+ const subscribers = new Set();
102
+ function broadcast(event) {
103
+ for (const res of subscribers) {
104
+ try {
105
+ res.write(`data: ${event}\n\n`);
106
+ }
107
+ catch {
108
+ subscribers.delete(res);
109
+ }
110
+ }
111
+ }
112
+ const server = (0, node_http_1.createServer)((req, res) => {
113
+ void handle(req, res).catch(() => {
114
+ if (!res.headersSent)
115
+ sendJson(res, 500, { error: 'internal error' });
116
+ else
117
+ res.end();
118
+ });
119
+ });
120
+ async function handle(req, res) {
121
+ setBaseHeaders(res);
122
+ if (hostCheckEnabled && !isLocalHostname(req.headers.host, host)) {
123
+ sendJson(res, 403, { error: 'unexpected host' });
124
+ return;
125
+ }
126
+ const url = new URL(req.url ?? '/', 'http://localhost');
127
+ const pathname = url.pathname;
128
+ if (pathname.startsWith('/api/')) {
129
+ await handleApi(req, res, pathname, url);
130
+ return;
131
+ }
132
+ serveStatic(res, assetsDir, pathname, shell);
133
+ }
134
+ async function handleApi(req, res, pathname, url) {
135
+ const method = req.method ?? 'GET';
136
+ // One guard, applied to every mutating request that will ever exist here,
137
+ // rather than a check bolted onto `/api/action` that the next endpoint
138
+ // forgets to copy.
139
+ if (MUTATING_METHODS.has(method)) {
140
+ const refusal = guardMutation(req, hostCheckEnabled ? host : undefined);
141
+ if (refusal) {
142
+ sendJson(res, refusal.status, { error: refusal.error });
143
+ return;
144
+ }
145
+ }
146
+ // Canonical name for the view payload. `/api/ir` is kept as an alias: it
147
+ // was the original spelling, and the body is a presentation, not the IR.
148
+ if (method === 'GET' && (pathname === '/api/presentation' || pathname === '/api/ir')) {
149
+ sendJson(res, 200, workspace.presentation);
150
+ return;
151
+ }
152
+ if (method === 'GET' && pathname === '/api/artifact') {
153
+ const rel = url.searchParams.get('path') ?? '';
154
+ const mode = url.searchParams.get('mode') === 'full' ? 'full' : 'tail';
155
+ const payload = workspace.renderPayload(rel, mode);
156
+ if (!payload) {
157
+ sendJson(res, 404, { error: 'artifact not found' });
158
+ return;
159
+ }
160
+ sendJson(res, 200, payload);
161
+ return;
162
+ }
163
+ if (method === 'GET' && pathname === '/api/file') {
164
+ serveFile(res, workspace, url.searchParams.get('path') ?? '');
165
+ return;
166
+ }
167
+ if (pathname === '/api/action') {
168
+ await handleAction(req, res);
169
+ return;
170
+ }
171
+ // Same-origin only, and `no-store` — this is the one response that must
172
+ // never end up in a shared cache.
173
+ if (method === 'GET' && pathname === '/api/session') {
174
+ res.setHeader('Cache-Control', 'no-store');
175
+ sendJson(res, 200, { token: sessionToken });
176
+ return;
177
+ }
178
+ if (method === 'GET' && pathname === '/api/events') {
179
+ subscribeSse(req, res, subscribers);
180
+ return;
181
+ }
182
+ if (method === 'GET' && pathname === '/api/health') {
183
+ sendJson(res, 200, {
184
+ ok: true,
185
+ version: workspace.version,
186
+ semantics: workspace.presentation.semantics,
187
+ simulatedActions: workspace.presentation.simulatedActions,
188
+ providers: workspace.registry.executors.map((e) => e.id),
189
+ tasks: workspace.presentation.tasks.length,
190
+ artifacts: workspace.presentation.stats.artifacts,
191
+ secured: hostCheckEnabled,
192
+ });
193
+ return;
194
+ }
195
+ sendJson(res, 404, { error: 'unknown endpoint' });
196
+ }
197
+ /**
198
+ * The mutation guard. Returns a refusal, or undefined to proceed.
199
+ *
200
+ * The token comparison is constant-time; the length pre-check exists because
201
+ * `timingSafeEqual` throws on a length mismatch rather than returning false.
202
+ */
203
+ function guardMutation(req, bindingHost) {
204
+ if (bindingHost && !isLocalOrigin(req.headers.origin, bindingHost)) {
205
+ return { status: 403, error: 'cross-origin request refused' };
206
+ }
207
+ const contentType = String(req.headers['content-type'] ?? '').toLowerCase();
208
+ if (!contentType.startsWith('application/json')) {
209
+ return { status: 415, error: 'content-type must be application/json' };
210
+ }
211
+ const supplied = req.headers['x-a2h-token'];
212
+ if (typeof supplied !== 'string' || supplied.length !== sessionToken.length) {
213
+ return { status: 403, error: 'missing or invalid session token' };
214
+ }
215
+ if (!(0, node_crypto_1.timingSafeEqual)(Buffer.from(supplied), Buffer.from(sessionToken))) {
216
+ return { status: 403, error: 'missing or invalid session token' };
217
+ }
218
+ return undefined;
219
+ }
220
+ async function handleAction(req, res) {
221
+ if (req.method !== 'POST') {
222
+ res.setHeader('Allow', 'POST');
223
+ sendJson(res, 405, { error: 'method not allowed' });
224
+ return;
225
+ }
226
+ let body;
227
+ try {
228
+ body = await readBody(req, MAX_ACTION_BODY_BYTES);
229
+ }
230
+ catch (err) {
231
+ sendJson(res, 413, { error: err.message });
232
+ return;
233
+ }
234
+ let parsed;
235
+ try {
236
+ parsed = JSON.parse(body || '{}');
237
+ }
238
+ catch {
239
+ sendJson(res, 400, { error: 'body must be JSON' });
240
+ return;
241
+ }
242
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
243
+ sendJson(res, 400, { error: 'body must be a JSON object' });
244
+ return;
245
+ }
246
+ const record = parsed;
247
+ const id = typeof record.id === 'string' ? record.id : '';
248
+ if (!id) {
249
+ sendJson(res, 400, { error: 'missing action id' });
250
+ return;
251
+ }
252
+ const result = await workspace.engine.execute({
253
+ id,
254
+ params: typeof record.params === 'object' && record.params !== null && !Array.isArray(record.params)
255
+ ? record.params
256
+ : undefined,
257
+ confirm: record.confirm === true,
258
+ }, workspace.declaredActions());
259
+ if (result.ok) {
260
+ broadcast('action');
261
+ sendJson(res, 200, result);
262
+ return;
263
+ }
264
+ const status = result.error === 'unknown_action' ? 404
265
+ : result.error === 'confirmation_required' ? 409
266
+ : result.error === 'missing_params' ? 400
267
+ : 400;
268
+ sendJson(res, status, result);
269
+ }
270
+ return { server, broadcast, host };
271
+ }
272
+ // ---------------------------------------------------------------------------
273
+ // Helpers
274
+ // ---------------------------------------------------------------------------
275
+ function setBaseHeaders(res) {
276
+ res.setHeader('X-Content-Type-Options', 'nosniff');
277
+ res.setHeader('Referrer-Policy', 'no-referrer');
278
+ res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
279
+ }
280
+ /**
281
+ * Extracts a hostname from either a `Host` header (`127.0.0.1:5173`) or an
282
+ * `Origin` header (`http://127.0.0.1:5173`). Brackets around an IPv6 literal
283
+ * are stripped so `[::1]` and `::1` compare equal.
284
+ */
285
+ function hostnameOf(value) {
286
+ if (!value)
287
+ return undefined;
288
+ try {
289
+ const parsed = new URL(value.includes('://') ? value : `http://${value}`);
290
+ return parsed.hostname.toLowerCase().replace(/^\[|\]$/g, '');
291
+ }
292
+ catch {
293
+ return undefined;
294
+ }
295
+ }
296
+ /**
297
+ * Whether a `Host` header names this machine.
298
+ *
299
+ * A missing Host is allowed rather than refused: HTTP/1.0 clients and
300
+ * non-browser tooling do not send one, and the token — not this check — is
301
+ * what actually authorises a mutation.
302
+ */
303
+ function isLocalHostname(hostHeader, bindingHost) {
304
+ const name = hostnameOf(hostHeader);
305
+ if (name === undefined)
306
+ return true;
307
+ return LOCAL_HOSTNAMES.has(name) || name === bindingHost.toLowerCase();
308
+ }
309
+ /**
310
+ * Whether an `Origin` header names this machine. A missing Origin means the
311
+ * request did not come from a browser page, so there is no cross-origin
312
+ * confusion to prevent; `"null"` (sandboxed iframes, some redirects) is not
313
+ * local and is refused.
314
+ */
315
+ function isLocalOrigin(origin, bindingHost) {
316
+ if (origin === undefined || origin === '')
317
+ return true;
318
+ const name = hostnameOf(origin);
319
+ if (name === undefined)
320
+ return false;
321
+ return LOCAL_HOSTNAMES.has(name) || name === bindingHost.toLowerCase();
322
+ }
323
+ function sendJson(res, status, body) {
324
+ const json = JSON.stringify(body);
325
+ res.statusCode = status;
326
+ res.setHeader('Content-Type', 'application/json; charset=utf-8');
327
+ res.setHeader('Cache-Control', 'no-store');
328
+ res.setHeader('Content-Length', Buffer.byteLength(json));
329
+ res.end(json);
330
+ }
331
+ function readBody(req, maxBytes) {
332
+ return new Promise((resolvePromise, reject) => {
333
+ const chunks = [];
334
+ let size = 0;
335
+ req.on('data', (chunk) => {
336
+ size += chunk.length;
337
+ if (size > maxBytes) {
338
+ reject(new Error('request body too large'));
339
+ req.destroy();
340
+ return;
341
+ }
342
+ chunks.push(chunk);
343
+ });
344
+ req.on('end', () => resolvePromise(Buffer.concat(chunks).toString('utf8')));
345
+ req.on('error', (err) => reject(err));
346
+ });
347
+ }
348
+ /**
349
+ * Serves raw bytes for a workspace file, subject to a strict allowlist. Only
350
+ * files the scanner knows about, that are not sensitive and not symlinks, and
351
+ * whose type cannot execute in the document context, are served.
352
+ */
353
+ function serveFile(res, workspace, rel) {
354
+ if (!rel) {
355
+ sendJson(res, 400, { error: 'missing path' });
356
+ return;
357
+ }
358
+ // The scanner's view of the workspace is the allowlist.
359
+ const entry = workspace.getFile(rel);
360
+ if (!entry) {
361
+ sendJson(res, 404, { error: 'not found' });
362
+ return;
363
+ }
364
+ if (entry.sensitive) {
365
+ sendJson(res, 403, { error: 'sensitive file' });
366
+ return;
367
+ }
368
+ if (entry.isSymlink) {
369
+ sendJson(res, 403, { error: 'symlink not served' });
370
+ return;
371
+ }
372
+ const ext = (0, node_path_1.extname)(rel).toLowerCase();
373
+ if (!INLINE_SAFE_EXTS.has(ext)) {
374
+ sendJson(res, 403, { error: `type ${ext || '(none)'} is not served inline` });
375
+ return;
376
+ }
377
+ // Re-validate containment on the real path (defence in depth).
378
+ const real = (0, boundary_1.resolveRealPath)(workspace.rootDir, rel);
379
+ if (real === null) {
380
+ sendJson(res, 404, { error: 'not found' });
381
+ return;
382
+ }
383
+ // Opened the same way as every other read in A2H, then handed to the stream
384
+ // as a descriptor: the bytes come from the file we checked, not from
385
+ // whatever the path resolves to a moment later.
386
+ let fd;
387
+ try {
388
+ fd = (0, safeRead_1.openNoFollow)(real);
389
+ }
390
+ catch {
391
+ sendJson(res, 404, { error: 'not found' });
392
+ return;
393
+ }
394
+ let size;
395
+ try {
396
+ size = (0, node_fs_1.fstatSync)(fd).size;
397
+ }
398
+ catch {
399
+ (0, node_fs_1.closeSync)(fd);
400
+ sendJson(res, 404, { error: 'not found' });
401
+ return;
402
+ }
403
+ res.statusCode = 200;
404
+ res.setHeader('Content-Type', CONTENT_TYPES[ext] ?? 'application/octet-stream');
405
+ res.setHeader('Content-Length', size);
406
+ res.setHeader('Content-Disposition', 'inline');
407
+ if (ext === '.svg')
408
+ res.setHeader('Content-Security-Policy', SVG_CSP);
409
+ const stream = (0, node_fs_1.createReadStream)(real, { fd });
410
+ stream.on('error', () => {
411
+ if (!res.headersSent) {
412
+ res.statusCode = 500;
413
+ res.end();
414
+ }
415
+ else {
416
+ res.end();
417
+ }
418
+ });
419
+ stream.pipe(res);
420
+ }
421
+ function subscribeSse(req, res, subscribers) {
422
+ res.statusCode = 200;
423
+ res.setHeader('Content-Type', 'text/event-stream');
424
+ res.setHeader('Cache-Control', 'no-cache, no-transform');
425
+ res.setHeader('Connection', 'keep-alive');
426
+ res.write('retry: 1000\n\n');
427
+ subscribers.add(res);
428
+ req.on('close', () => subscribers.delete(res));
429
+ }
430
+ /**
431
+ * Static assets for the viewer itself. Only known asset extensions are served,
432
+ * and the resolved path must stay inside the assets directory, so a crafted
433
+ * URL cannot read anything else on disk.
434
+ *
435
+ * `shell` is index.html with the session token injected; it is served in place
436
+ * of the file on disk so the token never has to be written anywhere.
437
+ */
438
+ function serveStatic(res, assetsDir, pathname, shell) {
439
+ let rel = pathname === '/' ? '/index.html' : pathname;
440
+ rel = rel.replace(/\/+/g, '/');
441
+ const ext = (0, node_path_1.extname)(rel).toLowerCase();
442
+ if (ASSET_EXTS.has(ext)) {
443
+ const candidate = (0, node_path_1.resolve)(assetsDir, `.${rel}`);
444
+ if ((0, boundary_1.isWithin)(assetsDir, candidate) && (0, node_fs_1.existsSync)(candidate)) {
445
+ let isFile = false;
446
+ try {
447
+ isFile = (0, node_fs_1.statSync)(candidate).isFile();
448
+ }
449
+ catch {
450
+ isFile = false;
451
+ }
452
+ if (isFile) {
453
+ if (rel === '/index.html' && shell) {
454
+ sendShell(res, shell);
455
+ return;
456
+ }
457
+ res.statusCode = 200;
458
+ res.setHeader('Content-Type', CONTENT_TYPES[ext] ?? 'application/octet-stream');
459
+ if (rel === '/index.html')
460
+ res.setHeader('Content-Security-Policy', PAGE_CSP);
461
+ const stream = (0, node_fs_1.createReadStream)(candidate);
462
+ stream.on('error', () => res.end());
463
+ stream.pipe(res);
464
+ return;
465
+ }
466
+ }
467
+ }
468
+ // SPA fallback: unknown paths get the shell so client-side routes work.
469
+ if (shell) {
470
+ sendShell(res, shell);
471
+ return;
472
+ }
473
+ res.statusCode = 404;
474
+ res.end('a2h renderer assets missing — run the build first');
475
+ }
476
+ function sendShell(res, shell) {
477
+ res.statusCode = 200;
478
+ res.setHeader('Content-Type', CONTENT_TYPES['.html']);
479
+ res.setHeader('Content-Security-Policy', PAGE_CSP);
480
+ // The document carries a per-process token; caching it would hand a stale
481
+ // one to the next tab.
482
+ res.setHeader('Cache-Control', 'no-store');
483
+ res.setHeader('Content-Length', shell.length);
484
+ res.end(shell);
485
+ }
486
+ const TOKEN_META = /<meta\s+name="a2h-token"\s+content="[^"]*"\s*\/?>/i;
487
+ /**
488
+ * index.html with this process's session token in it.
489
+ *
490
+ * The page needs the token to mutate anything, and the only source of truth
491
+ * for it is this process. Injecting at serve time keeps the token out of the
492
+ * build output, out of git, and out of any on-disk copy of the shell.
493
+ */
494
+ function buildShell(assetsDir, token) {
495
+ const file = (0, node_path_1.join)(assetsDir, 'index.html');
496
+ if (!(0, node_fs_1.existsSync)(file))
497
+ return undefined;
498
+ try {
499
+ const html = (0, node_fs_1.readFileSync)(file, 'utf8');
500
+ const meta = `<meta name="a2h-token" content="${token}" />`;
501
+ const withToken = TOKEN_META.test(html)
502
+ ? html.replace(TOKEN_META, meta)
503
+ : html.replace(/<\/head>/i, ` ${meta}\n</head>`);
504
+ return Buffer.from(withToken, 'utf8');
505
+ }
506
+ catch {
507
+ return undefined;
508
+ }
509
+ }
510
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { ArtifactPayload, ArtifactView, FileEntry, Presentation, SemanticIR } from '../types';
2
+ import { scanWorkspace } from '../scanner/scan';
3
+ import { type ResolvedSemantics } from '../semantics/resolve';
4
+ import { ActionEngine } from '../actions/engine';
5
+ import type { ProviderRegistry } from '../providers/types';
6
+ export interface WorkspaceOptions {
7
+ rootDir: string;
8
+ registry?: ProviderRegistry;
9
+ now?: () => Date;
10
+ }
11
+ export declare class Workspace {
12
+ rootDir: string;
13
+ scan: ReturnType<typeof scanWorkspace>;
14
+ semantics: ResolvedSemantics;
15
+ ir: SemanticIR;
16
+ readonly engine: ActionEngine;
17
+ readonly registry: ProviderRegistry;
18
+ /** What is on disk, before any action the human took this session. */
19
+ private base;
20
+ private filesByPath;
21
+ private viewsByPath;
22
+ private nodesByPath;
23
+ private knownImages;
24
+ /**
25
+ * The single route from a producer-authored path to bytes. Rebuilt on every
26
+ * scan, so it always describes the tree we last looked at.
27
+ */
28
+ private reader;
29
+ /** Incremented on every (re)scan; used as the change signal for watch. */
30
+ version: number;
31
+ /**
32
+ * The presentation the UI sees: disk-derived structure with this session's
33
+ * action state (run records, task status, audit trail) overlaid. Computed on
34
+ * read so an action result is visible without a rescan.
35
+ */
36
+ get presentation(): Presentation;
37
+ constructor(options: WorkspaceOptions | string);
38
+ rescan(): void;
39
+ fileUrl(relPath: string): string;
40
+ getFile(path: string): FileEntry | undefined;
41
+ getView(path: string): ArtifactView | undefined;
42
+ /** The action registry as published to the client (the execution allowlist). */
43
+ declaredActions(): import("../types").ActionView[];
44
+ renderPayload(path: string, mode?: 'tail' | 'full'): ArtifactPayload | undefined;
45
+ private blockContext;
46
+ private rebuild;
47
+ /**
48
+ * Overlays state produced by executed actions on top of the disk-derived
49
+ * presentation: new runs, task status changes, and the session audit trail.
50
+ */
51
+ private applyRuntimeState;
52
+ }
53
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/server/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EAEZ,SAAS,EACT,YAAY,EACZ,UAAU,EAEX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMhD,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAU3D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,qBAAa,SAAS;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;IACvC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,EAAE,EAAE,UAAU,CAAC;IACf,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAEpC,sEAAsE;IACtE,OAAO,CAAC,IAAI,CAAe;IAE3B,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,WAAW,CAAwC;IAC3D,OAAO,CAAC,WAAW,CAAwC;IAC3D,OAAO,CAAC,WAAW,CAA0B;IAE7C;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAkB;IAEhC,0EAA0E;IAC1E,OAAO,SAAK;IAEZ;;;;OAIG;IACH,IAAI,YAAY,IAAI,YAAY,CAE/B;gBAEW,OAAO,EAAE,gBAAgB,GAAG,MAAM;IAoD9C,MAAM,IAAI,IAAI;IAKd,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIhC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI5C,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI/C,gFAAgF;IAChF,eAAe;IAIf,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,eAAe,GAAG,SAAS;IAiChF,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,OAAO;IA8Cf;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAwB1B"}