Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added request-local `baseUrl()` support for relative request and download URLs.
- Added `FetchResponse::statusIs()` and named helpers for common HTTP statuses.
- Added application-wide Laravel listeners for the existing request started, completed, and failed events.
- Added opt-in named terminal events for delivering request, upload, and download results to the active NativePHP screen.
- Added active-request snapshots, per-request activity checks, and bulk cancellation for native operations.
- Added live transfer progress and retry-waiting state to active-request snapshots.
- Added throttled `FetchActiveRequestsChanged` component events for reactive activity screens.
- Added a version-organized What's New documentation page with quick examples and links to full guides.

### Changed

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Laravel's HTTP client instead.
- JSON, form-encoded, raw, and multipart request bodies
- Multiple attachments and repeated multipart field names
- Upload and download progress events
- Named terminal events delivered to the active screen
- Active-request inspection and bulk cancellation
- Streaming file downloads
- Opt-in retries with exponential backoff
- Per-attempt timeouts and explicit cancellation
Expand All @@ -33,6 +35,8 @@ excludes future major versions.
Read the complete documentation at
[victorycodedev.github.io/nativephp-fetch](https://victorycodedev.github.io/nativephp-fetch/).

See [what's new](https://victorycodedev.github.io/nativephp-fetch/whats-new) for short, versioned examples of recently added APIs.

## Installation

See the [installation guide](https://victorycodedev.github.io/nativephp-fetch/getting-started).
Expand All @@ -51,6 +55,8 @@ See the [JavaScript client guide](https://victorycodedev.github.io/nativephp-fet
- [Uploads](https://victorycodedev.github.io/nativephp-fetch/uploads)
- [Downloads](https://victorycodedev.github.io/nativephp-fetch/downloads)
- [Events and responses](https://victorycodedev.github.io/nativephp-fetch/events)
- [Shared events](https://victorycodedev.github.io/nativephp-fetch/shared-events)
- [Active requests](https://victorycodedev.github.io/nativephp-fetch/active-requests)
- [Retries and cancellation](https://victorycodedev.github.io/nativephp-fetch/retries-cancellation)
- [API reference](https://victorycodedev.github.io/nativephp-fetch/api-reference)

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
}
},
"require-dev": {
"illuminate/container": "^11.0 || ^12.0 || ^13.0",
"laravel/pint": "^1.30",
"pestphp/pest": "^4.0",
"phpstan/phpstan": "^2.2"
Expand All @@ -59,4 +60,4 @@
"pestphp/pest-plugin": true
}
}
}
}
4 changes: 4 additions & 0 deletions docs/.vitepress/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default defineConfig({
search: { provider: "local" },
nav: [
{ text: "Guide", link: "/getting-started" },
{ text: "What's New", link: "/whats-new" },
{ text: "API", link: "/api-reference" },
{ text: "GitHub", link: "https://github.com/victorycodedev/nativephp-fetch" },
],
Expand All @@ -20,6 +21,7 @@ export default defineConfig({
text: "Getting started",
items: [
{ text: "Introduction", link: "/" },
{ text: "What's new", link: "/whats-new" },
{ text: "Installation", link: "/getting-started" },
{ text: "Making requests", link: "/requests" },
],
Expand All @@ -29,6 +31,8 @@ export default defineConfig({
items: [
{ text: "Uploads", link: "/uploads" },
{ text: "Downloads", link: "/downloads" },
{ text: "Shared events", link: "/shared-events" },
{ text: "Active requests", link: "/active-requests" },
{ text: "NativeComponent example", link: "/native-component" },
{ text: "Retries and cancellation", link: "/retries-cancellation" },
{ text: "Events and responses", link: "/events" },
Expand Down
98 changes: 98 additions & 0 deletions docs/active-requests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Active requests

Fetch can inspect the logical requests currently owned by the native networking layer. This is useful for showing an activity screen, preventing duplicate work, or cancelling operations that began on another screen.

## List active work

```php
use Victorycodedev\NativephpFetch\Facades\Fetch;

$requests = Fetch::active();

foreach ($requests as $request) {
$request->requestId;
$request->method;
$request->url;
$request->type; // request or download
$request->attempt; // current attempt, starting at 1
$request->state; // running or waiting_retry
$request->bytesTransferred;
$request->bytesTotal; // null when unknown
$request->progress; // null or 0.0–1.0
$request->nextRetryAt; // Unix time in milliseconds, or null
}
```

Each entry is an immutable `ActiveRequest` snapshot. Uploads have the `request` type because they use the normal request lifecycle. Downloads use the `download` type.

Ordinary requests generally have `null` progress because their response body is not exposed as a streaming download. Uploads and downloads update their byte and progress fields while transferring. During native retry backoff, `state` becomes `waiting_retry` and `nextRetryAt` indicates when the next attempt is scheduled.

## Activity-screen example

```php
use Native\Mobile\Attributes\On;
use Victorycodedev\NativephpFetch\Events\FetchActiveRequestsChanged;

public function mount(): void
{
$this->refreshTransfers();
}

#[On(FetchActiveRequestsChanged::class)]
public function activeRequestsChanged(string $requestId, string $change): void
{
$this->refreshTransfers();
}

public function refreshTransfers(): void
{
$this->transfers = array_map(
fn ($request) => [
'id' => $request->requestId,
'label' => $request->type === 'download' ? 'Downloading' : 'Uploading',
'progress' => $request->progress,
'waiting' => $request->state === 'waiting_retry',
],
Fetch::active(),
);
}
```

Call `refreshTransfers()` when the screen opens so work started on another screen appears immediately. `FetchActiveRequestsChanged` then refreshes the active screen when an operation starts, progresses, enters or leaves retry waiting, or finishes.

The event contains `requestId` and `change`. The change is `started`, `progress`, `waiting_retry`, `running`, or `finished`. Progress notifications are throttled natively to at most one every 250 milliseconds per request, while lifecycle changes are immediate. `active()` still returns a point-in-time snapshot; it does not continuously mutate PHP state.

## Check one request

```php
if (Fetch::isActive($requestId)) {
// The native operation or one of its retry delays is still active.
}
```

## Cancel everything

```php
$cancelled = Fetch::cancelAll();
```

`cancelAll()` returns the number of logical operations that accepted cancellation. Every cancelled operation still emits its existing `FetchRequestCancelled` event and its named terminal event when `shared()` was configured.

## JavaScript

```javascript
const requests = await Fetch.active();
const running = await Fetch.isActive(requestId);
const cancelled = await Fetch.cancelAll();
```

JavaScript receives the same snapshot fields as plain objects.

## Lifecycle semantics

- A request appears after native preparation succeeds and remains listed during retry delays.
- Retries update `attempt`; they do not create duplicate entries.
- Transfer counters describe the current attempt and reset when a retry begins.
- Completed, failed, and cancelled operations are removed.
- The registry is held by the running native application process. It is not durable after application termination.
- Fetch fakes complete synchronously, so `active()` is empty and `cancelAll()` returns `0` while faking.
Loading
Loading