@yadsh/dsh-qa-surface 0.6.0 → 0.7.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 (292) hide show
  1. package/README.md +148 -9
  2. package/capability-policy.json +1 -1
  3. package/cordis.patch.yml +2 -1
  4. package/lib/access/capability-catalog.js +144 -0
  5. package/lib/access/capability-catalog.js.map +1 -0
  6. package/lib/access/model.js +379 -0
  7. package/lib/access/model.js.map +1 -0
  8. package/lib/access/role-repository.js +195 -0
  9. package/lib/access/role-repository.js.map +1 -0
  10. package/lib/access/service.js +380 -0
  11. package/lib/access/service.js.map +1 -0
  12. package/lib/access/skill-metadata.js +234 -0
  13. package/lib/access/skill-metadata.js.map +1 -0
  14. package/lib/account-remotes.js +20 -10
  15. package/lib/account-remotes.js.map +1 -1
  16. package/lib/accounts/errors.js.map +1 -1
  17. package/lib/accounts/file.js.map +1 -1
  18. package/lib/accounts/store.js +202 -3
  19. package/lib/accounts/store.js.map +1 -1
  20. package/lib/admin/conversation-log.js +256 -0
  21. package/lib/admin/conversation-log.js.map +1 -0
  22. package/lib/admin/index.js +17 -0
  23. package/lib/admin/index.js.map +1 -0
  24. package/lib/admin/metrics.js +103 -0
  25. package/lib/admin/metrics.js.map +1 -0
  26. package/lib/admin/paging.js +23 -0
  27. package/lib/admin/paging.js.map +1 -0
  28. package/lib/admin/permissions.js +50 -0
  29. package/lib/admin/permissions.js.map +1 -0
  30. package/lib/admin/quality-store.js +485 -0
  31. package/lib/admin/quality-store.js.map +1 -0
  32. package/lib/admin/queue.js +107 -0
  33. package/lib/admin/queue.js.map +1 -0
  34. package/lib/admin/redaction.js +45 -0
  35. package/lib/admin/redaction.js.map +1 -0
  36. package/lib/admin/service.js +897 -0
  37. package/lib/admin/service.js.map +1 -0
  38. package/lib/admin/session-log.js +142 -0
  39. package/lib/admin/session-log.js.map +1 -0
  40. package/lib/attestation.js +6 -0
  41. package/lib/attestation.js.map +1 -1
  42. package/lib/cli.js +9 -6
  43. package/lib/cli.js.map +1 -1
  44. package/lib/client/QaSessionController.js +65 -15
  45. package/lib/client/QaSessionController.js.map +1 -1
  46. package/lib/client/QaSurface.js +144 -6
  47. package/lib/client/QaSurface.js.map +1 -1
  48. package/lib/client/QaTranscriptAdapter.js +1 -0
  49. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  50. package/lib/client/admin/QaAdmin.js +458 -0
  51. package/lib/client/admin/QaAdmin.js.map +1 -0
  52. package/lib/client/admin/format.js +177 -0
  53. package/lib/client/admin/format.js.map +1 -0
  54. package/lib/client/admin/pages/Conversations.js +114 -0
  55. package/lib/client/admin/pages/Conversations.js.map +1 -0
  56. package/lib/client/admin/pages/Overview.js +24 -0
  57. package/lib/client/admin/pages/Overview.js.map +1 -0
  58. package/lib/client/admin/pages/Quality.js +71 -0
  59. package/lib/client/admin/pages/Quality.js.map +1 -0
  60. package/lib/client/admin/pages/Review.js +93 -0
  61. package/lib/client/admin/pages/Review.js.map +1 -0
  62. package/lib/client/admin/pages/Users.js +95 -0
  63. package/lib/client/admin/pages/Users.js.map +1 -0
  64. package/lib/client/admin/routes.js +127 -0
  65. package/lib/client/admin/routes.js.map +1 -0
  66. package/lib/client/admin/shared.js +91 -0
  67. package/lib/client/admin/shared.js.map +1 -0
  68. package/lib/client/admin/styles.js +111 -0
  69. package/lib/client/admin/styles.js.map +1 -0
  70. package/lib/client/attestation.js +14 -2
  71. package/lib/client/attestation.js.map +1 -1
  72. package/lib/client/components/QaChangelog.js +48 -0
  73. package/lib/client/components/QaChangelog.js.map +1 -1
  74. package/lib/client/components/QaHeader.js +3 -3
  75. package/lib/client/components/QaHeader.js.map +1 -1
  76. package/lib/client/components/QaMessage.js +61 -2
  77. package/lib/client/components/QaMessage.js.map +1 -1
  78. package/lib/client/create-session.js +1 -1
  79. package/lib/client/create-session.js.map +1 -1
  80. package/lib/client/index.js +33 -1
  81. package/lib/client/index.js.map +1 -1
  82. package/lib/client/project-session-state.js +10 -5
  83. package/lib/client/project-session-state.js.map +1 -1
  84. package/lib/client/role/RoleSelector.js +31 -0
  85. package/lib/client/role/RoleSelector.js.map +1 -0
  86. package/lib/client/session-sources.js +37 -1
  87. package/lib/client/session-sources.js.map +1 -1
  88. package/lib/client/settings/card.js +2 -2
  89. package/lib/client/settings/card.js.map +1 -1
  90. package/lib/client/settings/sections.js +0 -1
  91. package/lib/client/settings/sections.js.map +1 -1
  92. package/lib/client/styles.js +32 -0
  93. package/lib/client/styles.js.map +1 -1
  94. package/lib/client/types.js +1 -0
  95. package/lib/client/types.js.map +1 -1
  96. package/lib/client.js +10786 -5684
  97. package/lib/client.js.map +1 -1
  98. package/lib/config-resolvers/defaults.js +0 -2
  99. package/lib/config-resolvers/defaults.js.map +1 -1
  100. package/lib/config.js +0 -249
  101. package/lib/config.js.map +1 -1
  102. package/lib/enforcement/skill-policy.js +172 -0
  103. package/lib/enforcement/skill-policy.js.map +1 -0
  104. package/lib/enforcement/tool-grants.js +151 -0
  105. package/lib/enforcement/tool-grants.js.map +1 -0
  106. package/lib/index.js +230 -44
  107. package/lib/index.js.map +1 -1
  108. package/lib/personal-skills/service.js +10 -3
  109. package/lib/personal-skills/service.js.map +1 -1
  110. package/lib/qa-tools/index.js +4 -0
  111. package/lib/qa-tools/index.js.map +1 -1
  112. package/lib/resolve-config.js +0 -2
  113. package/lib/resolve-config.js.map +1 -1
  114. package/lib/secure-session.js +111 -32
  115. package/lib/secure-session.js.map +1 -1
  116. package/lib/typert.host.js +2237 -202
  117. package/lib/typert.remote-client.d.ts +49 -3
  118. package/lib/typert.remote-client.js +1863 -183
  119. package/lib/types/access/capability-catalog.d.ts +37 -0
  120. package/lib/types/access/model.d.ts +60 -0
  121. package/lib/types/access/role-repository.d.ts +32 -0
  122. package/lib/types/access/service.d.ts +57 -0
  123. package/lib/types/access/skill-metadata.d.ts +53 -0
  124. package/lib/types/account-remotes.d.ts +6 -0
  125. package/lib/types/accounts/errors.d.ts +1 -1
  126. package/lib/types/accounts/file.d.ts +16 -5
  127. package/lib/types/accounts/store.d.ts +83 -3
  128. package/lib/types/admin/conversation-log.d.ts +39 -0
  129. package/lib/types/admin/index.d.ts +24 -0
  130. package/lib/types/admin/metrics.d.ts +29 -0
  131. package/lib/types/admin/paging.d.ts +33 -0
  132. package/lib/types/admin/permissions.d.ts +10 -0
  133. package/lib/types/admin/quality-store.d.ts +82 -0
  134. package/lib/types/admin/queue.d.ts +21 -0
  135. package/lib/types/admin/redaction.d.ts +29 -0
  136. package/lib/types/admin/service.d.ts +105 -0
  137. package/lib/types/admin/session-log.d.ts +53 -0
  138. package/lib/types/attestation.d.ts +2 -0
  139. package/lib/types/client/QaSessionController.d.ts +14 -1
  140. package/lib/types/client/QaSurface.d.ts +7 -1
  141. package/lib/types/client/admin/QaAdmin.d.ts +17 -0
  142. package/lib/types/client/admin/format.d.ts +43 -0
  143. package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
  144. package/lib/types/client/admin/pages/Overview.d.ts +13 -0
  145. package/lib/types/client/admin/pages/Quality.d.ts +18 -0
  146. package/lib/types/client/admin/pages/Review.d.ts +15 -0
  147. package/lib/types/client/admin/pages/Users.d.ts +22 -0
  148. package/lib/types/client/admin/routes.d.ts +50 -0
  149. package/lib/types/client/admin/shared.d.ts +53 -0
  150. package/lib/types/client/admin/styles.d.ts +11 -0
  151. package/lib/types/client/attestation.d.ts +8 -1
  152. package/lib/types/client/components/QaHeader.d.ts +5 -1
  153. package/lib/types/client/components/QaMessage.d.ts +14 -1
  154. package/lib/types/client/create-session.d.ts +2 -0
  155. package/lib/types/client/project-session-state.d.ts +2 -0
  156. package/lib/types/client/role/RoleSelector.d.ts +14 -0
  157. package/lib/types/client/session-sources.d.ts +9 -0
  158. package/lib/types/client/settings/sections.d.ts +0 -1
  159. package/lib/types/client/types.d.ts +39 -2
  160. package/lib/types/enforcement/skill-policy.d.ts +29 -0
  161. package/lib/types/enforcement/tool-grants.d.ts +84 -0
  162. package/lib/types/index.d.ts +62 -14
  163. package/lib/types/qa-tools/index.d.ts +2 -0
  164. package/lib/types/secure-session.d.ts +19 -1
  165. package/lib/types/types.d.ts +574 -5
  166. package/package.json +3 -3
  167. package/lib/client/settings/sections/documents.js +0 -88
  168. package/lib/client/settings/sections/documents.js.map +0 -1
  169. package/lib/documents/artifacts/ids.js +0 -43
  170. package/lib/documents/artifacts/ids.js.map +0 -1
  171. package/lib/documents/artifacts/manifest.js +0 -66
  172. package/lib/documents/artifacts/manifest.js.map +0 -1
  173. package/lib/documents/artifacts/store.js +0 -169
  174. package/lib/documents/artifacts/store.js.map +0 -1
  175. package/lib/documents/capabilities.js +0 -93
  176. package/lib/documents/capabilities.js.map +0 -1
  177. package/lib/documents/config.js +0 -302
  178. package/lib/documents/config.js.map +0 -1
  179. package/lib/documents/defaults.js +0 -78
  180. package/lib/documents/defaults.js.map +0 -1
  181. package/lib/documents/errors.js +0 -101
  182. package/lib/documents/errors.js.map +0 -1
  183. package/lib/documents/index.js +0 -80
  184. package/lib/documents/index.js.map +0 -1
  185. package/lib/documents/inspect/facts.js +0 -161
  186. package/lib/documents/inspect/facts.js.map +0 -1
  187. package/lib/documents/inspect/zip.js +0 -108
  188. package/lib/documents/inspect/zip.js.map +0 -1
  189. package/lib/documents/markdown/directives.js +0 -135
  190. package/lib/documents/markdown/directives.js.map +0 -1
  191. package/lib/documents/markdown/frontmatter.js +0 -35
  192. package/lib/documents/markdown/frontmatter.js.map +0 -1
  193. package/lib/documents/markdown/normalize.js +0 -113
  194. package/lib/documents/markdown/normalize.js.map +0 -1
  195. package/lib/documents/orchestrator/assets.js +0 -243
  196. package/lib/documents/orchestrator/assets.js.map +0 -1
  197. package/lib/documents/orchestrator/convert-document.js +0 -186
  198. package/lib/documents/orchestrator/convert-document.js.map +0 -1
  199. package/lib/documents/orchestrator/create-document.js +0 -292
  200. package/lib/documents/orchestrator/create-document.js.map +0 -1
  201. package/lib/documents/orchestrator/extract-document.js +0 -162
  202. package/lib/documents/orchestrator/extract-document.js.map +0 -1
  203. package/lib/documents/orchestrator/inspect-document.js +0 -89
  204. package/lib/documents/orchestrator/inspect-document.js.map +0 -1
  205. package/lib/documents/orchestrator/runtime-deps.js +0 -59
  206. package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
  207. package/lib/documents/orchestrator/scope.js +0 -132
  208. package/lib/documents/orchestrator/scope.js.map +0 -1
  209. package/lib/documents/providers/docling.js +0 -247
  210. package/lib/documents/providers/docling.js.map +0 -1
  211. package/lib/documents/providers/libreoffice.js +0 -130
  212. package/lib/documents/providers/libreoffice.js.map +0 -1
  213. package/lib/documents/providers/markitdown.js +0 -89
  214. package/lib/documents/providers/markitdown.js.map +0 -1
  215. package/lib/documents/providers/pandoc.js +0 -161
  216. package/lib/documents/providers/pandoc.js.map +0 -1
  217. package/lib/documents/providers/process.js +0 -164
  218. package/lib/documents/providers/process.js.map +0 -1
  219. package/lib/documents/providers/registry.js +0 -152
  220. package/lib/documents/providers/registry.js.map +0 -1
  221. package/lib/documents/providers/shared.js +0 -75
  222. package/lib/documents/providers/shared.js.map +0 -1
  223. package/lib/documents/runtime.js +0 -114
  224. package/lib/documents/runtime.js.map +0 -1
  225. package/lib/documents/security/file-types.js +0 -188
  226. package/lib/documents/security/file-types.js.map +0 -1
  227. package/lib/documents/security/limits.js +0 -78
  228. package/lib/documents/security/limits.js.map +0 -1
  229. package/lib/documents/security/mime.js +0 -43
  230. package/lib/documents/security/mime.js.map +0 -1
  231. package/lib/documents/security/paths.js +0 -133
  232. package/lib/documents/security/paths.js.map +0 -1
  233. package/lib/documents/templates/registry.js +0 -147
  234. package/lib/documents/templates/registry.js.map +0 -1
  235. package/lib/documents/templates/resolver.js +0 -59
  236. package/lib/documents/templates/resolver.js.map +0 -1
  237. package/lib/documents/tools/convert.js +0 -125
  238. package/lib/documents/tools/convert.js.map +0 -1
  239. package/lib/documents/tools/create.js +0 -187
  240. package/lib/documents/tools/create.js.map +0 -1
  241. package/lib/documents/tools/index.js +0 -41
  242. package/lib/documents/tools/index.js.map +0 -1
  243. package/lib/documents/tools/inspect.js +0 -135
  244. package/lib/documents/tools/inspect.js.map +0 -1
  245. package/lib/documents/tools/shared.js +0 -88
  246. package/lib/documents/tools/shared.js.map +0 -1
  247. package/lib/documents/tools/to-markdown.js +0 -125
  248. package/lib/documents/tools/to-markdown.js.map +0 -1
  249. package/lib/documents/types.js +0 -12
  250. package/lib/documents/types.js.map +0 -1
  251. package/lib/types/client/settings/sections/documents.d.ts +0 -13
  252. package/lib/types/documents/artifacts/ids.d.ts +0 -14
  253. package/lib/types/documents/artifacts/manifest.d.ts +0 -32
  254. package/lib/types/documents/artifacts/store.d.ts +0 -67
  255. package/lib/types/documents/capabilities.d.ts +0 -32
  256. package/lib/types/documents/config.d.ts +0 -27
  257. package/lib/types/documents/defaults.d.ts +0 -161
  258. package/lib/types/documents/errors.d.ts +0 -42
  259. package/lib/types/documents/index.d.ts +0 -63
  260. package/lib/types/documents/inspect/facts.d.ts +0 -43
  261. package/lib/types/documents/inspect/zip.d.ts +0 -28
  262. package/lib/types/documents/markdown/directives.d.ts +0 -39
  263. package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
  264. package/lib/types/documents/markdown/normalize.d.ts +0 -30
  265. package/lib/types/documents/orchestrator/assets.d.ts +0 -55
  266. package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
  267. package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
  268. package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
  269. package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
  270. package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
  271. package/lib/types/documents/orchestrator/scope.d.ts +0 -52
  272. package/lib/types/documents/providers/docling.d.ts +0 -54
  273. package/lib/types/documents/providers/libreoffice.d.ts +0 -40
  274. package/lib/types/documents/providers/markitdown.d.ts +0 -28
  275. package/lib/types/documents/providers/pandoc.d.ts +0 -42
  276. package/lib/types/documents/providers/process.d.ts +0 -54
  277. package/lib/types/documents/providers/registry.d.ts +0 -68
  278. package/lib/types/documents/providers/shared.d.ts +0 -27
  279. package/lib/types/documents/runtime.d.ts +0 -59
  280. package/lib/types/documents/security/file-types.d.ts +0 -39
  281. package/lib/types/documents/security/limits.d.ts +0 -24
  282. package/lib/types/documents/security/mime.d.ts +0 -13
  283. package/lib/types/documents/security/paths.d.ts +0 -38
  284. package/lib/types/documents/templates/registry.d.ts +0 -50
  285. package/lib/types/documents/templates/resolver.d.ts +0 -30
  286. package/lib/types/documents/tools/convert.d.ts +0 -9
  287. package/lib/types/documents/tools/create.d.ts +0 -14
  288. package/lib/types/documents/tools/index.d.ts +0 -33
  289. package/lib/types/documents/tools/inspect.d.ts +0 -9
  290. package/lib/types/documents/tools/shared.d.ts +0 -77
  291. package/lib/types/documents/tools/to-markdown.d.ts +0 -12
  292. package/lib/types/documents/types.d.ts +0 -294
