theseus/addon-build/docx-editor/pack.mjs
Local Dev 5e4bd22609 refactor(docx-editor): ship it as a community extension, not part of the browser
A .docx editor is a megabyte of vendored library. Bundling it would charge
that to everyone who wanted a browser, including the people who will never
open a Word document in it.

So it leaves the build: out of bundled-addons/, out of extraResources, absent
from a fresh profile. It arrives the way anyone else's extension does —
Settings › Extensions › Community, from the catalogue the gateway builds, and
listed on theseus.x/extensions alongside everything else published there.
That also means it is signed by the owner of a BNS name rather than by the
operator key, which is the right trust story for something that isn't part of
the browser.

`npm run pack` produces the tarball the publish page takes; the signature
needs the publisher name's wallet, so it isn't something the repo can do.

The end-to-end test now installs the extension into a throwaway profile the
way the community installer would, and asserts up front that a fresh profile
doesn't already have it — the bundling is what was being removed, so it is
worth a test that would notice it coming back.
2026-09-21 01:06:58 +02:00

65 lines
3.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package the extension for the community channel.
//
// node pack.mjs (from addon-build/docx-editor/)
//
// Produces out/docx-editor-<version>.tar.gz and prints its sha256.
//
// This channel is NOT the operator-signed one that bundled add-ons use
// (scripts/sign-addon-update.mjs). A community extension is signed by the
// owner of a BNS name, with that name's wallet, and uploaded to the gateway:
//
// PUT https://silentmode.st/api/ext/<publisher-name>/docx-editor/<version>
// x-bns-sig: BNS-EXT1\n<name>\n<id>\n<version>\n<sha256>\n<ts>
// x-bns-entry-sig: silentmode.extension-v1|<id>|<version>|<sha256>|<name>
// body: this tarball
//
// Both signatures are 65-byte BCH message signatures over the raw sha256
// digest, made by the key that owns the publisher name's NFT. Nothing here
// can produce them — the wallet is the user's. The easy route is the publish
// page at theseus.x/extensions/publish, which unlocks a wallet in the
// browser, checks ownership, signs and PUTs the tarball you drop on it.
//
// Once the gateway accepts it, the extension appears in the catalog, which is
// what Settings Extensions Community and theseus.x/extensions both read.
import { execFileSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
const here = path.dirname(fileURLToPath(import.meta.url));
const addonDir = path.resolve(here, "../../extensions/docx-editor");
const outDir = path.join(here, "out");
const manifest = JSON.parse(fs.readFileSync(path.join(addonDir, "addon.json"), "utf8"));
const { id, version } = manifest;
if (!id || !version) throw new Error("addon.json is missing id or version");
if (!fs.existsSync(path.join(addonDir, "vendor", "docx-vendor.js"))) {
throw new Error("vendor/docx-vendor.js is missing — run `npm run build` first");
}
fs.mkdirSync(outDir, { recursive: true });
const tarPath = path.join(outDir, `${id}-${version}.tar.gz`);
// Tar the CONTENTS of the folder so addon.json sits at the archive root,
// which is where both the gateway's validator and the installer look.
//
// On Windows, Git-Bash tar mistakes a drive letter for remote-archive
// host:file syntax and mangles backslashes on the way to argv;
// --force-local fixes the first and forward slashes fix the second.
const posix = (p) => p.replace(/\\/g, "/");
execFileSync("tar", ["--force-local", "-c", "-z", "-f", posix(tarPath),
"-C", posix(addonDir), "."], { stdio: "inherit" });
const bytes = fs.readFileSync(tarPath);
const sha256 = crypto.createHash("sha256").update(bytes).digest("hex");
const MAX = 8 * 1024 * 1024;
console.log(`\n${id} ${version}`);
console.log(` tarball : ${tarPath}`);
console.log(` size : ${(bytes.length / 1024).toFixed(0)} KB${bytes.length > MAX ? " ** over the gateway's 8 MB limit **" : ""}`);
console.log(` sha256 : ${sha256}`);
console.log(`\nPublish it from theseus.x/extensions/publish — unlock the publisher name's`);
console.log(`wallet there, drop this tarball in, and it signs and uploads.`);
if (bytes.length > MAX) process.exit(1);