Skip to content
Open
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
3 changes: 3 additions & 0 deletions .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ jobs:
- name: Check release environment
run: |
bash ./bin/check-release-environment
env:
PACKAGIST_USERNAME: ${{ secrets.LEGALESIGN_SDK_PACKAGIST_USERNAME || secrets.PACKAGIST_USERNAME }}
PACKAGIST_SAFE_KEY: ${{ secrets.LEGALESIGN_SDK_PACKAGIST_SAFE_KEY || secrets.PACKAGIST_SAFE_KEY }}
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.0.2"
".": "0.1.0"
}
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Changelog

## 0.1.0 (2025-11-21)

Full Changelog: [v0.0.2...v0.1.0](https://github.com/legalesign/legalesign-rest-php/compare/v0.0.2...v0.1.0)

### ⚠ BREAKING CHANGES

* **client:** redesign methods
* remove confusing `toArray()` alias to `__serialize()` in favour of `toProperties()`

### Features

* **client:** redesign methods ([b87bd20](https://github.com/legalesign/legalesign-rest-php/commit/b87bd20ef5c1ea5acb9b93afe2444a891fb815ec))
* remove confusing `toArray()` alias to `__serialize()` in favour of `toProperties()` ([bf37591](https://github.com/legalesign/legalesign-rest-php/commit/bf3759140c9a01bcb0fbe3146c287dc2b017b5dd))


### Bug Fixes

* **ci:** release doctor workflow ([310295d](https://github.com/legalesign/legalesign-rest-php/commit/310295d4faf056e60db3bea642b56ede1fbe94ae))
* ensure auth methods return non-nullable arrays ([50fd6a3](https://github.com/legalesign/legalesign-rest-php/commit/50fd6a367f425117f47c55fc4c45d1d484b2f2ae))
* inverted retry condition ([4dc29ef](https://github.com/legalesign/legalesign-rest-php/commit/4dc29ef02033890b21b15568dc0ddc46c2720d04))
* rename invalid types ([48928d5](https://github.com/legalesign/legalesign-rest-php/commit/48928d511add9acafeaa99ab8f50f964dc1793fb))


### Chores

* add license ([3260f92](https://github.com/legalesign/legalesign-rest-php/commit/3260f921032f819561e6f7d92c4b22e2efb88604))
* **client:** refactor error type constructors ([e4b55a3](https://github.com/legalesign/legalesign-rest-php/commit/e4b55a33b54d105319eec00954fb07aed25c708f))
* **client:** send metadata headers ([e8c30b5](https://github.com/legalesign/legalesign-rest-php/commit/e8c30b5349cae440f50c79ed0a5652dbaf546baa))
* **internal:** codegen related update ([0c8a123](https://github.com/legalesign/legalesign-rest-php/commit/0c8a123285894fa8f9990f3d2a79061c05cee492))
* refactor methods ([9db1cb8](https://github.com/legalesign/legalesign-rest-php/commit/9db1cb856e0e6a5aac3e724c16f95f10ac28762e))
* use pascal case for phpstan typedefs ([be21370](https://github.com/legalesign/legalesign-rest-php/commit/be213708da8645553228ed4814d20d1b9292b443))

## 0.0.2 (2025-09-23)

Full Changelog: [v0.0.1...v0.0.2](https://github.com/legalesign/legalesign-rest-php/compare/v0.0.1...v0.0.2)
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use LegalesignSDK\Client;

$client = new Client(apiKey: getenv("LEGALESIGN_SDK_API_KEY") ?: "My API Key");

$documents = $client->document->list(group: "REPLACE_ME");
$documents = $client->document->list(["group" => "REPLACE_ME"]);

var_dump($documents->meta);
```
Expand All @@ -71,7 +71,7 @@ When the library is unable to connect to the API, or if the API returns a non-su
use LegalesignSDK\Core\Exceptions\APIConnectionException;

try {
$documents = $client->document->list(group: "REPLACE_ME");
$documents = $client->document->list(["group" => "REPLACE_ME"]);
} catch (APIConnectionException $e) {
echo "The server could not be reached", PHP_EOL;
var_dump($e->getPrevious());
Expand Down Expand Up @@ -118,7 +118,7 @@ $client = new Client(maxRetries: 0);

// Or, configure per-request:
$result = $client->document->list(
group: "REPLACE_ME", requestOptions: RequestOptions::with(maxRetries: 5)
["group" => "REPLACE_ME"], RequestOptions::with(maxRetries: 5)
);
```

Expand All @@ -138,15 +138,13 @@ Note: the `extra*` parameters of the same name overrides the documented paramete
use LegalesignSDK\RequestOptions;

$documents = $client->document->list(
group: "REPLACE_ME",
requestOptions: RequestOptions::with(
["group" => "REPLACE_ME"],
RequestOptions::with(
extraQueryParams: ["my_query_parameter" => "value"],
extraBodyParams: ["my_body_parameter" => "value"],
extraHeaders: ["my-header" => "value"],
),
);

var_dump($documents["my_undocumented_property"]);
```

#### Undocumented request params
Expand Down
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"$schema": "https://getcomposer.org/schema.json",
"license": "Apache-2.0",
"autoload": {
"files": ["src/Core.php", "src/Client.php"],
"files": [
"src/Core.php",
"src/Client.php"
],
"psr-4": {
"LegalesignSDK\\": "src/"
}
Expand Down
3 changes: 2 additions & 1 deletion release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
],
"release-type": "php",
"extra-files": [
"README.md"
"README.md",
"src/Client.php"
]
}
2 changes: 1 addition & 1 deletion scripts/lint
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ set -e
cd -- "$(dirname -- "$0")/.."

echo "==> Running PHPStan"
exec -- ./vendor/bin/phpstan analyse --memory-limit=1G
exec -- ./vendor/bin/phpstan analyse --memory-limit=2G
20 changes: 15 additions & 5 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function __construct(?string $apiKey = null, ?string $baseUrl = null)
{
$this->apiKey = (string) ($apiKey ?? getenv('LEGALESIGN_SDK_API_KEY'));

$base = $baseUrl ?? getenv(
$baseUrl ??= getenv(
'LEGALESIGN_SDK_BASE_URL'
) ?: 'https://eu-api.legalesign.com/api/v1';

Expand All @@ -70,10 +70,20 @@ public function __construct(?string $apiKey = null, ?string $baseUrl = null)
);

parent::__construct(
// x-release-please-start-version
headers: [
'Content-Type' => 'application/json', 'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'User-Agent' => sprintf('legalesign-sdk/PHP %s', '0.1.0'),
'X-Stainless-Lang' => 'php',
'X-Stainless-Package-Version' => '0.1.0',
'X-Stainless-OS' => $this->getNormalizedOS(),
'X-Stainless-Arch' => $this->getNormalizedArchitecture(),
'X-Stainless-Runtime' => 'php',
'X-Stainless-Runtime-Version' => phpversion(),
],
baseUrl: $base,
// x-release-please-end
baseUrl: $baseUrl,
options: $options,
);

Expand All @@ -86,9 +96,9 @@ public function __construct(?string $apiKey = null, ?string $baseUrl = null)
$this->templatepdf = new TemplatepdfService($this);
}

/** @return array<string, string> */
/** @return array<string,string> */
protected function authHeaders(): array
{
return ['Authorization' => $this->apiKey];
return $this->apiKey ? ['Authorization' => $this->apiKey] : [];
}
}
97 changes: 71 additions & 26 deletions src/Core/BaseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@
* @phpstan-type normalized_request = array{
* method: string,
* path: string,
* query: array<string, mixed>,
* headers: array<string, string|null|list<string>>,
* query: array<string,mixed>,
* headers: array<string,string|null|list<string>>,
* body: mixed,
* }
*/
class BaseClient
abstract class BaseClient
{
protected UriInterface $baseUrl;

/**
* @internal
*
* @param array<string, string|int|list<string|int>|null> $headers
* @param array<string,string|int|list<string|int>|null> $headers
*/
public function __construct(
protected array $headers,
Expand All @@ -49,11 +49,11 @@ public function __construct(

/**
* @param string|list<mixed> $path
* @param array<string, mixed> $query
* @param array<string, mixed> $headers
* @param array<string,mixed> $query
* @param array<string,mixed> $headers
* @param class-string<BasePage<mixed>> $page
* @param class-string<BaseStream<mixed>> $stream
* @param RequestOptions|array<string, mixed>|null $options
* @param RequestOptions|array<string,mixed>|null $options
*/
public function request(
string $method,
Expand All @@ -77,14 +77,11 @@ public function request(
// @phpstan-ignore-next-line
$rsp = $this->sendRequest($opts, req: $request, data: $body, redirectCount: 0, retryCount: 0);

$decoded = Util::decodeContent($rsp);

if (!is_null($stream)) {
return new $stream(
convert: $convert,
request: $request,
response: $rsp,
stream: $decoded
response: $rsp
);
}

Expand All @@ -93,37 +90,84 @@ public function request(
convert: $convert,
client: $this,
request: $req,
response: $rsp,
options: $opts,
data: $decoded,
);
}

if (!is_null($convert)) {
return Conversion::coerce($convert, value: $decoded);
return Conversion::coerceResponse($convert, response: $rsp);
}

return $decoded;
return Util::decodeContent($rsp);
}

/** @return array<string, string> */
protected function authHeaders(): array
/** @return array<string,string> */
abstract protected function authHeaders(): array;

protected function getNormalizedOS(): string
{
return [];
$os = strtolower(PHP_OS_FAMILY);

switch ($os) {
case 'windows':
return 'Windows';

case 'darwin':
return 'MacOS';

case 'linux':
return 'Linux';

case 'bsd':
case 'freebsd':
case 'openbsd':
return 'BSD';

case 'solaris':
return 'Solaris';

case 'unix':
case 'unknown':
return 'Unknown';

default:
return 'Other:'.$os;
}
}

protected function getNormalizedArchitecture(): string
{
$arch = php_uname('m');
if (false !== strpos($arch, 'x86_64') || false !== strpos($arch, 'amd64')) {
return 'x64';
}
if (false !== strpos($arch, 'i386') || false !== strpos($arch, 'i686')) {
return 'x32';
}
if (false !== strpos($arch, 'aarch64') || false !== strpos($arch, 'arm64')) {
return 'arm64';
}
if (false !== strpos($arch, 'arm')) {
return 'arm';
}

return 'unknown';
}

/**
* @internal
*
* @param string|list<string> $path
* @param array<string, mixed> $query
* @param array<string, string|int|list<string|int>|null> $headers
* @param array<string,mixed> $query
* @param array<string,string|int|list<string|int>|null> $headers
* @param array{
* timeout?: float|null,
* maxRetries?: int|null,
* initialRetryDelay?: float|null,
* maxRetryDelay?: float|null,
* extraHeaders?: array<string, string|int|list<string|int>|null>|null,
* extraQueryParams?: array<string, mixed>|null,
* extraHeaders?: array<string,string|int|list<string|int>|null>|null,
* extraQueryParams?: array<string,mixed>|null,
* extraBodyParams?: mixed,
* transporter?: ClientInterface|null,
* uriFactory?: UriFactoryInterface|null,
Expand All @@ -145,14 +189,14 @@ protected function buildRequest(

$parsedPath = Util::parsePath($path);

/** @var array<string, mixed> $mergedQuery */
/** @var array<string,mixed> $mergedQuery */
$mergedQuery = array_merge_recursive(
$query,
$options->extraQueryParams ?? [],
);
$uri = Util::joinUri($this->baseUrl, path: $parsedPath, query: $mergedQuery)->__toString();

/** @var array<string, string|list<string>|null> $mergedHeaders */
/** @var array<string,string|list<string>|null> $mergedHeaders */
$mergedHeaders = [...$this->headers,
...$this->authHeaders(),
...$headers,
Expand Down Expand Up @@ -232,8 +276,7 @@ protected function retryDelay(
/**
* @internal
*
* @param bool|int|float|string|resource|\Traversable<mixed>|array<string,
* mixed,>|null $data
* @param bool|int|float|string|resource|\Traversable<mixed,>|array<string,mixed>|null $data
*/
protected function sendRequest(
RequestOptions $opts,
Expand All @@ -244,6 +287,8 @@ protected function sendRequest(
): ResponseInterface {
assert(null !== $opts->streamFactory && null !== $opts->transporter);

$req = $req->withHeader('X-Stainless-Retry-Count', strval($retryCount));

$req = Util::withSetBody($opts->streamFactory, req: $req, body: $data);

$rsp = null;
Expand All @@ -270,7 +315,7 @@ protected function sendRequest(
}

if ($code >= 400 || is_null($rsp)) {
if ($this->shouldRetry($opts, retryCount: $retryCount, rsp: $rsp)) {
if (!$this->shouldRetry($opts, retryCount: $retryCount, rsp: $rsp)) {
$exn = is_null($rsp) ? new APIConnectionException($req, previous: $err) : APIStatusException::from(request: $req, response: $rsp);

throw $exn;
Expand Down
Loading
Loading