arc-1 1.6.0 → 1.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 (282) hide show
  1. package/README.md +22 -15
  2. package/dist/adt/application-log.d.ts +36 -0
  3. package/dist/adt/application-log.d.ts.map +1 -0
  4. package/dist/adt/application-log.js +143 -0
  5. package/dist/adt/application-log.js.map +1 -0
  6. package/dist/adt/class-structure.d.ts +2 -1
  7. package/dist/adt/class-structure.d.ts.map +1 -1
  8. package/dist/adt/class-structure.js +28 -10
  9. package/dist/adt/class-structure.js.map +1 -1
  10. package/dist/adt/client.d.ts +6 -4
  11. package/dist/adt/client.d.ts.map +1 -1
  12. package/dist/adt/client.js +9 -9
  13. package/dist/adt/client.js.map +1 -1
  14. package/dist/adt/codeintel.d.ts +9 -23
  15. package/dist/adt/codeintel.d.ts.map +1 -1
  16. package/dist/adt/codeintel.js +14 -34
  17. package/dist/adt/codeintel.js.map +1 -1
  18. package/dist/adt/devtools.d.ts +8 -1
  19. package/dist/adt/devtools.d.ts.map +1 -1
  20. package/dist/adt/devtools.js +67 -37
  21. package/dist/adt/devtools.js.map +1 -1
  22. package/dist/adt/diagnostics.d.ts +2 -0
  23. package/dist/adt/diagnostics.d.ts.map +1 -1
  24. package/dist/adt/diagnostics.js +10 -8
  25. package/dist/adt/diagnostics.js.map +1 -1
  26. package/dist/adt/errors.d.ts +5 -1
  27. package/dist/adt/errors.d.ts.map +1 -1
  28. package/dist/adt/errors.js +26 -0
  29. package/dist/adt/errors.js.map +1 -1
  30. package/dist/adt/feed-schema.d.ts +32 -0
  31. package/dist/adt/feed-schema.d.ts.map +1 -0
  32. package/dist/adt/feed-schema.js +123 -0
  33. package/dist/adt/feed-schema.js.map +1 -0
  34. package/dist/adt/fm-parameter-docs.d.ts +7 -0
  35. package/dist/adt/fm-parameter-docs.d.ts.map +1 -0
  36. package/dist/adt/fm-parameter-docs.js +134 -0
  37. package/dist/adt/fm-parameter-docs.js.map +1 -0
  38. package/dist/adt/fm-signature.d.ts +8 -1
  39. package/dist/adt/fm-signature.d.ts.map +1 -1
  40. package/dist/adt/fm-signature.js +37 -28
  41. package/dist/adt/fm-signature.js.map +1 -1
  42. package/dist/adt/http-deadline.d.ts.map +1 -1
  43. package/dist/adt/http-deadline.js +4 -1
  44. package/dist/adt/http-deadline.js.map +1 -1
  45. package/dist/adt/http-retry-after.d.ts +20 -0
  46. package/dist/adt/http-retry-after.d.ts.map +1 -0
  47. package/dist/adt/http-retry-after.js +37 -0
  48. package/dist/adt/http-retry-after.js.map +1 -0
  49. package/dist/adt/http.d.ts +6 -19
  50. package/dist/adt/http.d.ts.map +1 -1
  51. package/dist/adt/http.js +78 -79
  52. package/dist/adt/http.js.map +1 -1
  53. package/dist/adt/include-expansion.d.ts +143 -0
  54. package/dist/adt/include-expansion.d.ts.map +1 -0
  55. package/dist/adt/include-expansion.js +475 -0
  56. package/dist/adt/include-expansion.js.map +1 -0
  57. package/dist/adt/internal-data-operations.d.ts +3 -3
  58. package/dist/adt/internal-data-operations.d.ts.map +1 -1
  59. package/dist/adt/internal-data-operations.js +9 -2
  60. package/dist/adt/internal-data-operations.js.map +1 -1
  61. package/dist/adt/revision-feed.d.ts +8 -0
  62. package/dist/adt/revision-feed.d.ts.map +1 -0
  63. package/dist/adt/revision-feed.js +108 -0
  64. package/dist/adt/revision-feed.js.map +1 -0
  65. package/dist/adt/security-session-gate.d.ts +23 -0
  66. package/dist/adt/security-session-gate.d.ts.map +1 -0
  67. package/dist/adt/security-session-gate.js +56 -0
  68. package/dist/adt/security-session-gate.js.map +1 -0
  69. package/dist/adt/source-diff.d.ts +4 -1
  70. package/dist/adt/source-diff.d.ts.map +1 -1
  71. package/dist/adt/source-diff.js +5 -3
  72. package/dist/adt/source-diff.js.map +1 -1
  73. package/dist/adt/stored-text/chunks.d.ts +8 -0
  74. package/dist/adt/stored-text/chunks.d.ts.map +1 -0
  75. package/dist/adt/stored-text/chunks.js +55 -0
  76. package/dist/adt/stored-text/chunks.js.map +1 -0
  77. package/dist/adt/stored-text/decoder.d.ts +31 -0
  78. package/dist/adt/stored-text/decoder.d.ts.map +1 -0
  79. package/dist/adt/stored-text/decoder.js +319 -0
  80. package/dist/adt/stored-text/decoder.js.map +1 -0
  81. package/dist/adt/stored-text/errors.d.ts +10 -0
  82. package/dist/adt/stored-text/errors.d.ts.map +1 -0
  83. package/dist/adt/stored-text/errors.js +10 -0
  84. package/dist/adt/stored-text/errors.js.map +1 -0
  85. package/dist/adt/stored-text/index.d.ts +7 -0
  86. package/dist/adt/stored-text/index.d.ts.map +1 -0
  87. package/dist/adt/stored-text/index.js +6 -0
  88. package/dist/adt/stored-text/index.js.map +1 -0
  89. package/dist/adt/stored-text/key.d.ts +3 -0
  90. package/dist/adt/stored-text/key.d.ts.map +1 -0
  91. package/dist/adt/stored-text/key.js +23 -0
  92. package/dist/adt/stored-text/key.js.map +1 -0
  93. package/dist/adt/stored-text/reader.d.ts +52 -0
  94. package/dist/adt/stored-text/reader.d.ts.map +1 -0
  95. package/dist/adt/stored-text/reader.js +142 -0
  96. package/dist/adt/stored-text/reader.js.map +1 -0
  97. package/dist/adt/stored-text/source.d.ts +5 -0
  98. package/dist/adt/stored-text/source.d.ts.map +1 -0
  99. package/dist/adt/stored-text/source.js +284 -0
  100. package/dist/adt/stored-text/source.js.map +1 -0
  101. package/dist/adt/stored-text/types.d.ts +38 -0
  102. package/dist/adt/stored-text/types.d.ts.map +1 -0
  103. package/dist/adt/stored-text/types.js +2 -0
  104. package/dist/adt/stored-text/types.js.map +1 -0
  105. package/dist/adt/structure-hierarchy.d.ts.map +1 -1
  106. package/dist/adt/structure-hierarchy.js +11 -27
  107. package/dist/adt/structure-hierarchy.js.map +1 -1
  108. package/dist/adt/syntax-batch.d.ts +66 -0
  109. package/dist/adt/syntax-batch.d.ts.map +1 -0
  110. package/dist/adt/syntax-batch.js +115 -0
  111. package/dist/adt/syntax-batch.js.map +1 -0
  112. package/dist/adt/table-query.d.ts +3 -1
  113. package/dist/adt/table-query.d.ts.map +1 -1
  114. package/dist/adt/table-query.js +32 -4
  115. package/dist/adt/table-query.js.map +1 -1
  116. package/dist/adt/text-elements.js +1 -1
  117. package/dist/adt/text-elements.js.map +1 -1
  118. package/dist/adt/transport-diff.d.ts +16 -25
  119. package/dist/adt/transport-diff.d.ts.map +1 -1
  120. package/dist/adt/transport-diff.js +201 -103
  121. package/dist/adt/transport-diff.js.map +1 -1
  122. package/dist/adt/transport-review-budget.d.ts +15 -0
  123. package/dist/adt/transport-review-budget.d.ts.map +1 -0
  124. package/dist/adt/transport-review-budget.js +57 -0
  125. package/dist/adt/transport-review-budget.js.map +1 -0
  126. package/dist/adt/transport.d.ts +1 -1
  127. package/dist/adt/transport.d.ts.map +1 -1
  128. package/dist/adt/transport.js +2 -2
  129. package/dist/adt/transport.js.map +1 -1
  130. package/dist/adt/types.d.ts +1 -0
  131. package/dist/adt/types.d.ts.map +1 -1
  132. package/dist/adt/user-agent.d.ts +1 -1
  133. package/dist/adt/where-used-native.d.ts +22 -0
  134. package/dist/adt/where-used-native.d.ts.map +1 -0
  135. package/dist/adt/where-used-native.js +111 -0
  136. package/dist/adt/where-used-native.js.map +1 -0
  137. package/dist/adt/xml-parser.d.ts +2 -3
  138. package/dist/adt/xml-parser.d.ts.map +1 -1
  139. package/dist/adt/xml-parser.js +1 -91
  140. package/dist/adt/xml-parser.js.map +1 -1
  141. package/dist/aff/validator.d.ts.map +1 -1
  142. package/dist/aff/validator.js +8 -2
  143. package/dist/aff/validator.js.map +1 -1
  144. package/dist/authz/policy.d.ts.map +1 -1
  145. package/dist/authz/policy.js +10 -2
  146. package/dist/authz/policy.js.map +1 -1
  147. package/dist/cache/sqlite-driver.d.ts +24 -0
  148. package/dist/cache/sqlite-driver.d.ts.map +1 -0
  149. package/dist/cache/sqlite-driver.js +59 -0
  150. package/dist/cache/sqlite-driver.js.map +1 -0
  151. package/dist/cache/sqlite.d.ts +4 -2
  152. package/dist/cache/sqlite.d.ts.map +1 -1
  153. package/dist/cache/sqlite.js +5 -4
  154. package/dist/cache/sqlite.js.map +1 -1
  155. package/dist/cli.js +4 -1
  156. package/dist/cli.js.map +1 -1
  157. package/dist/context/grep.d.ts +2 -0
  158. package/dist/context/grep.d.ts.map +1 -1
  159. package/dist/context/grep.js +8 -7
  160. package/dist/context/grep.js.map +1 -1
  161. package/dist/extract-sap-cookies.js +1 -0
  162. package/dist/extract-sap-cookies.js.map +1 -1
  163. package/dist/handlers/application-log-input.d.ts +32 -0
  164. package/dist/handlers/application-log-input.d.ts.map +1 -0
  165. package/dist/handlers/application-log-input.js +34 -0
  166. package/dist/handlers/application-log-input.js.map +1 -0
  167. package/dist/handlers/application-log.d.ts +4 -0
  168. package/dist/handlers/application-log.d.ts.map +1 -0
  169. package/dist/handlers/application-log.js +14 -0
  170. package/dist/handlers/application-log.js.map +1 -0
  171. package/dist/handlers/cds-hints.d.ts +1 -1
  172. package/dist/handlers/cds-hints.d.ts.map +1 -1
  173. package/dist/handlers/cds-hints.js +21 -63
  174. package/dist/handlers/cds-hints.js.map +1 -1
  175. package/dist/handlers/context.d.ts.map +1 -1
  176. package/dist/handlers/context.js +7 -3
  177. package/dist/handlers/context.js.map +1 -1
  178. package/dist/handlers/diagnose.d.ts.map +1 -1
  179. package/dist/handlers/diagnose.js +10 -1
  180. package/dist/handlers/diagnose.js.map +1 -1
  181. package/dist/handlers/dispatch.d.ts.map +1 -1
  182. package/dist/handlers/dispatch.js +54 -9
  183. package/dist/handlers/dispatch.js.map +1 -1
  184. package/dist/handlers/dump-filter-inputs.d.ts +38 -0
  185. package/dist/handlers/dump-filter-inputs.d.ts.map +1 -0
  186. package/dist/handlers/dump-filter-inputs.js +44 -0
  187. package/dist/handlers/dump-filter-inputs.js.map +1 -0
  188. package/dist/handlers/expanded-read.d.ts +24 -0
  189. package/dist/handlers/expanded-read.d.ts.map +1 -0
  190. package/dist/handlers/expanded-read.js +56 -0
  191. package/dist/handlers/expanded-read.js.map +1 -0
  192. package/dist/handlers/function-parameter-language.d.ts +5 -0
  193. package/dist/handlers/function-parameter-language.d.ts.map +1 -0
  194. package/dist/handlers/function-parameter-language.js +19 -0
  195. package/dist/handlers/function-parameter-language.js.map +1 -0
  196. package/dist/handlers/function-processing.d.ts +5 -0
  197. package/dist/handlers/function-processing.d.ts.map +1 -1
  198. package/dist/handlers/function-processing.js +5 -0
  199. package/dist/handlers/function-processing.js.map +1 -1
  200. package/dist/handlers/hyperfocused.d.ts.map +1 -1
  201. package/dist/handlers/hyperfocused.js +2 -1
  202. package/dist/handlers/hyperfocused.js.map +1 -1
  203. package/dist/handlers/long-text-input.d.ts +113 -0
  204. package/dist/handlers/long-text-input.d.ts.map +1 -0
  205. package/dist/handlers/long-text-input.js +113 -0
  206. package/dist/handlers/long-text-input.js.map +1 -0
  207. package/dist/handlers/long-text.d.ts +5 -0
  208. package/dist/handlers/long-text.d.ts.map +1 -0
  209. package/dist/handlers/long-text.js +122 -0
  210. package/dist/handlers/long-text.js.map +1 -0
  211. package/dist/handlers/navigate.d.ts.map +1 -1
  212. package/dist/handlers/navigate.js +8 -3
  213. package/dist/handlers/navigate.js.map +1 -1
  214. package/dist/handlers/object-types.d.ts.map +1 -1
  215. package/dist/handlers/object-types.js +7 -4
  216. package/dist/handlers/object-types.js.map +1 -1
  217. package/dist/handlers/query-input.d.ts +50 -0
  218. package/dist/handlers/query-input.d.ts.map +1 -0
  219. package/dist/handlers/query-input.js +59 -0
  220. package/dist/handlers/query-input.js.map +1 -0
  221. package/dist/handlers/query-tool.d.ts +11 -0
  222. package/dist/handlers/query-tool.d.ts.map +1 -0
  223. package/dist/handlers/query-tool.js +99 -0
  224. package/dist/handlers/query-tool.js.map +1 -0
  225. package/dist/handlers/query.d.ts +1 -1
  226. package/dist/handlers/query.d.ts.map +1 -1
  227. package/dist/handlers/query.js +7 -1
  228. package/dist/handlers/query.js.map +1 -1
  229. package/dist/handlers/read.d.ts +1 -0
  230. package/dist/handlers/read.d.ts.map +1 -1
  231. package/dist/handlers/read.js +57 -9
  232. package/dist/handlers/read.js.map +1 -1
  233. package/dist/handlers/schemas.d.ts +17 -4
  234. package/dist/handlers/schemas.d.ts.map +1 -1
  235. package/dist/handlers/schemas.js +51 -9
  236. package/dist/handlers/schemas.js.map +1 -1
  237. package/dist/handlers/syntax.d.ts.map +1 -1
  238. package/dist/handlers/syntax.js +8 -0
  239. package/dist/handlers/syntax.js.map +1 -1
  240. package/dist/handlers/tools.d.ts.map +1 -1
  241. package/dist/handlers/tools.js +72 -70
  242. package/dist/handlers/tools.js.map +1 -1
  243. package/dist/handlers/transport-review.d.ts +5 -0
  244. package/dist/handlers/transport-review.d.ts.map +1 -0
  245. package/dist/handlers/transport-review.js +108 -0
  246. package/dist/handlers/transport-review.js.map +1 -0
  247. package/dist/handlers/transport.d.ts.map +1 -1
  248. package/dist/handlers/transport.js +3 -58
  249. package/dist/handlers/transport.js.map +1 -1
  250. package/dist/handlers/where-used-details.d.ts +28 -0
  251. package/dist/handlers/where-used-details.d.ts.map +1 -0
  252. package/dist/handlers/where-used-details.js +67 -0
  253. package/dist/handlers/where-used-details.js.map +1 -0
  254. package/dist/handlers/where-used.d.ts +8 -3
  255. package/dist/handlers/where-used.d.ts.map +1 -1
  256. package/dist/handlers/where-used.js +40 -18
  257. package/dist/handlers/where-used.js.map +1 -1
  258. package/dist/handlers/write/create.d.ts.map +1 -1
  259. package/dist/handlers/write/create.js +15 -12
  260. package/dist/handlers/write/create.js.map +1 -1
  261. package/dist/handlers/write/update-delete.d.ts.map +1 -1
  262. package/dist/handlers/write/update-delete.js +5 -3
  263. package/dist/handlers/write/update-delete.js.map +1 -1
  264. package/dist/server/audit.d.ts.map +1 -1
  265. package/dist/server/audit.js +49 -2
  266. package/dist/server/audit.js.map +1 -1
  267. package/dist/server/config.d.ts.map +1 -1
  268. package/dist/server/config.js +5 -1
  269. package/dist/server/config.js.map +1 -1
  270. package/dist/server/multi-target-tools.d.ts.map +1 -1
  271. package/dist/server/multi-target-tools.js +8 -7
  272. package/dist/server/multi-target-tools.js.map +1 -1
  273. package/dist/server/server.d.ts.map +1 -1
  274. package/dist/server/server.js +3 -2
  275. package/dist/server/server.js.map +1 -1
  276. package/dist/server/tool-auth.d.ts +1 -1
  277. package/dist/server/tool-auth.d.ts.map +1 -1
  278. package/dist/server/tool-auth.js +24 -4
  279. package/dist/server/tool-auth.js.map +1 -1
  280. package/dist/version.d.ts +1 -1
  281. package/dist/version.js +1 -1
  282. package/package.json +13 -9
