Skip to content

feat!: sync PHP client with apify-client-js master and spec v2-2026-10-01T153946Z - #15

Merged
Pijukatel merged 5 commits into
masterfrom
claude/dazzling-ritchie-ciag1b
Oct 6, 2026
Merged

Pijukatel merged 5 commits into
masterfrom
claude/dazzling-ritchie-ciag1b

Conversation

@Pijukatel

@Pijukatel Pijukatel commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Syncs the client to OpenAPI spec v2-2026-10-01T153946Z (up from v2-2026-09-28T115051Z, #14) and to all 33 referenced apify-client-js PRs. All 33 are merged into its master. An earlier revision of this PR wrongly left out 27 of them as targeting an unmerged v3 branch; this revision checks each of the 33 against a fresh clone and finds every one on apify-client-js origin/master.

Spec delta (apify/apify-docs#3037, apify/apify-docs#3024):

  • Build::getImageDigest() returns the new imageDigest field.
  • The task-publish docs no longer carry a stale "contact support" sentence (text-only change).

Reference-client delta: ported

  • New InvalidRequestException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException, RateLimitException and ServerException, thrown by HTTP status. They all extend ApifyApiException.

  • 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 null or doing nothing in two cases:

    • get()/delete() on a resource client obtained without an ID: RunClient::dataset(), keyValueStore(), requestQueue(), log(), and BuildClient::log().
    • The fixed sub-paths getStatistics(), getInput(), getLog() and getOpenApiDefinition().

    In both cases the response can't tell a missing parent from a missing sub-resource.

  • Behavior change: ActorClient::version()/build() and ActorVersionClient::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, timeoutLongSecs and timeoutMaxSecs on ApifyClient. Every method that sends a request also takes a per-call $timeoutSecs override: seconds, a tier name, or 'noTimeout'.

  • compression option on ApifyClient: 'brotli', 'gzip' or a custom HttpCompressorInterface. Without it, behavior doesn't change.

  • Request-body compression is skipped for content types that are already compressed.

  • baseUrl/publicBaseUrl accept a URL that already ends with /v2 without doubling it.

  • RequestQueueClient::batchAddRequests() serializes each request once, and its per-item size check uses the reference client's byte accounting.

  • DatasetClient::createItemsPublicUrl() takes a format parameter.

  • DatasetClient::iterateItems() paginates by the scanned-row count.

  • ActorClient::start()/validateInput() and RunClient::metamorph() send a string input as raw bytes.

Reference-client delta: not ported. Every PR has a reason recorded in the archived notes:

  • No PHP equivalent:
    • URL-field normalization
    • TypeScript-only type changes
    • an AbortSignal cancellation API, which doesn't fit a synchronous client
    • ESM, zod and dependency tooling changes
  • Not removed: options that were already deprecated, because removing them would be a public-interface break.
  • Already covered by the existing design: a custom HTTP client and the error body of a failed streaming request.

CLIENT_VERSION goes from 0.6.2 to 0.8.0.

Review: two /review-client rounds on the corrected scope. Their findings on timeout tiers, path safety and docs are fixed in 57a2475, 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.

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
@apify-service-account apify-service-account added the tested Temporary label used only programatically for some analytics. label Oct 2, 2026
@apify-service-account apify-service-account added the t-tooling Issues with this label are in the ownership of the tooling team. label Oct 2, 2026
claude added 3 commits October 2, 2026 19:21
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
@Pijukatel Pijukatel changed the title chore: sync PHP client with Apify OpenAPI spec v2-2026-10-01T153946Z fix: sync PHP client with apify-client-js master (spec v2-2026-10-01T153946Z) Oct 2, 2026
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
@Pijukatel Pijukatel added the adhoc Ad-hoc unplanned task added during the sprint. label Oct 2, 2026 — with Claude
@Pijukatel Pijukatel changed the title fix: sync PHP client with apify-client-js master (spec v2-2026-10-01T153946Z) feat!: sync PHP client with apify-client-js master and spec v2-2026-10-01T153946Z Oct 2, 2026
@Pijukatel
Pijukatel merged commit b10f18a into master Oct 6, 2026
3 of 6 checks passed
@Pijukatel
Pijukatel deleted the claude/dazzling-ritchie-ciag1b branch October 6, 2026 08:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

adhoc Ad-hoc unplanned task added during the sprint. t-tooling Issues with this label are in the ownership of the tooling team. tested Temporary label used only programatically for some analytics.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants