Repository navigation
feat!: sync PHP client with apify-client-js master and spec v2-2026-10-01T153946Z - #15
Merged
Merged
Conversation
Covers the exact spec delta (apify-docs #3037 imageDigest field, #3024 task-publish text fix) plus the master-targeted subset of the referenced apify-client-js PRs (the rest target its unmerged v3 branch and are out of scope per client_requirements.md's master-only reference pin): Build::getImageDigest(), DatasetClient::createItemsPublicUrl() format parameter, a scanned-count pagination fix for DatasetClient::iterateItems() (X-Apify-Pagination-Count), and raw-bytes Actor input support for start()/validateInput()/metamorph(). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STUGToGEaEFoBGRbWTvF4m
Simplifies the redundant min() in DatasetClient::iterateItems()'s page cap and moves ResourceContext::minLimit()'s @internal tag onto its own line so phpDoc tooling recognizes it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STUGToGEaEFoBGRbWTvF4m
A prior sync wrongly excluded 27 of 33 referenced apify-client-js PRs as
targeting an unmerged v3 branch; all 33 are merged to its master. This
re-evaluates and ports every PHP-relevant behavior change, additively:
- Added ApifyApiException subclasses grouped by HTTP status
(InvalidRequestException, UnauthorizedException, ForbiddenException,
NotFoundException, ConflictException, RateLimitException, ServerException).
- A 404 is now swallowed regardless of its `type` (was a narrow allowlist).
- get()/delete() on an ID-less chained resource client (run.dataset(),
run.keyValueStore(), run.requestQueue(), run.log(), build.log()) and fixed
sub-paths of an ID-addressed resource (getStatistics(), getInput(),
getLog(), getOpenApiDefinition()) now throw instead of resolving to
null/no-op on a 404, since the response can't tell a missing parent apart
from a missing sub-resource/sub-path.
- ActorClient::version()/build() and ActorVersionClient::envVar() reject an
empty-string identifier.
- Fixed ResourceContext::toSafeId() to replace every "/" in an id, not just
the first. Resource ids and path segments built from caller input are now
rejected (InvalidArgumentException) when empty or "."/"..", instead of
being percent-encoded and sent as literal dot-segments.
- Added timeout tiers (timeoutShortSecs/timeoutMediumSecs/timeoutLongSecs/
timeoutMaxSecs on ApifyClient, each defaulting to the existing timeoutSecs)
and an optional per-call $timeoutSecs override on every resource client's
get()/update()/delete().
- Added a `compression` option to ApifyClient ('brotli'/'gzip'/a custom
HttpCompressorInterface); left unset, behavior is unchanged.
- Request-body compression is now skipped for content types that already
carry their own compression (images, audio, video, archives, fonts).
- ApifyClient's baseUrl/publicBaseUrl now accept a URL that already ends
with /v2 without doubling it.
- RequestQueueClient::batchAddRequests() now serializes each request once
instead of re-encoding it for the size check, the chunk split, and the
request body.
Every one of the 27 PRs is accounted for in notes.md, including the ones
with no PHP change and why (architecture mismatches or changes that would
themselves be a disallowed breaking change).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STUGToGEaEFoBGRbWTvF4m
- Fixed the Test examples CI step: the README error-handling snippet duplicated the harness-injected `use ApifyApiException`; also added NotFoundException to the harness's shared imports. - Wired the medium/long timeout tiers to every listing/batch/trigger and download/upload/streaming method across all resource and collection clients (previously only short was used, on get/update/delete), with a per-call $timeoutSecs override threaded through every new call site. - Fixed 'noTimeout' to actually disable the request timeout (TimeoutTiers now resolves it to 0.0, which the transport treats as infinite, instead of null, which every `??` fallback silently discarded back to the default). Fixed the per-queue timeoutSecs cap (requestQueue(id, options)) to keep applying now that tier resolution never returns null. - Fixed two bugs the tier wiring surfaced under the full test suite: RequestQueueCollectionClient::getOrCreate() passed the resolved timeout into the wrong positional parameter, and ActorEnvVarCollectionClient::iterate()'s per-page closure didn't capture $timeoutSecs. - Fixed batchAddRequests()'s per-item size check to account for both brackets of a single-item batch body, matching the reference client's accounting exactly. - ScheduleClient::getLog() is no longer nullable: it always throws instead of returning null now that it never swallows a 404. Tightened related docblocks on getInput()/getStatistics()/getOpenApiDefinition() to describe their remaining (non-404) null source. - Removed a redundant double-min in ResourceContext::paginateOffset() and a redundant size-gate duplication in request-body compression. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STUGToGEaEFoBGRbWTvF4m
CI's `composer stan` (phpstan, unavailable in this sandbox via the usual
composer install path) caught two real static-analysis errors in the test
files added for this PR:
- AmbiguousNotFoundTest::statusClassProvider()'s array used numeric-string
keys ('400', '401', ...), which PHP auto-casts to int keys, so the
inferred type didn't match the declared array<string, ...> docblock.
Switched to non-numeric keys ('status 400', ...).
- CompressionConfigTest::largeBody() was missing a value type on its
array return type.
Verified by downloading phpstan.phar directly (matching CI's locked
1.12.33) and running `phpstan analyse`: 0 errors.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STUGToGEaEFoBGRbWTvF4m
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.
Syncs the client to OpenAPI spec
v2-2026-10-01T153946Z(up fromv2-2026-09-28T115051Z, #14) and to all 33 referenced apify-client-js PRs. All 33 are merged into itsmaster. An earlier revision of this PR wrongly left out 27 of them as targeting an unmergedv3branch; this revision checks each of the 33 against a fresh clone and finds every one onapify-client-jsorigin/master.Spec delta (apify/apify-docs#3037, apify/apify-docs#3024):
Build::getImageDigest()returns the newimageDigestfield.Reference-client delta: ported
New
InvalidRequestException,UnauthorizedException,ForbiddenException,NotFoundException,ConflictException,RateLimitExceptionandServerException, thrown by HTTP status. They all extendApifyApiException.A 404 is swallowed regardless of its
type. Before, only a short allowlist of types was swallowed.Behavior change: a 404 now throws instead of resolving to
nullor doing nothing in two cases:get()/delete()on a resource client obtained without an ID:RunClient::dataset(),keyValueStore(),requestQueue(),log(), andBuildClient::log().getStatistics(),getInput(),getLog()andgetOpenApiDefinition().In both cases the response can't tell a missing parent from a missing sub-resource.
Behavior change:
ActorClient::version()/build()andActorVersionClient::envVar()reject an empty-string identifier.Behavior change: IDs and path segments built from caller input are rejected when empty or
./... Before, they were percent-encoded and sent as literal dot-segments.ResourceContext::toSafeId()replaces every/in an ID, not just the first one.Timeout tiers:
timeoutShortSecs,timeoutMediumSecs,timeoutLongSecsandtimeoutMaxSecsonApifyClient. Every method that sends a request also takes a per-call$timeoutSecsoverride: seconds, a tier name, or'noTimeout'.compressionoption onApifyClient:'brotli','gzip'or a customHttpCompressorInterface. Without it, behavior doesn't change.Request-body compression is skipped for content types that are already compressed.
baseUrl/publicBaseUrlaccept a URL that already ends with/v2without doubling it.RequestQueueClient::batchAddRequests()serializes each request once, and its per-item size check uses the reference client's byte accounting.DatasetClient::createItemsPublicUrl()takes aformatparameter.DatasetClient::iterateItems()paginates by the scanned-row count.ActorClient::start()/validateInput()andRunClient::metamorph()send astringinput as raw bytes.Reference-client delta: not ported. Every PR has a reason recorded in the archived notes:
AbortSignalcancellation API, which doesn't fit a synchronous clientCLIENT_VERSIONgoes from0.6.2to0.8.0.Review: two
/review-clientrounds on the corrected scope. Their findings on timeout tiers, path safety and docs are fixed in57a2475, and the final round was Approved with no open items.Verification: lint 0/146, unit tests 189/189, examples 46/46, integration tests 59/59 against the live API, PHPStan 0 errors. CI is green on
5313016.