28 std::ifstream in(p, std::ios::binary);
29 return std::string((std::istreambuf_iterator<char>(in)),
30 std::istreambuf_iterator<char>());
38 const std::string& plugin_id,
39 std::uint64_t pack_version,
40 const std::string& update_channel) {
41 namespace fs = std::filesystem;
44 if (!fs::is_directory(bundle_dir, ec) || ec) {
45 r.error =
"bundle is not a directory: " + bundle_dir.string();
49 std::vector<fs::path> files;
50 for (
auto it = fs::recursive_directory_iterator(bundle_dir, ec);
51 !ec && it != fs::recursive_directory_iterator(); it.increment(ec)) {
52 if (it->is_symlink()) {
53 r.error =
"bundle contains a symlink: " + it->path().string();
56 if (it->is_regular_file()) files.push_back(it->path());
59 r.error =
"bundle has no files: " + bundle_dir.string();
62 std::sort(files.begin(), files.end());
65 m.id = plugin_id +
"@" + std::to_string(pack_version);
66 m.plugin_id = plugin_id;
67 m.pack_version = pack_version;
69 m.update_channel = update_channel;
72 for (
const auto& f : files) {
74 std::string rel = fs::relative(f, bundle_dir, ec).generic_string();
79 m.files.push_back(std::move(pf));
80 const auto ext = f.extension().string();
81 if (ext ==
".js" || ext ==
".mjs") { all_js += bytes; all_js +=
'\n'; }
86 r.manifest = std::move(m);
std::string sha256_hex(const uint8_t *data, size_t size)
Compute SHA-256 hash as hex string (64 chars).
std::vector< std::string > infer_capability_names_from_js(std::string_view js_source)
The capability NAMES a scripted UI needs, sorted + de-duplicated — ready to drop into a manifest's de...
Definition reload_autocaps.hpp:99
Sealed swap-pack manifest + per-file integrity.