Simpler Tax Copyright 2026 Simpler Tax This product includes software developed by third parties. This file lists every third-party component the SHIPPED APPLICATION carries — the Windows installer and what it puts on disk — with its license and, where a license asks for more than attribution, what we are doing about it. Simpler Tax itself is PROPRIETARY and closed source, and is supplied under the end user licence agreement in EULA.txt. That changed on 5 August 2026; it was previously Apache-2.0. Closing this product's own source removed OUR licence obligation and not one of the obligations below. Where a component's licence entitles you to ITS source — libvips under the LGPL is the one that matters most here — that entitlement is unaffected, and how to exercise it is stated against the component. The full text of each component's own license travels with the installed app: \engine-payload\EULA.txt this product's own terms \engine-payload\NOTICE this file \engine-payload\THIRD-PARTY-NOTICES.txt this file, followed by an appendix carrying the FULL TEXT of every licence in the bundle — the name and the claim the EULA's clause 7 makes. Generated at stage time by tools/stage-engine.mjs. The front end (section 4) ships no node_modules, so its licence texts travel in that appendix and nowhere else \engine-payload\licenses\ Node.js, the fonts, tessdata, and the LGPL-3.0 + GPL-3.0 texts libvips is under (3.1) \engine-payload\app\node_modules\\LICENSE every npm package, as published \engine-payload\licenses\npm-packages-without-license-text.txt the three that publish none (@napi-rs/canvas-win32-x64-msvc, @nodable/entities, tr46 — all MIT): their declared licence reproduced, because MIT requires the notice to travel even when upstream forgot it The installer displays this product's EULA before installing (bundle.licenseFile in src-tauri/tauri.conf.json -> EULA.txt). Regenerate the tables below, and re-check the flags, with: cd app && node tools/license-audit.mjs That tool exits non-zero if any BUNDLED component — in the engine payload or in the front-end closure vite bundles into dist/ — has no declared licence, would ship without its licence text travelling, is missing from this file's own tables (or sits in a table without shipping), or carries copyleft this file has not already reasoned about. As of the build this NOTICE describes it reports: BLOCKING none. --------------------------------------------------------------------------------- 1. THE ENGINE RUNTIME --------------------------------------------------------------------------------- Component Node.js v22.22.3 (shipped as simpler-tax-engine.exe, 82.9 MB) License MIT Modified? No. The official node.exe, byte-for-byte, copied and renamed. Its Authenticode signature from the OpenJS Foundation remains valid on the shipped file. Notes Node's own LICENSE is an aggregate covering the libraries compiled into it, and it ships in full at engine-payload\licenses\nodejs.LICENSE.txt. Among them: V8 (BSD-3-Clause), libuv (MIT), OpenSSL 3 (Apache-2.0), ICU (Unicode-DFS-2016), zlib (Zlib), brotli (MIT), llhttp / ada / simdutf / ngtcp2 / nghttp2 (MIT), c-ares (MIT). No obligation beyond retaining that text. --------------------------------------------------------------------------------- 2. ENGINE DEPENDENCIES (engine-payload\app\node_modules) --------------------------------------------------------------------------------- Every package below is present because the engine imports it at runtime. The tree is pruned to what is reachable — 32 packages, not the 200+ that a full install carries. Roll-up: MIT x22, Apache-2.0 x7, "Apache-2.0 AND LGPL-3.0-or-later" x1 (flag 3.1), ISC x1, BSD-2-Clause x1. Package License Why it ships -------------------------------- ---------------------------------- ------------------------------------------ better-sqlite3 MIT the company file; the only writer of books sharp Apache-2.0 image preprocessing before OCR @img/sharp-win32-x64 Apache-2.0 AND LGPL-3.0-or-later ** see flag 3.1 ** @img/colour MIT colour handling for the above detect-libc Apache-2.0 sharp's platform probe semver ISC sharp's version check tesseract.js Apache-2.0 OCR orchestration tesseract.js-core Apache-2.0 the Tesseract 5 wasm engine wasm-feature-detect Apache-2.0 picks the SIMD core variant zlibjs MIT gunzip for tesseract language data bmp-js MIT tesseract.js image input idb-keyval Apache-2.0 tesseract.js cache shim (unused, see 3.4) is-url MIT tesseract.js input classification node-fetch MIT ** see flag 3.4 ** regenerator-runtime MIT tesseract.js build artefact opencollective-postinstall MIT tesseract.js funding hook (inert) pdfjs-dist Apache-2.0 PDF text layer extraction @napi-rs/canvas MIT rasterises scanned PDF pages @napi-rs/canvas-win32-x64-msvc MIT the native binding for the above @firecrawl/anydoc-wasm MIT the office door: decodes dropped .xls/.xlsx/.docx/.odt/.rtf (office-scan.mjs) fast-xml-parser MIT PINT-SG / UBL invoice parsing fast-xml-builder MIT the XML we issue strnum, anynum MIT fast-xml-parser numerics xml-naming, @nodable/entities MIT fast-xml-parser internals is-unsafe MIT fast-xml-parser guard path-expression-matcher MIT fast-xml-parser paths node-addon-api MIT better-sqlite3 build header whatwg-url, tr46 MIT node-fetch URL parsing webidl-conversions BSD-2-Clause node-fetch URL parsing Vendored data, not an npm package: eng.traineddata Apache-2.0 Tesseract English LSTM model, from (app/vendor/tessdata) tesseract-ocr/tessdata_fast. Unmodified. This file is why OCR needs no network. Shared with the corpus generator, not an npm package: docgen/lib/*.js proprietary (this project) the UBL emitter that writes the PINT-SG invoices this app issues --------------------------------------------------------------------------------- 3. FLAGS — things that are not simply "retain this notice" --------------------------------------------------------------------------------- 3.1 libvips is LGPL-3.0-or-later, and this is the one copyleft obligation in the bundle. @img/sharp-win32-x64 declares `Apache-2.0 AND LGPL-3.0-or-later`. The Apache-2.0 half is sharp's own prebuilt addon (lib\sharp-win32-x64-0.35.3.node). The LGPL half is libvips and its native dependency stack, shipped as two ordinary DLLs beside the addon: lib\libvips-42.dll 17.6 MB lib\libvips-cpp-8.18.3.dll 0.3 MB Its versions.json names 28 libraries compiled into them, including glib, cairo, pango, harfbuzz, freetype, librsvg, libheif, libtiff, libpng, libwebp, mozjpeg, lcms2, libimagequant and zlib-ng, whose licenses range across LGPL-2.1+, LGPL-3.0+, MIT, BSD and Zlib. The aggregate declaration LGPL-3.0-or-later is the binding one. OUR POSITION, stated plainly rather than assumed: · The linking is DYNAMIC. `sharp-win32-x64-0.35.3.node` resolves libvips at load time from the DLLs above; there is no static archive and no relinking step in our build. We do not modify libvips. · We ship the library as a separate, replaceable file. A recipient can substitute their own build of libvips-42.dll of the same soname and the application will use it — which is the substance of what LGPL-3.0 §4 asks of a work that merely uses the library (Combined Works: allow the user to recombine with a modified version). · Complete corresponding source for libvips and its dependencies is not redistributed by us; the upstream sources are the ones sharp itself builds from and are published at https://github.com/lovell/sharp-libvips (which carries the exact build recipe and pinned source revisions for every library in versions.json) and https://github.com/libvips/libvips. HOW IT IS SETTLED (2026-08-24, for the public release). The source is conveyed the way the binary is conveyed — from the same place, at no charge (LGPL-3.0 §4(d)(0), via GPLv3 §6(d)), mirrored by us rather than linked to a third party's uptime: https://simpler.tax/third-party-source/vips-8.18.3.tar.xz the exact libvips release the DLLs were built from (25,422,084 bytes, SHA-256 f41285b61bfb495605494f074ca341f779 1a1d406e2f157dcea606ef1ae1b146) https://simpler.tax/third-party-source/build-win64-mxe-8.18.3.tar.gz the complete Windows build recipe those DLLs come from — libvips' own build-win64-mxe project at tag v8.18.3, whose build/vips.mk pins 8.18.3 and whose recipes pin the revision and checksum of every companion library in versions.json (76,915 bytes, SHA-256 05c9f3708ce8afe820d4a401e8b270e30c8bd6 270e75a6cfb97f918f2f087962) https://simpler.tax/third-party-source/SOURCE.txt the offer itself, which adds: should anything above be unavailable, support@simpler.asia supplies the archives at no charge for at least three years from release. Both tarballs live in this repository (site/third-party-source/) and deploy with the landing page, so the offer survives a fresh clone. Found while settling this: the npm package carries only sharp's Apache-2.0 text, so the LGPL-3.0 and GPL-3.0 texts §4(b) requires to ACCOMPANY the work were shipping nowhere — they are now vendored (app/vendor/licenses/, canonical gnu.org bytes) and staged to engine-payload\licenses\ by tools/stage-engine.mjs. Dropping sharp remains a possible future simplification — it does one thing (grayscale, lanczos upscale and a light sharpen before OCR, ingest/image-scan.mjs preprocess()), and replacing it against a permissively-licensed decoder would remove 18 MB, the largest single native surface in the bundle, and this flag. The obligation is met without it. 3.2 @univerjs-pro/* is commercial software, is installed, and does NOT ship. `@univerjs/presets` declares 25 `@univerjs-pro/*` packages (collaboration, print, pivot, chart, sheets-exchange-client, and `@univerjs-pro/license` itself) as transitive dependencies. Every one of them has NO `license` field in its package.json — they are Univer's paid tier, not Apache-2.0 like the `@univerjs/*` core. They are in app/node_modules because npm installed the whole preset bundle's dependency graph. They are NOT in the shipped application, and that was verified rather than assumed: · workpapers.mjs imports exactly `@univerjs/presets`, `@univerjs/presets/preset-sheets-core` and its locale + CSS · a search of the built dist/ for `univerjs-pro` returns zero matches across zero files THE TRAP: importing `preset-sheets-advanced`, any `preset-*-collaboration`, print, pivot or chart preset would pull proprietary code into dist/ and make this application undistributable, with no build error to say so. If the workpapers grid ever needs charts, pivots or print, that is a commercial licensing conversation with Univer first and a code change second. 3.3 SheetJS (xlsx) is installed from the vendor's CDN, not from npm. app/package.json pins `"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"`. The license is Apache-2.0 and the code is bundled into dist/ by vite (assets/xlsx-*.js, 0.47 MB) — no license problem. It is noted because a dependency fetched from a URL rather than the registry has no npm audit trail, no integrity entry that a registry mirror can re-verify, and will break the build the day that CDN path moves. A vendored tarball committed to the repo would fix all three. 3.4 A network client ships in the bundle and cannot be reached. `node-fetch` is a dependency of tesseract.js. It appears in the bundle, and the zero-egress claim has to survive that being true. · Both call sites are `const fetch = global.fetch || require('node-fetch')` (worker-script/node/index.js:13, worker/node/loadImage.js:6). On Node 18+ `global.fetch` exists, so node-fetch is never even required at runtime. · The two things tesseract.js would use fetch FOR are both configured away in ingest/image-scan.mjs: language data comes from `langPath` pointed at the vendored folder with `cacheMethod: 'none'` and `gzip: false`, and images arrive as Buffers from the HTTP request rather than as URLs. · `idb-keyval` is in the same category: a browser-cache shim on a code path the node worker does not take. Nothing in the bundle is reached by a code path that opens an outbound socket. The engine binds 127.0.0.1 only, and the webview's CSP allows `connect-src 'self' http://127.0.0.1:5174` and nothing else. 3.5 THE WINDOW ITSELF TALKS TO MICROSOFT, AND WE COULD NOT FULLY STOP IT. This one was found by measurement, not by reading, and it is the most important entry in this file because it is the only place the product's central claim was actually false. The app window is Microsoft Edge WebView2 — a runtime already installed on the machine, not something we ship (which is why it has no row in the tables above; there is nothing of Microsoft's in our installer). But we host it, so its traffic is our traffic as far as a user is concerned. Measured on the first working packaged build, with the app open and idle, by listing every socket owned by the app's own process tree: pid 84580 msedgewebview2.exe (child of simpler-tax-app.exe) -> 2603:1046:c01:2004::2:443 ESTABLISHED -> 2603:1046:c01:2004::2:443 ESTABLISHED A Microsoft address, on 443, that nothing in this application asked for. Not our page — the CSP confines that to 127.0.0.1:5174 and the engine's own sockets were loopback only. This is WebView2's platform background networking: component/experiment fetches, telemetry and reliability pings that the runtime performs on its own account. WHAT WE DID. `app.windows[0].additionalBrowserArgs` in tauri.conf.json now starts the runtime with background networking off: --disable-background-networking --disable-component-update --disable-domain-reliability --disable-breakpad --disable-sync --no-pings --no-default-browser-check --no-first-run --disable-features=…,OptimizationHints,AutofillServerCommunication,Translate (That setting REPLACES Tauri's own default browser args, so Tauri's msWebOOUI / msPdfOOUI / msSmartScreenProtection disables are repeated in the same string rather than lost.) AND IT WAS NOT ENOUGH. This is the part that would have been easy to leave out. The flags are demonstrably applied — they appear verbatim on the msedgewebview2.exe command line of the installed app — and the runtime STILL holds two connections to a Microsoft address on 443: msedgewebview2.exe (child of "Simpler Tax.exe", our flags present) -> 2603:1046:c01:2007::2:443 ESTABLISHED x2 So the honest state of this is: switched off as far as an application is permitted to switch it off, and not off. WebView2's platform telemetry is governed by Windows' own diagnostic-data setting and by Edge/WebView2 enterprise policy (HKLM\SOFTWARE\Policies\Microsoft\Edge\WebView2), neither of which an installed application may set for the user without asking — and an app that silently wrote machine policy to quieten its own telemetry would be a worse actor than the telemetry. OPEN, and named as open rather than closed: decide before public release whether to (a) document the policy keys for administrators who want the runtime silent, (b) offer it as an explicit, opt-in step in the installer, or (c) say plainly in the app's own privacy copy that the Microsoft window component talks to Microsoft and that we do not control it. (c) is the minimum and is not optional. WHAT IS HONEST TO SAY AFTERWARDS. "Simpler Tax sends nothing anywhere" is true of every line of code in this repository and of everything in the bundle: the engine binds 127.0.0.1 and nothing else, the CSP permits one origin, and no component listed above is reached by a code path that opens an outbound socket. It is NOT, on its own, a claim anybody can make about a Microsoft runtime on a Windows machine — the switches above are the runtime's own, we do not control its source, and a future WebView2 version may not honour all of them. The claim to make in public is the one that stays true: your books never leave your machine, and the app asks the network for nothing. The window frame is Microsoft's and behaves as Microsoft's software does; your data is not in it. The check that found this is worth keeping: list `Get-NetTCPConnection` for the app's whole process tree while it is open, select the tree by PARENT PROCESS rather than by start time, and expect loopback from everything except the WebView2 runtime itself. 3.6 The Rust crate graph is rolled up, not enumerated per crate. The shell binary statically links the Tauri 2 crate graph. A roll-up of Cargo.lock against the local registry gives: 206 crates `MIT OR Apache-2.0`, 101 `MIT`, 34 `Apache-2.0 OR MIT`, 18 `MIT/Apache-2.0`, 18 `Unicode-3.0`, 16 `Zlib OR Apache-2.0 OR MIT`, and small counts of BSD-2/3-Clause, ISC, 0BSD, Unlicense-or-MIT and CC0. Permissive throughout, with one exception worth naming: MPL-2.0 (5 crates): cssparser, cssparser-macros, dtoa-short, selectors, option-ext. MPL-2.0 is file-level copyleft. We do not modify these crates, so the obligation is source availability for those files, which crates.io provides. Not a distribution problem for a permissively licensed app. One crate reads as copyleft and is not: `r-efi` declares `MIT OR Apache-2.0 OR LGPL-2.1-or-later`. That is a disjunction offering three alternatives and we take MIT; the LGPL branch binds nobody who does not choose it. (Contrast @img/sharp-win32-x64 above, whose `Apache-2.0 AND LGPL-3.0-or-later` is a conjunction and binds us to both — which is why one is flag 3.1 and the other is this sentence.) tools/license-audit.mjs makes the same distinction rather than flagging every string containing "GPL", because a NOTICE full of false alarms is one nobody reads. DEFERRED: a per-crate NOTICE section generated by `cargo about` (or `cargo deny licenses`), committed as part of the release build rather than rolled up by hand. Adding either tool means a network fetch and a compile, and it is bookkeeping rather than a licensing risk — every license above requires attribution and nothing more. --------------------------------------------------------------------------------- 4. THE FRONT END (bundled into dist/ by vite, shipped in the app window) --------------------------------------------------------------------------------- The population here is the DECLARED dependency closure of the three imports the front end makes (@univerjs/presets, @univerjs/icons, xlsx), minus the -pro tier that flag 3.2 verifies absent from the built dist/. vite's tree-shaking bundles a SUBSET of that closure; the closure is what this table lists, deliberately — tools/license-audit.mjs diffs it against this table by name, and a shipped package missing from here is a blocking failure while a listed package that stops shipping is only surplus attribution. That diff is why the transitive utility tail at the foot of the table is named one by one. Component License Notes -------------------------- -------------- -------------------------------------------- @univerjs/* (core presets) Apache-2.0 the workpapers spreadsheet grid. 70+ packages, all Apache-2.0. See flag 3.2 for the -pro tier. One of them earns its own sentence: @univerjs/telemetry is in the graph — 847 bytes defining a dependency- injection token, no network code, and absent from the built dist/ itself (content search, 2026-08-30). Its package.json omits the license field; tools/license-audit.mjs attests its LICENSE file (Apache-2.0) instead, pinned to the file's own text. @univerjs/icons MIT icons used by the above xlsx (SheetJS CE) Apache-2.0 workbook export. See flag 3.3. pdfjs-dist Apache-2.0 also used engine-side; see section 2 react, react-dom MIT Univer's rendering layer scheduler, react-is, MIT React ecosystem, pulled by Univer prop-types, loose-envify @radix-ui/* (30 packages) MIT Univer's menus, dialogs, popovers @floating-ui/* (4) MIT positioning for the above rxjs Apache-2.0 Univer's reactive core @wendellhu/redi MIT Univer's dependency injection localforage, lie MIT / Apache-2.0 Univer persistence layer fast-diff Apache-2.0 Univer document diffing decimal.js, numfmt MIT Univer number formatting protobufjs + @protobufjs/* BSD-3-Clause Univer's wire format @grpc/grpc-js, Apache-2.0 Univer's transport layer. Present in the @grpc/proto-loader graph; no code path in this app opens a connection (see flag 3.4's argument). opentype.js, tiny-inflate MIT Univer font handling rbush, quickselect, kdbush MIT / ISC Univer spatial indexes franc-min, n-gram, MIT Univer language detection trigram-utils ot-json1, ot-text-unicode ISC Univer operational transform @noble/hashes, MIT Univer crypto primitives @noble/ciphers, @noble/ed25519 tslib 0BSD TypeScript runtime helpers clsx, tailwind-merge, MIT Univer styling utilities class-variance-authority sonner MIT Univer toasts lodash-es MIT Univer utilities nanoid, uuid MIT Univer id generation csstype, @babel/runtime MIT build-time / runtime helpers react-remove-scroll, MIT Radix's grip on the page while a react-remove-scroll-bar, dialog or menu is open — scroll and react-style-singleton, focus containment, eight packages use-callback-ref, use-sidecar, aria-hidden, get-nonce, detect-node-es react-transition-group BSD-3-Clause Radix open/close animation timing dom-helpers MIT react-transition-group's DOM shims object-assign, js-tokens MIT React ecosystem utilities yargs, escalade, MIT @grpc/proto-loader's command-line require-directory, surface. In the graph; nothing in string-width, this app runs a CLI, and flag 3.4's strip-ansi, argument covers the transport it ansi-regex, rides in with ansi-styles, wrap-ansi, color-convert, color-name, emoji-regex, is-fullwidth-code-point cliui, y18n, ISC more of the same CLI surface yargs-parser, get-caller-file lodash.camelcase MIT @grpc/proto-loader field renaming long Apache-2.0 protobufjs 64-bit integers @types/node, undici-types MIT type declarations only — no runtime code exists to be bundled fflate MIT Univer's deflate (xlsx containers) @flatten-js/interval-tree, MIT Univer interval-tree and ordered-map @js-sdsl/ordered-map structures async-lock MIT Univer async serialisation immediate MIT lie's scheduler (under localforage) cjk-regex, unicode-regex, MIT Univer text segmentation and CJK regexp-util, width/join handling collapse-white-space, string.prototype.codepointat unicount ISC more of the text segmentation Fonts, shipped as .woff2 in dist/assets: Geist Variable OFL-1.1 Copyright 2024 The Geist Project Authors. Full license at engine-payload\licenses\geist.OFL.txt JetBrains Mono Variable OFL-1.1 Copyright 2020 The JetBrains Mono Project Authors. Full license at engine-payload\licenses\ jetbrains-mono.OFL.txt OFL-1.1 note: the licence permits bundling in a product without making the product open, and requires the Reserved Font Name not be used for modified versions. We ship the fonts unmodified under their own names, so the only obligation is to include the license text — which is done, and is the reason the two .txt files are staged into the installed app rather than living only in the repository. --------------------------------------------------------------------------------- 5. WHAT THE BUNDLE DOES NOT CONTAIN --------------------------------------------------------------------------------- Named because their absence is a licensing and privacy fact, not an oversight: · No language model. Assisted naming lights up only if a Gemma gguf is already present in the shared Simpler AI model home on the machine (server.mjs probeFamilyModel). We neither ship nor download one, so no model weights license applies to this distribution. · No telemetry or analytics SDK, and no crash reporter. · No auto-updater. `tauri-plugin-updater` is not a dependency; the app makes no outbound request of any kind, including for its own version. · No CDN references. The webview's CSP is `default-src 'self'` with a single `connect-src` exception for 127.0.0.1:5174; every font, style and script is a local file. · No Playwright, no test fixtures, no benchmark corpus, no *.test.mjs. The staging script excludes them (app/tools/stage-engine.mjs). · No Microsoft Edge WebView2 runtime. The window is hosted by the copy already present on the machine (Windows 10/11 ship it), and nothing of Microsoft's is inside our installer — so no Microsoft licence attaches to this distribution. One correction, found 2026-08-24 by reading the config rather than assuming: tauri.conf.json sets no webviewInstallMode, so Tauri's NSIS default (downloadBootstrapper) applies — on the rare machine WITHOUT WebView2, the installer downloads Microsoft's Evergreen Bootstrapper from Microsoft and runs it. That is the one network act the install can perform, it is Microsoft's download on Microsoft's terms, and it happens only when the runtime is absent. An earlier revision of this file said the installer "neither carries nor downloads it"; the first half was true, the second was a claim about a default that had not been checked. The runtime's own background traffic is a different question, and is flag 3.5.