v0.22.0
Closing-the-gaps minor — every remaining item from the v0.17 deep
audit, plus React parity, hardened CI, and the long-promised
release-via-workflow_dispatch automation.
Added (backend)
SimpleDirectoryContextclass form of the registry's "simple"
flow (src/Contexts/SimpleDirectoryContext.php). The
ContextRegistry::registerSimple()helper now instantiates it
rather than carrying inline closures, which makes the simple flow
subclassable and unit-testable in isolation.AssembleFileJobis fully configurable via the new
chunky.assemblynamespace:tries,backoff,timeout, and
queue. The previous hard-coded$tries = 3, $backoff = 30and
the implicit 60s queue timeout are gone — the queue worker default
was far too short for multi-GB assemblies.HasArrayPayloadtrait on the DTOs (UploadMetadata,
BatchMetadata). Centralises the snake_case ↔ camelCase mapping
the tracker storage layer uses, so adding a field touches one
place instead of three.- Broadcast channel auth cache — the
routes/channels.php
callbacks now memoise the upload/batch lookup for
chunky.broadcasting.auth_cache_ttl_seconds(default 30s). A
client disconnect/reconnect storm no longer fans out to the
tracker on every subscription auth. UploadStatusController,BatchStatusController,
CancelUploadController,CancelBatchControlleraccept
Illuminate\Http\Requestvia DI instead of pulling the user from
theauth()facade. Mockable from a unit test without booting the
auth manager.- Livewire blade fallback markup — when
chunkUploadis missing
from the global JS scope, the rendered component shows a clear
"frontend not loaded" message instead of silently dying with an
Alpine console error. UploadChunkRequest.checksumregex validation (/^[a-f0-9]{64}$/i).
Prevents arbitrary strings from being stuffed into the cache key
via the idempotency lookup path.DatabaseTracker::claimForAssembly()explicit status allowlist
in the CAS query. Makes the legal source statuses declarative —
adding a newUploadStatusenum case can no longer slip through
the orWhere chain unnoticed.Metricshonours theMetricsListenercontract first when a
class-string handler implements it. The interface stops being
vestigial.
Added (frontend)
- Tools subpath export
@netipar/chunky-core/toolsexposes
EventEmitterandRetryPolicyfor advanced consumers building
their own orchestrators on the same primitives the package uses.
Marked@internaluntil v1.0; pin the package version exactly
when importing from this surface. mergeDefaults()+resetDefaults()functions on the core
defaults API (andmergeDefaults/resetonDefaultsScope).
Replaces the silent-overwrite footgun where back-to-back
setDefaults({ headers: ... })+setDefaults({ context: ... })
would drop the headers.HeadersInitaccepted everywhere for theheadersoption
(record / array tuple /Headersinstance).normalizeHeaders()
flattens internally; the package still stores headers as a flat
record so individual keys (X-XSRF-TOKEN,Idempotency-Key)
can be read without.get().BatchUploader.validateBatchEndpoints()— refuses to
construct whenbatchUpload/batchStatuslack the{batchId}
placeholder. Catches typos at construction time instead of at
call time with a 404 on a literal{batchId}URL.BatchUploadOptions.chunkEndpoints/batchEndpointssplit.
Lets new code keep the per-chunk and batch endpoints in separate
objects. The legacy mixedendpointsshape still works.useBatchCompletionhook on React — parity with the Vue
composable. Tracks caller callbacks viauseRefso a re-render
with a new options literal does not trigger re-subscription
churn.BatchInitiateResponseis now an open type ([extra: string]: unknown),
so server-supplied extras pass through untyped instead of being
silently dropped at the type boundary.- Dev-mode warning on unknown event names in
ChunkUploader.on().
The compile-time check catches typos in the typed call site, but
a(name as any)dispatch would silently never fire — this gives
a console hint. scripts/bump-version.shis now consumed by a new
release.ymlGitHub Actions workflow with aworkflow_dispatch
trigger. Triggering "Run workflow" with a version input bumps
the four npm package.json files, commits, tags, and publishes
the GitHub Release end-to-end.
Changed (breaking)
UploadTracker::markChunkUploaded()no longer accepts the
unused?string $checksumparameter. The signature was
defined but never persisted — the contract is now honest.ChunkyManager::handler()andtracker()@internal
accessors removed. Resolve the underlying services through the
container instead.- AWS-style "full jitter" retry delays in
RetryPolicy(was
baseDelay + Math.random() * 250). Many parallel chunk workers
now genuinely de-synchronise on retry instead of all hammering
the server in lockstep. upload()resume falls through to a fresh initiate on 404
(was: surfaced the 404 as the upload's own error). Lets a
client transparently recover when the server's expiration
sweep collected the upload between pause and resume.ChunkUploader.uploadId!non-null assertion replaced by a
local capture. A future edit that resetsthis.uploadId
earlier in the flow can no longer crash the result-payload
build.BatchUploaderhonours thescope-supplied defaults in its
ownfetchJsoncalls, not just in the per-file
ChunkUploaders it creates. Multi-scope setups now behave
consistently.BatchUploaderclones itsoptionssnapshot at construction.
Caller-side mutations after the fact (common in reactive
frameworks) no longer bleed into in-flight uploads.- React
useBatchUpload/useChunkUploadare mount-only on
options. The olduseMemo(() => JSON.stringify(options))
threw on circular refs (Headers, functions) and silently lost
data onDate/Mapvalues — neither edge case is a real
use, so the option snapshot is now taken viauseRefonce on
mount. Callers that need to change options at runtime should
unmount/remount the hook or use the imperative core
BatchUploaderdirectly. - Vue
useChunkyEcho/ ReactuseChunkyEchotrack callbacks
via ref. A re-render that creates a freshcallbacks = { ... }
literal no longer dispatches into stale closures.
Removed
broadcasting.user_channel,idempotency.enabled,
skip_local_disk_guardflags — already dropped in v0.18; this
release deletes the last remaining?string $checksumshim from
the tracker contract and theChunkyManager::handler()/tracker()
accessors.
Tooling / governance
- CI quality job consolidation. Pint, PHPStan, and
composer auditrun in onequalityjob (instead of three identical
composer installjobs). Frontend gets a singlejs-quality
job covering typecheck + tests + build +pnpm audit. actionlintGitHub workflow lints every.github/workflows/*.yml
on every push. Catches a malformed YAML before the workflow
silently dies.markdownlint-cli2runs against README, CHANGELOG, UPGRADE,
SECURITY, CONTRIBUTING, anddocs/**/*.md. Continue-on-error so
a stylistic nit does not block the merge queue.release.ymlworkflow_dispatch trigger lets a maintainer
release v$X.Y.Z by clicking "Run workflow" — the workflow
validates the CHANGELOG entry exists, runsbump-version.sh,
commits the bumps, and creates the GitHub Release with the
CHANGELOG entry as release notes.- TypeScript pre-check on build. Every package's
buildscript
now runstsc --noEmit -p tsconfig.jsonfirst, so a typo in
source surfaces during the build instead of after publish.
Tests
mockFetchSequencehelper bumped to supportdelayMs,
validateRequest, custom headers / raw body. The previous
signature didn't let a test assert what headers a chunk POST
carried.
npm packages
- All packages bumped to
0.22.0(frontend changes — tools
subpath, mergeDefaults, HeadersInit, useBatchCompletion on React,
validateBatchEndpoints, options clone, full jitter retry, resume
404 recovery, mount-only React options snapshot, callback-ref
tracking).