Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ body:
placeholder: Firefox 156 on Windows 11, Safari on iOS 18.7, Chrome 139 on Android 15
validations:
required: true
- type: textarea
id: selftest
- type: input
id: version
attributes:
label: Self-test
description: Open https://sqzer.dev/selftest/ in the same browser and paste what it prints. It names the package version and what the browser can decode.
render: text
label: Version of `sqzer`
description: The number in the page's footer, after "`sqzer` on npm".
placeholder: 0.3.0
validations:
required: true
- type: textarea
Expand Down
91 changes: 0 additions & 91 deletions .github/check.mjs

This file was deleted.

10 changes: 7 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
version: 2
updates:
# The version of `sqzer` the page imports, which `site/worker.js` reads
# from `site/package.json`. Merging the pull request is the whole bump.
# `sqzer` comes alone: a release of the package is one pull request with
# nothing else in it, and merging it is the whole bump. The build and test
# tooling comes grouped.
- package-ecosystem: npm
directory: /site
directory: /
schedule:
interval: daily
groups:
tooling:
dependency-type: development
8 changes: 4 additions & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@

## Browsers tried

<!-- CI covers headless Chromium. Which browsers did you load the page in? For a change to the canvas fallback or the comparison, Safari matters. -->
<!-- CI covers headless Chromium and Firefox. Which browsers did you load the page in? For a change to the canvas fallback or the comparison, Safari matters. -->

## New dependencies

<!-- The page has one, `sqzer`. Anything else: what, why the page cannot do without it, and its licence. Or "none". -->
<!-- What, why the page cannot do without it, and its licence. Or "none". -->

## Checklist

- [ ] `.github/check.mjs` passes locally, or CI shows it green
- [ ] a path that depends on the browser got a line in `/selftest/`, if one changed
- [ ] `pnpm check` passes locally, or CI shows it green
- [ ] a path that depends on the browser got a Vitest test next to it, if one changed
- [ ] a new ADR has its row in `docs/adr/README.md` and its entry in `.greptile/files.json`, if there is one
- [ ] the `Content-Security-Policy` is unchanged, or the PR says why it had to change
24 changes: 18 additions & 6 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Check

# The page in headless Chromium against the version of `sqzer` that
# `site/package.json` names, so a Dependabot bump is tested before it merges.
# The checks of ADR-0002 D6, against the version of `sqzer` that `package.json`
# names, so a Dependabot bump is tested before it merges.
on:
pull_request:
push:
Expand All @@ -17,7 +17,19 @@ jobs:
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- run: npm install --no-save --no-package-lock playwright@1.63.0
- run: npx playwright install --with-deps chromium
- run: python3 -m http.server -d site 8000 &
- run: node .github/check.mjs
# the version of pnpm is the `packageManager` of `package.json`
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- run: pnpm lint
- run: pnpm format:check
- run: pnpm fsd
- run: pnpm exec playwright install --with-deps chromium firefox
# units, components and `decodeAny`, in Chromium and Firefox
- run: pnpm test
# the built page, served by `vite preview`, in Chromium and Firefox
- run: pnpm test:e2e
12 changes: 10 additions & 2 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Pages