@@ -1,114 +0,0 @@
1
- /**
2
- * The runtime facade the tools talk to.
3
- *
4
- * One instance lives in the plugin and survives across calls, so the backend
5
- * registry, the concurrency semaphores and the version caches are shared
6
- * instead of rebuilt per request. The four operations are the whole surface:
7
- * everything else in this subsystem is an implementation detail behind them.
8
- */
9
- import { ArtifactStore } from "./artifacts/store.js";
10
- import { applyDocumentsEnvOverrides, resolveDocumentsConfig, } from "./config.js";
11
- import { documentCapabilities, documentHealth, } from "./capabilities.js";
12
- import { DocumentError } from "./errors.js";
13
- import { createProviders, } from "./providers/registry.js";
14
- import { convertDocument } from "./orchestrator/convert-document.js";
15
- import { createDocument } from "./orchestrator/create-document.js";
16
- import { inspectDocument } from "./orchestrator/inspect-document.js";
17
- import { toMarkdown } from "./orchestrator/extract-document.js";
18
- import { createRuntimeDeps, silentDocumentLogger, } from "./orchestrator/runtime-deps.js";
19
- import { loadScopeTemplates, resolveDocumentScope, } from "./orchestrator/scope.js";
20
- import { loadTemplateRegistry } from "./templates/registry.js";
21
- import { CONVERSION_ROUTES } from "./orchestrator/convert-document.js";
22
- export class DocumentRuntime {
23
- config;
24
- providers;
25
- deps;
26
- seams;
27
- constructor(options) {
28
- this.config = options.config;
29
- this.seams = options.seams ?? {};
30
- this.providers =
31
- options.providers ?? createProviders(this.config, this.seams);
32
- this.deps = createRuntimeDeps({
33
- config: this.config,
34
- providers: this.providers,
35
- logger: options.logger ?? silentDocumentLogger,
36
- ...(options.now === undefined ? {} : { now: options.now }),
37
- });
38
- }
39
- async create(input, scope) {
40
- return await createDocument(this.deps, input, scope);
41
- }
42
- async toMarkdown(input, scope) {
43
- return await toMarkdown(this.deps, input, scope);
44
- }
45
- async convert(input, scope) {
46
- return await convertDocument(this.deps, input, scope);
47
- }
48
- async inspect(input, scope) {
49
- return await inspectDocument(this.deps, input, scope);
50
- }
51
- async health(options = {}) {
52
- const healthOptions = {
53
- config: this.config,
54
- providers: this.providers,
55
- ...(options.probeProcessBackends === undefined
56
- ? {}
57
- : { probeProcessBackends: options.probeProcessBackends }),
58
- };
59
- return await documentHealth(healthOptions);
60
- }
61
- async capabilities(scope) {
62
- const templates = scope === undefined
63
- ? await loadTemplateRegistry(undefined)
64
- : await loadScopeTemplates(this.config, scope.workspaceRoot);
65
- return documentCapabilities({
66
- config: this.config,
67
- providers: this.providers,
68
- templates,
69
- });
70
- }
71
- /** Routes this runtime advertises, in documentation order. */
72
- routes() {
73
- return CONVERSION_ROUTES;
74
- }
75
- /**
76
- * Retention sweep (§41). Meaningful only for a pinned storage root: with the
77
- * default per-workspace layout the plugin cannot enumerate workspaces, and a
78
- * sweep that guessed would delete other projects' artifacts.
79
- */
80
- async cleanup(options = {}) {
81
- if (!this.config.retention.enabled || this.config.storage.root === null)
82
- return undefined;
83
- const store = new ArtifactStore({ root: this.config.storage.root });
84
- const removed = await store.cleanup({
85
- maxAgeDays: this.config.retention.maxAgeDays,
86
- ...(options.now === undefined ? {} : { now: options.now }),
87
- });
88
- if (removed.removed.length > 0) {
89
- this.deps.logger.info("documents.retention", {
90
- removed: removed.removed.length,
91
- });
92
- }
93
- return removed;
94
- }
95
- }
96
- /** Build a runtime from raw (schema-parsed) configuration. */
97
- export function createDocumentRuntime(options) {
98
- const withEnv = applyDocumentsEnvOverrides(options.config, options.env ?? process.env);
99
- const resolved = resolveDocumentsConfig(withEnv);
100
- if (!resolved.enabled) {
101
- throw new DocumentError("BACKEND_UNAVAILABLE", "the document subsystem is disabled in this deployment");
102
- }
103
- return new DocumentRuntime({
104
- config: resolved,
105
- ...(options.logger === undefined ? {} : { logger: options.logger }),
106
- ...(options.seams === undefined ? {} : { seams: options.seams }),
107
- ...(options.providers === undefined
108
- ? {}
109
- : { providers: options.providers }),
110
- ...(options.now === undefined ? {} : { now: options.now }),
111
- });
112
- }
113
- export { resolveDocumentScope };
114
- //# sourceMappingURL=runtime.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/documents/runtime.ts"],"names":[],"mappings":"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"}
@@ -1,188 +0,0 @@
1
- /**
2
- * File-type identification and asset MIME policy (§26.3, §26.6, §17.1).
3
- *
4
- * The extension is a hint, never the authority: PDF is recognized by its
5
- * header (after a bounded scan, because a PDF may carry leading junk), OOXML
6
- * by its ZIP container plus the parts it holds, and macro-enabled documents by
7
- * the presence of a VBA project. Legacy OLE documents (`.doc`, `.xls`, `.ppt`)
8
- * are recognized only to be refused with a precise message.
9
- */
10
- import path from "node:path";
11
- import { findZipEntry, readZipEntries, readZipEntry } from "../inspect/zip.js";
12
- import { sanitizeBackendOutput } from "../errors.js";
13
- const PDF_HEADER = Buffer.from("%PDF-", "latin1");
14
- const ZIP_LOCAL_HEADER = Buffer.from([0x50, 0x4b, 0x03, 0x04]);
15
- const ZIP_EMPTY_HEADER = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
16
- const CFB_HEADER = Buffer.from([
17
- 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1,
18
- ]);
19
- /** A PDF header may be preceded by junk; the spec fixes no bound, we use 4 KiB. */
20
- const PDF_HEADER_SCAN_BYTES = 4 * 1024;
21
- /** Bounded text sniffing window for Markdown/plain-text inputs. */
22
- const TEXT_SNIFF_BYTES = 4 * 1024;
23
- export const DOCUMENT_MEDIA_TYPES = {
24
- md: "text/markdown",
25
- docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
26
- pdf: "application/pdf",
27
- };
28
- export function mediaTypeFor(format) {
29
- return DOCUMENT_MEDIA_TYPES[format];
30
- }
31
- export function extensionFor(format) {
32
- return format === "md" ? "md" : format;
33
- }
34
- const DOCX_PART = /^word\/(?:document|styles|settings)\.xml$/iu;
35
- const MACRO_PART = /^word\/vbaProject\.bin$/iu;
36
- const CONTENT_TYPES_PART = "[Content_Types].xml";
37
- const MACRO_CONTENT_TYPE = /macroEnabled/iu;
38
- function sniffZip(buffer) {
39
- const entries = readZipEntries(buffer);
40
- if (entries === undefined) {
41
- return { format: "unknown", mediaType: "application/octet-stream" };
42
- }
43
- const word = entries.some((entry) => DOCX_PART.test(entry.name));
44
- const macroPart = entries.some((entry) => MACRO_PART.test(entry.name));
45
- const contentTypes = findZipEntry(entries, CONTENT_TYPES_PART);
46
- let macroContentType = false;
47
- if (contentTypes !== undefined && !macroPart) {
48
- const payload = readZipEntry(buffer, contentTypes);
49
- if (payload !== undefined) {
50
- macroContentType = MACRO_CONTENT_TYPE.test(payload.toString("utf8", 0, Math.min(payload.length, 8 * 1024)));
51
- }
52
- }
53
- if (!word && !macroPart && !macroContentType) {
54
- return {
55
- format: "unknown",
56
- mediaType: "application/zip",
57
- unsupportedOffice: true,
58
- };
59
- }
60
- const macroEnabled = macroPart || macroContentType;
61
- return {
62
- format: macroEnabled ? "docm" : "docx",
63
- mediaType: macroEnabled
64
- ? "application/vnd.ms-word.document.macroEnabled.12"
65
- : DOCUMENT_MEDIA_TYPES.docx,
66
- wordprocessing: true,
67
- macroEnabled,
68
- };
69
- }
70
- /** Detect binary content without trusting the extension. */
71
- function looksLikeText(buffer) {
72
- const window = buffer.subarray(0, TEXT_SNIFF_BYTES);
73
- for (const byte of window) {
74
- if (byte === 0)
75
- return false;
76
- }
77
- return true;
78
- }
79
- const MARKDOWN_EXTENSIONS = new Set([
80
- ".md",
81
- ".markdown",
82
- ".mdown",
83
- ".mkd",
84
- ".txt",
85
- ]);
86
- export function detectFormatByExtension(filename) {
87
- const extension = path.extname(filename).toLowerCase();
88
- if (extension === ".pdf")
89
- return "pdf";
90
- if (extension === ".docx" || extension === ".docm")
91
- return "docx";
92
- if (MARKDOWN_EXTENSIONS.has(extension))
93
- return "md";
94
- return undefined;
95
- }
96
- /**
97
- * Identify a document from its bytes, falling back to the extension only where
98
- * bytes are inconclusive (plain text and Markdown are both just text).
99
- */
100
- export function sniffDocument(buffer, filename) {
101
- const head = buffer.subarray(0, Math.max(PDF_HEADER_SCAN_BYTES, ZIP_LOCAL_HEADER.length));
102
- if (head.includes(PDF_HEADER)) {
103
- return { format: "pdf", mediaType: DOCUMENT_MEDIA_TYPES.pdf };
104
- }
105
- if (head.subarray(0, ZIP_LOCAL_HEADER.length).equals(ZIP_LOCAL_HEADER) ||
106
- head.subarray(0, ZIP_EMPTY_HEADER.length).equals(ZIP_EMPTY_HEADER)) {
107
- return sniffZip(buffer);
108
- }
109
- if (head.subarray(0, CFB_HEADER.length).equals(CFB_HEADER)) {
110
- return { format: "unknown", mediaType: "application/x-ole-storage" };
111
- }
112
- const byExtension = filename === undefined ? undefined : detectFormatByExtension(filename);
113
- if (byExtension === "md" && looksLikeText(buffer)) {
114
- return { format: "markdown", mediaType: DOCUMENT_MEDIA_TYPES.md };
115
- }
116
- if (byExtension === "pdf" || byExtension === "docx") {
117
- // The bytes contradict the name; the bytes win.
118
- return { format: "unknown", mediaType: "application/octet-stream" };
119
- }
120
- if (looksLikeText(buffer)) {
121
- return { format: "markdown", mediaType: DOCUMENT_MEDIA_TYPES.md };
122
- }
123
- return { format: "unknown", mediaType: "application/octet-stream" };
124
- }
125
- /** The supported source format behind a sniff result, or `undefined`. */
126
- export function supportedFormatOf(sniffed) {
127
- if (sniffed.format === "pdf")
128
- return "pdf";
129
- if (sniffed.format === "docx")
130
- return "docx";
131
- if (sniffed.format === "markdown")
132
- return "md";
133
- return undefined;
134
- }
135
- /** Human-facing explanation of a sniff result the pipeline refuses. */
136
- export function describeUnsupported(sniffed, filename) {
137
- if (sniffed.format === "docm") {
138
- return `"${path.basename(filename)}" is a macro-enabled document; macro-enabled documents are not processed`;
139
- }
140
- if (sniffed.unsupportedOffice) {
141
- return `"${path.basename(filename)}" is an OOXML package this pipeline does not support (supported: DOCX, PDF, Markdown)`;
142
- }
143
- if (sniffed.mediaType === "application/x-ole-storage") {
144
- return `"${path.basename(filename)}" is a legacy OLE Office document (supported: DOCX, PDF, Markdown)`;
145
- }
146
- return `"${path.basename(filename)}" is not a supported document (supported: DOCX, PDF, Markdown)`;
147
- }
148
- export { DEFAULT_ASSET_MIME_TYPES, isAllowedAssetMimeType, mimeTypeForFilename, } from "./mime.js";
149
- /** Magic-byte MIME detection for the asset types the pipeline accepts. */
150
- export function mimeTypeOfBytes(buffer) {
151
- if (buffer.length >= 8 &&
152
- buffer
153
- .subarray(0, 8)
154
- .equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
155
- return "image/png";
156
- }
157
- if (buffer.length >= 3 &&
158
- buffer[0] === 0xff &&
159
- buffer[1] === 0xd8 &&
160
- buffer[2] === 0xff) {
161
- return "image/jpeg";
162
- }
163
- if (buffer.length >= 6 &&
164
- buffer.toString("latin1", 0, 6).startsWith("GIF8")) {
165
- return "image/gif";
166
- }
167
- if (buffer.length >= 12 &&
168
- buffer.toString("latin1", 0, 4) === "RIFF" &&
169
- buffer.toString("latin1", 8, 12) === "WEBP") {
170
- return "image/webp";
171
- }
172
- if (buffer.length >= 2 && buffer.toString("latin1", 0, 2) === "BM") {
173
- return "image/bmp";
174
- }
175
- if (buffer.length >= 4) {
176
- const little = buffer.toString("latin1", 0, 4);
177
- if (little === "II*\u0000" || little === "MM\u0000*")
178
- return "image/tiff";
179
- }
180
- return undefined;
181
- }
182
- /** A short, sanitized description of the first bytes, for error messages. */
183
- export function describeBytes(buffer) {
184
- return sanitizeBackendOutput([...buffer.subarray(0, 16)]
185
- .map((byte) => byte.toString(16).padStart(2, "0"))
186
- .join(" "), 120);
187
- }
188
- //# sourceMappingURL=file-types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-types.js","sourceRoot":"","sources":["../../../src/documents/security/file-types.ts"],"names":[],"mappings":"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"}
@@ -1,78 +0,0 @@
1
- /**
2
- * Resource limits and concurrency control (§26.4, §27).
3
- *
4
- * Every expensive stage (render, extraction, OCR) runs behind a semaphore so a
5
- * burst of documents cannot exhaust the host, and every size/count budget is
6
- * checked before the work starts rather than after a backend has already spent
7
- * minutes on it.
8
- */
9
- import { DocumentError } from "../errors.js";
10
- export function assertBytesWithinBudget(bytes, maxBytes, label) {
11
- if (bytes > maxBytes) {
12
- throw new DocumentError("INPUT_TOO_LARGE", `${label} is ${bytes} bytes; the configured limit is ${maxBytes}`, { details: { bytes, maxBytes } });
13
- }
14
- }
15
- export function assertCharsWithinBudget(chars, maxChars, label) {
16
- if (chars > maxChars) {
17
- throw new DocumentError("DOCUMENT_TOO_LARGE", `${label} is ${chars} characters; the configured limit is ${maxChars}`, { details: { chars, maxChars } });
18
- }
19
- }
20
- export function assertCountWithinBudget(count, maxCount, label) {
21
- if (count > maxCount) {
22
- throw new DocumentError("DOCUMENT_TOO_LARGE", `${label} is ${count}; the configured limit is ${maxCount}`, { details: { count, maxCount } });
23
- }
24
- }
25
- /**
26
- * Counting semaphore with FIFO fairness. An aborted waiter leaves the queue
27
- * without consuming a slot, so a stopped turn never leaks capacity.
28
- */
29
- export function createSemaphore(limit) {
30
- const max = Math.max(1, Math.floor(limit));
31
- let inUse = 0;
32
- const waiters = [];
33
- const releaseOnce = () => {
34
- let released = false;
35
- return () => {
36
- if (released)
37
- return;
38
- released = true;
39
- inUse -= 1;
40
- const next = waiters.shift();
41
- if (next !== undefined) {
42
- inUse += 1;
43
- next.signal?.removeEventListener("abort", next.reject);
44
- next.resolve(releaseOnce());
45
- }
46
- };
47
- };
48
- return {
49
- limit: max,
50
- get inUse() {
51
- return inUse;
52
- },
53
- async acquire(signal) {
54
- if (signal?.aborted === true) {
55
- throw new DocumentError("INVALID_INPUT", "the operation was cancelled");
56
- }
57
- if (inUse < max) {
58
- inUse += 1;
59
- return releaseOnce();
60
- }
61
- return await new Promise((resolve, reject) => {
62
- const waiter = {
63
- resolve,
64
- reject,
65
- ...(signal === undefined ? {} : { signal }),
66
- };
67
- waiters.push(waiter);
68
- signal?.addEventListener("abort", () => {
69
- const index = waiters.indexOf(waiter);
70
- if (index >= 0)
71
- waiters.splice(index, 1);
72
- reject(new DocumentError("INVALID_INPUT", "the operation was cancelled"));
73
- }, { once: true });
74
- });
75
- },
76
- };
77
- }
78
- //# sourceMappingURL=limits.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"limits.js","sourceRoot":"","sources":["../../../src/documents/security/limits.ts"],"names":[],"mappings":"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"}
@@ -1,43 +0,0 @@
1
- /**
2
- * MIME policy for document assets (§17.1).
3
- *
4
- * Kept free of Node builtins on purpose: the QA settings schema reaches this
5
- * module from the browser bundle, so anything imported here also has to run in
6
- * a page. The byte sniffing stays with the pipeline's file-type module, which
7
- * may import whatever it needs.
8
- */
9
- /** Asset MIME types accepted by default. */
10
- export const DEFAULT_ASSET_MIME_TYPES = [
11
- "image/png",
12
- "image/jpeg",
13
- "image/gif",
14
- "image/webp",
15
- "image/bmp",
16
- "image/tiff",
17
- ];
18
- const MIME_BY_EXTENSION = {
19
- ".png": "image/png",
20
- ".jpg": "image/jpeg",
21
- ".jpeg": "image/jpeg",
22
- ".gif": "image/gif",
23
- ".webp": "image/webp",
24
- ".bmp": "image/bmp",
25
- ".tif": "image/tiff",
26
- ".tiff": "image/tiff",
27
- ".svg": "image/svg+xml",
28
- };
29
- /** Lowercased extension of a file name, including the dot. */
30
- function extensionOf(filename) {
31
- const separator = Math.max(filename.lastIndexOf("/"), filename.lastIndexOf("\\"));
32
- const base = separator < 0 ? filename : filename.slice(separator + 1);
33
- const dot = base.lastIndexOf(".");
34
- return dot <= 0 ? "" : base.slice(dot).toLowerCase();
35
- }
36
- export function mimeTypeForFilename(filename) {
37
- return MIME_BY_EXTENSION[extensionOf(filename)];
38
- }
39
- export function isAllowedAssetMimeType(mimeType, allowed) {
40
- const normalized = mimeType.trim().toLowerCase();
41
- return allowed.some((entry) => entry.trim().toLowerCase() === normalized);
42
- }
43
- //# sourceMappingURL=mime.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mime.js","sourceRoot":"","sources":["../../../src/documents/security/mime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4CAA4C;AAC5C,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,WAAW;IACX,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,WAAW;IACX,YAAY;CACb,CAAC;AAEF,MAAM,iBAAiB,GAAqC;IAC1D,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,eAAe;CACxB,CAAC;AAEF,8DAA8D;AAC9D,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,EACzB,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAC3B,CAAC;IACF,MAAM,IAAI,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACtE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,OAAO,iBAAiB,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,OAA0B;IAE1B,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,CAAC;AAC5E,CAAC"}
@@ -1,133 +0,0 @@
1
- /**
2
- * Path containment and filename hygiene (§26.2, §32).
3
- *
4
- * Two rules hold everywhere in the pipeline:
5
- *
6
- * - every path the pipeline touches is resolved against an allowed root and
7
- * the resolution must stay inside it — traversal, absolute escapes and
8
- * `file://` references are refused before anything is opened;
9
- * - a caller-supplied filename is a label, never a path: directories are
10
- * dropped, separators and reserved characters collapse to `-`, and the
11
- * extension is the one the operation itself chose.
12
- */
13
- import { realpath } from "node:fs/promises";
14
- import path from "node:path";
15
- import { pathToFileURL } from "node:url";
16
- import { DocumentError } from "../errors.js";
17
- /** Whether `target` is `root` or a descendant of it (no symlink resolution). */
18
- export function isInsideRoot(root, target) {
19
- const relative = path.relative(root, target);
20
- return (relative === "" ||
21
- (!relative.startsWith(`..${path.sep}`) &&
22
- relative !== ".." &&
23
- !path.isAbsolute(relative)));
24
- }
25
- export function assertInsideRoot(root, target, label) {
26
- const resolvedRoot = path.resolve(root);
27
- const resolvedTarget = path.resolve(target);
28
- if (!isInsideRoot(resolvedRoot, resolvedTarget)) {
29
- throw new DocumentError("PATH_NOT_ALLOWED", `${label} is outside the allowed document scope`, { details: { label } });
30
- }
31
- return resolvedTarget;
32
- }
33
- /**
34
- * Canonicalize a path for containment checks: the existing prefix is resolved
35
- * through symlinks, the non-existent remainder is appended unresolved. A
36
- * symlink pointing outside the root therefore canonicalizes outside it.
37
- */
38
- export async function canonicalizeForContainment(input) {
39
- const resolved = path.resolve(input);
40
- let current = resolved;
41
- const remainder = [];
42
- for (;;) {
43
- try {
44
- const canonical = await realpath(current);
45
- return remainder.length === 0
46
- ? canonical
47
- : path.join(canonical, ...remainder.reverse());
48
- }
49
- catch {
50
- const parent = path.dirname(current);
51
- if (parent === current)
52
- return resolved;
53
- remainder.push(path.basename(current));
54
- current = parent;
55
- }
56
- }
57
- }
58
- /** Resolve a caller-supplied path against `root`, refusing any escape. */
59
- export async function resolveInsideRoot(root, requested, label) {
60
- if (requested.trim() === "") {
61
- throw new DocumentError("INVALID_INPUT", `${label} must be a non-empty path`);
62
- }
63
- if (requested.toLowerCase().startsWith("file:")) {
64
- throw new DocumentError("PATH_NOT_ALLOWED", `${label} must be a filesystem path, not a file URL`);
65
- }
66
- const canonicalRoot = await canonicalizeForContainment(root);
67
- const target = path.resolve(canonicalRoot, requested);
68
- const canonicalTarget = await canonicalizeForContainment(target);
69
- assertInsideRoot(canonicalRoot, canonicalTarget, label);
70
- return canonicalTarget;
71
- }
72
- /**
73
- * Turn a caller-supplied filename into a safe file name (§32).
74
- * `../../foo report?.docx` becomes `foo-report.docx`.
75
- */
76
- export function sanitizeFilename(requested, fallbackStem, extension) {
77
- const suffix = extension === ""
78
- ? ""
79
- : extension.startsWith(".")
80
- ? extension
81
- : `.${extension}`;
82
- const source = (requested ?? "").trim();
83
- let stem = "";
84
- if (source !== "") {
85
- // A Windows-style separator survives `path.basename` on POSIX, so both are
86
- // cut explicitly before any further normalization.
87
- const basename = source.split(/[\\/]+/u).pop() ?? "";
88
- const withoutExtension = basename.replace(/\.[A-Za-z0-9]{1,8}$/u, "");
89
- stem = withoutExtension
90
- .normalize("NFC")
91
- /* eslint-disable-next-line no-control-regex -- control characters are the point */
92
- .replace(/[\u0000-\u001F\u007F]/gu, "")
93
- .replace(/[<>:"|?*]+/gu, "")
94
- .replace(/[\s._]+/gu, "-")
95
- .replace(/-{2,}/gu, "-")
96
- .replace(/^[-.]+|[-.]+$/gu, "");
97
- }
98
- const safeStem = stem === "" ? fallbackStem : stem.slice(0, 80);
99
- return `${safeStem}${suffix}`;
100
- }
101
- /** `file:///...` form required by `-env:UserInstallation` and friends. */
102
- export function toFileUri(target) {
103
- return pathToFileURL(path.resolve(target)).href;
104
- }
105
- /**
106
- * Assert an asset reference inside Markdown targets the assets directory and
107
- * nothing else: no absolute paths, no URLs, no traversal (§17.1).
108
- */
109
- export function assertRelativeAssetReference(reference) {
110
- const trimmed = reference.trim();
111
- if (trimmed === "") {
112
- throw new DocumentError("INVALID_ASSET", "asset reference is empty");
113
- }
114
- if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//u.test(trimmed) ||
115
- trimmed.startsWith("//") ||
116
- trimmed.startsWith("\\\\") ||
117
- /^(?:data|file|javascript):/iu.test(trimmed)) {
118
- throw new DocumentError("INVALID_ASSET", `asset reference must be relative to the artifact assets directory (${trimmed})`);
119
- }
120
- const normalized = trimmed.replace(/\\/gu, "/");
121
- if (normalized.startsWith("/") || normalized.split("/").includes("..")) {
122
- throw new DocumentError("INVALID_ASSET", `asset reference must not leave the assets directory (${trimmed})`);
123
- }
124
- return normalized;
125
- }
126
- /** Recursively-size snapshot helper used by the limits guard. */
127
- export function assertNotBlank(value, label) {
128
- if (value.trim() === "") {
129
- throw new DocumentError("INVALID_INPUT", `${label} must not be blank`);
130
- }
131
- return value;
132
- }
133
- //# sourceMappingURL=paths.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/documents/security/paths.ts"],"names":[],"mappings":"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"}