Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
4d226b4
remove spatie/data-transfer-object dependency
herpaderpaldent Jan 19, 2023
73d4686
Fix styling
herpaderpaldent Jan 19, 2023
c4bbdd0
Fix/badges (#18)
herpaderpaldent Jan 19, 2023
7364a2a
Update PHP version requirement to 8.3 and add Rector/rector in requir…
herpaderpaldent Sep 16, 2024
70053ee
Update GuzzleFetcherTest for Carbon\Carbon::now() usage.
herpaderpaldent Sep 16, 2024
a76dcdd
Add VerifyAccessTokenTest.php and VerifyAccessToken.php files for tok…
herpaderpaldent Sep 18, 2024
5bbae86
Refactored UpdateRefreshTokenService constructor for dependency injec…
herpaderpaldent Sep 18, 2024
efb5e6c
Create JwtService class with methods to decode JWT and parse JWKS.
herpaderpaldent Sep 20, 2024
22ee2c1
Create Null Logger Test
herpaderpaldent Sep 20, 2024
664a59a
Refactor __set method to return void and remove unnecessary return st…
herpaderpaldent Sep 20, 2024
07c786f
Refactor getErrorMessage method to return string directly.
herpaderpaldent Sep 20, 2024
bbe5539
Refactor EsiConfiguration to use new instance singleton pattern.
herpaderpaldent Sep 26, 2024
f4d3b2f
Refactor CheckAccess to use EsiConfiguration instead of Configuration.
herpaderpaldent Sep 26, 2024
67ca9da
Update RotatingFileLogger to use EsiConfiguration singleton for logge…
herpaderpaldent Sep 26, 2024
e976950
Refactor EsiClient invoke method for better error handling and readab…
herpaderpaldent Sep 27, 2024
58e4124
Refactor GuzzleFetcher constructor for better dependency injection.
herpaderpaldent Sep 27, 2024
7e09d87
Add method to make $method lowercase before checking URI.
herpaderpaldent Sep 27, 2024
1fc124a
Remove outdated interface implementation and add method to reset the …
herpaderpaldent Sep 27, 2024
f532dc3
improve export format
herpaderpaldent Sep 27, 2024
fdf5039
Add unit test for LaravelFileCacheMiddleware returning CacheMiddlewar…
herpaderpaldent Sep 27, 2024
2328085
Add EsiResponseTest with parsing and handling methods.
herpaderpaldent Sep 27, 2024
0de253c
lint
herpaderpaldent Sep 27, 2024
2f2f5db
Lint: enforce type declaration in GuzzleFetcher and EsiResponse methods.
herpaderpaldent Sep 27, 2024
ce783b7
rector
herpaderpaldent Sep 28, 2024
91663a6
lint
herpaderpaldent Sep 28, 2024
dfdf3ef
Workflow update
herpaderpaldent Sep 28, 2024
dd14fbf
Update code climate badges for maintainability and test coverage.
herpaderpaldent Sep 28, 2024
fb461d1
Refactor RotatingFileLoggerTest.php for log level functionality. (#19)
herpaderpaldent Sep 30, 2024
e89ae36
fix: upgrade firebase/php-jwt from v5 to v6 (#20)
herpaderpaldent Apr 24, 2026
f4cd67a
fix: upgrade firebase/php-jwt to ^7.0
herpaderpaldent Apr 24, 2026
0f27389
style: apply pint fixes for updated ruleset
herpaderpaldent Apr 24, 2026
2d621f9
chore: add logs, .phpunit.cache to .gitignore
herpaderpaldent Apr 24, 2026
8513d76
fix: pin phpstan <1.12.28 to fix pest-plugin-type-coverage incompatib…
herpaderpaldent Apr 24, 2026
f24b99c
fix: upgrade pest to v4 to resolve phpstan incompatibility
herpaderpaldent Apr 24, 2026
f02f6b9
ci: add pull_request trigger and composer.json path to formats workflow
herpaderpaldent Apr 24, 2026
0c5e244
fix: pin phpstan <1.12.28 (pest-plugin-type-coverage v4 still broken)
herpaderpaldent Apr 24, 2026
ea4f125
fix: upgrade to PHPUnit 12 / PHPStan 2 / Rector 2 for Pest 4 compatib…
herpaderpaldent Apr 24, 2026
0ff83a7
ci: remove pull_request trigger and composer.json path from formats w…
herpaderpaldent Apr 24, 2026
6744f5e
ci: add pull_request trigger for 3.x branch in formats workflow
herpaderpaldent Apr 24, 2026
a050f6b
feat: ESI rate-limit support + EsiResponse ArrayObject refactor
herpaderpaldent May 10, 2026
7e67487
feat: parse ratelimit window seconds from X-Ratelimit-Limit header
herpaderpaldent May 10, 2026
bc75600
chore: bump PHP requirement to ^8.5, add typed constants
herpaderpaldent May 11, 2026
8d575a9
chore: add version 4.0.0 field for path-repo dev workaround
herpaderpaldent May 11, 2026
96c01e7
feat!: remove deprecated EsiResponse __get/__isset shim
herpaderpaldent May 11, 2026
aac5baa
docs: update README with usage, DTO contract, and rate-limit notes
herpaderpaldent May 11, 2026
6c7ad41
feat: add EsiResult<T>, withToken(), and 30 resource stubs (typed SDK…
herpaderpaldent May 11, 2026
7c9e35d
fix(generator): body params in invoke, constant interpolation in head…
herpaderpaldent May 11, 2026
6a80c1f
test(esi-client): add tests for EsiResult and generated resources
herpaderpaldent May 11, 2026
6225faf
feat: rewrite generator for OpenAPI 3.1 YAML spec
herpaderpaldent May 11, 2026
cca5fbb
fix: remove stale Clones/ subdirectory leftover from Swagger 2.0 gene…
herpaderpaldent May 11, 2026
a77de40
fix(generator): defensive ?? fallbacks in from() for all required fields
herpaderpaldent May 11, 2026
8b81b0d
feat: integrate seatplus/esi-schema, return DTOs directly from object…
herpaderpaldent May 11, 2026
c6c8c9e
chore: delete obsolete tools/ folder, bump Rector target to PHP_85
herpaderpaldent May 11, 2026
8de41f4
feat: implement EsiTransportInterface, delete Generated/Resources
herpaderpaldent May 12, 2026
01178ca
fix: remove $version from invoke() — always uses 'latest'
herpaderpaldent May 12, 2026
32f70ae
refactor: remove dead EsiClient\EsiResult
herpaderpaldent May 12, 2026
a4aaebf
feat: populate cursor and rate-limit fields in EsiRawResponse from in…
herpaderpaldent May 12, 2026
159300d
chore: bump PHP requirement to ^8.5, Carbon to ^3.0
herpaderpaldent May 12, 2026
28595a0
fix: use seatplus/esi-schema ^1.0 stable release from Packagist
herpaderpaldent May 13, 2026
b1a190c
test: add coverage for all EsiClient factory methods; remove dead cod…
herpaderpaldent May 14, 2026
5c9b0b8
chore: lower PHP requirement from ^8.5 to ^8.2
herpaderpaldent May 14, 2026
bb3b071
chore: remove hardcoded version from composer.json
herpaderpaldent May 14, 2026
3a5dc66
chore: raise PHP requirement to ^8.3
herpaderpaldent May 14, 2026
bc3936d
refactor: replace CheckAccess with assertScope() — delete 250-line ha…
herpaderpaldent May 15, 2026
7f85db4
fix: remove /latest/ URL prefix — use server+path per ESI OpenAPI 3.1…
herpaderpaldent May 16, 2026
f2e4159
style: apply Spatie coding guidelines across all source files
herpaderpaldent May 18, 2026
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
34 changes: 34 additions & 0 deletions .github/workflows/formats.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Formats

on:
push:
paths:
- '**.php'
- 'composer.json'
pull_request:
branches: [ 3.x, 4.x ]

jobs:
ci:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
with:
php-version: '8.3'

- name: Install Composer dependencies
run: composer update --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

- name: Coding Style Checks
run: composer test:lint

- name: Type Checks
run: composer test:types

- name: Type Coverage Checks
run: composer test:type-coverage
23 changes: 0 additions & 23 deletions .github/workflows/php-cs-fixer.yml

This file was deleted.

35 changes: 0 additions & 35 deletions .github/workflows/run-tests.yml

This file was deleted.

24 changes: 24 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Tests

on:
push:
branches: [ 2.x, 3.x, 4.x ]
pull_request:
branches: [ 2.x, 3.x, 4.x ]

jobs:
ci:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
with:
php-version: '8.3'
coverage: xdebug
- name: Install Dependencies
run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Run tests with coverage
run: vendor/bin/pest --coverage --ci --min=100
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
.php_cs
.php_cs.cache
.phpunit.result.cache
.phpunit.cache
build
composer.lock
coverage
docs
logs
phpunit.xml
vendor
node_modules
Expand Down
64 changes: 55 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# Esi-Client

[![Latest Version on Packagist](https://img.shields.io/packagist/v/seatplus/esi-client.svg?style=flat-square)](https://packagist.org/packages/seatplus/esi-client)
[![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/seatplus/esi-client/run-tests?label=tests)](https://github.com/seatplus/esi-client/actions?query=workflow%3Arun-tests+branch%3Amain)
[![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/seatplus/esi-client/Check%20&%20fix%20styling?label=code%20style)](https://github.com/seatplus/esi-client/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/seatplus/esi-client.svg?style=flat-square)](https://packagist.org/packages/seatplus/esi-client)
[![Latest Stable Version](https://poser.pugx.org/seatplus/esi-client/v/stable)](https://packagist.org/packages/seatplus/esi-client)
[![Tests](https://github.com/seatplus/esi-client/actions/workflows/tests.yml/badge.svg)](https://github.com/seatplus/esi-client/actions/workflows/tests.yml)
[![Formats](https://github.com/seatplus/esi-client/actions/workflows/formats.yml/badge.svg)](https://github.com/seatplus/esi-client/actions/workflows/formats.yml)
[![Maintainability](https://api.codeclimate.com/v1/badges/642d3b3ca41e7cc3cd4f/maintainability)](https://codeclimate.com/github/seatplus/esi-client/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/642d3b3ca41e7cc3cd4f/test_coverage)](https://codeclimate.com/github/seatplus/esi-client/test_coverage)
[![Total Downloads](https://poser.pugx.org/seatplus/esi-client/downloads)](https://packagist.org/packages/seatplus/esi-client)
[![License](https://poser.pugx.org/seatplus/esi-client/license)](https://packagist.org/packages/seatplus/esi-client)

A standalone ESI (Eve Swagger Interface) Client Library using kevinrob/guzzle-cache-middleware.

> **ESI compatibility date:** This branch of `esi-client` targets ESI compatibility date **`2025-12-16`** and forward.
> Responses DTOs are sourced from [`seatplus/esi-schema`](https://github.com/seatplus/esi-schema) (`1.x`).
> If CCP publishes a new breaking compatibility date, a new major version of both packages will be released.

## Installation

You can install the package via composer:
Expand All @@ -18,19 +25,58 @@ composer require seatplus/esi-client

## Usage

### Typed SDK (recommended)

The SDK exposes typed resource methods. Single-object endpoints return the DTO directly (a subclass of `AbstractEsiDto`); paginated list endpoints return `EsiResult<array<T>>`.

```php
$esi = new Seatplus\EsiClient\EsiClient();
use Seatplus\EsiClient\EsiClient;

$sdk = new EsiClient();

// Single object — returns AllianceDetail directly
$alliance = $sdk->alliance()->getAlliancesAllianceId(99000006);
echo $alliance->name; // typed readonly string
echo $alliance->ticker;
$alliance->isCachedLoad; // bool — true if served from RFC 7234 cache

// Authenticated endpoint — returns CharactersDetail directly
$character = $sdk->withToken($accessToken)->characters()->getCharactersCharacterId(95725047);
echo $character->name;

// Paginated list — returns EsiResult (pages metadata needed)
$result = $sdk->withToken($accessToken)->assets()->getCharactersCharacterIdAssets(95725047, page: 1);
echo $result->pages; // total pages from X-Pages header
foreach ($result->data as $asset) {
echo $asset->item_id; // typed readonly int
}
```

$esi->setVersion('v5'); // if you do not set a version, esi-client is using '/latest'
### Low-level transport

// make a call
$character_info = $esi->invoke('get', '/characters/{character_id}/', [
```php
$esi = new EsiClient();

// make a call — returns EsiResponse
$response = $esi->invoke('get', '/characters/{character_id}/', [
'character_id' => 95725047,
]);

echo $character_info;
// $response->data — stdClass decoded from the JSON body
// $response->pages — total pages (from X-Pages header, or 1)
// $response->isCachedLoad() — true if served from RFC 7234 cache
```

### Rate limiting

ESI enforces a **1800-token / 15-minute** rolling window (one token consumed per request,
irrespective of response code). `esi-client` itself does not throttle — rate limiting is
handled by the consumer layer (`eveapi`) using Laravel Horizon throttle middleware on each
queued job.

If the HTTP client receives a `420 Error Limited` response, the request is retried with
exponential backoff as configured on the job.

## Testing

```bash
Expand Down
41 changes: 27 additions & 14 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,26 @@
}
],
"require": {
"php": "^8.0",
"php": "^8.3",
"ext-json": "*",
"firebase/php-jwt": "^5.4",
"firebase/php-jwt": "^7.0",
"kevinrob/guzzle-cache-middleware": "^4.0",
"nesbot/carbon": "^2.53",
"spatie/data-transfer-object": "^3.7"
"monolog/monolog": "^3.7",
"nesbot/carbon": "^3.0",
"seatplus/esi-schema": "^1.1"
},
"require-dev": {
"ext-openssl": "*",
"fzaninotto/faker": "^1.5",
"illuminate/cache": "^8.60",
"mockery/mockery": "^1.4",
"nunomaduro/collision": "^5.3",
"pestphp/pest-plugin-laravel": "^1.1",
"illuminate/cache": "^11.23",
"laravel/pint": "^1.17",
"mikey179/vfsstream": "^1",
"ext-openssl": "*"
"mockery/mockery": "^1.4",
"nunomaduro/collision": "^8.0",
"pestphp/pest": "^4.0",
"pestphp/pest-plugin-type-coverage": "^4.0",
"phpstan/phpstan": "^2.1.46",
"rector/rector": "^2.0"
},
"autoload": {
"psr-4": {
Expand All @@ -51,15 +56,23 @@
}
},
"scripts": {
"test": "./vendor/bin/pest",
"test-coverage": "XDEBUG_MODE=coverage ./vendor/bin/pest --coverage"
"lint": "vendor/bin/pint",
"test:lint": "vendor/bin/pint --test",
"test:types": "vendor/bin/phpstan --ansi",
"test:type-coverage": "vendor/bin/pest --type-coverage --min=100",
"test:unit": "vendor/bin/pest --colors=always",
"test:unit-coverage": "XDEBUG_MODE=coverage vendor/bin/pest --coverage --coverage-html=build/coverage --coverage-clover=build/logs/clover.xml --colors=always",
"test": [
"@test:lint",
"@test:types",
"@test:type-coverage",
"@test:unit"
]
},
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
8 changes: 8 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
parameters:
editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%'
level: 4
paths:
- src
tmpDir: build/phpstan


51 changes: 14 additions & 37 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,39 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
executionOrder="random"
failOnWarning="true"
failOnRisky="true"
failOnEmptyTestSuite="true"
beStrictAboutOutputDuringTests="true"
verbose="true"
>
<testsuites>
<testsuite name="Seatplus Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">./src</directory>
</include>
<report>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
<clover outputFile="build/logs/clover.xml"/>
</report>
</coverage>
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.5/phpunit.xsd" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" executionOrder="random" failOnWarning="false" failOnRisky="true" failOnEmptyTestSuite="true" beStrictAboutOutputDuringTests="true" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
<testsuites>
<testsuite name="Seatplus Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>
<source>
<include>
<directory suffix=".php">./src</directory>
</include>
</source>
</phpunit>
18 changes: 18 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\SetList;

return RectorConfig::configure()
->withSets([
SetList::PHP_85,
])
->withPaths([
__DIR__.'/src',
__DIR__.'/tests',
__DIR__.'/bin',
]);
// uncomment to reach your current PHP version
// ->withPhpSets()
2 changes: 1 addition & 1 deletion src/CacheMiddleware/CacheMiddlewareInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

interface CacheMiddlewareInterface
{
public function getCacheMiddleware() : CacheMiddleware;
public function getCacheMiddleware(): CacheMiddleware;
}
1 change: 1 addition & 0 deletions src/CacheMiddleware/LaravelFileCacheMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

class LaravelFileCacheMiddleware implements CacheMiddlewareInterface
{
#[\Override]
public function getCacheMiddleware(): CacheMiddleware
{
return new CacheMiddleware(
Expand Down
5 changes: 3 additions & 2 deletions src/CacheMiddleware/NullCacheMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

class NullCacheMiddleware implements CacheMiddlewareInterface
{
#[\Override]
public function getCacheMiddleware(): CacheMiddleware
{
return new CacheMiddleware(
new NullCacheStrategy()
return new CacheMiddleware(
new NullCacheStrategy
);
}
}
Loading
Loading