There's a lot of great, thoughtful decisionmaking that went into this tool—staying away from NPM ecosystem's tooling; keeping reliance on dependencies low; facing reality and compromising to use CryptoJS, anyway, but vendoring it in your own source tree. Some thoughts:<p>Before I even finished the post I was wondering how you'd choose to distribute tp-link-config-editor and whether you realized that, since this runs in the browser, you could use a bookmarklet to augment the TP-Link admin interface and integrate it directly with your tool. A bookmarklet might be overkill for something as seldomly used as a router configuration editor, however. I was happy to see, though, the remark that in the end tp-link-config-editor is just "a simple web page with two <button> elements and a <textarea>". On the other hand, I recommend distributing it as a single file. Hosted stuff is (or should be) suspect for things as security-sensitive as router configuration, even if it's a hosted utility. Better if you <i>give</i> people a copy, the way that you can give someone a copy of foo.exe for them run from disk. It makes sense to target the browser, because it's the most accessible platform, but being a utility written for the browser doesn't necessarily mean it has to be an editor for the Web. The ability of browsers to act as a runtime for offline apps is underappreciated. On that note, directories of files work, but they're a bit more fragile than a single file that you can move around (and email, etc...) on a whim. For comparison: <<a href="https://crussell.ichi.city/lines.app.htm" rel="nofollow">https://crussell.ichi.city/lines.app.htm</a>><p>> It avoids using the web's ArrayBuffer and NodeJS's Buffer<p>There's actually nothing "web" about ArrayBuffer (unlike TextDecoder, for comparison). ArrayBuffer is part of JS-the-language (as defined by the ECMAScript standard), and not a Web platform API.<p>> The only odd thing is the setTimeout but it's needed as createObjectURL will hold onto the blob forever and cause a memory leak. So revokeObjectURL releases it. There's no API to hook into the download's progress so a generous timeout is the best we can do.<p>It's up to the browser maker, but from what I understand most browsers expire the URI when the original context disappears (e.g. you close the tab/window containing the app that created it), thus releasing the blob that it's associated with. Also, strictly speaking, the new tab/window created with `window.open` isn't necessary. The `a` element supports a `download` property, which additionally lets you suggest a name for the file. See <<a href="https://codeberg.org/triplescripts/trplkt/src/commit/380411d46235ee3d93f3a868cff0830cfd423827/src/SystemB.src#L87" rel="nofollow">https://codeberg.org/triplescripts/trplkt/src/commit/380411d...</a>>