# Every merge to `main` is a deploy: the page never waits for a release of
# the crates. `site/` is published as it is, there is no build step.
# the crates. The page is built by Vite and `dist/` is published.
on:
push:
branches: [main]
Expand All @@ -26,8 +26,16 @@ jobs:
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/checkout@v7
# the version of pnpm is the `packageManager` of `package.json`
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 24
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- uses: actions/upload-pages-artifact@v5
with:
path: site
path: dist
- id: deploy
uses: actions/deploy-pages@v5
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
.DS_Store
node_modules/
dist/
test-results/
playwright-report/
75 changes: 17 additions & 58 deletions .greptile/config.json
Original file line number Diff line number Diff line change
@@ -1,78 +1,46 @@
{
"strictness": 2,
"commentTypes": [
"logic",
"syntax"
],
"autoReview": [
"open",
"push"
],
"commentTypes": ["logic", "syntax"],
"autoReview": ["open", "push"],
"statusCheck": true,
"excludeAuthors": [
"dependabot[bot]"
],
"ignorePatterns": "site/selftest/fixtures/*\nLICENSE-*\nCODE_OF_CONDUCT.md",
"instructions": "sqzer.dev is the page that runs the `sqzer` npm package in the browser. It moves from plain HTML to React 19, TypeScript and Vite under ADR-0002; until that port lands, `site/` is the page. CLAUDE.md is the rule book and docs/adr holds the decisions; where they disagree during the port, the accepted ADR wins. Review against them. The page depends on the published package by exact version and sends nothing anywhere. The page never writes a decoder, encoder, resampler or metric; what the package lacks is a change to sqzer-dev/sqzer, not to this repository.",
"excludeAuthors": ["dependabot[bot]"],
"ignorePatterns": "tests/fixtures/*\nLICENSE-*\nCODE_OF_CONDUCT.md",
"instructions": "sqzer.dev is the page that runs the `sqzer` npm package in the browser. It is a React 19 and TypeScript application built by Vite (ADR-0002), with the search as an XState machine whose worker outlives a search (ADR-0004). CLAUDE.md is the rule book and docs/adr holds the decisions; where they disagree, the accepted ADR wins. Review against them. The page depends on the published package by exact version and sends nothing anywhere. The page never writes a decoder, encoder, resampler or metric; what the package lacks is a change to sqzer-dev/sqzer, not to this repository.",
"rules": [
{
"id": "no-third-party",
"rule": "The page talks to its own origin and nothing else: no analytics, no error reporting, no font, script, stylesheet, image or wasm from another host, no `data:` URI. The `Content-Security-Policy` is written once in `vite.config.ts` and injected into the built `index.html`; it is not widened for convenience. Flag any new origin, any inline script in `index.html`, any `style` attribute or `<style>` block, a React `style` prop that sets anything but a custom property, a raised `build.assetsInlineLimit`, and any removal or loosening of a directive. Fonts are files bundled from our own packages, under `font-src 'self'`. The root stays wrapped in Base UI's `<CSPProvider disableStyleElements>`; flag any dependency that creates a `<style>` element at run time (Radix primitives that lock scroll through `react-remove-scroll`, Vaul, CSS-in-JS).",
"scope": [
"src/**",
"index.html",
"vite.config.ts",
"public/**"
],
"scope": ["src/**", "index.html", "vite.config.ts", "public/**"],
"severity": "high"
},
{
"id": "package-by-version",
"rule": "`sqzer` is a dependency in `package.json` at an exact version, installed by pnpm from the npm registry with the committed `pnpm-lock.yaml`, bundled by Vite and served from the page's own origin. Flag a range instead of an exact version, a second place the version is written, a URL import of the package, a checkout or vendored copy of it, an npm or Yarn lockfile, and a CI install that may change the lockfile instead of `pnpm install --frozen-lockfile`. Any new dependency states its licence in the pull request.",
"scope": [
"package.json",
"pnpm-lock.yaml",
"src/**",
"vite.config.ts",
".github/**"
],
"scope": ["package.json", "pnpm-lock.yaml", "src/**", "vite.config.ts", ".github/**"],
"severity": "high"
},
{
"id": "work-in-the-worker",
"rule": "Every call into the package happens in the worker in `src/shared/api/sqzer/`. Only that slice's client starts or ends the worker, and only the search machine in `src/features/encode-image/model/` uses the client, as an invoked callback actor whose cleanup terminates the worker. A search cannot be interrupted, so cancelling means stopping the actor, which ends the worker; that stays the only way. Flag an import of `sqzer` outside the worker, a `new Worker` outside the client, the client used outside the machine, and any attempt to interrupt an encode otherwise.",
"scope": [
"src/**"
],
"rule": "Every call into the package happens in the worker in `src/shared/api/sqzer/`. Only that slice's client starts or ends the worker, and only the search machine in `src/pages/compress/model/` uses the client, as a callback actor invoked by the machine's `open` state, whose cleanup terminates the worker (ADR-0004). The worker outlives a search and keeps the decoded image. A search cannot be interrupted, so cancelling means re-entering `open`, which stops the actor and ends the worker; that stays the only way. Flag an import of `sqzer` outside the worker, a `new Worker` outside the client, the client used outside the machine, a worker ended while it is idle, and any attempt to interrupt an encode otherwise.",
"scope": ["src/**"],
"severity": "high"
},
{
"id": "no-codecs-here",
"rule": "No decoder, encoder, resampler, colour transform or metric is written in this repository. The package's decoder comes first; the browser's canvas decodes only what the package cannot (SVG, HEIC where the browser can), never inside the search. An SVG is drawn on the page from an `<img>`, because `createImageBitmap` refuses an SVG blob inside a worker in every browser. A missing capability is a pull request to `sqzer-dev/sqzer`, followed by a version bump here.",
"scope": [
"src/**"
],
"scope": ["src/**"],
"severity": "high"
},
{
"id": "codecs-drive-the-controls",
"rule": "What the page offers as formats, backends and what it says it can read comes from the package's `codecs()` at run time. Flag a hardcoded list of formats or backends. The controls start at the package's defaults and the page never changes a default of the package on its own.",
"scope": [
"src/**"
],
"scope": ["src/**"],
"severity": "medium"
},
{
"id": "one-styling-system",
"rule": "Components are shadcn/ui's Base UI flavour in `src/shared/ui/`, styled with Tailwind 4 on shadcn's tokens, which map Radix Colors `gray` and `blackA`/`whiteA` (ADR-0003). Flag CSS Modules, CSS-in-JS, a second component library, a colour or font outside the tokens, Radix `red` anywhere but an alert, glass built other than through the `glass` utility, glass nested in glass or used on anything but the floating panels, the bottom expander and the corner labels, and a new dependency whose licence is not added to `licenses.txt`.",
"scope": [
"src/**",
"index.html",
"vite.config.ts",
"package.json",
"public/**",
"tests/**"
],
"scope": ["src/**", "index.html", "vite.config.ts", "package.json", "public/**", "tests/**"],
"severity": "medium"
},
{
Expand All @@ -82,31 +50,22 @@
},
{
"id": "browser-check",
"rule": "The `browser` job of `check.yml` runs on every pull request: `tsc --noEmit`, oxlint with `eslint-plugin-react-hooks` as the JS plugin `react-hooks-js`, Steiger, Vitest in browser mode in Chromium and Firefox, and the Playwright suite in `tests/e2e/` against the built page in Chromium and Firefox. A change keeps it green. A change to a path that depends on the browser (the canvas fallback, `decodeAny`, the comparison) adds a Vitest browser test for it, and the Playwright suite checks that no request leaves the page's origin. Tool versions change through `package.json` and Dependabot, on purpose.",
"scope": [
"src/**",
"tests/**",
"index.html",
"vite.config.ts",
".github/**"
],
"rule": "The `browser` job of `check.yml` runs on every pull request: `tsc`, oxlint with its type-aware rules and `eslint-plugin-react-hooks` as the JS plugin `react-hooks-js`, `oxfmt --check`, Steiger, Vitest in browser mode in Chromium and Firefox, and the Playwright suite in `tests/e2e/` against the built page in Chromium and Firefox. A change keeps it green, and does not loosen `.oxlintrc.json` or the `tsconfig` files to get there: a rule is turned off only with its reason next to it. A change to a path that depends on the browser (the canvas fallback, `decodeAny`, the comparison) adds a Vitest browser test for it, and the Playwright suite checks that no request leaves the page's origin. Tool versions change through `package.json` and Dependabot, on purpose.",
"scope": ["src/**", "tests/**", "index.html", "vite.config.ts", ".github/**"],
"severity": "medium"
},
{
"id": "accepted-adrs",
"rule": "An accepted ADR is never rewritten; ticking or annotating its own action items and adding a `Superseded by` line at the top are fine. A change of design or behaviour that an ADR decided gets a new numbered file, a row in `docs/adr/README.md`, an entry in `.greptile/files.json` scoped to what it governs, and an update to any rule in `.greptile/config.json` it changes, all in the same PR.",
"scope": [
"docs/adr/**",
".greptile/**"
],
"scope": ["docs/adr/**", ".greptile/**"],
"severity": "medium"
},
{
"id": "user-facing-prose",
"rule": "User-facing text (the page's copy, README, contributor docs, issue forms, PR template, docs): sentence-case headings, backticks on every identifier, flag and path, no em dashes, no emoji, no tables, explanation in `#` comments above a command rather than prose around it, uncertainty stated flatly with the next step named.",
"scope": [
"site/index.html",
"site/main.js",
"index.html",
"src/**",
"README.md",
"CONTRIBUTING.md",
"SECURITY.md",
Expand Down
Loading
Loading