@kvell007/embed-labs-cli 0.1.0-alpha.1 → 0.1.0-alpha.11
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/README.md +35 -13
- package/dist/image-compose.d.ts +38 -0
- package/dist/image-compose.js +334 -0
- package/dist/image-compose.js.map +1 -0
- package/dist/index.js +1182 -38
- package/dist/index.js.map +1 -1
- package/dist/local-toolchain.d.ts +173 -0
- package/dist/local-toolchain.js +834 -0
- package/dist/local-toolchain.js.map +1 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -4,14 +4,18 @@ Command-line interface for Embed Labs Cloud.
|
|
|
4
4
|
|
|
5
5
|
## Package Status
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
The experimental personal-scope CLI is published for integration testing as
|
|
8
|
+
`@kvell007/embed-labs-cli`. The long-term `@embed-labs/cli` release is still
|
|
9
|
+
pending organization scope ownership, license, support URLs, and release policy.
|
|
10
|
+
The workspace manifest intentionally remains marked `private: true`; release
|
|
11
|
+
scripts stage temporary public packages without changing the source package
|
|
12
|
+
names.
|
|
11
13
|
|
|
12
14
|
## What It Provides
|
|
13
15
|
|
|
14
|
-
- `
|
|
16
|
+
- `embedlabs` binary exposed by the npm `bin` entry after install.
|
|
17
|
+
- `embed` remains exposed as a compatibility alias while existing scripts,
|
|
18
|
+
plugin bridges, and docs finish migrating.
|
|
15
19
|
- First-run diagnostic command for CLI runtime, auth, Local Bridge, local scans,
|
|
16
20
|
and Cloud API readiness.
|
|
17
21
|
- Local bridge startup and status commands.
|
|
@@ -34,12 +38,21 @@ public SDK until a versioned API contract is approved.
|
|
|
34
38
|
|
|
35
39
|
## Install
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
Current experimental npm install:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g @kvell007/embed-labs-cli@alpha
|
|
45
|
+
embedlabs --help
|
|
46
|
+
embedlabs help getting-started
|
|
47
|
+
embedlabs plugin install all
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Future organization-scope install after final release approval:
|
|
38
51
|
|
|
39
52
|
```bash
|
|
40
53
|
npm install -g @embed-labs/cli
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
embedlabs --help
|
|
55
|
+
embedlabs help getting-started
|
|
43
56
|
```
|
|
44
57
|
|
|
45
58
|
Local package testing before public npm publish:
|
|
@@ -48,7 +61,7 @@ Local package testing before public npm publish:
|
|
|
48
61
|
npm run build
|
|
49
62
|
npm pack --workspace @embed-labs/cli --pack-destination ./tmp
|
|
50
63
|
npm install -g ./tmp/embed-labs-cli-*.tgz
|
|
51
|
-
|
|
64
|
+
embedlabs --help
|
|
52
65
|
```
|
|
53
66
|
|
|
54
67
|
Internal workspace usage without global install:
|
|
@@ -62,10 +75,10 @@ node packages/cli/dist/index.js help getting-started
|
|
|
62
75
|
## Quick Start
|
|
63
76
|
|
|
64
77
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
embedlabs --help
|
|
79
|
+
embedlabs help getting-started
|
|
80
|
+
embedlabs doctor
|
|
81
|
+
embedlabs auth login --token <token>
|
|
69
82
|
```
|
|
70
83
|
|
|
71
84
|
For the current public API plus local TaishanPi verification path, see
|
|
@@ -88,6 +101,8 @@ For local hardware access:
|
|
|
88
101
|
```bash
|
|
89
102
|
embed bridge start
|
|
90
103
|
embed device list
|
|
104
|
+
embed tool call wifi.scan --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
105
|
+
embed tool call chip.temperature --input-json '{"host":"198.19.77.2","user":"root"}'
|
|
91
106
|
embed flash plan --board <rp2350|taishanpi> --artifact ./artifact.bin
|
|
92
107
|
```
|
|
93
108
|
|
|
@@ -160,6 +175,13 @@ embed debug tools [--json]
|
|
|
160
175
|
|
|
161
176
|
embed device list [--json]
|
|
162
177
|
embed device probe --host <host> --ports 22,15301 [--serial-path <path>] [--timeout-ms 1000] [--json]
|
|
178
|
+
embed tool list [--json]
|
|
179
|
+
embed tool call wifi.scan --input-json '{"host":"198.19.77.2","user":"root"}' [--json]
|
|
180
|
+
embed tool call bluetooth.scan --input-json '{"host":"198.19.77.2","user":"root","duration_seconds":8}' [--json]
|
|
181
|
+
embed tool call chip.cpu.frequency --input-json '{"host":"198.19.77.2","user":"root"}' [--json]
|
|
182
|
+
embed tool call chip.temperature --input-json '{"host":"198.19.77.2","user":"root"}' [--json]
|
|
183
|
+
embed tool call qml.runtime.status --input-json '{"host":"198.19.77.2","user":"root","port":18130}' [--json]
|
|
184
|
+
embed tool call qml.runtime.start --input-json '{"host":"198.19.77.2","user":"root","port":18130}' [--json]
|
|
163
185
|
|
|
164
186
|
embed serial list [--json]
|
|
165
187
|
embed serial capture --path <port> [--baud 115200] [--duration 5] [--json]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface BootLogoComposeOptions {
|
|
2
|
+
packagePath: string;
|
|
3
|
+
baseImagePath: string;
|
|
4
|
+
outputImagePath: string;
|
|
5
|
+
manifestPath?: string;
|
|
6
|
+
force?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface BootLogoComposeResult {
|
|
9
|
+
schema_version: "1.0";
|
|
10
|
+
operation_kind: "image.boot_logo.compose" | "image.dtb.compose";
|
|
11
|
+
board_id: string;
|
|
12
|
+
variant_id?: string;
|
|
13
|
+
package_path: string;
|
|
14
|
+
base_image_path: string;
|
|
15
|
+
output_image_path: string;
|
|
16
|
+
manifest_path: string;
|
|
17
|
+
package_sha256: string;
|
|
18
|
+
base_image_sha256: string;
|
|
19
|
+
output_image_sha256: string;
|
|
20
|
+
logo_sha256?: string;
|
|
21
|
+
kernel_logo_sha256?: string;
|
|
22
|
+
dtb_sha256?: string;
|
|
23
|
+
patch_operations_total: number;
|
|
24
|
+
patch_operations_applied: number;
|
|
25
|
+
replacement_applied: boolean;
|
|
26
|
+
ready_for_flash: boolean;
|
|
27
|
+
requires_board_specific_patcher: boolean;
|
|
28
|
+
local_merge_strategy: string;
|
|
29
|
+
cross_platform: true;
|
|
30
|
+
platform: NodeJS.Platform;
|
|
31
|
+
arch: string;
|
|
32
|
+
node_version: string;
|
|
33
|
+
observed_at: string;
|
|
34
|
+
summary_for_user: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function composeBootLogoPackage(options: BootLogoComposeOptions): Promise<BootLogoComposeResult>;
|
|
37
|
+
export declare function defaultBootLogoComposeManifestPath(outputImagePath: string): string;
|
|
38
|
+
export declare function safeBootLogoComposeOutputName(name: string): string;
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
3
|
+
import { copyFile, mkdir, open, readFile, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { basename, dirname, resolve } from "node:path";
|
|
5
|
+
export async function composeBootLogoPackage(options) {
|
|
6
|
+
const packagePath = resolve(options.packagePath);
|
|
7
|
+
const baseImagePath = resolve(options.baseImagePath);
|
|
8
|
+
const outputImagePath = resolve(options.outputImagePath);
|
|
9
|
+
const manifestPath = resolve(options.manifestPath ?? `${outputImagePath}.embed-logo-compose.json`);
|
|
10
|
+
if (baseImagePath === outputImagePath) {
|
|
11
|
+
throw new Error("output image must be different from base image.");
|
|
12
|
+
}
|
|
13
|
+
await assertReadableFile(packagePath, "package");
|
|
14
|
+
await assertReadableFile(baseImagePath, "base image");
|
|
15
|
+
if (!options.force && await pathExists(outputImagePath)) {
|
|
16
|
+
throw new Error(`output image already exists: ${outputImagePath}. Use --force to overwrite it.`);
|
|
17
|
+
}
|
|
18
|
+
const packageBytes = await readFile(packagePath);
|
|
19
|
+
const packageSha256 = sha256Buffer(packageBytes);
|
|
20
|
+
const payload = parseBootLogoPackage(packageBytes, packagePath);
|
|
21
|
+
let logoSha256;
|
|
22
|
+
let dtbSha256;
|
|
23
|
+
if (payload.kind === "boot-logo-package") {
|
|
24
|
+
const logoBytes = decodeBase64Strict(payload.logo?.content_base64, "logo.content_base64");
|
|
25
|
+
logoSha256 = sha256Buffer(logoBytes);
|
|
26
|
+
if (payload.logo?.sha256 && payload.logo.sha256.toLowerCase() !== logoSha256) {
|
|
27
|
+
throw new Error("logo.sha256 does not match logo.content_base64.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const dtbBytes = decodeBase64Strict(payload.dtb?.content_base64, "dtb.content_base64");
|
|
32
|
+
dtbSha256 = sha256Buffer(dtbBytes);
|
|
33
|
+
if (payload.dtb?.sha256 && payload.dtb.sha256.toLowerCase() !== dtbSha256) {
|
|
34
|
+
throw new Error("dtb.sha256 does not match dtb.content_base64.");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
let kernelLogoSha256;
|
|
38
|
+
if (payload.kernel_logo?.content_base64) {
|
|
39
|
+
const kernelLogoBytes = decodeBase64Strict(payload.kernel_logo.content_base64, "kernel_logo.content_base64");
|
|
40
|
+
kernelLogoSha256 = sha256Buffer(kernelLogoBytes);
|
|
41
|
+
if (payload.kernel_logo.sha256 && payload.kernel_logo.sha256.toLowerCase() !== kernelLogoSha256) {
|
|
42
|
+
throw new Error("kernel_logo.sha256 does not match kernel_logo.content_base64.");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const baseImageInfo = await stat(baseImagePath);
|
|
46
|
+
if (!baseImageInfo.isFile()) {
|
|
47
|
+
throw new Error(`base image is not a file: ${baseImagePath}`);
|
|
48
|
+
}
|
|
49
|
+
const baseImageSha256 = await sha256File(baseImagePath);
|
|
50
|
+
const expectedBaseSha256 = payload.local_merge?.base_image?.sha256;
|
|
51
|
+
if (expectedBaseSha256 !== undefined) {
|
|
52
|
+
if (!isSha256Hex(expectedBaseSha256)) {
|
|
53
|
+
throw new Error("local_merge.base_image.sha256 must be a SHA256 hex string.");
|
|
54
|
+
}
|
|
55
|
+
if (expectedBaseSha256.toLowerCase() !== baseImageSha256) {
|
|
56
|
+
throw new Error(`base image SHA256 mismatch. Expected ${expectedBaseSha256.toLowerCase()} but found ${baseImageSha256}.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const expectedBaseSize = payload.local_merge?.base_image?.size_bytes;
|
|
60
|
+
if (expectedBaseSize !== undefined
|
|
61
|
+
&& (!Number.isSafeInteger(expectedBaseSize) || expectedBaseSize < 0 || expectedBaseSize !== baseImageInfo.size)) {
|
|
62
|
+
throw new Error(`base image size mismatch. Expected ${expectedBaseSize} bytes but found ${baseImageInfo.size}.`);
|
|
63
|
+
}
|
|
64
|
+
await mkdir(dirname(outputImagePath), { recursive: true });
|
|
65
|
+
await copyFile(baseImagePath, outputImagePath);
|
|
66
|
+
const patchOperations = parsePatchOperations(payload.local_merge?.patch_operations ?? []);
|
|
67
|
+
const applied = await applyPatchOperations(outputImagePath, {
|
|
68
|
+
size: baseImageInfo.size,
|
|
69
|
+
sha256: baseImageSha256
|
|
70
|
+
}, patchOperations);
|
|
71
|
+
const outputImageSha256 = await sha256File(outputImagePath);
|
|
72
|
+
const replacementApplied = applied > 0;
|
|
73
|
+
const readyForFlash = replacementApplied
|
|
74
|
+
&& applied === patchOperations.length
|
|
75
|
+
&& payload.local_merge?.ready_for_flash_when_all_patch_operations_apply !== false;
|
|
76
|
+
const requiresBoardSpecificPatcher = !readyForFlash;
|
|
77
|
+
const observedAt = new Date().toISOString();
|
|
78
|
+
const localMergeStrategy = payload.local_merge?.strategy
|
|
79
|
+
?? (patchOperations.length > 0 ? "byte_patch_operations" : "copy_with_manifest");
|
|
80
|
+
const result = {
|
|
81
|
+
schema_version: "1.0",
|
|
82
|
+
operation_kind: payload.kind === "dtb-package" ? "image.dtb.compose" : "image.boot_logo.compose",
|
|
83
|
+
board_id: requiredString(payload.board_id, "board_id"),
|
|
84
|
+
variant_id: optionalString(payload.variant_id),
|
|
85
|
+
package_path: packagePath,
|
|
86
|
+
base_image_path: baseImagePath,
|
|
87
|
+
output_image_path: outputImagePath,
|
|
88
|
+
manifest_path: manifestPath,
|
|
89
|
+
package_sha256: packageSha256,
|
|
90
|
+
base_image_sha256: baseImageSha256,
|
|
91
|
+
output_image_sha256: outputImageSha256,
|
|
92
|
+
logo_sha256: logoSha256,
|
|
93
|
+
kernel_logo_sha256: kernelLogoSha256,
|
|
94
|
+
dtb_sha256: dtbSha256,
|
|
95
|
+
patch_operations_total: patchOperations.length,
|
|
96
|
+
patch_operations_applied: applied,
|
|
97
|
+
replacement_applied: replacementApplied,
|
|
98
|
+
ready_for_flash: readyForFlash,
|
|
99
|
+
requires_board_specific_patcher: requiresBoardSpecificPatcher,
|
|
100
|
+
local_merge_strategy: localMergeStrategy,
|
|
101
|
+
cross_platform: true,
|
|
102
|
+
platform: process.platform,
|
|
103
|
+
arch: process.arch,
|
|
104
|
+
node_version: process.version,
|
|
105
|
+
observed_at: observedAt,
|
|
106
|
+
summary_for_user: readyForFlash
|
|
107
|
+
? `${imagePackageLabel(payload)} package was merged into the local base image. Review the manifest before any approved flash.`
|
|
108
|
+
: `${imagePackageLabel(payload)} package and base image were validated and copied, but this package does not include board-specific byte patches yet; do not flash the output as a completed image replacement.`
|
|
109
|
+
};
|
|
110
|
+
await mkdir(dirname(manifestPath), { recursive: true });
|
|
111
|
+
await writeFile(manifestPath, `${JSON.stringify({
|
|
112
|
+
...result,
|
|
113
|
+
package: {
|
|
114
|
+
schema_version: payload.schema_version,
|
|
115
|
+
kind: payload.kind,
|
|
116
|
+
logo_name: payload.logo?.name,
|
|
117
|
+
kernel_logo_name: payload.kernel_logo?.name,
|
|
118
|
+
dtb_name: payload.dtb?.name,
|
|
119
|
+
execution: payload.execution,
|
|
120
|
+
local_merge: {
|
|
121
|
+
strategy: localMergeStrategy,
|
|
122
|
+
patch_operations_total: patchOperations.length,
|
|
123
|
+
base_image: payload.local_merge?.base_image
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}, null, 2)}\n`, "utf8");
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
function parseBootLogoPackage(bytes, filePath) {
|
|
130
|
+
let parsed;
|
|
131
|
+
try {
|
|
132
|
+
parsed = JSON.parse(bytes.toString("utf8"));
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
throw new Error(`boot-logo package is not valid JSON: ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
136
|
+
}
|
|
137
|
+
if (!isRecord(parsed)) {
|
|
138
|
+
throw new Error(`boot-logo package must be a JSON object: ${filePath}`);
|
|
139
|
+
}
|
|
140
|
+
const payload = parsed;
|
|
141
|
+
if (payload.kind !== "boot-logo-package" && payload.kind !== "dtb-package") {
|
|
142
|
+
throw new Error(`image patch package kind must be boot-logo-package or dtb-package: ${payload.kind ?? "<missing>"}`);
|
|
143
|
+
}
|
|
144
|
+
requiredString(payload.board_id, "board_id");
|
|
145
|
+
if (payload.kind === "boot-logo-package" && (!isRecord(payload.logo) || typeof payload.logo.content_base64 !== "string")) {
|
|
146
|
+
throw new Error("boot-logo package must include logo.content_base64.");
|
|
147
|
+
}
|
|
148
|
+
if (payload.kind === "dtb-package" && (!isRecord(payload.dtb) || typeof payload.dtb.content_base64 !== "string")) {
|
|
149
|
+
throw new Error("dtb package must include dtb.content_base64.");
|
|
150
|
+
}
|
|
151
|
+
if (payload.execution?.local_merge_required !== true) {
|
|
152
|
+
throw new Error("image patch package must declare execution.local_merge_required=true.");
|
|
153
|
+
}
|
|
154
|
+
return payload;
|
|
155
|
+
}
|
|
156
|
+
function imagePackageLabel(payload) {
|
|
157
|
+
return payload.kind === "dtb-package" ? "DTB" : "Boot-logo";
|
|
158
|
+
}
|
|
159
|
+
function parsePatchOperations(items) {
|
|
160
|
+
const operations = [];
|
|
161
|
+
for (const [index, item] of items.entries()) {
|
|
162
|
+
if (!isRecord(item)) {
|
|
163
|
+
throw new Error(`local_merge.patch_operations[${index}] must be an object.`);
|
|
164
|
+
}
|
|
165
|
+
if (item.type === "replace_file") {
|
|
166
|
+
if (typeof item.content_base64 !== "string" || item.content_base64.length === 0) {
|
|
167
|
+
throw new Error(`replace_file content_base64 is required at index ${index}.`);
|
|
168
|
+
}
|
|
169
|
+
if (item.content_sha256 !== undefined && !isSha256Hex(item.content_sha256)) {
|
|
170
|
+
throw new Error(`replace_file content_sha256 must be a SHA256 hex string at index ${index}.`);
|
|
171
|
+
}
|
|
172
|
+
if (item.expected_base_sha256 !== undefined && !isSha256Hex(item.expected_base_sha256)) {
|
|
173
|
+
throw new Error(`replace_file expected_base_sha256 must be a SHA256 hex string at index ${index}.`);
|
|
174
|
+
}
|
|
175
|
+
const expectedBaseLength = item.expected_base_length;
|
|
176
|
+
if (expectedBaseLength !== undefined && (typeof expectedBaseLength !== "number" || !Number.isSafeInteger(expectedBaseLength) || expectedBaseLength < 0)) {
|
|
177
|
+
throw new Error(`replace_file expected_base_length must be a safe non-negative integer at index ${index}.`);
|
|
178
|
+
}
|
|
179
|
+
operations.push({
|
|
180
|
+
type: "replace_file",
|
|
181
|
+
content_base64: item.content_base64,
|
|
182
|
+
content_sha256: typeof item.content_sha256 === "string" ? item.content_sha256.toLowerCase() : undefined,
|
|
183
|
+
expected_base_sha256: typeof item.expected_base_sha256 === "string" ? item.expected_base_sha256.toLowerCase() : undefined,
|
|
184
|
+
expected_base_length: typeof expectedBaseLength === "number" ? expectedBaseLength : undefined,
|
|
185
|
+
label: typeof item.label === "string" ? item.label : undefined
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (item.type !== "replace_bytes") {
|
|
190
|
+
throw new Error(`Unsupported patch operation type at index ${index}: ${String(item.type)}`);
|
|
191
|
+
}
|
|
192
|
+
const offset = item.offset;
|
|
193
|
+
if (typeof offset !== "number" || !Number.isSafeInteger(offset) || offset < 0) {
|
|
194
|
+
throw new Error(`replace_bytes offset must be a safe non-negative integer at index ${index}.`);
|
|
195
|
+
}
|
|
196
|
+
if (typeof item.content_base64 !== "string" || item.content_base64.length === 0) {
|
|
197
|
+
throw new Error(`replace_bytes content_base64 is required at index ${index}.`);
|
|
198
|
+
}
|
|
199
|
+
if (item.expected_sha256 !== undefined && !isSha256Hex(item.expected_sha256)) {
|
|
200
|
+
throw new Error(`replace_bytes expected_sha256 must be a SHA256 hex string at index ${index}.`);
|
|
201
|
+
}
|
|
202
|
+
const expectedLength = item.expected_length;
|
|
203
|
+
if (expectedLength !== undefined && (typeof expectedLength !== "number" || !Number.isSafeInteger(expectedLength) || expectedLength < 0)) {
|
|
204
|
+
throw new Error(`replace_bytes expected_length must be a safe non-negative integer at index ${index}.`);
|
|
205
|
+
}
|
|
206
|
+
operations.push({
|
|
207
|
+
type: "replace_bytes",
|
|
208
|
+
offset,
|
|
209
|
+
content_base64: item.content_base64,
|
|
210
|
+
expected_sha256: typeof item.expected_sha256 === "string" ? item.expected_sha256.toLowerCase() : undefined,
|
|
211
|
+
expected_length: typeof expectedLength === "number" ? expectedLength : undefined,
|
|
212
|
+
label: typeof item.label === "string" ? item.label : undefined
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return operations;
|
|
216
|
+
}
|
|
217
|
+
async function applyPatchOperations(outputImagePath, baseImage, operations) {
|
|
218
|
+
if (operations.length === 0) {
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
const replaceFileOperations = operations.filter((operation) => operation.type === "replace_file");
|
|
222
|
+
if (replaceFileOperations.length > 1 || (replaceFileOperations.length === 1 && operations.length > 1)) {
|
|
223
|
+
throw new Error("replace_file must be the only boot-logo patch operation.");
|
|
224
|
+
}
|
|
225
|
+
if (replaceFileOperations.length === 1) {
|
|
226
|
+
const operation = replaceFileOperations[0];
|
|
227
|
+
if (operation.expected_base_length !== undefined && operation.expected_base_length !== baseImage.size) {
|
|
228
|
+
throw new Error(`replace_file expected base length mismatch. Expected ${operation.expected_base_length} bytes but found ${baseImage.size}.`);
|
|
229
|
+
}
|
|
230
|
+
if (operation.expected_base_sha256 !== undefined && operation.expected_base_sha256 !== baseImage.sha256) {
|
|
231
|
+
throw new Error(`replace_file expected base SHA256 mismatch. Expected ${operation.expected_base_sha256} but found ${baseImage.sha256}.`);
|
|
232
|
+
}
|
|
233
|
+
const content = decodeBase64Strict(operation.content_base64, "local_merge.patch_operations[0].content_base64");
|
|
234
|
+
const contentSha256 = sha256Buffer(content);
|
|
235
|
+
if (operation.content_sha256 !== undefined && operation.content_sha256 !== contentSha256) {
|
|
236
|
+
throw new Error(`replace_file content SHA256 mismatch. Expected ${operation.content_sha256} but found ${contentSha256}.`);
|
|
237
|
+
}
|
|
238
|
+
await writeFile(outputImagePath, content);
|
|
239
|
+
return 1;
|
|
240
|
+
}
|
|
241
|
+
let applied = 0;
|
|
242
|
+
const handle = await open(outputImagePath, "r+");
|
|
243
|
+
try {
|
|
244
|
+
for (const [index, operation] of operations.entries()) {
|
|
245
|
+
if (operation.type !== "replace_bytes") {
|
|
246
|
+
throw new Error(`Unsupported patch operation type at index ${index}: ${operation.type}`);
|
|
247
|
+
}
|
|
248
|
+
const content = decodeBase64Strict(operation.content_base64, `local_merge.patch_operations[${index}].content_base64`);
|
|
249
|
+
const expectedLength = operation.expected_length ?? content.length;
|
|
250
|
+
if (operation.offset + expectedLength > baseImage.size) {
|
|
251
|
+
throw new Error(`replace_bytes operation ${index} exceeds base image size.`);
|
|
252
|
+
}
|
|
253
|
+
if (operation.expected_sha256) {
|
|
254
|
+
const existing = Buffer.alloc(expectedLength);
|
|
255
|
+
await handle.read(existing, 0, expectedLength, operation.offset);
|
|
256
|
+
const existingSha256 = sha256Buffer(existing);
|
|
257
|
+
if (existingSha256 !== operation.expected_sha256) {
|
|
258
|
+
throw new Error(`replace_bytes operation ${index} expected SHA256 mismatch at offset ${operation.offset}.`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (operation.offset + content.length > baseImage.size) {
|
|
262
|
+
throw new Error(`replace_bytes operation ${index} content exceeds base image size.`);
|
|
263
|
+
}
|
|
264
|
+
await handle.write(content, 0, content.length, operation.offset);
|
|
265
|
+
applied += 1;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
finally {
|
|
269
|
+
await handle.close();
|
|
270
|
+
}
|
|
271
|
+
return applied;
|
|
272
|
+
}
|
|
273
|
+
async function assertReadableFile(filePath, label) {
|
|
274
|
+
const info = await stat(filePath);
|
|
275
|
+
if (!info.isFile()) {
|
|
276
|
+
throw new Error(`${label} is not a file: ${filePath}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async function pathExists(filePath) {
|
|
280
|
+
try {
|
|
281
|
+
await stat(filePath);
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function decodeBase64Strict(value, label) {
|
|
289
|
+
if (typeof value !== "string" || !/^[A-Za-z0-9+/]*={0,2}$/.test(value) || value.length % 4 !== 0) {
|
|
290
|
+
throw new Error(`${label} must be valid base64.`);
|
|
291
|
+
}
|
|
292
|
+
const decoded = Buffer.from(value, "base64");
|
|
293
|
+
if (decoded.length === 0) {
|
|
294
|
+
throw new Error(`${label} must not be empty.`);
|
|
295
|
+
}
|
|
296
|
+
return decoded;
|
|
297
|
+
}
|
|
298
|
+
async function sha256File(filePath) {
|
|
299
|
+
const hash = createHash("sha256");
|
|
300
|
+
await new Promise((resolveHash, rejectHash) => {
|
|
301
|
+
const stream = createReadStream(filePath);
|
|
302
|
+
stream.on("data", (chunk) => {
|
|
303
|
+
hash.update(chunk);
|
|
304
|
+
});
|
|
305
|
+
stream.on("error", rejectHash);
|
|
306
|
+
stream.on("end", resolveHash);
|
|
307
|
+
});
|
|
308
|
+
return hash.digest("hex");
|
|
309
|
+
}
|
|
310
|
+
function sha256Buffer(bytes) {
|
|
311
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
312
|
+
}
|
|
313
|
+
function requiredString(value, label) {
|
|
314
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
315
|
+
throw new Error(`boot-logo package must include ${label}.`);
|
|
316
|
+
}
|
|
317
|
+
return value.trim();
|
|
318
|
+
}
|
|
319
|
+
function optionalString(value) {
|
|
320
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
321
|
+
}
|
|
322
|
+
function isSha256Hex(value) {
|
|
323
|
+
return typeof value === "string" && /^[a-fA-F0-9]{64}$/.test(value);
|
|
324
|
+
}
|
|
325
|
+
function isRecord(value) {
|
|
326
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
327
|
+
}
|
|
328
|
+
export function defaultBootLogoComposeManifestPath(outputImagePath) {
|
|
329
|
+
return `${resolve(outputImagePath)}.embed-logo-compose.json`;
|
|
330
|
+
}
|
|
331
|
+
export function safeBootLogoComposeOutputName(name) {
|
|
332
|
+
return basename(name).replace(/[^A-Za-z0-9._-]+/g, "_") || "boot-logo-output.img";
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=image-compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-compose.js","sourceRoot":"","sources":["../src/image-compose.ts"],"names":[],"mappings":"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"}
|