@@ -0,0 +1,319 @@
1
+ /**
2
+ * STXL container marker research and portions of the traversal design are adapted from:
3
+ * https://github.com/aamelin1/sap-long-texts
4
+ * Revision: 19c8c272b23f0ab481f7d63b6b36c45db15fd095
5
+ *
6
+ * MIT License
7
+ *
8
+ * Copyright (c) 2026 Andrey
9
+ *
10
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ * of this software and associated documentation files (the "Software"), to deal
12
+ * in the Software without restriction, including without limitation the rights
13
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ * copies of the Software, and to permit persons to whom the Software is
15
+ * furnished to do so, subject to the following conditions:
16
+ *
17
+ * The above copyright notice and this permission notice shall be included in all
18
+ * copies or substantial portions of the Software.
19
+ *
20
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ * SOFTWARE.
27
+ */
28
+ /**
29
+ * Bounded STXL/TLINE decoder; no SAP installation, RFC, Python, or third-party runtime.
30
+ * Container marker research: aamelin1/sap-long-texts, commit 19c8c272 (MIT; attribution above).
31
+ * Verified profile: FF06, Unicode little-endian (4103), flat TLINE, CS_LZH or plain.
32
+ * This accepts the qualified stored profile; it is not a universal IMPORT/READ_TEXT implementation.
33
+ */
34
+ import { promisify } from 'node:util';
35
+ import { inflateRaw } from 'node:zlib';
36
+ import { TextReadError } from './errors.js';
37
+ const inflate = promisify(inflateRaw);
38
+ const CONTAINER_HEADER_BYTES = 16;
39
+ const COMPRESSION_HEADER_BYTES = 8;
40
+ const TLINE_FORMAT_UNITS = 2;
41
+ const TLINE_TEXT_UNITS = 132;
42
+ const UTF16_BYTES_PER_UNIT = 2;
43
+ const TLINE_ROW_BYTES = (TLINE_FORMAT_UNITS + TLINE_TEXT_UNITS) * UTF16_BYTES_PER_UNIT;
44
+ // Empirical ceiling for the verified SAP-produced compressed profile; not a trailer grammar.
45
+ const MAX_COMPRESSED_TRAILING_BYTES = 6;
46
+ const MARKER = {
47
+ segment: 3,
48
+ containerEnd: 4,
49
+ characterField: 0xaa,
50
+ structureStart: 0xad,
51
+ structureEnd: 0xae,
52
+ fixedRow: 0xbb,
53
+ sizedRow: 0xbc,
54
+ rowEnd: 0xbd,
55
+ table: 0xbe,
56
+ tableEnd: 0xbf,
57
+ };
58
+ export const DEFAULT_LIMITS = Object.freeze({
59
+ maxInputBytes: 2 * 1024 * 1024,
60
+ maxOutputBytes: 4 * 1024 * 1024,
61
+ maxLines: 10_000,
62
+ });
63
+ function fail(message, code = 'CORRUPT_CLUSTER') {
64
+ throw new TextReadError(code, message);
65
+ }
66
+ function checkLimits(limits) {
67
+ for (const name of Object.keys(DEFAULT_LIMITS)) {
68
+ const value = limits?.[name];
69
+ if (!Number.isSafeInteger(value) || value < 1 || value > DEFAULT_LIMITS[name]) {
70
+ fail(`invalid ${name}; limits may only narrow the hard ceiling`, 'LIMIT_EXCEEDED');
71
+ }
72
+ }
73
+ }
74
+ function range(data, offset, size) {
75
+ if (!Number.isSafeInteger(offset) ||
76
+ !Number.isSafeInteger(size) ||
77
+ offset < 0 ||
78
+ size < 0 ||
79
+ offset + size > data.length) {
80
+ fail(`truncated container at byte ${offset}`);
81
+ }
82
+ return data.subarray(offset, offset + size);
83
+ }
84
+ function uint(data, offset, size) {
85
+ return range(data, offset, size).readUIntBE(0, size);
86
+ }
87
+ function textBytes(bytes, codePage) {
88
+ if (codePage !== '4103')
89
+ fail(`unverified code page ${codePage}`, 'UNSUPPORTED_PROFILE');
90
+ // ABAP CHAR truncation can leave a lone surrogate. Preserve its code unit, as IMPORT does.
91
+ // JSON.stringify escapes such units; callers must not silently replace them during encoding.
92
+ return bytes.toString('utf16le');
93
+ }
94
+ /** Remove SAP's bit prefix while preserving the bounded input size for native zlib. */
95
+ function reframeLzh(source) {
96
+ const shift = 2 + (source[0] & 3);
97
+ const reframed = Buffer.alloc(source.length);
98
+ for (let i = 0; i < source.length; i++) {
99
+ reframed[i] = (source[i] >>> shift) | ((source[i + 1] ?? 0) << (8 - shift));
100
+ }
101
+ return reframed;
102
+ }
103
+ /** Validate the tested container profile and return its bounded decompressed payload. */
104
+ export async function unpackCluster(data, limits = DEFAULT_LIMITS) {
105
+ checkLimits(limits);
106
+ if (data.length > limits.maxInputBytes)
107
+ fail('compressed input limit exceeded', 'LIMIT_EXCEEDED');
108
+ range(data, 0, CONTAINER_HEADER_BYTES);
109
+ if (data[0] !== 0xff || data[1] !== 6 || data[2] !== 2)
110
+ fail('unverified container signature/version/byte order', 'UNSUPPORTED_PROFILE');
111
+ const version = data[1];
112
+ const codePage = data.subarray(8, 12).toString('latin1');
113
+ textBytes(Buffer.alloc(0), codePage); // Reject unknown code pages even for an empty table.
114
+ const compression = data[4];
115
+ let payload;
116
+ let compressedTrailingBytes = 0;
117
+ if (compression === 1) {
118
+ payload = data.subarray(CONTAINER_HEADER_BYTES);
119
+ if (payload.length > limits.maxOutputBytes)
120
+ fail('uncompressed output limit exceeded', 'LIMIT_EXCEEDED');
121
+ }
122
+ else if (compression === 2) {
123
+ range(data, CONTAINER_HEADER_BYTES, COMPRESSION_HEADER_BYTES + 1);
124
+ if (data[20] !== 0x12 || data[21] !== 0x1f || data[22] !== 0x9d)
125
+ fail('unsupported compression header', 'UNSUPPORTED_PROFILE');
126
+ const expected = data.readUInt32LE(CONTAINER_HEADER_BYTES);
127
+ if (expected < 1 || expected > limits.maxOutputBytes)
128
+ fail('declared output limit exceeded', 'LIMIT_EXCEEDED');
129
+ const reframed = reframeLzh(data.subarray(CONTAINER_HEADER_BYTES + COMPRESSION_HEADER_BYTES));
130
+ const firstBlockType = (reframed[0] >>> 1) & 3;
131
+ if (firstBlockType !== 1 && firstBlockType !== 2)
132
+ fail('unsupported initial LZH block type', 'UNSUPPORTED_PROFILE');
133
+ let consumed;
134
+ try {
135
+ // Node's callback typings omit the info:true result shape.
136
+ const inflated = (await inflate(reframed, {
137
+ maxOutputLength: expected,
138
+ windowBits: 14,
139
+ info: true,
140
+ }));
141
+ payload = inflated.buffer;
142
+ consumed = inflated.engine.bytesWritten;
143
+ }
144
+ catch {
145
+ return fail('invalid, truncated, oversized, or unsupported LZH stream');
146
+ }
147
+ if (payload.length !== expected)
148
+ fail('decompressed length mismatch');
149
+ compressedTrailingBytes = reframed.length - consumed;
150
+ // Live SAP buffers have 1–6 residual bytes, sometimes nonzero. Their grammar is unverified.
151
+ // Bound the opaque tail to reject appended stale chunks; this is not an integrity check.
152
+ if (!Number.isSafeInteger(consumed) ||
153
+ consumed < 1 ||
154
+ compressedTrailingBytes < 0 ||
155
+ compressedTrailingBytes > MAX_COMPRESSED_TRAILING_BYTES)
156
+ fail('excess compressed trailer bytes');
157
+ }
158
+ else {
159
+ return fail(`unsupported compression flag ${compression}`, 'UNSUPPORTED_PROFILE');
160
+ }
161
+ return { version, codePage, compressed: compression === 2, compressedTrailingBytes, payload };
162
+ }
163
+ /** Parse one complete named TLINE table; every transition checks its required predecessor. */
164
+ function parseTlinePayload(payload, codePage, limits) {
165
+ // unpackCluster has already rejected all profiles except UTF-16LE / 4103.
166
+ const charBytes = UTF16_BYTES_PER_UNIT;
167
+ const lines = [];
168
+ let p = 0;
169
+ let descriptor = false;
170
+ let ended = false;
171
+ let rowBytes = 0;
172
+ const fields = [];
173
+ let declaredRows;
174
+ let structureStarted = false;
175
+ let structureEnded = false;
176
+ let rowPending = false;
177
+ let tableClosed = false;
178
+ let segmentLength = 0;
179
+ const emit = (offset, length) => {
180
+ if (ended ||
181
+ tableClosed ||
182
+ rowPending ||
183
+ !descriptor ||
184
+ declaredRows === undefined ||
185
+ length !== TLINE_ROW_BYTES ||
186
+ rowBytes !== length ||
187
+ fields.length !== 2 ||
188
+ fields[0] !== TLINE_FORMAT_UNITS * charBytes ||
189
+ fields[1] !== TLINE_TEXT_UNITS * charBytes)
190
+ fail('unexpected TLINE row shape');
191
+ if (lines.length >= limits.maxLines)
192
+ fail('line limit exceeded', 'LIMIT_EXCEEDED');
193
+ const row = range(payload, offset, length);
194
+ lines.push({
195
+ format: textBytes(row.subarray(0, TLINE_FORMAT_UNITS * charBytes), codePage).replace(/ +$/u, ''),
196
+ text: textBytes(row.subarray(TLINE_FORMAT_UNITS * charBytes), codePage).replace(/ +$/u, ''),
197
+ });
198
+ rowPending = true;
199
+ };
200
+ while (p < payload.length) {
201
+ const marker = payload[p];
202
+ // Verified plain and inflated TLINE payloads end exactly at marker 04. CLUSTR has
203
+ // already removed storage padding; accepting zeros here could hide stale chunks.
204
+ if (ended)
205
+ fail('non-padding bytes after container end (trailing padding is unsupported)');
206
+ switch (marker) {
207
+ case MARKER.segment: {
208
+ if (descriptor)
209
+ fail('multiple tables in TLINE container');
210
+ const nameOffset = 32;
211
+ if (uint(payload, p + 1, 1) !== 14 ||
212
+ uint(payload, p + 2, 1) !== 0 ||
213
+ uint(payload, p + 3, 4) !== TLINE_ROW_BYTES)
214
+ fail('unexpected TLINE segment descriptor');
215
+ if (range(payload, p + 12, 20).some((byte) => byte !== 0))
216
+ fail('unsupported segment header fields');
217
+ segmentLength = uint(payload, p + 7, 4);
218
+ const nameLength = uint(payload, p + 11, 1);
219
+ const bytes = charBytes;
220
+ const name = textBytes(range(payload, p + nameOffset, nameLength * bytes), codePage);
221
+ if (name !== 'TLINE')
222
+ fail('container does not hold TLINE');
223
+ range(payload, p, nameOffset + nameLength * bytes);
224
+ p += nameOffset + nameLength * bytes;
225
+ descriptor = true;
226
+ break;
227
+ }
228
+ case MARKER.structureStart:
229
+ if (!descriptor || structureStarted || fields.length || declaredRows !== undefined)
230
+ fail('misplaced structure start');
231
+ if (uint(payload, p + 3, 4) !== TLINE_ROW_BYTES)
232
+ fail('unexpected structure length');
233
+ structureStarted = true;
234
+ p += 7;
235
+ break;
236
+ case MARKER.structureEnd:
237
+ if (!structureStarted || structureEnded || fields.length !== 2 || declaredRows !== undefined)
238
+ fail('misplaced structure end');
239
+ if (uint(payload, p + 3, 4) !== TLINE_ROW_BYTES)
240
+ fail('unexpected structure length');
241
+ structureEnded = true;
242
+ p += 7;
243
+ break;
244
+ case MARKER.characterField: {
245
+ if (!structureStarted || structureEnded || fields.length >= 2)
246
+ fail('unexpected character descriptor');
247
+ const length = uint(payload, p + 3, 4);
248
+ if (length !== (fields.length === 0 ? TLINE_FORMAT_UNITS : TLINE_TEXT_UNITS) * charBytes)
249
+ fail('unexpected TLINE field length');
250
+ fields.push(length);
251
+ rowBytes += length;
252
+ p += 7;
253
+ break;
254
+ }
255
+ case MARKER.table:
256
+ if (!structureEnded || declaredRows !== undefined || lines.length)
257
+ fail('misplaced table descriptor');
258
+ if (uint(payload, p + 1, 4) !== rowBytes)
259
+ fail('table row length mismatch');
260
+ declaredRows = uint(payload, p + 5, 4);
261
+ if (declaredRows > limits.maxLines)
262
+ fail('declared line limit exceeded', 'LIMIT_EXCEEDED');
263
+ p += 9;
264
+ break;
265
+ case MARKER.sizedRow: {
266
+ const length = uint(payload, p + 1, 4);
267
+ emit(p + 5, length);
268
+ p += 5 + length;
269
+ break;
270
+ }
271
+ case MARKER.fixedRow:
272
+ emit(p + 1, rowBytes);
273
+ p += 1 + rowBytes;
274
+ break;
275
+ case MARKER.rowEnd:
276
+ if (!rowPending || tableClosed)
277
+ fail('misplaced row end');
278
+ rowPending = false;
279
+ p++;
280
+ break;
281
+ case MARKER.tableEnd:
282
+ if (declaredRows === undefined || tableClosed || rowPending || declaredRows !== lines.length)
283
+ fail('misplaced table end');
284
+ tableClosed = true;
285
+ p++;
286
+ break;
287
+ case MARKER.containerEnd:
288
+ if (!tableClosed)
289
+ fail('container ended before table');
290
+ if (segmentLength !== 0 && segmentLength !== p)
291
+ fail('segment length mismatch');
292
+ ended = true;
293
+ p++;
294
+ break;
295
+ default:
296
+ return fail(`unsupported container marker ${marker} at ${p}`);
297
+ }
298
+ }
299
+ if (!descriptor || !ended)
300
+ fail('missing TLINE descriptor or end marker');
301
+ if (declaredRows !== undefined && declaredRows !== lines.length)
302
+ fail('declared line count mismatch');
303
+ return lines;
304
+ }
305
+ /** Decode the verified stored-TLINE profile; returned lines retain ITF formatting codes. */
306
+ export async function decodeStxl(data, limits = DEFAULT_LIMITS) {
307
+ const { version, codePage, compressed, compressedTrailingBytes, payload } = await unpackCluster(data, limits);
308
+ const lines = parseTlinePayload(payload, codePage, limits);
309
+ return {
310
+ version,
311
+ codePage,
312
+ compressed,
313
+ compressedTrailingBytes,
314
+ wellFormedUnicode: lines.every((line) => !/\p{Surrogate}/u.test(line.format) && !/\p{Surrogate}/u.test(line.text)),
315
+ lines,
316
+ outputBytes: payload.length,
317
+ };
318
+ }
319
+ //# sourceMappingURL=decoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../../src/adt/stored-text/decoder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /** Stable failure categories for the stored-text reader and codec. */
2
+ export type TextReadErrorCode = 'INVALID_KEY' | 'NOT_FOUND' | 'UNSUPPORTED_PROFILE' | 'UNSUPPORTED_PERSISTENCE' | 'NON_ITF_TEXT' | 'REFERENCE_ERROR' | 'REFERENCE_CYCLE' | 'REFERENCE_LIMIT' | 'INCONSISTENT_READ' | 'CORRUPT_CLUSTER' | 'LIMIT_EXCEEDED';
3
+ /** Messages must describe the failure without including text keys, contents, or raw SAP errors. */
4
+ export declare class TextReadError extends Error {
5
+ readonly code: TextReadErrorCode;
6
+ constructor(code: TextReadErrorCode, message: string, options?: {
7
+ cause?: unknown;
8
+ });
9
+ }
10
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/adt/stored-text/errors.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,WAAW,GACX,qBAAqB,GACrB,yBAAyB,GACzB,cAAc,GACd,iBAAiB,GACjB,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,GACnB,iBAAiB,GACjB,gBAAgB,CAAC;AAErB,mGAAmG;AACnG,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAEjC,YAAY,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAIlF;CACF"}
@@ -0,0 +1,10 @@
1
+ /** Messages must describe the failure without including text keys, contents, or raw SAP errors. */
2
+ export class TextReadError extends Error {
3
+ code;
4
+ constructor(code, message, options) {
5
+ super(`STXL: ${message}`, options);
6
+ this.name = 'TextReadError';
7
+ this.code = code;
8
+ }
9
+ }
10
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/adt/stored-text/errors.ts"],"names":[],"mappings":"AAcA,mGAAmG;AACnG,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAAoB;IAEjC,YAAY,IAAuB,EAAE,OAAe,EAAE,OAA6B;QACjF,KAAK,CAAC,SAAS,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ /** Qualified classic persisted ITF reads through the caller's guarded ADT session. */
2
+ export { TextReadError, type TextReadErrorCode } from './errors.js';
3
+ export { normalizeTextKey } from './key.js';
4
+ export { type ClassicTextBatchItem, type ClassicTextResult, findTextMatches, readClassicText, readClassicTextBatch, } from './reader.js';
5
+ export { withStoredTextSession } from './source.js';
6
+ export type { StoredTextHeader, StoredTextSource, TextDiscovery, TextKey } from './types.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adt/stored-text/index.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,eAAe,EACf,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** Qualified classic persisted ITF reads through the caller's guarded ADT session. */
2
+ export { TextReadError } from './errors.js';
3
+ export { normalizeTextKey } from './key.js';
4
+ export { findTextMatches, readClassicText, readClassicTextBatch, } from './reader.js';
5
+ export { withStoredTextSession } from './source.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adt/stored-text/index.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,OAAO,EAAE,aAAa,EAA0B,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAGL,eAAe,EACf,eAAe,EACf,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { TextKey } from './types.js';
2
+ export declare function normalizeTextKey(value: unknown): TextKey;
3
+ //# sourceMappingURL=key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../../../src/adt/stored-text/key.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAmBxD"}
@@ -0,0 +1,23 @@
1
+ /** Exact SAP text identity. Only fixed-width trailing ASCII padding is normalized. */
2
+ import { TextReadError } from './errors.js';
3
+ const KEY_LENGTHS = { TDOBJECT: 10, TDNAME: 70, TDID: 4, TDSPRAS: 1 };
4
+ export function normalizeTextKey(value) {
5
+ if (!value || typeof value !== 'object' || Array.isArray(value))
6
+ throw new TextReadError('INVALID_KEY', 'provide an exact object, name, ID and SAP language key');
7
+ const input = value;
8
+ const result = {};
9
+ for (const [field, length] of Object.entries(KEY_LENGTHS)) {
10
+ const item = input[field];
11
+ if (typeof item !== 'string' ||
12
+ item.length > length ||
13
+ /\p{Surrogate}/u.test(item) ||
14
+ Array.from(item).some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127))
15
+ throw new TextReadError('INVALID_KEY', `invalid ${field}`);
16
+ const normalized = item.replace(/ +$/u, '');
17
+ if (!normalized)
18
+ throw new TextReadError('INVALID_KEY', `empty ${field}`);
19
+ result[field] = normalized;
20
+ }
21
+ return result;
22
+ }
23
+ //# sourceMappingURL=key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key.js","sourceRoot":"","sources":["../../../src/adt/stored-text/key.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,WAAW,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAW,CAAC;AAE/E,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC7D,MAAM,IAAI,aAAa,CAAC,aAAa,EAAE,wDAAwD,CAAC,CAAC;IACnG,MAAM,KAAK,GAAG,KAAgC,CAAC;IAC/C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,IACE,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,CAAC,MAAM,GAAG,MAAM;YACpB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;YAEtF,MAAM,IAAI,aAAa,CAAC,aAAa,EAAE,WAAW,KAAK,EAAE,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,aAAa,CAAC,aAAa,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC;IAC7B,CAAC;IACD,OAAO,MAA4B,CAAC;AACtC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { type DecodedText, type TextLine } from './decoder.js';
2
+ import { type TextReadErrorCode } from './errors.js';
3
+ import type { StoredTextHeader, StoredTextSource, TextKey } from './types.js';
4
+ export { normalizeTextKey } from './key.js';
5
+ export interface ClassicTextResult {
6
+ requestedKey: TextKey;
7
+ resolvedKey: TextKey;
8
+ header: StoredTextHeader;
9
+ referenceChain: TextKey[];
10
+ lines: TextLine[];
11
+ lineCount: number;
12
+ storage: {
13
+ kind: 'classic-stxh-stxl';
14
+ clusterPresent: boolean;
15
+ consistency: 'reread-matched';
16
+ /** A matching reread is change detection, not a transactional snapshot. */
17
+ snapshotGuaranteed: false;
18
+ codec?: Omit<DecodedText, 'lines'>;
19
+ };
20
+ warnings: Array<'STORED_LINE_COUNT_DIFFERS' | 'LONE_SURROGATE' | 'ITF_COMMANDS_PRESENT'>;
21
+ }
22
+ /** Resolve exact, same-language stored references, then verify headers and bytes by rereading. */
23
+ export declare function readClassicText(source: StoredTextSource, input: unknown): Promise<ClassicTextResult>;
24
+ export type ClassicTextBatchItem = {
25
+ index: number;
26
+ status: 'ok';
27
+ text: ClassicTextResult;
28
+ } | {
29
+ index: number;
30
+ status: 'error';
31
+ key?: TextKey;
32
+ error: {
33
+ code: TextReadErrorCode;
34
+ message: string;
35
+ };
36
+ };
37
+ /** Preserve input order/duplicates; isolate semantic failures, but abort on infrastructure or budget errors. */
38
+ export declare function readClassicTextBatch(source: StoredTextSource, inputs: unknown[]): Promise<ClassicTextBatchItem[]>;
39
+ /** Literal search of an already bounded batch; includes ITF command lines, no rendering or global scan. */
40
+ export declare function findTextMatches(items: ClassicTextBatchItem[], phrase: string): {
41
+ matches: {
42
+ index: number;
43
+ key: TextKey;
44
+ lineNumber: number;
45
+ format: string;
46
+ text: string;
47
+ }[];
48
+ truncated: boolean;
49
+ caseSensitive: boolean;
50
+ scope: 'supplied-batch-only';
51
+ };
52
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../../src/adt/stored-text/reader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAc,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAW5C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,cAAc,EAAE,OAAO,EAAE,CAAC;IAC1B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE;QACP,IAAI,EAAE,mBAAmB,CAAC;QAC1B,cAAc,EAAE,OAAO,CAAC;QACxB,WAAW,EAAE,gBAAgB,CAAC;QAC9B,2EAA2E;QAC3E,kBAAkB,EAAE,KAAK,CAAC;QAC1B,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;KACpC,CAAC;IACF,QAAQ,EAAE,KAAK,CAAC,2BAA2B,GAAG,gBAAgB,GAAG,sBAAsB,CAAC,CAAC;CAC1F;AAED,kGAAkG;AAClG,wBAAsB,eAAe,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmE1G;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GACxD;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,iBAAiB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE3G,gHAAgH;AAChH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,OAAO,EAAE,GAChB,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA0BjC;AAED,2GAA2G;AAC3G,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,EAAE,EAAE,MAAM,EAAE,MAAM;;eAK7C,MAAM;aAAO,OAAO;oBAAc,MAAM;gBAAU,MAAM;cAAQ,MAAM;;;;WAgB3C,qBAAqB;EAC/E"}
@@ -0,0 +1,142 @@
1
+ /** Classic persisted ITF semantics. No SQL, credentials, RFC, text-memory or rendering. */
2
+ import { createHash } from 'node:crypto';
3
+ import { decodeStxl } from './decoder.js';
4
+ import { TextReadError } from './errors.js';
5
+ import { normalizeTextKey } from './key.js';
6
+ export { normalizeTextKey } from './key.js';
7
+ const MAX_REFERENCE_HOPS = 8;
8
+ const MAX_BATCH_KEYS = 25;
9
+ const MAX_BATCH_LINES = 10_000;
10
+ const MAX_BATCH_JSON_BYTES = 2 * 1024 * 1024;
11
+ const keyId = (key) => JSON.stringify([key.TDOBJECT, key.TDNAME, key.TDID, key.TDSPRAS]);
12
+ const fingerprint = (bytes) => bytes === undefined ? 'absent' : createHash('sha256').update(bytes).digest('hex');
13
+ /** Resolve exact, same-language stored references, then verify headers and bytes by rereading. */
14
+ export async function readClassicText(source, input) {
15
+ const requestedKey = normalizeTextKey(input);
16
+ let key = requestedKey;
17
+ const headers = [];
18
+ const visited = new Set();
19
+ for (;;) {
20
+ if (visited.has(keyId(key)))
21
+ throw new TextReadError('REFERENCE_CYCLE', 'stored reference cycle');
22
+ visited.add(keyId(key));
23
+ try {
24
+ await source.assertSupportedKey(key);
25
+ }
26
+ catch (error) {
27
+ if (headers.length && error instanceof TextReadError && error.code === 'INVALID_KEY')
28
+ throw new TextReadError('REFERENCE_ERROR', 'reference target has an invalid configured key');
29
+ throw error;
30
+ }
31
+ const header = await source.readHeader(key);
32
+ if (!header)
33
+ throw new TextReadError(headers.length ? 'REFERENCE_ERROR' : 'NOT_FOUND', headers.length ? 'reference target has no classic stored header' : 'no header in classic storage');
34
+ if (header.textType.replace(/ +$/u, ''))
35
+ throw new TextReadError('NON_ITF_TEXT', 'non-ITF text requires a different storage reader');
36
+ if (header.legacyReference)
37
+ throw new TextReadError('UNSUPPORTED_PROFILE', 'legacy or incomplete reference metadata requires ITCRF support');
38
+ headers.push(header);
39
+ if (!header.reference)
40
+ break;
41
+ if (headers.length > MAX_REFERENCE_HOPS)
42
+ throw new TextReadError('REFERENCE_LIMIT', 'stored reference hop limit exceeded');
43
+ key = normalizeTextKey(header.reference);
44
+ if (key.TDSPRAS !== requestedKey.TDSPRAS)
45
+ throw new TextReadError('REFERENCE_ERROR', 'stored references must retain the requested language');
46
+ }
47
+ const bytes = await source.readCluster(key);
48
+ const decoded = bytes === undefined ? undefined : await decodeStxl(bytes);
49
+ // A count alone is insufficient: references and valid header-only texts can have stale counts.
50
+ for (const original of headers) {
51
+ const current = await source.readHeader(original.key);
52
+ if (!current || current.revision !== original.revision)
53
+ throw new TextReadError('INCONSISTENT_READ', 'stored header changed during the read; retry the exact key');
54
+ }
55
+ if (fingerprint(await source.readCluster(key)) !== fingerprint(bytes))
56
+ throw new TextReadError('INCONSISTENT_READ', 'stored chunks changed during the read; retry the exact key');
57
+ const lines = decoded?.lines ?? [];
58
+ const warnings = [];
59
+ if (headers[headers.length - 1].storedLineCount !== lines.length)
60
+ warnings.push('STORED_LINE_COUNT_DIFFERS');
61
+ if (decoded && !decoded.wellFormedUnicode)
62
+ warnings.push('LONE_SURROGATE');
63
+ if (lines.some((line) => line.format === '/:'))
64
+ warnings.push('ITF_COMMANDS_PRESENT');
65
+ const codec = decoded ? (({ lines: _lines, ...details }) => details)(decoded) : undefined;
66
+ return {
67
+ requestedKey,
68
+ resolvedKey: key,
69
+ header: headers[0],
70
+ referenceChain: headers.map((header) => header.key),
71
+ lines,
72
+ lineCount: lines.length,
73
+ storage: {
74
+ kind: 'classic-stxh-stxl',
75
+ clusterPresent: bytes !== undefined,
76
+ consistency: 'reread-matched',
77
+ snapshotGuaranteed: false,
78
+ codec,
79
+ },
80
+ warnings,
81
+ };
82
+ }
83
+ /** Preserve input order/duplicates; isolate semantic failures, but abort on infrastructure or budget errors. */
84
+ export async function readClassicTextBatch(source, inputs) {
85
+ if (!Array.isArray(inputs) || inputs.length < 1 || inputs.length > MAX_BATCH_KEYS)
86
+ throw new TextReadError('LIMIT_EXCEEDED', `batch must contain 1–${MAX_BATCH_KEYS} exact keys`);
87
+ const completed = new Map();
88
+ const results = [];
89
+ let totalLines = 0;
90
+ let totalBytes = 2; // JSON array brackets.
91
+ for (const [index, input] of inputs.entries()) {
92
+ let key;
93
+ let item;
94
+ try {
95
+ key = normalizeTextKey(input);
96
+ const previous = completed.get(keyId(key));
97
+ item = previous ? { ...previous, index } : { index, status: 'ok', text: await readClassicText(source, key) };
98
+ }
99
+ catch (error) {
100
+ if (!(error instanceof TextReadError) || error.code === 'LIMIT_EXCEEDED')
101
+ throw error;
102
+ item = { index, status: 'error', key, error: { code: error.code, message: error.message } };
103
+ }
104
+ if (key)
105
+ completed.set(keyId(key), item);
106
+ totalLines += item.status === 'ok' ? item.text.lineCount : 0;
107
+ totalBytes += Buffer.byteLength(JSON.stringify(item)) + (index > 0 ? 1 : 0);
108
+ if (totalLines > MAX_BATCH_LINES || totalBytes > MAX_BATCH_JSON_BYTES)
109
+ throw new TextReadError('LIMIT_EXCEEDED', 'batch decoded result budget exceeded; request fewer texts');
110
+ results.push(item);
111
+ }
112
+ return results;
113
+ }
114
+ /** Literal search of an already bounded batch; includes ITF command lines, no rendering or global scan. */
115
+ export function findTextMatches(items, phrase) {
116
+ if (!Array.isArray(items) || items.length > MAX_BATCH_KEYS)
117
+ throw new TextReadError('LIMIT_EXCEEDED', 'search must use a bounded text batch');
118
+ if (typeof phrase !== 'string' || !phrase.length || phrase.length > 200)
119
+ throw new TextReadError('INVALID_KEY', 'search phrase must contain 1–200 characters');
120
+ const matches = [];
121
+ let truncated = false;
122
+ let scanned = 0;
123
+ for (const item of items) {
124
+ if (item.status !== 'ok')
125
+ continue;
126
+ for (const [lineIndex, line] of item.text.lines.entries()) {
127
+ if (++scanned > MAX_BATCH_LINES)
128
+ throw new TextReadError('LIMIT_EXCEEDED', 'search line budget exceeded');
129
+ if (!line.text.includes(phrase))
130
+ continue;
131
+ if (matches.length === 50) {
132
+ truncated = true;
133
+ break;
134
+ }
135
+ matches.push({ index: item.index, key: item.text.requestedKey, lineNumber: lineIndex + 1, ...line });
136
+ }
137
+ if (truncated)
138
+ break;
139
+ }
140
+ return { matches, truncated, caseSensitive: true, scope: 'supplied-batch-only' };
141
+ }
142
+ //# sourceMappingURL=reader.js.map