Promote dev to master: post-3.3.0 fixes for 3.3.1 - #400
Merged
Merged
Conversation
…onsumers install core declares libheif-js as an optionalDependency with `^1.19.8`. The workspace lockfile pinned 1.19.8, but a lockfile-less install — the package smoke consumer, and every real user — resolves 1.23.2, the newest 1.x. So the HEIC integration suite proved a decoder that nobody installs, and `smoke:packages` installs 1.23.2 but only measures bundle shape and size (assertConsumerBundleShape never executes a decode). Nothing in CI exercised the version users actually get. Verified before pinning: 1.23.2 decodes the repo's real 64x64 HEIC fixture through heic-decode.ts unchanged — same module shape (default factory), same HeifDecoder/decode/display/free API, 406 source bytes -> 64x64 -> a 785-byte JPEG with valid SOI/EOI markers, byte-for-byte the same result as 1.19.8. Applied as a three-hunk lockfile edit rather than through pnpm: both `pnpm update libheif-js --filter @useupup/core` and `pnpm add libheif-js@^1.19.8 --filter @useupup/core --save-optional` re-resolved unrelated peer graphs (1194-2828 changed lines, including a vitest 4.1.11 -> 4.1.2 downgrade), and the first also rewrote core's manifest range. A control `pnpm install` with no dependency change produced no diff, so the churn came from the re-resolution, not from lockfile drift. `pnpm install --frozen-lockfile` accepts the edited lockfile — it refuses to rewrite one — which is what proves it self-consistent. core's `^1.19.8` range is unchanged, so consumers receive exactly what they did before; this moves only what we test.
Sync dev with master after the #383 promotion
…kfile chore(deps): pin libheif-js 1.23.2 in the lockfile so CI tests what consumers install
A pre-existing security-review notice flagged mutable action tags. Every `uses:` across .github/workflows is now pinned to a 40-char commit SHA with the resolved version in a trailing comment: - actions/upload-artifact@v4 -> ea165f8d # v4.6.2 (main, e2e, nightly). v4 currently resolves to the same commit as v4.6.2, so this is a no-op behaviorally; it just stops the tag from moving under us. - publish-sdk.yml's actions/checkout@v7 / actions/setup-node@v7 -> the same SHAs the other workflows already pin (v7.0.1 / v7.0.0). Actions that were already SHA-pinned are untouched, as is changesets/action (pinned at v1.9.0 because its major is coupled to the Changesets CLI major). publish-sdk.yml also picks up a whole-file prettier reformat: it was committed with 2-space indentation against this repo's 4-space prettier config, so it has been failing `prettier --check` since it landed. CI never caught it because prettier-check is scoped to packages/*/src; staging the file for the pin change put it in front of lint-staged, which does check it.
The old comment asserted that every @useupup package already had its npm trusted publisher configured, dated 2026-08-01. That claim was false for @useupup/server until today, and a dated "this is already done" note decays the moment a package is added or a scope moves. Reworded as a standing precondition instead of a status report: publishing is OIDC-only; every @useupup package must have a trusted publisher (GitHub Actions, DevinoSolutions/upup, workflow publish.yml); a package without one fails its own publish and therefore the job, but its version number is not burned, so the fix is to add the publisher and re-run; verify each package's npm access page before merging a Version Packages PR. The npm-upgrade-after-setup-node ordering note is preserved verbatim in substance — it is the other half of why this step is shaped the way it is.
…r flow Two staleness fixes in the operating guide: - The npm scope moved to @useupup on 2026-09-02, but CLAUDE.md still named @upupjs/* in 34 places (package map, principles, gates, test paths, subpath examples). Swept with an exact-substring codemod over every line outside the "Naming vocabulary" scope-history bullet, which deliberately narrates the @upupjs era and is preserved verbatim. The only surviving `upupjs` tokens in the file are that bullet's three, which is also why vocab:check's scan roots exclude this file. - The "Git & commits" section still described `v2-clean` as the integration branch and forbade touching master. Replaced with the model actually in use: master is production/release (publish.yml runs on push to master), dev is the integration branch, feature branches PR into dev, dev is promoted to master via a dev->master PR and master is synced back with a master->dev PR, and PRs merge with --admin because self-approval is impossible here. Remaining bullets in that section (conventional commits, explicit staging, docs/superpowers, the hooks) are unchanged.
chore: post-release hygiene — action SHA pins, publish.yml precondition, CLAUDE.md sweep
…dFileTypes A host that set allowedFileTypes to a type no capture source can produce still got camera/microphone/screen chips in the default source set, and every recording they made was rejected on add (#340). normalizeUploaderOptions now drops a DEFAULT capture source when no entry in the resolved accept list could match anything that source emits. The declared output sets come from the code that builds the File: camera image/jpeg (plus image/png, the toDataURL fallback), microphone audio/webm|ogg|mp4, screen video/webm|mp4. The matcher fails open - a wildcard, an extension it cannot classify, or an entry that is neither a MIME type nor an extension keeps every source. local and url are never filtered, cloud drives are unaffected, and an explicit sources array is honored verbatim. Each dropped source logs one dev-only console.warn.
stripExifData skips animated GIF/WebP/APNG because canvas has no animated encoder, so those files reach storage with the metadata the host asked to remove - and animated WebP and APNG both carry EXIF. The skip was silent, so a privacy-sensitive host had no way to detect it (#367 item 4). The exif step now records it on the file: metadata.metadataStripSkipped true with metadata.metadataStripSkippedReason 'animated-image', using the same assign-a-new-metadata-object shape the thumbnail step already uses. No new event, no new option. The compress step deliberately does NOT set it: nothing was asked to be removed there, so the marker would be a false privacy signal.
…e string A failure carrying a machine code rendered as uploadFailedWithCode, which interpolated the code and nothing else - so an endpoint that returned a useful sentence watched it disappear between onError and the panel (#367 item 2). The key gains a second {message} slot fed from the error's own message, and all nine locale bundles carry both slots so translators control placement: overriding the key can reorder them, drop the code, or show only the host's wording. All six framework panels pass both values identically (react is the canon; preact re-exports it), and the value renders as a text node, so a markup-looking message is never interpreted. The empty-message case cannot render: every framework already gates the upload-error slot on a truthy uploadError, which is pinned by the react suite - so no second key variant is needed.
fix(core): hide default capture sources that can never satisfy allowedFileTypes
fix(core): host error message slot and EXIF-skip signal (#367 items 2, 4)
Two UI fixes across React and its five DOM-identical ports. #352 part 2 — the compact FileRow wrapped ProgressBar in a second `!!progress` gate. ProgressBar already self-gates on `progress || isUploadActive(status)`, so the outer wrapper only ever subtracted: between "run started" and "first byte acknowledged" the list row stayed blank while the grid tile, the hero and the list footer all showed their bars. Removing the wrapper (not rewriting the condition) leaves one gate, inside ProgressBar. Idle is unchanged — no progress, no active run, still no bar — so parity fixtures do not move. #229 — the four base64 PNG logos in src/assets/logos.ts shipped at up to 1905x580 for a fixed 61x13 CSS-pixel box. They are re-exported at 122x26 (2x the rendered box, palette-quantized where that wins, alpha kept), regenerated once and copied byte-identically into all five packages. Per-file: 167 KB to 13 KB; about 109 KB gzipped off every UI bundle. Rendered appearance is unchanged, including the existing horizontal squash of the devino wordmark, which the fixed-size box already applied.
Four comment-only corrections. No SHA, no workflow logic, no code changes. The 23 `pnpm/action-setup@0977fd99` pins across e2e, main, nightly and publish were all annotated `# v4.4.0`. That SHA is v6.0.10: the annotated tag refs/tags/v6.0.10 is ff378ebe, which dereferences to commit 0977fd99 (PGP signature verified). Since the pin is what actually runs, the comment was understating the action by two majors to anyone reading or reviewing it. CLAUDE.md's lint gate claimed "3 apps (playground, landing, docs)". There is no apps/docs — the docs moved into apps/landing — and only landing and playground define a `lint` script, so the leaf count is 2. publish-sdk.yml's header said this repo's release flow "publishes the root `upup` package". Root package.json is `name: upup`, `private: true`, and is never published; changesets publishes the nine `@useupup/*` workspace packages. The point the sentence was making — that this workflow must never fire as a side effect of the release flow — is preserved and now rests on a true premise. CLAUDE.md's package map had no entry for `sdk/` at all, leaving a publishable directory and a second publish workflow undocumented. Added as a name reservation: `@useupup/sdk@0.0.1`, outside the pnpm workspace globs, outside the changesets release, workflow_dispatch only, maintainer decision to touch.
chore: correct action pin comments and stale doc statements
Review or Edit in CodeSandboxOpen the branch in Web Editor • VS Code • Insiders |
This was referenced Sep 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotes dev (
c7b681de) to master.Included since the last promotion (#383):
uploadFailedWithCodemessage slot + EXIF-skip metadata signal (Follow-ups from the #364/#365 review: HTML error-page fallback, panel message for host codes, animated-skip runtime signal, prefix-read sniffing #367 items 2, 4)Changesets from #389/#396/#397/#398 will fold into the Version Packages PR (#384) on merge; 3.3.1 is published only when #384 is merged.