[PHP] Add zstd decoder stream for tar bundles - #3927
Merged
Conversation
adamziel
force-pushed
the
adamziel/tar-zst-parser
branch
from
July 7, 2026 14:54
eb99759 to
9140ea5
Compare
adamziel
force-pushed
the
adamziel/tar-zst-decoder
branch
from
July 7, 2026 14:56
cfaaf1e to
0b38e65
Compare
adamziel
force-pushed
the
adamziel/tar-zst-parser
branch
from
July 7, 2026 16:16
9140ea5 to
0b0f230
Compare
adamziel
force-pushed
the
adamziel/tar-zst-decoder
branch
from
July 7, 2026 16:20
0b38e65 to
938b848
Compare
adamziel
force-pushed
the
adamziel/tar-zst-parser
branch
from
July 7, 2026 18:36
0b0f230 to
09faba8
Compare
adamziel
force-pushed
the
adamziel/tar-zst-decoder
branch
from
July 7, 2026 18:37
938b848 to
69d9d07
Compare
adamziel
force-pushed
the
adamziel/tar-zst-parser
branch
from
July 7, 2026 19:30
09faba8 to
4ce5b5e
Compare
adamziel
force-pushed
the
adamziel/tar-zst-decoder
branch
from
July 7, 2026 19:31
69d9d07 to
1ca7b06
Compare
adamziel
force-pushed
the
adamziel/tar-zst-decoder
branch
from
July 7, 2026 19:49
1ca7b06 to
5155c1b
Compare
adamziel
marked this pull request as ready for review
July 7, 2026 19:52
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a streaming decoder layer that converts compressed TAR bundle bytes into a decoded ReadableStream<Uint8Array> suitable for StreamingTarParser, including a zstddec streaming fallback for .tar.zst bundles where DecompressionStream('zstd') isn’t available.
Changes:
- Introduces
createDecodedTarStream()with nativeDecompressionStreamfirst andzstddec/streamfallback for Zstandard. - Adds zstd round-trip tests (conditionally skipped if Node lacks zstd in
node:zlib). - Adds
zstddecdependency.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| packages/playground/wordpress/src/streaming-tar-extract.ts | Adds createDecodedTarStream() plus helpers to normalize inputs and decode tar bytes (native + zstd fallback). |
| packages/playground/wordpress/src/streaming-tar-extract.spec.ts | Adds round-trip tests and helpers to validate zstd decoding into StreamingTarParser. |
| package.json | Adds zstddec dependency needed for zstd fallback decoding. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
adamziel
added a commit
that referenced
this pull request
Jul 7, 2026
## What it does Adds the runtime extraction path for `tar.zst` WordPress core bundles while keeping the existing `wordPressZip` / `unzipWordPress()` API names. This PR does not switch committed WordPress core bundle artifacts to `tar.zst`. ZIP inputs from wordpress.org, custom URLs, trunk/nightly downloads, plugins, themes, Blueprints, and GitHub artifacts stay on the existing ZIP path. ## Rationale #3926 added the TAR parser and #3927 added the zstd decoder stream. The next step for #3913 is making WordPress boot able to consume a `tar.zst` core bundle before changing the produced bundle artifacts. Keeping runtime support separate from the artifact switch lets reviewers validate the extraction behavior, API compatibility, and ZIP fallback path independently. ## Implementation `unzipWordPress()` now sniffs the first four bytes of the supplied `File`: 1. zstd magic (`28 b5 2f fd`) routes through `createDecodedTarStream(..., 'zstd')`. 2. Decoded TAR bytes stream into `extractTarStreamToPhp()` one entry at a time. 3. ZIP and all other inputs continue through `unzipFile()` / PHP `ZipArchive`. 4. `wordPressBundleFileCount` enables a tar.zst-only file-count parity check when bundle metadata provides one. The extractor writes files under `/tmp/unzipped-wordpress`, rejects unsafe TAR entries through the parser, preserves `overwriteFiles=false`, and handles `targetRoot='/'` as an absolute root instead of producing relative paths. ## Testing instructions ```bash npx nx test playground-wordpress --testFile=streaming-tar-extract.spec.ts npx nx run playground-wordpress:lint ``` CI should run the broader package, typecheck, and browser/CLI coverage for the rebased PR.
adamziel
added a commit
that referenced
this pull request
Jul 7, 2026
## What it does Related to #3913. Replaces the committed minified WordPress core bundle artifacts from `wp-*.zip` to deterministic `wp-*.tar.zst` files. This PR builds on the already-merged runtime/parser work: #3926, #3927, and #3925. It does not change non-core ZIP flows. WordPress.org downloads, custom URLs, `trunk`/`nightly`, plugins, themes, GitHub artifacts, and Blueprint ZIP imports continue to use ZIP. ## Rationale After #3916 removed the duplicated embedded `wordpress-static.zip`, the remaining minified WordPress tree compresses better as a solid zstd-compressed tar than as ZIP. The runtime can now stream-decode zstd and parse TAR entries incrementally, so the committed core bundle can switch formats without changing the public boot API. Keeping remote and user-supplied archives as ZIP avoids expanding the scope of this change beyond the committed Playground-managed core bundles. ## Implementation Adds a deterministic core-bundle build path that: - re-containers the minified WordPress ZIP build output into `wp-<version>.tar.zst`, - writes `format`, `container`, `codec`, `size`, `sha256`, and `fileCount` descriptors, - verifies committed tar.zst artifacts against those descriptors, - fails loudly for unsafe source archive paths instead of silently dropping them, - removes committed `wp-*.zip` artifacts for minified core versions, and - teaches Vite/offline asset handling about `.tar.zst` and hashed `.zst` files. The generated descriptor still marks `trunk`/`nightly` as ZIP because those versions are fetched directly from GitHub as ZIP archives instead of using committed Playground core artifacts. ## Testing instructions ```bash node packages/playground/wordpress-builds/build/build-tar-zst.mjs --verify npx nx test playground-wordpress-builds npx nx test playground-wordpress npx nx test playground-remote npx nx typecheck playground-remote npx nx run-many -t lint -p playground-wordpress-builds,playground-remote,playground-wordpress ```
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.
What it does
Adds
createDecodedTarStream(), a streaming codec layer that turns compressed TAR bundle bytes into aReadableStream<Uint8Array>forStreamingTarParserfrom #3926.This PR adds the
zstddecfallback needed for futuretar.zstWordPress core bundles. It does not switch any WordPress bundle URLs or boot paths totar.zstyet.Rationale
The parser from #3926 consumes plain TAR bytes. The bundle work in #3913 needs to feed it
.tar.zstbytes, but browser support for nativeDecompressionStream('zstd')is not universal.Keeping this as a small follow-up makes the dependency and decoder behavior reviewable on their own before the PR that changes the actual WordPress bundle format.
Implementation
createDecodedTarStream(compressed, codec):Uint8ArrayorReadableStream<Uint8Array>.DecompressionStreamwhen the runtime supports the requested codec.zstddec/streamforcodec === 'zstd'.The zstd fallback uses
ZSTDDecoder.decodeStreaming()to emit decoded TAR chunks without materializing the full decompressed archive in JS. Becausezstddecconsumes a synchronous iterable,ReadableStreaminput is first collected as compressed chunks before the decoder stream is returned.Related: #3913
Testing instructions
npx nx test playground-wordpress --testFile=streaming-tar-extract.spec.ts npx nx run playground-wordpress:lint npx nx build playground-wordpressThe zstd fallback test uses a checked-in
.tar.zstbyte fixture generated withbsdtarandzstd, so it runs on Node 20 withoutnode:zlibzstd compression support.