@oh-my-pi/pi-utils 16.2.2 → 16.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/types/sanitize-text.d.ts +8 -0
- package/package.json +2 -2
- package/src/ptree.ts +6 -1
- package/src/sanitize-text.ts +30 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.2.3] - 2026-06-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `escapeXmlAttribute` utility function for safe XML attribute value encoding.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed a crash in `ptree.ChildProcess.bytes()` and the `ssh://` read path when handling large subprocess outputs (over 128 KB) under Bun by ensuring it consistently returns a `Uint8Array`.
|
|
14
|
+
|
|
5
15
|
## [16.2.0] - 2026-06-27
|
|
6
16
|
|
|
7
17
|
### Added
|
|
@@ -19,3 +19,11 @@ export declare function sanitizeText(text: string): string;
|
|
|
19
19
|
* — use it for element text, not attribute values.
|
|
20
20
|
*/
|
|
21
21
|
export declare function escapeXmlText(input: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Escape XML-significant characters for an attribute VALUE: the three body
|
|
24
|
+
* characters (`&`, `<`, `>`) plus the double quote (`"` → `"`) that would
|
|
25
|
+
* otherwise close the attribute. Allocation-conscious: returns the input
|
|
26
|
+
* unchanged (same reference) when nothing needs escaping. Use it for attribute
|
|
27
|
+
* values; {@link escapeXmlText} is for element bodies and leaves `"` intact.
|
|
28
|
+
*/
|
|
29
|
+
export declare function escapeXmlAttribute(input: string): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-utils",
|
|
4
|
-
"version": "16.2.
|
|
4
|
+
"version": "16.2.3",
|
|
5
5
|
"description": "Shared utilities for pi packages",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"fmt": "biome format --write ."
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@oh-my-pi/pi-natives": "16.2.
|
|
34
|
+
"@oh-my-pi/pi-natives": "16.2.3",
|
|
35
35
|
"handlebars": "^4.7.9",
|
|
36
36
|
"winston": "^3.19.0",
|
|
37
37
|
"winston-daily-rotate-file": "^5.0.0"
|
package/src/ptree.ts
CHANGED
|
@@ -247,7 +247,12 @@ export class ChildProcess<In extends InMask = InMask> {
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
async bytes(): Promise<Uint8Array> {
|
|
250
|
-
|
|
250
|
+
// Bun's `Response(stream).bytes()` returns the raw `ArrayBuffer` once the
|
|
251
|
+
// stream emits more than one chunk (subprocess stdout chunks past ~128 KB).
|
|
252
|
+
// Normalize at the contract boundary so every caller — SSH read,
|
|
253
|
+
// `decodeUtf8Text`, callers slicing with `.subarray` — sees a `Uint8Array`.
|
|
254
|
+
const body = (await new Response(this.stdout).bytes()) as Uint8Array | ArrayBuffer;
|
|
255
|
+
return body instanceof Uint8Array ? body : new Uint8Array(body);
|
|
251
256
|
}
|
|
252
257
|
|
|
253
258
|
// ── Wait ─────────────────────────────────────────────────────────────
|
package/src/sanitize-text.ts
CHANGED
|
@@ -64,3 +64,33 @@ export function escapeXmlText(input: string): string {
|
|
|
64
64
|
}
|
|
65
65
|
return output;
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Escape XML-significant characters for an attribute VALUE: the three body
|
|
70
|
+
* characters (`&`, `<`, `>`) plus the double quote (`"` → `"`) that would
|
|
71
|
+
* otherwise close the attribute. Allocation-conscious: returns the input
|
|
72
|
+
* unchanged (same reference) when nothing needs escaping. Use it for attribute
|
|
73
|
+
* values; {@link escapeXmlText} is for element bodies and leaves `"` intact.
|
|
74
|
+
*/
|
|
75
|
+
export function escapeXmlAttribute(input: string): string {
|
|
76
|
+
let firstEscapable = -1;
|
|
77
|
+
for (let index = 0; index < input.length; index++) {
|
|
78
|
+
const char = input.charCodeAt(index);
|
|
79
|
+
if (char === 38 || char === 60 || char === 62 || char === 34) {
|
|
80
|
+
firstEscapable = index;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (firstEscapable === -1) return input;
|
|
85
|
+
|
|
86
|
+
let output = input.slice(0, firstEscapable);
|
|
87
|
+
for (let index = firstEscapable; index < input.length; index++) {
|
|
88
|
+
const char = input[index];
|
|
89
|
+
if (char === "&") output += "&";
|
|
90
|
+
else if (char === "<") output += "<";
|
|
91
|
+
else if (char === ">") output += ">";
|
|
92
|
+
else if (char === '"') output += """;
|
|
93
|
+
else output += char;
|
|
94
|
+
}
|
|
95
|
+
return output;
|
|
96
|
+
}
|