Compare commits

..
1 Commits
Author SHA1 Message Date
zemion d2d0c9098d feat: publish Toolbox 0.17.0 with Colour and Office Tools 2026-09-01 00:54:22 +02:00
19 changed files with 228 additions and 52 deletions
+2 -2
View File
@@ -5,5 +5,5 @@ TRAEFIK_NETWORK=internal
TRAEFIK_CERT_RESOLVER=netcup TRAEFIK_CERT_RESOLVER=netcup
# Keep these two values paired when deploying a newer published toolbox release. # Keep these two values paired when deploying a newer published toolbox release.
TOOLBOX_RELEASE_VERSION=0.16.0 TOOLBOX_RELEASE_VERSION=0.17.0
TOOLBOX_RELEASE_SHA256=2ae120dd54196428893420a236b32ee260a08af3e0d390362da3457d85110f4e TOOLBOX_RELEASE_SHA256=116e0f335e593aef3d4b345dc6b8e37294ba4fb489ee48abdb0b46fa0251b4b9
+4 -2
View File
@@ -2,8 +2,8 @@ ARG NGINX_IMAGE=nginxinc/nginx-unprivileged:1.31.3-alpine@sha256:18d67281256ded3
FROM ${NGINX_IMAGE} AS release FROM ${NGINX_IMAGE} AS release
ARG TOOLBOX_RELEASE_VERSION=0.16.0 ARG TOOLBOX_RELEASE_VERSION=0.17.0
ARG TOOLBOX_RELEASE_SHA256=2ae120dd54196428893420a236b32ee260a08af3e0d390362da3457d85110f4e ARG TOOLBOX_RELEASE_SHA256=116e0f335e593aef3d4b345dc6b8e37294ba4fb489ee48abdb0b46fa0251b4b9
ARG TOOLBOX_RELEASE_BASE_URL=https://git.add-ideas.de/lotobo/toolbox-portal/releases/download ARG TOOLBOX_RELEASE_BASE_URL=https://git.add-ideas.de/lotobo/toolbox-portal/releases/download
RUN set -eu; \ RUN set -eu; \
@@ -26,6 +26,8 @@ RUN set -eu; \
test -f /tmp/toolbox/apps/svg/toolbox-app.json; \ test -f /tmp/toolbox/apps/svg/toolbox-app.json; \
test -f /tmp/toolbox/apps/auth/toolbox-app.json; \ test -f /tmp/toolbox/apps/auth/toolbox-app.json; \
test -f /tmp/toolbox/apps/sudoku/toolbox-app.json; \ test -f /tmp/toolbox/apps/sudoku/toolbox-app.json; \
test -f /tmp/toolbox/apps/colour/toolbox-app.json; \
test -f /tmp/toolbox/apps/office/toolbox-app.json; \
rm "/tmp/${archive}" rm "/tmp/${archive}"
FROM ${NGINX_IMAGE} FROM ${NGINX_IMAGE}
+35 -30
View File
@@ -1,7 +1,7 @@
# add·ideas Toolbox Portal # add·ideas Toolbox Portal
`toolbox-portal` is the static launcher and release assembler for the add·ideas `toolbox-portal` is the static launcher and release assembler for the add·ideas
browser toolbox. Version `0.2.18` reads one same-origin catalogue, shows each app browser toolbox. Version `0.2.19` reads one same-origin catalogue, shows each app
as a compact launch tile, and keeps personal pins, drag-and-drop ordering, as a compact launch tile, and keeps personal pins, drag-and-drop ordering,
visibility, and appearance in the current browser. Pinned tools have their own visibility, and appearance in the current browser. Pinned tools have their own
section; search, category, and clickable tag filters stay close to the tool section; search, category, and clickable tag filters stay close to the tool
@@ -37,7 +37,8 @@ the SDK and portal together.
Vite uses `base: './'`, so the built portal works at `/` or a nested static path. Vite uses `base: './'`, so the built portal works at `/` or a nested static path.
The development catalogue at `public/toolbox.catalog.json` points to assembled The development catalogue at `public/toolbox.catalog.json` points to assembled
paths (`./apps/pdf/`, `./apps/xslt/`, `./apps/onenote/`, `./apps/av/`, paths (`./apps/pdf/`, `./apps/xslt/`, `./apps/onenote/`, `./apps/av/`,
`./apps/regex/`, `./apps/svg/`, `./apps/auth/`, and `./apps/sudoku/`). `./apps/regex/`, `./apps/svg/`, `./apps/auth/`, `./apps/sudoku/`,
`./apps/colour/`, and `./apps/office/`).
Those manifests will correctly appear as unavailable until an assembled release Those manifests will correctly appear as unavailable until an assembled release
is being served. is being served.
@@ -69,7 +70,7 @@ privacy and executable-code warning. Light, dark, and system modes are supported
## Production deployment behind Traefik ## Production deployment behind Traefik
The committed `compose.yaml` is the shortest production path. Its release The committed `compose.yaml` is the shortest production path. Its release
container downloads the immutable Toolbox 0.16.0 ZIP during the image build, container downloads the immutable Toolbox 0.17.0 ZIP during the image build,
verifies SHA-256 before extracting it, and then copies only the verified static verifies SHA-256 before extracting it, and then copies only the verified static
files into the pinned unprivileged nginx image. Node.js and a local portal files into the pinned unprivileged nginx image. Node.js and a local portal
assembly are not required on the deployment host. assembly are not required on the deployment host.
@@ -133,10 +134,12 @@ The app release should also publish a matching `.sha256` sidecar. The manifest
must declare the pinned reverse-DNS id and version. Application and portal must declare the pinned reverse-DNS id and version. Application and portal
versions are independent. versions are independent.
`release/toolbox.lock.json` is the reviewed v0.16.0 lock. Its URLs and checksums `release/toolbox.lock.json` is the reviewed Toolbox v0.17.0 / Portal v0.2.19
pin the published PDF Tools 0.4.4, XSLT Tools 0.4.3, OneNote Tools 0.3.4, lock. Its URLs and checksums pin the published PDF Tools 0.4.4, XSLT Tools
0.4.3, OneNote Tools 0.3.4,
Audio & Video Tools 0.3.0, Regex Tools 0.4.2, SVG Tools 0.1.0, OTP & Passkey Audio & Video Tools 0.3.0, Regex Tools 0.4.2, SVG Tools 0.1.0, OTP & Passkey
Tools 0.3.0, and Sudoku Tools 0.2.1 release bytes. Use Tools 0.3.0, Sudoku Tools 0.2.1, Colour Tools 0.1.0, and Office Tools 0.1.0
release bytes. Use
`release/toolbox.lock.example.json` as the template for a future release and `release/toolbox.lock.example.json` as the template for a future release and
verify every downloaded asset before committing updated values. Artifacts may be: verify every downloaded asset before committing updated values. Artifacts may be:
@@ -157,7 +160,7 @@ npm run assemble -- \
--lock release/toolbox.lock.json \ --lock release/toolbox.lock.json \
--portal-dist dist \ --portal-dist dist \
--output build/toolbox \ --output build/toolbox \
--archive build/add-ideas-toolbox-0.16.0.zip --archive build/add-ideas-toolbox-0.17.0.zip
``` ```
Existing output is refused. Pass `--force` only when replacing those exact Existing output is refused. Pass `--force` only when replacing those exact
@@ -180,10 +183,12 @@ build/toolbox/
├── regex/ ├── regex/
├── svg/ ├── svg/
├── auth/ ├── auth/
── sudoku/ ── sudoku/
├── colour/
└── office/
build/add-ideas-toolbox-0.16.0.zip build/add-ideas-toolbox-0.17.0.zip
build/add-ideas-toolbox-0.16.0.zip.sha256 build/add-ideas-toolbox-0.17.0.zip.sha256
``` ```
The assembler verifies SHA-256 before opening an artifact, validates every app The assembler verifies SHA-256 before opening an artifact, validates every app
@@ -204,7 +209,7 @@ directory separately:
```sh ```sh
npm run package:static -- \ npm run package:static -- \
--input build/toolbox \ --input build/toolbox \
--output artifacts/add-ideas-toolbox-0.16.0.zip --output artifacts/add-ideas-toolbox-0.17.0.zip
``` ```
This also emits a `.sha256` sidecar. This also emits a `.sha256` sidecar.
@@ -232,9 +237,9 @@ normal local XML/XSLT transformations do not require that permission.
```sh ```sh
podman build -f Containerfile \ podman build -f Containerfile \
-t git.add-ideas.de/lotobo/toolbox:0.16.0 . -t git.add-ideas.de/lotobo/toolbox:0.17.0 .
podman run --rm -p 8080:8080 \ podman run --rm -p 8080:8080 \
git.add-ideas.de/lotobo/toolbox:0.16.0 git.add-ideas.de/lotobo/toolbox:0.17.0
``` ```
For a direct-port local deployment after assembly, use the separate example: For a direct-port local deployment after assembly, use the separate example:
@@ -251,8 +256,8 @@ docker login git.add-ideas.de
docker buildx build \ docker buildx build \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64,linux/arm64 \
--file Containerfile.release \ --file Containerfile.release \
--tag git.add-ideas.de/lotobo/toolbox:0.16.0 \ --tag git.add-ideas.de/lotobo/toolbox:0.17.0 \
--tag git.add-ideas.de/lotobo/toolbox:0.16 \ --tag git.add-ideas.de/lotobo/toolbox:0.17 \
--push . --push .
``` ```
@@ -274,11 +279,11 @@ needs permission to push code, releases, and container packages to
3. Verify downloaded app assets with `sha256sum -c <asset>.sha256`; copy those 3. Verify downloaded app assets with `sha256sum -c <asset>.sha256`; copy those
exact values into a reviewed toolbox lock. exact values into a reviewed toolbox lock.
4. Run the assembler and serve `build/toolbox` from a nested test path. Open 4. Run the assembler and serve `build/toolbox` from a nested test path. Open
all eight apps, switch between them, and confirm the encoded `toolbox` all ten apps, switch between them, and confirm the encoded `toolbox`
context. context.
5. Verify the distribution with 5. Verify the distribution with
`(cd build && sha256sum -c add-ideas-toolbox-0.16.0.zip.sha256)`. `(cd build && sha256sum -c add-ideas-toolbox-0.17.0.zip.sha256)`.
6. Commit the reviewed lock, tag the toolbox release (for example `v0.16.0`), and 6. Commit the reviewed lock, tag the toolbox release (for example `v0.17.0`), and
push the branch and tag to Gitea. push the branch and tag to Gitea.
7. In Gitea, open **Releases → New release**, select the tag, and upload the 7. In Gitea, open **Releases → New release**, select the tag, and upload the
static ZIP plus its `.sha256` file. Do not use a mutable “latest” URL in a static ZIP plus its `.sha256` file. Do not use a mutable “latest” URL in a
@@ -293,16 +298,18 @@ must not re-resolve app versions or substitute a newer release.
## Existing tools ## Existing tools
| Tool | State and boundary | Principal workflows | Important concrete scope | Critical considerations and integrations | | Tool | State and boundary | Principal workflows | Important concrete scope | Critical considerations and integrations |
| ------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`pdf-tools`** | Existing; dedicated repository | Merge, split, reorder, rotate and export PDF pages | Thumbnail workspace; multi-document operations; ZIP and PDF output; saved local workspace | Workers and IndexedDB; large-document memory control; future signature inspection through `crypto-tools`; metadata and safe-sharing through `privacy-tools` | | **`pdf-tools`** | Existing; dedicated repository | Merge, split, reorder, rotate and export PDF pages | Thumbnail workspace; multi-document operations; ZIP and PDF output; saved local workspace | Workers and IndexedDB; large-document memory control; future signature inspection through `crypto-tools`; metadata and safe-sharing through `privacy-tools` |
| **`xslt-tools`** | Existing; dedicated repository | Develop, test and run XSLT transformations | XML/XSLT editors; transformation results; local files; saved projects; validation and diagnostics | Lazy SaxonJS loading; relocatable assets; useful handoffs to `data-tools`, `schema-tools` and `diff-tools` | | **`xslt-tools`** | Existing; dedicated repository | Develop, test and run XSLT transformations | XML/XSLT editors; transformation results; local files; saved projects; validation and diagnostics | Lazy SaxonJS loading; relocatable assets; useful handoffs to `data-tools`, `schema-tools` and `diff-tools` |
| **`onenote-tools`** | Existing rich-reader release; dedicated repository | Open, browse, inspect and export OneNote sections and packages locally | Desktop/unfragmented FSSHTTPB `.one`/`.onetoc2`; none/LZX/MSZIP/Quantum and multi-cabinet `.onepkg`; trees, rich text, images, tables, ink, attachments and export | Native TypeScript worker with no Wasm; bounded parsing, rendering and export; fragmented FSSHTTP fails safely; no editing or pixel-perfect fidelity | | **`onenote-tools`** | Existing rich-reader release; dedicated repository | Open, browse, inspect and export OneNote sections and packages locally | Desktop/unfragmented FSSHTTPB `.one`/`.onetoc2`; none/LZX/MSZIP/Quantum and multi-cabinet `.onepkg`; trees, rich text, images, tables, ink, attachments and export | Native TypeScript worker with no Wasm; bounded parsing, rendering and export; fragmented FSSHTTP fails safely; no editing or pixel-perfect fidelity |
| **`av-tools`** | Existing local-first v0.3.0 release; dedicated repository | Convert and lightly edit audio and video locally in the browser | Immediate native playback and basic file information; progressive stream inspection on demand; quick conversion; trim, split and crossfade concatenate; crop, resize, normalize, fades, waveform, metadata, chapters, subtitles, scene thumbnails/contact sheets, presets and export | Reviewed ffmpeg.wasm 0.12.10 ST/MT build with verified Opus and bundled label font; bounded queue, temporary storage and resource policy; isolation enables MT with automatic ST fallback; versioned core assets are immutable | | **`av-tools`** | Existing local-first v0.3.0 release; dedicated repository | Convert and lightly edit audio and video locally in the browser | Immediate native playback and basic file information; progressive stream inspection on demand; quick conversion; trim, split and crossfade concatenate; crop, resize, normalize, fades, waveform, metadata, chapters, subtitles, scene thumbnails/contact sheets, presets and export | Reviewed ffmpeg.wasm 0.12.10 ST/MT build with verified Opus and bundled label font; bounded queue, temporary storage and resource policy; isolation enables MT with automatic ST fallback; versioned core assets are immutable |
| **`regex-tools`** | Current local-first v0.4.2 release; dedicated repository | Develop, explain, test and apply JavaScript, PCRE2, PHP, Perl, Python, Ruby, Java, C++, Go, .NET, Rust and Scala/JVM-compatible regular expressions | Deterministic syntax trees; engine-native matching, captures and bounded replacement; stable double-buffered live results; PCRE2 tracing and C17 generation; comparison; corpus apply; tests; risk/growth/benchmark analysis; generated cases; bounded minimization; validated ECMAScript formatting; project import/export and optional local persistence | Open-source regexpp and pinned local WebAssembly runtimes for PCRE2, PHP preg, legacy Perl, CPython, CRuby, TeaVM Java/Scala compatibility, libc++ C++, Go, .NET and Rust in killable workers; explicit source/licence inventories, resource limits and engine-specific offset semantics | | **`regex-tools`** | Current local-first v0.4.2 release; dedicated repository | Develop, explain, test and apply JavaScript, PCRE2, PHP, Perl, Python, Ruby, Java, C++, Go, .NET, Rust and Scala/JVM-compatible regular expressions | Deterministic syntax trees; engine-native matching, captures and bounded replacement; stable double-buffered live results; PCRE2 tracing and C17 generation; comparison; corpus apply; tests; risk/growth/benchmark analysis; generated cases; bounded minimization; validated ECMAScript formatting; project import/export and optional local persistence | Open-source regexpp and pinned local WebAssembly runtimes for PCRE2, PHP preg, legacy Perl, CPython, CRuby, TeaVM Java/Scala compatibility, libc++ C++, Go, .NET and Rust in killable workers; explicit source/licence inventories, resource limits and engine-specific offset semantics |
| **`svg-tools`** | Initial local-first v0.1.0 release; dedicated repository | Inspect and edit SVG source, structure, geometry, references and accessibility locally | Synchronized source/tree/canvas/inspector; path and transform tools; reference analysis; optimization; CSS animation preview; exact, sanitized, raster and project export | Untrusted SVG is sanitized into an opaque-origin sandbox; bounded parsing and decompression, explicit security findings and a URI-scoped controller header exception; later milestone slices remain intentionally tracked in the app repository | | **`svg-tools`** | Initial local-first v0.1.0 release; dedicated repository | Inspect and edit SVG source, structure, geometry, references and accessibility locally | Synchronized source/tree/canvas/inspector; path and transform tools; reference analysis; optimization; CSS animation preview; exact, sanitized, raster and project export | Untrusted SVG is sanitized into an opaque-origin sandbox; bounded parsing and decompression, explicit security findings and a URI-scoped controller header exception; later milestone slices remain intentionally tracked in the app repository |
| **`auth-tools`** | Current local-first v0.3.0 release; dedicated repository | Generate, migrate and diagnose OTP credentials, and inspect, verify and test WebAuthn/passkey ceremonies locally | HOTP/TOTP/OCRA with time travel, resynchronization and rotation planning; QR, Google, Aegis and encrypted PSKC migration; WebAuthn extension experiments and replayable traces; assertion, attestation, signer-chain and historical metadata-policy evaluation | Authentication material remains memory-only unless explicitly exported; redaction is deliberate but not a secrecy guarantee; live ceremonies and camera scanning are enabled only at the exact dedicated `auth.toolbox.add-ideas.de` origin, while the shared Portal path remains inspect-only; no raw CTAP administration | | **`auth-tools`** | Current local-first v0.3.0 release; dedicated repository | Generate, migrate and diagnose OTP credentials, and inspect, verify and test WebAuthn/passkey ceremonies locally | HOTP/TOTP/OCRA with time travel, resynchronization and rotation planning; QR, Google, Aegis and encrypted PSKC migration; WebAuthn extension experiments and replayable traces; assertion, attestation, signer-chain and historical metadata-policy evaluation | Authentication material remains memory-only unless explicitly exported; redaction is deliberate but not a secrecy guarantee; live ceremonies and camera scanning are enabled only at the exact dedicated `auth.toolbox.add-ideas.de` origin, while the shared Portal path remains inspect-only; no raw CTAP administration |
| **`sudoku-tools`** | Current local-first v0.2.1 release; dedicated repository | Set, play, generate, analyse and solve classic, Killer and rich variant Sudoku locally | 4×416×16 grids; registry-backed constraint packs including cages, lines, dots, XV, inequalities, indexing and Fog of War; staged hints, candidate maintenance, advanced logical techniques, setter quality checks, mixed-variant generation, source-preserving f-puzzles/SudokuPad interoperability, autosave recovery and searchable local projects | Worker-bounded solving, generation and quality analysis; strict inert imported-visual validation; fog-safe play assistance; IndexedDB history with memory fallback; stable workspace geometry, responsive zoom and pan, a 3×3 standard keypad, tap selection, patterned colours, accessibility controls and an offline-capable PWA shell | | **`sudoku-tools`** | Current local-first v0.2.1 release; dedicated repository | Set, play, generate, analyse and solve classic, Killer and rich variant Sudoku locally | 4×416×16 grids; registry-backed constraint packs including cages, lines, dots, XV, inequalities, indexing and Fog of War; staged hints, candidate maintenance, advanced logical techniques, setter quality checks, mixed-variant generation, source-preserving f-puzzles/SudokuPad interoperability, autosave recovery and searchable local projects | Worker-bounded solving, generation and quality analysis; strict inert imported-visual validation; fog-safe play assistance; IndexedDB history with memory fallback; stable workspace geometry, responsive zoom and pan, a 3×3 standard keypad, tap selection, patterned colours, accessibility controls and an offline-capable PWA shell |
| **`colour-tools`** | Initial local-first v0.1.0 release; dedicated repository | Convert, composite, interpolate, pick, sample, analyse and export colours locally | General colour conversion; arbitrary RGBA compositing; multi-stop colour steps; large visual and native pickers; local image sampling and palette extraction; contrast, gamut and colour-vision-deficiency analysis; harmonies and design-token export | Processing and image access remain local; colour spaces, encoded versus linear-light compositing, interpolation and gamut-mapping assumptions are explicit; mathematical conversion is distinguished from display simulation; integrates with SVG, image and token tools |
| **`office-tools`** | Initial local-first v0.1.0 read-only release; dedicated repository | Open and view word-processing documents, spreadsheets and presentations locally | DOCX, XLSX and PPTX plus ODT, ODS and ODP; document, sheet and slide views with search, outline or thumbnail navigation and zoom; text, tables, images, styles, metadata, cached formula values and presentation notes | Bounded worker-based inert package and XML parsers never execute macros, scripts, formulas, active content or external resources; legacy binary DOC, XLS and PPT are unsupported; viewing is intentionally read-only and does not promise pixel-perfect Office-suite layout fidelity |
## Planned tools ## Planned tools
@@ -317,7 +324,6 @@ must not re-resolve app versions or substitute a newer release.
| **`query-tools`** | High-value but large; dedicated repository | Analyse local tabular and relational data with SQL | CSV, JSON, NDJSON, Parquet and SQLite; schema inference; joins; aggregation; pivots; charts; export to common data formats | WASM memory and streaming; distinguish this analytical product from document-oriented `data-tools`; query work must remain local | | **`query-tools`** | High-value but large; dedicated repository | Analyse local tabular and relational data with SQL | CSV, JSON, NDJSON, Parquet and SQLite; schema inference; joins; aggregation; pivots; charts; export to common data formats | WASM memory and streaming; distinguish this analytical product from document-oriented `data-tools`; query work must remain local |
| **`epub-tools`** | Medium app | EPUB inspection, metadata and cover editing, link validation, chapter extraction and structural repair; sanitize embedded HTML and SVG | | | **`epub-tools`** | Medium app | EPUB inspection, metadata and cover editing, link validation, chapter extraction and structural repair; sanitize embedded HTML and SVG | |
| **`scan-tools`** | Large app | Camera/document correction; crop, deskew and threshold; page assembly; local OCR; PDF output; model downloads and memory use must be explicit | | | **`scan-tools`** | Large app | Camera/document correction; crop, deskew and threshold; page assembly; local OCR; PDF output; model downloads and memory use must be explicit | |
| **`office-tools`** | Medium-to-large app | Inspect rather than reproduce an office suite: package structure, relationships, metadata, comments, embedded images and basic repairs | |
| **`package-tools`** | Medium priority | Inspect compound and package-based formats | EPUB; DOCX/XLSX/PPTX; ODF; JAR; APK; browser extensions; package trees; manifests; relationships; embedded media; signatures; orphaned parts | Generic container inspector with format adapters; complements rather than replaces `onenote-tools`, `epub-tools` and `office-tools` | | **`package-tools`** | Medium priority | Inspect compound and package-based formats | EPUB; DOCX/XLSX/PPTX; ODF; JAR; APK; browser extensions; package trees; manifests; relationships; embedded media; signatures; orphaned parts | Generic container inspector with format adapters; complements rather than replaces `onenote-tools`, `epub-tools` and `office-tools` |
| **`archive-tools`** | Medium-to-high priority; dedicated repository | Inspect, create, compare and extract archives | ZIP, TAR, gzip and selected additional formats; selective extraction; content preview; deterministic archives; timestamp normalization; archive comparison | Expansion-ratio, entry-count and total-size limits; traversal-safe extraction; never execute extracted files | | **`archive-tools`** | Medium-to-high priority; dedicated repository | Inspect, create, compare and extract archives | ZIP, TAR, gzip and selected additional formats; selective extraction; content preview; deterministic archives; timestamp normalization; archive comparison | Expansion-ratio, entry-count and total-size limits; traversal-safe extraction; never execute extracted files |
| **`privacy-tools`** | High priority; dedicated repository | Inspect and remove metadata before sharing | EXIF and GPS; document author/comments; embedded thumbnails; PDF metadata and attachments; hidden package entries; AV tags; personal filenames; structured safe-sharing report | Never promise absolute anonymity; explicitly state inspected, removed, preserved and unsupported structures; integrate with most file-oriented apps | | **`privacy-tools`** | High priority; dedicated repository | Inspect and remove metadata before sharing | EXIF and GPS; document author/comments; embedded thumbnails; PDF metadata and attachments; hidden package entries; AV tags; personal filenames; structured safe-sharing report | Never promise absolute anonymity; explicitly state inspected, removed, preserved and unsupported structures; integrate with most file-oriented apps |
@@ -350,7 +356,6 @@ Helpers export funcionality for other tools to use. They may also present a tool
| Tool | State and boundary | Principal workflows | Important concrete scope | Critical considerations and integrations | | Tool | State and boundary | Principal workflows | Important concrete scope | Critical considerations and integrations |
| ------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **`helpers-tools`** | One shared artifact with deep links | Stateless Base64, URL encoding, case conversion, number bases, Unicode code points, unit conversion, small checksums, subnet and timestamp calculators; avoid a repository per calculator | | | **`helpers-tools`** | One shared artifact with deep links | Stateless Base64, URL encoding, case conversion, number bases, Unicode code points, unit conversion, small checksums, subnet and timestamp calculators; avoid a repository per calculator | |
| **`colour-tools`** | Planned; small-to-medium dedicated repository | Colour conversion, calculation and palette work | sRGB, Display P3, Lab, LCH, OKLab and OKLCH; gamut mapping; contrast; colour-vision simulation; gradients; palette extraction; design-token export | Make colour-space assumptions explicit; distinguish mathematical conversion from display simulation; integrate with SVG, image and token tools |
| **`rand-tools`** | Planned; small dedicated repository | Generate random numbers, strings, identifiers and samples | Cryptographically secure generation; deterministic seeded generation; UUIDs, ULIDs, passphrases, dice notation, distributions, weighted selection and shuffling | Clearly separate secure randomness from reproducible pseudorandomness; no misleading “strength” claims; natural foundation for `fixture-tools` | | **`rand-tools`** | Planned; small dedicated repository | Generate random numbers, strings, identifiers and samples | Cryptographically secure generation; deterministic seeded generation; UUIDs, ULIDs, passphrases, dice notation, distributions, weighted selection and shuffling | Clearly separate secure randomness from reproducible pseudorandomness; no misleading “strength” claims; natural foundation for `fixture-tools` |
| **`data-tools`** | High priority; dedicated repository | Inspect, edit, validate, query and convert structured data | JSON, YAML, TOML, XML, CSV and NDJSON; tree/table/source views; schema inference; flattening; filtering; field mapping; JSONPath-style queries; conversion recipes | Every conversion should disclose information loss, coercion and round-trip instability; XML-specialist workflows hand off to `xslt-tools` | | **`data-tools`** | High priority; dedicated repository | Inspect, edit, validate, query and convert structured data | JSON, YAML, TOML, XML, CSV and NDJSON; tree/table/source views; schema inference; flattening; filtering; field mapping; JSONPath-style queries; conversion recipes | Every conversion should disclose information loss, coercion and round-trip instability; XML-specialist workflows hand off to `xslt-tools` |
| **`diff-tools`** | High priority; dedicated repository or shared engine plus UI | Compare documents and files semantically | Text; JSON object-aware comparison; XML normalization; CSV keyed comparison; images with overlay/heatmap; archives and directories; PDF pages; optional audio waveform comparison | Normalization and ignored properties must be visible; produce portable reports and standard patch formats where possible | | **`diff-tools`** | High priority; dedicated repository or shared engine plus UI | Compare documents and files semantically | Text; JSON object-aware comparison; XML normalization; CSV keyed comparison; images with overlay/heatmap; archives and directories; PDF pages; optional audio waveform comparison | Normalization and ignored properties must be visible; produce portable reports and standard patch formats where possible |
+1 -1
View File
@@ -3,7 +3,7 @@ services:
build: build:
context: . context: .
dockerfile: Containerfile dockerfile: Containerfile
image: git.add-ideas.de/lotobo/toolbox:0.16.0 image: git.add-ideas.de/lotobo/toolbox:0.17.0
restart: unless-stopped restart: unless-stopped
read_only: true read_only: true
ports: ports:
+3 -3
View File
@@ -6,9 +6,9 @@ services:
context: . context: .
dockerfile: Containerfile.release dockerfile: Containerfile.release
args: args:
TOOLBOX_RELEASE_VERSION: "${TOOLBOX_RELEASE_VERSION:-0.16.0}" TOOLBOX_RELEASE_VERSION: "${TOOLBOX_RELEASE_VERSION:-0.17.0}"
TOOLBOX_RELEASE_SHA256: "${TOOLBOX_RELEASE_SHA256:-2ae120dd54196428893420a236b32ee260a08af3e0d390362da3457d85110f4e}" TOOLBOX_RELEASE_SHA256: "${TOOLBOX_RELEASE_SHA256:-116e0f335e593aef3d4b345dc6b8e37294ba4fb489ee48abdb0b46fa0251b4b9}"
image: "git.add-ideas.de/lotobo/toolbox:${TOOLBOX_RELEASE_VERSION:-0.16.0}" image: "git.add-ideas.de/lotobo/toolbox:${TOOLBOX_RELEASE_VERSION:-0.17.0}"
restart: unless-stopped restart: unless-stopped
read_only: true read_only: true
tmpfs: tmpfs:
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "@add-ideas/toolbox-portal", "name": "@add-ideas/toolbox-portal",
"version": "0.2.18", "version": "0.2.19",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@add-ideas/toolbox-portal", "name": "@add-ideas/toolbox-portal",
"version": "0.2.18", "version": "0.2.19",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"dependencies": { "dependencies": {
"@add-ideas/toolbox-contract": "^0.2.3", "@add-ideas/toolbox-contract": "^0.2.3",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@add-ideas/toolbox-portal", "name": "@add-ideas/toolbox-portal",
"version": "0.2.18", "version": "0.2.19",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"private": true, "private": true,
"type": "module", "type": "module",
+2 -2
View File
@@ -1,8 +1,8 @@
# Corresponding source # Corresponding source
The source code corresponding to add·ideas Toolbox Portal 0.2.18 is available at: The source code corresponding to add·ideas Toolbox Portal 0.2.19 is available at:
https://git.add-ideas.de/lotobo/toolbox-portal/src/tag/v0.16.0 https://git.add-ideas.de/lotobo/toolbox-portal/src/tag/v0.17.0
Each bundled application contains its own `SOURCE.md`, license, and third-party Each bundled application contains its own `SOURCE.md`, license, and third-party
license materials. The application sources are also linked from the portal. license materials. The application sources are also linked from the portal.
+8
View File
@@ -40,6 +40,14 @@
{ {
"manifest": "./apps/sudoku/toolbox-app.json", "manifest": "./apps/sudoku/toolbox-app.json",
"enabled": true "enabled": true
},
{
"manifest": "./apps/colour/toolbox-app.json",
"enabled": true
},
{
"manifest": "./apps/office/toolbox-app.json",
"enabled": true
} }
] ]
} }
+16 -2
View File
@@ -1,8 +1,8 @@
{ {
"$schema": "./toolbox-release-lock.schema.json", "$schema": "./toolbox-release-lock.schema.json",
"schemaVersion": 1, "schemaVersion": 1,
"releaseVersion": "0.16.0", "releaseVersion": "0.17.0",
"portalVersion": "0.2.18", "portalVersion": "0.2.19",
"catalogue": { "catalogue": {
"id": "de.add-ideas.toolbox", "id": "de.add-ideas.toolbox",
"name": "add·ideas Toolbox", "name": "add·ideas Toolbox",
@@ -68,6 +68,20 @@
"artifact": "https://git.add-ideas.de/lotobo/sudoku-tools/releases/download/v0.2.1/sudoku-tools-0.2.1.zip", "artifact": "https://git.add-ideas.de/lotobo/sudoku-tools/releases/download/v0.2.1/sudoku-tools-0.2.1.zip",
"sha256": "3987813a3bcd24056b9ca9607ba5d74a094d54c15b0e8a7966df7373e87df67a", "sha256": "3987813a3bcd24056b9ca9607ba5d74a094d54c15b0e8a7966df7373e87df67a",
"target": "sudoku" "target": "sudoku"
},
{
"id": "de.add-ideas.colour-tools",
"version": "0.1.0",
"artifact": "https://git.add-ideas.de/lotobo/colour-tools/releases/download/v0.1.0/colour-tools-0.1.0.zip",
"sha256": "c933f506362709a031a5cd830657604510b8e4ccb1800be77d40d0eee256490b",
"target": "colour"
},
{
"id": "de.add-ideas.office-tools",
"version": "0.1.0",
"artifact": "https://git.add-ideas.de/lotobo/office-tools/releases/download/v0.1.0/office-tools-0.1.0.zip",
"sha256": "3f950a413c74bae3b8f190954272fd91c9b141aab4fa50c936d5ad3741539aaf",
"target": "office"
} }
] ]
} }
+16 -2
View File
@@ -1,8 +1,8 @@
{ {
"$schema": "./toolbox-release-lock.schema.json", "$schema": "./toolbox-release-lock.schema.json",
"schemaVersion": 1, "schemaVersion": 1,
"releaseVersion": "0.16.0", "releaseVersion": "0.17.0",
"portalVersion": "0.2.18", "portalVersion": "0.2.19",
"catalogue": { "catalogue": {
"id": "de.add-ideas.toolbox", "id": "de.add-ideas.toolbox",
"name": "add·ideas Toolbox", "name": "add·ideas Toolbox",
@@ -68,6 +68,20 @@
"artifact": "https://git.add-ideas.de/lotobo/sudoku-tools/releases/download/v0.2.1/sudoku-tools-0.2.1.zip", "artifact": "https://git.add-ideas.de/lotobo/sudoku-tools/releases/download/v0.2.1/sudoku-tools-0.2.1.zip",
"sha256": "3987813a3bcd24056b9ca9607ba5d74a094d54c15b0e8a7966df7373e87df67a", "sha256": "3987813a3bcd24056b9ca9607ba5d74a094d54c15b0e8a7966df7373e87df67a",
"target": "sudoku" "target": "sudoku"
},
{
"id": "de.add-ideas.colour-tools",
"version": "0.1.0",
"artifact": "https://git.add-ideas.de/lotobo/colour-tools/releases/download/v0.1.0/colour-tools-0.1.0.zip",
"sha256": "c933f506362709a031a5cd830657604510b8e4ccb1800be77d40d0eee256490b",
"target": "colour"
},
{
"id": "de.add-ideas.office-tools",
"version": "0.1.0",
"artifact": "https://git.add-ideas.de/lotobo/office-tools/releases/download/v0.1.0/office-tools-0.1.0.zip",
"sha256": "3f950a413c74bae3b8f190954272fd91c9b141aab4fa50c936d5ad3741539aaf",
"target": "office"
} }
] ]
} }
+1 -1
View File
@@ -83,7 +83,7 @@ function makeLock(artifact: string, sha256: string) {
return { return {
schemaVersion: 1, schemaVersion: 1,
releaseVersion: '0.1.0', releaseVersion: '0.1.0',
portalVersion: '0.2.18', portalVersion: '0.2.19',
catalogue: { catalogue: {
id: 'de.add-ideas.toolbox', id: 'de.add-ideas.toolbox',
name: 'Test Toolbox', name: 'Test Toolbox',
+2
View File
@@ -94,6 +94,8 @@ describe('production deployment', () => {
'svg', 'svg',
'auth', 'auth',
'sudoku', 'sudoku',
'colour',
'office',
]) { ]) {
expect(containerfile).toContain( expect(containerfile).toContain(
`test -f /tmp/toolbox/apps/${app}/toolbox-app.json` `test -f /tmp/toolbox/apps/${app}/toolbox-app.json`
+22 -1
View File
@@ -48,6 +48,12 @@ describe('portal UI', () => {
expect( expect(
screen.getByTestId('app-card-de.add-ideas.auth-tools') screen.getByTestId('app-card-de.add-ideas.auth-tools')
).toHaveTextContent('OTP & Passkeys'); ).toHaveTextContent('OTP & Passkeys');
expect(
screen.getByTestId('app-card-de.add-ideas.colour-tools')
).toHaveTextContent('Colour');
expect(
screen.getByTestId('app-card-de.add-ideas.office-tools')
).toHaveTextContent('Office');
expect( expect(
screen.queryByText( screen.queryByText(
'Page-level PDF operations performed locally in the browser.' 'Page-level PDF operations performed locally in the browser.'
@@ -416,6 +422,8 @@ describe('portal UI', () => {
'de.add-ideas.svg-tools', 'de.add-ideas.svg-tools',
'de.add-ideas.auth-tools', 'de.add-ideas.auth-tools',
'de.add-ideas.sudoku-tools', 'de.add-ideas.sudoku-tools',
'de.add-ideas.colour-tools',
'de.add-ideas.office-tools',
], ],
hidden: [], hidden: [],
theme: 'light', theme: 'light',
@@ -436,6 +444,8 @@ describe('portal UI', () => {
screen.getByTestId('app-card-de.add-ideas.svg-tools'), screen.getByTestId('app-card-de.add-ideas.svg-tools'),
screen.getByTestId('app-card-de.add-ideas.auth-tools'), screen.getByTestId('app-card-de.add-ideas.auth-tools'),
screen.getByTestId('app-card-de.add-ideas.sudoku-tools'), screen.getByTestId('app-card-de.add-ideas.sudoku-tools'),
screen.getByTestId('app-card-de.add-ideas.colour-tools'),
screen.getByTestId('app-card-de.add-ideas.office-tools'),
]; ];
cards.forEach((card, index) => { cards.forEach((card, index) => {
const rect = { const rect = {
@@ -466,7 +476,16 @@ describe('portal UI', () => {
within(tools) within(tools)
.getAllByRole('heading', { level: 3 }) .getAllByRole('heading', { level: 3 })
.map((heading) => heading.textContent) .map((heading) => heading.textContent)
).toEqual(['XSLT', 'PDF', 'OneNote', 'SVG', 'OTP & Passkeys', 'Sudoku']); ).toEqual([
'XSLT',
'PDF',
'OneNote',
'SVG',
'OTP & Passkeys',
'Sudoku',
'Colour',
'Office',
]);
}); });
expect( expect(
JSON.parse(localStorage.getItem(PREFERENCES_KEY) ?? '{}').order JSON.parse(localStorage.getItem(PREFERENCES_KEY) ?? '{}').order
@@ -477,6 +496,8 @@ describe('portal UI', () => {
'de.add-ideas.svg-tools', 'de.add-ideas.svg-tools',
'de.add-ideas.auth-tools', 'de.add-ideas.auth-tools',
'de.add-ideas.sudoku-tools', 'de.add-ideas.sudoku-tools',
'de.add-ideas.colour-tools',
'de.add-ideas.office-tools',
]); ]);
}); });
+2 -2
View File
@@ -489,9 +489,9 @@ export default function App() {
</span> </span>
</p> </p>
<span> <span>
Portal v0.2.18 ·{' '} Portal v0.2.19 ·{' '}
<a <a
href="https://git.add-ideas.de/lotobo/toolbox-portal/src/tag/v0.16.0" href="https://git.add-ideas.de/lotobo/toolbox-portal/src/tag/v0.17.0"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
+3 -1
View File
@@ -10,7 +10,7 @@ describe('catalogue loading', () => {
const loaded = await loadCatalogue('/toolbox.catalog.json'); const loaded = await loadCatalogue('/toolbox.catalog.json');
expect(loaded.catalogue.name).toBe('add·ideas Toolbox'); expect(loaded.catalogue.name).toBe('add·ideas Toolbox');
expect(loaded.homeUrl).toBe('http://localhost:3000/'); expect(loaded.homeUrl).toBe('http://localhost:3000/');
expect(loaded.apps).toHaveLength(6); expect(loaded.apps).toHaveLength(8);
expect(loaded.apps[0]).toMatchObject({ expect(loaded.apps[0]).toMatchObject({
id: 'de.add-ideas.pdf-tools', id: 'de.add-ideas.pdf-tools',
name: 'PDF Workbench', name: 'PDF Workbench',
@@ -43,6 +43,8 @@ describe('catalogue loading', () => {
'de.add-ideas.svg-tools', 'de.add-ideas.svg-tools',
'de.add-ideas.auth-tools', 'de.add-ideas.auth-tools',
'de.add-ideas.sudoku-tools', 'de.add-ideas.sudoku-tools',
'de.add-ideas.colour-tools',
'de.add-ideas.office-tools',
]); ]);
expect(loaded.unavailable).toHaveLength(1); expect(loaded.unavailable).toHaveLength(1);
expect(loaded.unavailable[0]?.reason).toMatch(/HTTP 404/); expect(loaded.unavailable[0]?.reason).toMatch(/HTTP 404/);
+76
View File
@@ -202,6 +202,76 @@ export const sudokuManifest: ToolboxAppManifest = {
], ],
}; };
export const colourManifest: ToolboxAppManifest = {
...sudokuManifest,
id: 'de.add-ideas.colour-tools',
name: 'Colour Tools',
version: '0.1.0',
description:
'Convert, composite, compare and build colours locally in the browser.',
categories: ['graphics', 'design', 'developer'],
tags: ['colour', 'rgba', 'oklch', 'palette', 'gradient', 'contrast'],
requirements: {
secureContext: false,
workers: true,
indexedDb: false,
crossOriginIsolated: false,
topLevelContext: false,
},
privacy: {
processing: 'local',
fileUploads: false,
telemetry: false,
label: 'Colours and images stay in this browser; nothing is uploaded.',
},
source: {
repository: 'https://git.add-ideas.de/lotobo/colour-tools',
license: 'GPL-3.0-or-later',
},
actions: [
{
id: 'source',
label: 'Source',
url: 'https://git.add-ideas.de/lotobo/colour-tools',
},
],
};
export const officeManifest: ToolboxAppManifest = {
...sudokuManifest,
id: 'de.add-ideas.office-tools',
name: 'Office Tools',
version: '0.1.0',
description:
'Open and inspect documents, spreadsheets and presentations locally in the browser.',
categories: ['documents', 'office', 'productivity'],
tags: ['document', 'spreadsheet', 'presentation', 'docx', 'xlsx', 'pptx'],
requirements: {
secureContext: false,
workers: true,
indexedDb: false,
crossOriginIsolated: false,
topLevelContext: false,
},
privacy: {
processing: 'local',
fileUploads: false,
telemetry: false,
label: 'Office files stay in this browser; nothing is uploaded.',
},
source: {
repository: 'https://git.add-ideas.de/lotobo/office-tools',
license: 'GPL-3.0-or-later',
},
actions: [
{
id: 'source',
label: 'Source',
url: 'https://git.add-ideas.de/lotobo/office-tools',
},
],
};
export const catalogue: ToolboxCatalog = { export const catalogue: ToolboxCatalog = {
schemaVersion: 1, schemaVersion: 1,
id: 'de.add-ideas.toolbox', id: 'de.add-ideas.toolbox',
@@ -215,6 +285,8 @@ export const catalogue: ToolboxCatalog = {
{ manifest: './apps/svg/toolbox-app.json', enabled: true }, { manifest: './apps/svg/toolbox-app.json', enabled: true },
{ manifest: './apps/auth/toolbox-app.json', enabled: true }, { manifest: './apps/auth/toolbox-app.json', enabled: true },
{ manifest: './apps/sudoku/toolbox-app.json', enabled: true }, { manifest: './apps/sudoku/toolbox-app.json', enabled: true },
{ manifest: './apps/colour/toolbox-app.json', enabled: true },
{ manifest: './apps/office/toolbox-app.json', enabled: true },
], ],
}; };
@@ -242,6 +314,10 @@ export function catalogueFetch(overrides: Record<string, Response> = {}) {
return Response.json(authManifest); return Response.json(authManifest);
if (url.pathname.endsWith('/apps/sudoku/toolbox-app.json')) if (url.pathname.endsWith('/apps/sudoku/toolbox-app.json'))
return Response.json(sudokuManifest); return Response.json(sudokuManifest);
if (url.pathname.endsWith('/apps/colour/toolbox-app.json'))
return Response.json(colourManifest);
if (url.pathname.endsWith('/apps/office/toolbox-app.json'))
return Response.json(officeManifest);
return new Response('Not found', { status: 404 }); return new Response('Not found', { status: 404 });
}; };
} }
+24
View File
@@ -63,4 +63,28 @@ describe('compact tool presentation', () => {
expect(shortToolTitle(sudoku)).toBe('Sudoku'); expect(shortToolTitle(sudoku)).toBe('Sudoku');
expect(shortToolDescription(sudoku)).toBe('Set, play and solve locally.'); expect(shortToolDescription(sudoku)).toBe('Set, play and solve locally.');
}); });
it('uses the compact Colour tile copy', () => {
const colour = app(
'de.add-ideas.colour-tools',
'Colour Tools',
'Convert, composite, compare and build colours locally in the browser.'
);
expect(shortToolTitle(colour)).toBe('Colour');
expect(shortToolDescription(colour)).toBe(
'Convert and build colours locally.'
);
});
it('uses the compact Office tile copy', () => {
const office = app(
'de.add-ideas.office-tools',
'Office Tools',
'Open and inspect documents, spreadsheets and presentations locally in the browser.'
);
expect(shortToolTitle(office)).toBe('Office');
expect(shortToolDescription(office)).toBe('Open office files locally.');
});
}); });
+8
View File
@@ -33,6 +33,14 @@ const PRESENTATION: Record<string, { title: string; description: string }> = {
title: 'Sudoku', title: 'Sudoku',
description: 'Set, play and solve locally.', description: 'Set, play and solve locally.',
}, },
'de.add-ideas.colour-tools': {
title: 'Colour',
description: 'Convert and build colours locally.',
},
'de.add-ideas.office-tools': {
title: 'Office',
description: 'Open office files locally.',
},
}; };
export function shortToolTitle(app: ResolvedApp): string { export function shortToolTitle(app: ResolvedApp): string {