feat: initial ACRIB WordPress deployment

- WordPress 6.9.4 (es_ES) with Kadence theme
- Homepage: Hero, La Asociación, Pilares, Beneficios, Eventos, Miembros, Hazte Miembro, Contacto
- Brand identity: #13294b navy, #a12932 burgundy, #c69c48 gold
- Fonts: Raleway (headings) + Source Sans 3 (body) + Lato (UI)
- Plugins: Kadence Blocks, Polylang, Contact Form 7
- Custom CSS with full brand styling and responsive layout
- HTTPS enforced via wp-config.php proxy detection
This commit is contained in:
Malin
2026-05-19 19:25:59 +02:00
commit f3ff7b7186
6119 changed files with 1984255 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
This package is licensed under the GNU General Public License, version 2 or later (GPL-2.0-or-later).
For the full license text, see https://spdx.org/licenses/GPL-2.0-or-later.html

View File

@@ -0,0 +1,49 @@
# Licensing API Client
> ⚠️ **This is a read-only repository!**
> For pull requests or issues, see [stellarwp/licensing-api-client-monorepo](https://github.com/stellarwp/licensing-api-client-monorepo).
A PHP client for the Liquid Web Licensing API.
💡 In most cases you should use one of the transport-specific client packages instead of installing this package directly unless you plan to provide your own HTTP client:
- [stellarwp/licensing-api-client-wordpress](https://github.com/stellarwp/licensing-api-client-wordpress)
- [stellarwp/licensing-api-client-guzzle](https://github.com/stellarwp/licensing-api-client-guzzle)
This package is the core API layer they build on top of.
## Installation
Install with composer:
```shell
composer require stellarwp/licensing-api-client
```
## Examples
For end-to-end API cookbook examples, see:
- [API Examples](https://github.com/stellarwp/licensing-api-client-monorepo/blob/main/docs/examples/index.md)
Short example:
```php
<?php declare(strict_types=1);
use LiquidWeb\LicensingApiClient\Tracing\TraceParent;
$catalog = $api
->withTraceParent(TraceParent::generate())
->products()
->catalog('LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N', 'example.com');
```
Use `withTraceParent()` when you want the SDK to carry one validated W3C `traceparent` value. Build it with `TraceParent::generate()` when you are starting a new trace locally, or `TraceParent::fromString()` when you are continuing one from an inbound request. If you also have vendor-specific `tracestate`, use `TraceContext::fromValues()` and pass that to `withTraceContext()` instead. Use `withHeaders()` for unrelated custom headers.
> [!WARNING]
> This only pays off when your own application is also exporting spans to Axiom or another tracing backend. If your application is not instrumented, the licensing service can still continue the propagated trace context, but Axiom will not be able to find the real parent span because it never received it.
## Status
This package is being developed in the monorepo and published as a read-only split repository.

View File

@@ -0,0 +1,136 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Contracts\LicensingClientInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\EntitlementsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\LicensesResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\ProductsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\TokensResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\EntitlementsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\LicensesResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\ProductsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\TokensResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Tracing\TraceContext;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Tracing\TraceParent;
/**
* Exposes the built API resources and immutable auth-state transitions.
*/
final class Api implements LicensingClientInterface
{
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
private LicensesResource $licenses;
private ProductsResource $products;
private CreditsResource $credits;
private EntitlementsResource $entitlements;
private TokensResource $tokens;
public function __construct(
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection,
LicensesResource $licenses,
ProductsResource $products,
CreditsResource $credits,
EntitlementsResource $entitlements,
TokensResource $tokens
) {
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
$this->licenses = $licenses;
$this->products = $products;
$this->credits = $credits;
$this->entitlements = $entitlements;
$this->tokens = $tokens;
}
public function entitlements(): EntitlementsResourceInterface {
return $this->entitlements;
}
public function licenses(): LicensesResourceInterface {
return $this->licenses;
}
public function products(): ProductsResourceInterface {
return $this->products;
}
public function credits(): CreditsResourceInterface {
return $this->credits;
}
public function tokens(): TokensResourceInterface {
return $this->tokens;
}
public function withoutAuth(): LicensingClientInterface {
return $this->cloneWithAuthState($this->authState->withoutAuth());
}
private function cloneWithAuthState(AuthState $authState): self {
return new self(
$authState,
$this->requestHeaderCollection,
$this->licenses->withAuthState($authState),
$this->products->withAuthState($authState),
$this->credits->withAuthState($authState),
$this->entitlements->withAuthState($authState),
$this->tokens->withAuthState($authState)
);
}
/**
* @param array<string, string|int|float|bool> $headers
*/
public function withHeaders(array $headers): LicensingClientInterface {
return $this->cloneWithRequestHeaderCollection($this->requestHeaderCollection->withHeaders($headers));
}
public function withTraceParent(TraceParent $traceParent): LicensingClientInterface {
return $this->cloneWithRequestHeaderCollection($this->requestHeaderCollection->withTraceParent($traceParent));
}
public function withTraceContext(TraceContext $traceContext): LicensingClientInterface {
return $this->cloneWithRequestHeaderCollection($this->requestHeaderCollection->withTraceContext($traceContext));
}
public function withoutHeaders(): LicensingClientInterface {
return $this->cloneWithRequestHeaderCollection($this->requestHeaderCollection->withoutHeaders());
}
private function cloneWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
if ($this->requestHeaderCollection === $requestHeaderCollection) {
return $this;
}
return new self(
$this->authState,
$requestHeaderCollection,
$this->licenses->withRequestHeaderCollection($requestHeaderCollection),
$this->products->withRequestHeaderCollection($requestHeaderCollection),
$this->credits->withRequestHeaderCollection($requestHeaderCollection),
$this->entitlements->withRequestHeaderCollection($requestHeaderCollection),
$this->tokens->withRequestHeaderCollection($requestHeaderCollection)
);
}
public function withConfiguredToken(): LicensingClientInterface {
return $this->cloneWithAuthState($this->authState->withConfiguredToken());
}
public function withToken(string $token): LicensingClientInterface {
return $this->cloneWithAuthState($this->authState->withToken($token));
}
}

View File

@@ -0,0 +1,99 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\ApiVersion;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthContext;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ResponseExceptionFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\JsonDecoder;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestBuilder;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsLedgerResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsPoolsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsQuotasResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\EntitlementsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\LicensesResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\ProductsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\TokensResource;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientInterface as HttpClient;
use KadenceWP\KadenceBlocks\Psr\Http\Message\RequestFactoryInterface;
use KadenceWP\KadenceBlocks\Psr\Http\Message\StreamFactoryInterface;
/**
* Builds a fully-wired API client from the transport dependencies.
*
* Use this if your application is not using a container to build dependencies.
*/
final class ApiBuilder
{
private HttpClient $httpClient;
private RequestFactoryInterface $requestFactory;
private StreamFactoryInterface $streamFactory;
private Config $config;
public function __construct(
HttpClient $httpClient,
RequestFactoryInterface $requestFactory,
StreamFactoryInterface $streamFactory,
Config $config
) {
$this->httpClient = $httpClient;
$this->requestFactory = $requestFactory;
$this->streamFactory = $streamFactory;
$this->config = $config;
}
public function build(): Api {
$authState = new AuthState(new AuthContext(), $this->config->configuredToken);
$requestHeaderCollection = new RequestHeaderCollection();
$apiUriFactory = new ApiUriFactory($this->config, ApiVersion::default());
$requestExecutor = $this->buildRequestExecutor();
$creditsPools = new CreditsPoolsResource($requestExecutor, $apiUriFactory, $authState, $requestHeaderCollection);
$creditsQuotas = new CreditsQuotasResource($requestExecutor, $apiUriFactory, $authState, $requestHeaderCollection);
$creditsLedger = new CreditsLedgerResource(
$requestExecutor,
$apiUriFactory,
$authState,
$requestHeaderCollection
);
return new Api(
$authState,
$requestHeaderCollection,
new LicensesResource($requestExecutor, $apiUriFactory, $authState, $requestHeaderCollection),
new ProductsResource($requestExecutor, $apiUriFactory, $authState, $requestHeaderCollection),
new CreditsResource(
$requestExecutor,
$apiUriFactory,
$authState,
$requestHeaderCollection,
$creditsPools,
$creditsQuotas,
$creditsLedger
),
new EntitlementsResource($requestExecutor, $apiUriFactory, $authState, $requestHeaderCollection),
new TokensResource($requestExecutor, $apiUriFactory, $authState, $requestHeaderCollection)
);
}
private function buildRequestExecutor(): RequestExecutor {
$jsonDecoder = new JsonDecoder();
return new RequestExecutor(
$this->httpClient,
new RequestBuilder(
$this->requestFactory,
$this->streamFactory
),
$jsonDecoder,
new ResponseExceptionFactory($jsonDecoder)
);
}
}

View File

@@ -0,0 +1,39 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns;
use DateTimeImmutable;
use DateTimeZone;
use Exception;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
/**
* Provides shared DateTime parsing and UTC formatting helpers.
*/
trait InteractsWithDateTime
{
/**
* @throws UnexpectedResponseException
*/
private static function parseDateTime(string $value): DateTimeImmutable {
try {
return new DateTimeImmutable($value);
} catch (Exception $exception) {
throw new UnexpectedResponseException('Invalid date value [' . $value . '].', 0, $exception);
}
}
/**
* @throws UnexpectedResponseException
*/
private static function parseNullableDateTime(?string $value): ?DateTimeImmutable {
return $value === null ? null : self::parseDateTime($value);
}
/**
* Format a DateTimeImmutable for the API's UTC RFC3339 wire format.
*/
private function formatDateTime(DateTimeImmutable $dt): string {
return $dt->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d\TH:i:s\Z');
}
}

View File

@@ -0,0 +1,87 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient;
use InvalidArgumentException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RetryPolicy;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Value\AuthToken;
/**
* Stores stable client configuration shared across API requests.
*/
final class Config
{
public string $baseUri;
public ?AuthToken $configuredToken;
public string $userAgent;
public RetryPolicy $retryPolicy;
public string $restNamespace;
public string $apiRoot;
/**
* @throws InvalidArgumentException
*/
public function __construct(
string $baseUri,
?string $configuredToken = null,
?string $userAgent = null,
?RetryPolicy $retryPolicy = null,
?string $restNamespace = null,
?string $apiRoot = null
) {
$baseUri = rtrim($baseUri, '/');
$apiRoot = trim(($apiRoot ?? 'api'), '/');
$restNamespace = trim(($restNamespace ?? 'liquidweb'), '/');
if ($baseUri === '') {
throw new InvalidArgumentException('Base URI cannot be empty.');
}
if ($apiRoot === '') {
throw new InvalidArgumentException('API root cannot be empty.');
}
if ($restNamespace === '') {
throw new InvalidArgumentException('REST namespace cannot be empty.');
}
$this->baseUri = $baseUri;
$this->configuredToken = $configuredToken !== null ? new AuthToken($configuredToken) : null;
$this->userAgent = $userAgent !== null && $userAgent !== '' ? $userAgent : 'stellarwp/licensing-api-client';
$this->apiRoot = $apiRoot;
$this->restNamespace = $restNamespace;
$this->retryPolicy = $retryPolicy ?: RetryPolicy::default();
}
/**
* @param array{
* base_uri?: non-empty-string,
* configured_token?: non-empty-string|null,
* user_agent?: non-empty-string|null,
* retry_policy?: RetryPolicy|null,
* rest_namespace?: non-empty-string|null,
* api_root?: non-empty-string|null
* } $config
*
* @throws InvalidArgumentException
*/
public static function fromArray(array $config): self {
return new self(
$config['base_uri'] ?? '',
$config['configured_token'] ?? null,
$config['user_agent'] ?? null,
$config['retry_policy'] ?? null,
$config['rest_namespace'] ?? null,
$config['api_root'] ?? null
);
}
public function apiRootPath(): string {
return '/' . $this->apiRoot;
}
}

View File

@@ -0,0 +1,44 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Contracts;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\EntitlementsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\LicensesResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\ProductsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\TokensResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Tracing\TraceContext;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Tracing\TraceParent;
/**
* Defines the root entrypoint for the Licensing API client.
*/
interface LicensingClientInterface
{
public function entitlements(): EntitlementsResourceInterface;
public function licenses(): LicensesResourceInterface;
public function products(): ProductsResourceInterface;
public function credits(): CreditsResourceInterface;
public function tokens(): TokensResourceInterface;
public function withoutAuth(): self;
public function withConfiguredToken(): self;
public function withToken(string $token): self;
/**
* @param array<string, string|int|float|bool> $headers
*/
public function withHeaders(array $headers): self;
public function withTraceParent(TraceParent $traceParent): self;
public function withTraceContext(TraceContext $traceContext): self;
public function withoutHeaders(): self;
}

View File

@@ -0,0 +1,72 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\Psr\Http\Message\ResponseInterface;
use RuntimeException;
/**
* Base exception for HTTP error responses returned by the licensing API.
*/
class ApiResponseException extends RuntimeException implements ApiErrorExceptionInterface
{
private ResponseInterface $response;
private int $statusCode;
private string $errorCode;
/**
* @var array<array-key, mixed>|null
*/
private ?array $errorPayload;
/**
* @param array<array-key, mixed>|null $errorPayload
*/
public function __construct(
string $message,
ResponseInterface $response,
int $statusCode,
string $errorCode,
?array $errorPayload = null
) {
parent::__construct($message, $statusCode);
$this->response = $response;
$this->statusCode = $statusCode;
$this->errorCode = $errorCode;
$this->errorPayload = $errorPayload;
}
/**
* Returns the raw PSR-7 response that triggered the exception.
*/
public function getResponse(): ResponseInterface {
return $this->response;
}
/**
* Returns the HTTP status code from the failed response.
*/
public function statusCode(): int {
return $this->statusCode;
}
/**
* Returns the normalized API error code.
*/
public function errorCode(): string {
return $this->errorCode;
}
/**
* Returns the decoded error payload when the response body matched a known JSON error shape.
*
* @return array<array-key, mixed>|null
*/
public function errorPayload(): ?array {
return $this->errorPayload;
}
}

View File

@@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
/**
* Thrown when the API returns a 401 response.
*/
final class AuthenticationException extends ClientErrorException
{
}

View File

@@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
/**
* Thrown when the API returns a 403 response.
*/
final class AuthorizationException extends ClientErrorException
{
}

View File

@@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
/**
* Thrown when the API returns a 4xx response.
*/
class ClientErrorException extends ApiResponseException
{
}

View File

@@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
/**
* Thrown when the API returns a 409 conflict response.
*/
final class ConflictException extends ClientErrorException
{
}

View File

@@ -0,0 +1,21 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts;
/**
* Marks response exceptions that were normalized from a known API error shape.
*/
interface ApiErrorExceptionInterface extends ResponseExceptionInterface
{
/**
* Returns the normalized API error code.
*/
public function errorCode(): string;
/**
* Returns the decoded error payload when the response body matched a known JSON error shape.
*
* @return array<array-key, mixed>|null
*/
public function errorPayload(): ?array;
}

View File

@@ -0,0 +1,22 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts;
use KadenceWP\KadenceBlocks\Psr\Http\Message\ResponseInterface;
use Throwable;
/**
* Marks exceptions that were created from an HTTP response.
*/
interface ResponseExceptionInterface extends Throwable
{
/**
* Returns the raw PSR-7 response for debugging and inspection.
*/
public function getResponse(): ResponseInterface;
/**
* Returns the HTTP status code from the failed response.
*/
public function statusCode(): int;
}

View File

@@ -0,0 +1,12 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
use RuntimeException;
/**
* Thrown when a response body cannot be decoded into the expected JSON structure.
*/
final class DecodingException extends RuntimeException
{
}

View File

@@ -0,0 +1,12 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
use RuntimeException;
/**
* Thrown when a request requires authentication but no token is available.
*/
final class MissingAuthenticationException extends RuntimeException
{
}

View File

@@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
/**
* Thrown when the API returns a 404 response.
*/
final class NotFoundException extends ClientErrorException
{
}

View File

@@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
/**
* Thrown when the API returns a 5xx response.
*/
final class ServerErrorException extends ApiResponseException
{
}

View File

@@ -0,0 +1,12 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
use RuntimeException;
/**
* Thrown when the API returns a malformed or unexpected response.
*/
final class UnexpectedResponseException extends RuntimeException
{
}

View File

@@ -0,0 +1,10 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions;
/**
* Thrown when the API returns a 422 response.
*/
final class ValidationException extends ClientErrorException
{
}

View File

@@ -0,0 +1,19 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
/**
* Represents a fully resolved licensing API URI.
*/
final class ApiUri
{
private string $uri;
public function __construct(string $uri) {
$this->uri = $uri;
}
public function get(): string {
return $this->uri;
}
}

View File

@@ -0,0 +1,40 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
use InvalidArgumentException;
/**
* Represents an API version segment used when building endpoint URLs.
*/
final class ApiVersion
{
public const V1 = 'v1';
private string $version;
/**
* @throws InvalidArgumentException
*/
public function __construct(string $version) {
$version = trim($version, '/');
if ($version === '') {
throw new InvalidArgumentException('API version cannot be empty.');
}
$this->version = $version;
}
public static function default(): self {
return new self(self::V1);
}
public function get(): string {
return $this->version;
}
public function __toString(): string {
return $this->version;
}
}

View File

@@ -0,0 +1,55 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
use InvalidArgumentException;
/**
* Represents the authentication mode the API client should use for a request.
*/
final class AuthContext
{
public const MODE_AUTO = 'auto';
public const MODE_NONE = 'none';
public const MODE_CONFIGURED = 'configured';
public const MODE_EXPLICIT = 'explicit';
private string $mode;
/**
* @throws InvalidArgumentException
*/
public function __construct(string $mode = self::MODE_AUTO) {
$this->assertValidMode($mode);
$this->mode = $mode;
}
/**
* @throws InvalidArgumentException
*/
private function assertValidMode(string $mode): void {
$validModes = [
self::MODE_AUTO,
self::MODE_NONE,
self::MODE_CONFIGURED,
self::MODE_EXPLICIT,
];
if ( ! in_array($mode, $validModes, true)) {
throw new InvalidArgumentException('Unsupported auth mode [' . $mode . '].');
}
}
public function requiresToken(): bool {
return $this->mode === self::MODE_CONFIGURED || $this->mode === self::MODE_EXPLICIT;
}
public function equals(self $authContext): bool {
return $this->mode === $authContext->mode();
}
public function mode(): string {
return $this->mode;
}
}

View File

@@ -0,0 +1,98 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
use InvalidArgumentException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Value\AuthToken;
/**
* Combines auth policy and configured token state for request execution.
*/
final class AuthState
{
private AuthContext $authContext;
private ?AuthToken $token;
/**
* @throws InvalidArgumentException
*/
public function __construct(AuthContext $authContext, ?AuthToken $token = null) {
if ($authContext->mode() === AuthContext::MODE_EXPLICIT && $token === null) {
throw new InvalidArgumentException('Explicit auth mode requires a token.');
}
$this->authContext = $authContext;
$this->token = $token;
}
/**
* @throws MissingAuthenticationException
*/
public function optionalToken(): ?AuthToken {
if ($this->authContext->mode() === AuthContext::MODE_NONE) {
return null;
}
if ($this->authContext->mode() === AuthContext::MODE_CONFIGURED && $this->token === null) {
throw new MissingAuthenticationException(
'This request requires authentication, but no token is available.'
);
}
return $this->token;
}
/**
* @throws MissingAuthenticationException
*/
public function requiredToken(): AuthToken {
$token = $this->optionalToken();
if ($token === null) {
throw new MissingAuthenticationException(
'This request requires authentication, but no token is available.'
);
}
return $token;
}
public function withoutAuth(): self {
return $this->withAuthContext(new AuthContext(AuthContext::MODE_NONE), $this->token);
}
public function withConfiguredToken(): self {
return $this->withAuthContext(new AuthContext(AuthContext::MODE_CONFIGURED), $this->token);
}
public function withToken(string $token): self {
return $this->withAuthContext(
new AuthContext(AuthContext::MODE_EXPLICIT),
new AuthToken($token)
);
}
public function authContext(): AuthContext {
return $this->authContext;
}
public function token(): ?AuthToken {
return $this->token;
}
private function withAuthContext(AuthContext $authContext, ?AuthToken $token): self {
if (
$this->authContext->equals($authContext)
&& (
($this->token === null && $token === null)
|| ($this->token !== null && $token !== null && $this->token->equals($token))
)
) {
return $this;
}
return new self($authContext, $token);
}
}

View File

@@ -0,0 +1,89 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Config;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\ApiUri;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\ApiVersion;
/**
* Builds fully resolved licensing API URIs from endpoints and trusted pagination links.
*/
final class ApiUriFactory
{
private Config $config;
private ApiVersion $defaultVersion;
public function __construct(Config $config, ApiVersion $defaultVersion) {
$this->config = $config;
$this->defaultVersion = $defaultVersion;
}
public function make(string $path): ApiUri {
return $this->makeWithVersion($path, $this->defaultVersion);
}
public function makeWithVersion(string $path, ApiVersion $version): ApiUri {
return new ApiUri(
rtrim($this->config->baseUri, '/')
. $this->config->apiRootPath()
. '/'
. $this->config->restNamespace
. '/'
. $version->get()
. '/'
. ltrim($path, '/')
);
}
/**
* @throws UnexpectedResponseException
*/
public function fromPaginationLink(string $uri): ApiUri {
$target = parse_url($uri);
$base = parse_url($this->config->baseUri);
if (! is_array($target) || ! is_array($base)) {
throw new UnexpectedResponseException('Unexpected pagination link.');
}
$targetScheme = $this->requireString($target, 'scheme');
$baseScheme = $this->requireString($base, 'scheme');
$targetHost = $this->requireString($target, 'host');
$baseHost = $this->requireString($base, 'host');
$targetPort = $target['port'] ?? null;
$basePort = $base['port'] ?? null;
$targetPath = $this->requireString($target, 'path');
if (
strtolower($targetScheme) !== strtolower($baseScheme)
|| strtolower($targetHost) !== strtolower($baseHost)
|| $targetPort !== $basePort
) {
throw new UnexpectedResponseException('Unexpected pagination link origin.');
}
if (strpos($targetPath, $this->config->apiRootPath() . '/' . $this->config->restNamespace . '/') !== 0) {
throw new UnexpectedResponseException('Unexpected pagination link path.');
}
return new ApiUri($uri);
}
/**
* @param array<string, mixed> $parts
*
* @throws UnexpectedResponseException
*/
private function requireString(array $parts, string $key): string {
$value = $parts[$key] ?? null;
if (! is_string($value)) {
throw new UnexpectedResponseException('Unexpected pagination link.');
}
return $value;
}
}

View File

@@ -0,0 +1,234 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ApiResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\AuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\AuthorizationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ClientErrorException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ConflictException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\DecodingException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\NotFoundException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ServerErrorException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ValidationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\JsonDecoder;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\ErrorResponse;
use KadenceWP\KadenceBlocks\Psr\Http\Message\ResponseInterface;
/**
* Creates typed API response exceptions from failed HTTP responses.
*
* @phpstan-type ErrorPayload array{
* error: array{
* code?: mixed,
* message?: mixed
* }
* }
* @phpstan-type WordPressErrorPayload array{
* code?: mixed,
* message?: mixed,
* data?: array{
* status?: int
* }
* }
*/
final class ResponseExceptionFactory
{
private JsonDecoder $jsonDecoder;
public function __construct(JsonDecoder $jsonDecoder) {
$this->jsonDecoder = $jsonDecoder;
}
/**
* Creates the appropriate typed exception for a failed API response.
*
* @throws UnexpectedResponseException When the response is not an HTTP error.
*/
public function make(ResponseInterface $response): ApiResponseException {
$statusCode = $response->getStatusCode();
if ($statusCode >= 400 && $statusCode < 500) {
return $this->buildClientErrorException($response);
}
if ($statusCode >= 500) {
return $this->buildServerErrorException($response);
}
throw new UnexpectedResponseException('Unexpected response status code.', $statusCode);
}
private function buildClientErrorException(ResponseInterface $response): ClientErrorException {
$decoded = $this->decodeErrorPayload($response);
$normalized = $decoded !== null
? $this->parseApiError($decoded, $response->getStatusCode())
: null;
$errorCode = $normalized !== null && $normalized->code !== null
? $normalized->code
: $this->defaultErrorCodeForStatus($response->getStatusCode());
$message = $normalized !== null && $normalized->message !== null
? $normalized->message
: ($response->getReasonPhrase() ?: 'Client Error');
$statusCode = $normalized !== null && $normalized->statusCode !== null
? $normalized->statusCode
: $response->getStatusCode();
switch ($statusCode) {
case 401:
return new AuthenticationException(
$message,
$response,
$statusCode,
$errorCode,
$decoded
);
case 403:
return new AuthorizationException(
$message,
$response,
$statusCode,
$errorCode,
$decoded
);
case 409:
return new ConflictException(
$message,
$response,
$statusCode,
$errorCode,
$decoded
);
case 404:
return new NotFoundException(
$message,
$response,
$statusCode,
$errorCode,
$decoded
);
case 422:
return new ValidationException(
$message,
$response,
$statusCode,
$errorCode,
$decoded
);
default:
return new ClientErrorException(
$message,
$response,
$statusCode,
$errorCode,
$decoded
);
}
}
/**
* @return array<array-key, mixed>|null
*/
private function decodeErrorPayload(ResponseInterface $response): ?array {
try {
return $this->jsonDecoder->decode((string) $response->getBody());
} catch (DecodingException $exception) {
return null;
}
}
/**
* @param array<array-key, mixed> $payload
*/
private function parseApiError(array $payload, int $statusCode): ?ErrorResponse {
if ($this->isErrorPayload($payload)) {
return ErrorResponse::from([
'code' => $payload['error']['code'] ?? null,
'message' => $payload['error']['message'] ?? null,
'status_code' => $statusCode,
]);
}
if ($this->isWordPressErrorPayload($payload)) {
$payloadStatus = $payload['data']['status'] ?? null;
return ErrorResponse::from([
'code' => $payload['code'] ?? null,
'message' => $payload['message'] ?? null,
'status_code' => is_int($payloadStatus) ? $payloadStatus : $statusCode,
]);
}
return null;
}
/**
* @param array<array-key, mixed> $payload
*
* @phpstan-assert-if-true ErrorPayload $payload
*/
private function isErrorPayload(array $payload): bool {
if ( ! isset($payload['error']) || ! is_array($payload['error'])) {
return false;
}
return isset($payload['error']['code']) || isset($payload['error']['message']);
}
/**
* @param array<array-key, mixed> $payload
*
* @phpstan-assert-if-true WordPressErrorPayload $payload
*/
private function isWordPressErrorPayload(array $payload): bool {
return ! ( ! isset($payload['code']) && ! isset($payload['message']));
}
private function defaultErrorCodeForStatus(int $statusCode): string {
switch ($statusCode) {
case 401:
return 'authentication_error';
case 403:
return 'authorization_error';
case 409:
return 'conflict_error';
case 404:
return 'not_found';
case 422:
return 'validation_error';
default:
return 'client_error';
}
}
private function buildServerErrorException(ResponseInterface $response): ServerErrorException {
$decoded = $this->decodeErrorPayload($response);
$normalized = $decoded !== null
? $this->parseApiError($decoded, $response->getStatusCode())
: null;
if ($normalized !== null) {
return new ServerErrorException(
$normalized->message ?? ($response->getReasonPhrase() ?: 'Server Error'),
$response,
$normalized->statusCode ?? $response->getStatusCode(),
$normalized->code ?? 'server_error',
$decoded
);
}
$message = $response->getReasonPhrase() ?: 'Server Error';
return new ServerErrorException(
$message,
$response,
$response->getStatusCode(),
'server_error'
);
}
}

View File

@@ -0,0 +1,31 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\DecodingException;
/**
* Decodes JSON response bodies into arrays for response mappers.
*/
final class JsonDecoder
{
/**
*
* @throws DecodingException
* @return array<array-key, mixed>
*/
public function decode(string $json): array {
try {
$decoded = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw new DecodingException('Unable to decode JSON response.', 0, $exception);
}
if (!is_array($decoded)) {
throw new DecodingException('Decoded JSON response must be an array.');
}
return $decoded;
}
}

View File

@@ -0,0 +1,130 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Value\AuthToken;
use KadenceWP\KadenceBlocks\Psr\Http\Message\RequestFactoryInterface;
use KadenceWP\KadenceBlocks\Psr\Http\Message\RequestInterface;
use KadenceWP\KadenceBlocks\Psr\Http\Message\StreamFactoryInterface;
/**
* Builds PSR-7 requests from SDK configuration and endpoint input.
*
* @phpstan-type QueryScalar string|int|float|bool|null
* @phpstan-type QueryList list<QueryScalar>
* @phpstan-type QueryValue QueryScalar|QueryList
* @phpstan-type HeaderValue string|int|float|bool
* @phpstan-type JsonScalar string|int|float|bool|null
* @phpstan-type JsonCollection array<array-key, JsonScalar|array<array-key, JsonScalar|array<array-key, JsonScalar|null>|null>|null>
* @phpstan-type JsonObject array<string, JsonScalar|JsonCollection|null>
*/
final class RequestBuilder
{
private RequestFactoryInterface $requestFactory;
private StreamFactoryInterface $streamFactory;
public function __construct(
RequestFactoryInterface $requestFactory,
StreamFactoryInterface $streamFactory
) {
$this->requestFactory = $requestFactory;
$this->streamFactory = $streamFactory;
}
/**
* @param array<string, QueryValue> $query
* @param JsonObject|null $body
* @param array<string, HeaderValue> $headers
*
* @throws JsonException
*/
public function build(
string $method,
ApiUri $uri,
array $query = [],
?array $body = null,
?AuthToken $token = null,
array $headers = []
): RequestInterface {
$request = $this->requestFactory->createRequest($method, $this->buildUri($uri, $query));
return $this->finalizeRequest($request, $body, $token, $headers);
}
/**
* @param JsonObject|null $body
* @param array<string, HeaderValue> $headers
*
* @throws JsonException
*/
private function finalizeRequest(
RequestInterface $request,
?array $body = null,
?AuthToken $token = null,
array $headers = []
): RequestInterface {
if ($token !== null) {
$request = $request->withHeader('X-LWS-Token', $token->get());
}
foreach ($headers as $name => $value) {
$request = $request->withHeader($name, (string) $value);
}
if ($body !== null) {
$request = $request->withHeader('Content-Type', 'application/json');
$request = $request->withBody(
$this->streamFactory->createStream(json_encode($body, JSON_THROW_ON_ERROR))
);
}
return $request;
}
/**
* @param array<string, QueryValue> $query
*/
private function buildUri(ApiUri $uri, array $query): string {
$uri = $uri->get();
$queryString = $this->buildQueryString($query);
if ($queryString === '') {
return $uri;
}
return $uri . (strpos($uri, '?') === false ? '?' : '&') . $queryString;
}
/**
* @param array<string, QueryValue> $query
*/
private function buildQueryString(array $query): string {
$pairs = [];
foreach ($query as $key => $value) {
if (is_array($value)) {
foreach ($value as $item) {
if ($item === null) {
continue;
}
$pairs[] = rawurlencode($key . '[]') . '=' . rawurlencode((string) $item);
}
continue;
}
if ($value === null) {
continue;
}
$pairs[] = rawurlencode($key) . '=' . rawurlencode((string) $value);
}
return implode('&', $pairs);
}
}

View File

@@ -0,0 +1,107 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ApiResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\DecodingException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ResponseExceptionFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Value\AuthToken;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientInterface as HttpClient;
use KadenceWP\KadenceBlocks\Psr\Http\Message\ResponseInterface;
/**
* Executes API requests and delegates response error mapping.
*
* @phpstan-import-type QueryValue from RequestBuilder
* @phpstan-import-type HeaderValue from RequestBuilder
* @phpstan-import-type JsonObject from RequestBuilder
*/
final class RequestExecutor
{
private HttpClient $httpClient;
private RequestBuilder $requestBuilder;
private JsonDecoder $jsonDecoder;
private ResponseExceptionFactory $responseExceptionFactory;
public function __construct(
HttpClient $httpClient,
RequestBuilder $requestBuilder,
JsonDecoder $jsonDecoder,
ResponseExceptionFactory $responseExceptionFactory
) {
$this->httpClient = $httpClient;
$this->requestBuilder = $requestBuilder;
$this->jsonDecoder = $jsonDecoder;
$this->responseExceptionFactory = $responseExceptionFactory;
}
/**
* @param array<string, QueryValue> $query
* @param JsonObject|null $body
* @param array<string, HeaderValue> $headers
*
* @throws ApiResponseException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function execute(
string $method,
ApiUri $uri,
array $query = [],
?array $body = null,
?AuthToken $token = null,
array $headers = []
): ResponseInterface {
$request = $this->requestBuilder->build($method, $uri, $query, $body, $token, $headers);
$response = $this->httpClient->sendRequest($request);
$statusCode = $response->getStatusCode();
if ($statusCode >= 200 && $statusCode < 400) {
return $response;
}
if ($statusCode >= 400) {
throw $this->responseExceptionFactory->make($response);
}
throw new UnexpectedResponseException('Unexpected response status code.', $statusCode);
}
/**
* @param array<string, QueryValue> $query
* @param JsonObject|null $body
* @param array<string, HeaderValue> $headers
*
* @throws ApiResponseException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*
* @return array<array-key, mixed>
*/
public function executeJson(
string $method,
ApiUri $uri,
array $query = [],
?array $body = null,
?AuthToken $token = null,
array $headers = []
): array {
$response = $this->execute($method, $uri, $query, $body, $token, $headers);
$body = (string) $response->getBody();
try {
return $this->jsonDecoder->decode($body);
} catch (DecodingException $exception) {
throw new UnexpectedResponseException('Unable to decode JSON response.', 0, $exception);
}
}
}

View File

@@ -0,0 +1,137 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Tracing\TraceContext;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Tracing\TraceParent;
/**
* Immutable request-header state shared across resource views.
*
* @phpstan-import-type HeaderValue from RequestBuilder
*/
final class RequestHeaderCollection
{
/**
* @var array<string, array{name: string, value: HeaderValue}>
*/
private array $headers;
/**
* @param array<string, HeaderValue> $headers
*/
public function __construct(array $headers = []) {
$this->headers = $this->normalizeHeaders($headers);
}
/**
* @return array<string, HeaderValue>
*/
public function all(): array {
$headers = [];
foreach ($this->headers as $entry) {
$headers[$entry['name']] = $entry['value'];
}
return $headers;
}
public function withoutHeaders(): self {
if ($this->headers === []) {
return $this;
}
return new self();
}
/**
* @param array<string, HeaderValue> $headers
*/
public function withHeaders(array $headers): self {
if ($headers === []) {
return $this;
}
$merged = array_replace($this->headers, $this->normalizeHeaders($headers));
if ($merged === $this->headers) {
return $this;
}
return self::fromNormalized($merged);
}
public function withTraceParent(TraceParent $traceParent): self {
$normalized = $this->headers;
$normalized['traceparent'] = [
'name' => 'traceparent',
'value' => $traceParent->header(),
];
unset($normalized['tracestate']);
if ($normalized === $this->headers) {
return $this;
}
return self::fromNormalized($normalized);
}
public function withTraceContext(TraceContext $traceContext): self {
$normalized = array_replace($this->headers, $this->normalizeHeaders($traceContext->headers()));
if ($traceContext->traceState() === null) {
unset($normalized['tracestate']);
}
if ($normalized === $this->headers) {
return $this;
}
return self::fromNormalized($normalized);
}
/**
* @param array<string, HeaderValue> $headers
*
* @return array<string, HeaderValue>
*/
public function merge(array $headers): array {
return $this->withHeaders($headers)->all();
}
/**
* @param array<string, array{name: string, value: HeaderValue}> $headers
*/
private static function fromNormalized(array $headers): self {
$self = new self();
$self->headers = $headers;
return $self;
}
/**
* @param array<string, HeaderValue> $headers
*
* @return array<string, array{name: string, value: HeaderValue}>
*/
private function normalizeHeaders(array $headers): array {
$normalized = [];
foreach ($headers as $name => $value) {
$name = trim((string) $name);
if ($name === '') {
continue;
}
$normalized[strtolower($name)] = [
'name' => $name,
'value' => $value,
];
}
return $normalized;
}
}

View File

@@ -0,0 +1,22 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http;
/**
* Defines how transport-level retries should behave for a request.
*/
final class RetryPolicy
{
public int $maxRetries;
public int $delayMilliseconds;
public function __construct(int $maxRetries = 0, int $delayMilliseconds = 0) {
$this->maxRetries = $maxRetries;
$this->delayMilliseconds = $delayMilliseconds;
}
public static function default(): self {
return new self();
}
}

View File

@@ -0,0 +1,133 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
/**
* Represents a credit pool creation request payload.
*
* @phpstan-type CreatePoolPayload array{
* license_key: string,
* credit_type: string,
* credits_total: int,
* period: string,
* overage_limit?: int,
* priority: int,
* first_period_start?: string,
* expires_at?: string,
* metadata?: array<string, mixed>
* }
*/
final class CreatePool
{
use InteractsWithDateTime;
/**
* License key that owns the credit pool.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Credit type tracked by this pool.
*
* @example ai
*/
public string $creditType;
/**
* Total credits allocated to the pool.
*
* @example 1000
*/
public int $creditsTotal;
/**
* Reset cadence for the pool.
*
* @example month
*/
public string $period;
/**
* Optional overage allowance after the pool is depleted.
*
* @example 100
*/
public ?int $overageLimit;
/**
* Pool consumption priority. Lower values are consumed first.
*
* @example 25
*/
public int $priority;
/**
* First billing period start in the caller's timezone.
*
* @example 2026-03-01T00:00:00Z
*/
public ?DateTimeImmutable $firstPeriodStart;
/**
* Absolute pool expiration date in the caller's timezone.
*
* @example 2026-04-01T00:00:00Z
*/
public ?DateTimeImmutable $expiresAt;
/**
* Arbitrary pool metadata forwarded to the API.
*
* @var array<string, mixed>|null
*
* @example {"source":"portal"}
*/
public ?array $metadata;
/**
* @param array<string, mixed>|null $metadata
*/
public function __construct(
string $licenseKey,
string $creditType,
int $creditsTotal,
string $period,
?int $overageLimit = null,
int $priority = 50,
?DateTimeImmutable $firstPeriodStart = null,
?DateTimeImmutable $expiresAt = null,
?array $metadata = null
) {
$this->licenseKey = $licenseKey;
$this->creditType = $creditType;
$this->creditsTotal = $creditsTotal;
$this->period = $period;
$this->overageLimit = $overageLimit;
$this->priority = $priority;
$this->firstPeriodStart = $firstPeriodStart;
$this->expiresAt = $expiresAt;
$this->metadata = $metadata;
}
/**
* @return CreatePoolPayload
*/
public function toArray(): array {
return array_filter([
'license_key' => $this->licenseKey,
'credit_type' => $this->creditType,
'credits_total' => $this->creditsTotal,
'period' => $this->period,
'overage_limit' => $this->overageLimit,
'priority' => $this->priority,
'first_period_start' => $this->firstPeriodStart ? $this->formatDateTime($this->firstPeriodStart) : null,
'expires_at' => $this->expiresAt ? $this->formatDateTime($this->expiresAt) : null,
'metadata' => $this->metadata,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,58 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
/**
* Represents a credit pool delete request payload.
*
* @phpstan-type DeletePoolPayload array{
* license_key: string,
* pool_id: int,
* expires_at?: string
* }
*/
final class DeletePool
{
use InteractsWithDateTime;
/**
* License key that owns the credit pool.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Credit pool identifier to delete.
*
* @example 42
*/
public int $poolId;
/**
* Optional expiration timestamp to soft-delete the pool at a specific time.
*
* @example 2026-04-01T00:00:00Z
*/
public ?DateTimeImmutable $expiresAt;
public function __construct(string $licenseKey, int $poolId, ?DateTimeImmutable $expiresAt = null) {
$this->licenseKey = $licenseKey;
$this->poolId = $poolId;
$this->expiresAt = $expiresAt;
}
/**
* @return DeletePoolPayload
*/
public function toArray(): array {
return array_filter([
'license_key' => $this->licenseKey,
'pool_id' => $this->poolId,
'expires_at' => $this->expiresAt ? $this->formatDateTime($this->expiresAt) : null,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,140 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
/**
* Represents a credits ledger query request.
*
* @phpstan-type ListLedgerEntriesQuery array{
* license_key: string,
* domain?: string,
* credit_type?: string,
* pool_id?: int,
* entry_type?: string,
* after?: string,
* before?: string,
* limit: int,
* starting_after?: int,
* ending_before?: int
* }
*/
final class ListLedgerEntries
{
use InteractsWithDateTime;
/**
* License key to query ledger entries for.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Restrict results to a specific site domain.
*
* @example example.com
*/
public ?string $domain;
/**
* Restrict results to a single credit type.
*
* @example ai
*/
public ?string $creditType;
/**
* Restrict results to a specific credit pool ID.
*
* @example 42
*/
public ?int $poolId;
/**
* Restrict results to a single ledger entry type.
*
* @example usage
* @example refund
*/
public ?string $entryType;
/**
* Return entries created on or after this UTC timestamp.
*
* @example new DateTimeImmutable('2026-03-01T00:00:00Z')
*/
public ?DateTimeImmutable $after;
/**
* Return entries created on or before this UTC timestamp.
*
* @example new DateTimeImmutable('2026-03-31T23:59:59Z')
*/
public ?DateTimeImmutable $before;
/**
* Maximum number of entries to return.
*
* @example 50
*/
public int $limit;
/**
* Cursor for pagination. Return entries with IDs higher than this value.
*
* @example 1002
*/
public ?int $startingAfter;
/**
* Cursor for pagination. Return entries with IDs lower than this value.
*
* @example 1002
*/
public ?int $endingBefore;
public function __construct(
string $licenseKey,
?string $domain = null,
?string $creditType = null,
?int $poolId = null,
?string $entryType = null,
?DateTimeImmutable $after = null,
?DateTimeImmutable $before = null,
int $limit = 50,
?int $startingAfter = null,
?int $endingBefore = null
) {
$this->licenseKey = $licenseKey;
$this->domain = $domain;
$this->creditType = $creditType;
$this->poolId = $poolId;
$this->entryType = $entryType;
$this->after = $after;
$this->before = $before;
$this->limit = $limit;
$this->startingAfter = $startingAfter;
$this->endingBefore = $endingBefore;
}
/**
* @return ListLedgerEntriesQuery
*/
public function toQuery(): array {
return array_filter([
'license_key' => $this->licenseKey,
'domain' => $this->domain,
'credit_type' => $this->creditType,
'pool_id' => $this->poolId,
'entry_type' => $this->entryType,
'after' => $this->after ? $this->formatDateTime($this->after) : null,
'before' => $this->before ? $this->formatDateTime($this->before) : null,
'limit' => $this->limit,
'starting_after' => $this->startingAfter,
'ending_before' => $this->endingBefore,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,88 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit;
/**
* Represents a credit usage write request payload.
*
* @phpstan-type RecordUsagePayload array{
* license_key: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* credits_used: int
* }
*/
final class RecordUsage
{
/**
* License key to record usage against.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Site domain consuming the credits.
*
* @example example.com
*/
public string $domain;
/**
* Product identifier responsible for the usage.
*
* @example plugin-pro
*/
public string $productSlug;
/**
* Credit type being consumed.
*
* @example ai
*/
public string $creditType;
/**
* Number of credits to consume.
*
* @example 10
*/
public int $creditsUsed;
/**
* Idempotency key forwarded as the X-Idempotency-Key header.
*
* @example request_123
*/
public string $idempotencyKey;
public function __construct(
string $licenseKey,
string $domain,
string $productSlug,
string $creditType,
int $creditsUsed,
string $idempotencyKey
) {
$this->licenseKey = $licenseKey;
$this->domain = $domain;
$this->productSlug = $productSlug;
$this->creditType = $creditType;
$this->creditsUsed = $creditsUsed;
$this->idempotencyKey = $idempotencyKey;
}
/**
* @return RecordUsagePayload
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'domain' => $this->domain,
'product_slug' => $this->productSlug,
'credit_type' => $this->creditType,
'credits_used' => $this->creditsUsed,
];
}
}

View File

@@ -0,0 +1,99 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit;
/**
* Represents a credit refund write request payload.
*
* @phpstan-type RefundPayload array{
* license_key: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* pool_id: int,
* credits_refunded: int
* }
*/
final class Refund
{
/**
* License key to refund credits against.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Site domain receiving the refund.
*
* @example example.com
*/
public string $domain;
/**
* Product identifier responsible for the refund.
*
* @example plugin-pro
*/
public string $productSlug;
/**
* Credit type being refunded.
*
* @example ai
*/
public string $creditType;
/**
* Pool ID the refund should be applied to.
*
* @example 42
*/
public int $poolId;
/**
* Number of credits to refund.
*
* @example 5
*/
public int $creditsRefunded;
/**
* Idempotency key forwarded as the X-Idempotency-Key header.
*
* @example request_456
*/
public string $idempotencyKey;
public function __construct(
string $licenseKey,
string $domain,
string $productSlug,
string $creditType,
int $poolId,
int $creditsRefunded,
string $idempotencyKey
) {
$this->licenseKey = $licenseKey;
$this->domain = $domain;
$this->productSlug = $productSlug;
$this->creditType = $creditType;
$this->poolId = $poolId;
$this->creditsRefunded = $creditsRefunded;
$this->idempotencyKey = $idempotencyKey;
}
/**
* @return RefundPayload
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'domain' => $this->domain,
'product_slug' => $this->productSlug,
'credit_type' => $this->creditType,
'pool_id' => $this->poolId,
'credits_refunded' => $this->creditsRefunded,
];
}
}

View File

@@ -0,0 +1,122 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
/**
* Represents a site quota write request payload.
*
* `quota` semantics:
* - `null` means uncapped and is omitted from the outgoing payload
* - `0` means blocked
* - a positive integer means a fixed quota
*
* `firstPeriodStart` is normalized to the API's canonical UTC datetime format.
*
* @phpstan-type SetQuotaPayload array{
* license_key: string,
* domain: string,
* credit_type: string,
* quota?: int,
* period: string,
* first_period_start?: string,
* metadata?: array<string, mixed>
* }
*/
final class SetQuota
{
use InteractsWithDateTime;
/**
* License key that owns the quota.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Site domain the quota applies to.
*
* @example example.com
*/
public string $domain;
/**
* Credit type identifier.
*
* @example ai
*/
public string $creditType;
/**
* Quota amount for the domain.
*
* @example null Uncapped
* @example 0 Blocked
* @example 100 Fixed quota
*/
public ?int $quota;
/**
* Quota period strategy.
*
* @example lifetime
* @example month
* @example week
*/
public string $period;
/**
* UTC anchor for period calculations.
*
* @example new DateTimeImmutable('2026-03-01T00:00:00Z')
*/
public ?DateTimeImmutable $firstPeriodStart;
/**
* Structured metadata passed through to the API.
*
* @var array<string, mixed>|null
*
* @example ['source' => 'portal']
*/
public ?array $metadata;
/**
* @param array<string, mixed>|null $metadata
*/
public function __construct(
string $licenseKey,
string $domain,
string $creditType,
?int $quota = null,
string $period = 'lifetime',
?DateTimeImmutable $firstPeriodStart = null,
?array $metadata = null
) {
$this->licenseKey = $licenseKey;
$this->domain = $domain;
$this->creditType = $creditType;
$this->quota = $quota;
$this->period = $period;
$this->firstPeriodStart = $firstPeriodStart;
$this->metadata = $metadata;
}
/**
* @return SetQuotaPayload
*/
public function toArray(): array {
return array_filter([
'license_key' => $this->licenseKey,
'domain' => $this->domain,
'credit_type' => $this->creditType,
'quota' => $this->quota,
'period' => $this->period,
'first_period_start' => $this->firstPeriodStart ? $this->formatDateTime($this->firstPeriodStart) : null,
'metadata' => $this->metadata,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,111 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
/**
* Represents a credit pool update request payload.
*
* @phpstan-type UpdatePoolPayload array{
* license_key: string,
* pool_id: int,
* credits_total?: int,
* overage_limit?: int,
* priority?: int,
* expires_at?: string,
* metadata?: array<string, mixed>
* }
*/
final class UpdatePool
{
use InteractsWithDateTime;
/**
* License key that owns the credit pool.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Credit pool identifier to update.
*
* @example 42
*/
public int $poolId;
/**
* Updated total credits for the pool.
*
* @example 1500
*/
public ?int $creditsTotal;
/**
* Updated overage allowance after the pool is depleted.
*
* @example 250
*/
public ?int $overageLimit;
/**
* Updated pool priority. Lower values are consumed first.
*
* @example 10
*/
public ?int $priority;
/**
* Updated absolute pool expiration date in the caller's timezone.
*
* @example 2026-04-01T00:00:00Z
*/
public ?DateTimeImmutable $expiresAt;
/**
* Arbitrary pool metadata forwarded to the API.
*
* @var array<string, mixed>|null
*
* @example {"source":"portal"}
*/
public ?array $metadata;
/**
* @param array<string, mixed>|null $metadata
*/
public function __construct(
string $licenseKey,
int $poolId,
?int $creditsTotal = null,
?int $overageLimit = null,
?int $priority = null,
?DateTimeImmutable $expiresAt = null,
?array $metadata = null
) {
$this->licenseKey = $licenseKey;
$this->poolId = $poolId;
$this->creditsTotal = $creditsTotal;
$this->overageLimit = $overageLimit;
$this->priority = $priority;
$this->expiresAt = $expiresAt;
$this->metadata = $metadata;
}
/**
* @return UpdatePoolPayload
*/
public function toArray(): array {
return array_filter([
'license_key' => $this->licenseKey,
'pool_id' => $this->poolId,
'credits_total' => $this->creditsTotal,
'overage_limit' => $this->overageLimit,
'priority' => $this->priority,
'expires_at' => $this->expiresAt ? $this->formatDateTime($this->expiresAt) : null,
'metadata' => $this->metadata,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,90 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement;
/**
* Represents a switch entitlement tier request payload.
*
* @phpstan-type MetadataValue string|int|float|bool|null|array<int, string|int|float|bool|null>
* @phpstan-type MetadataMap array<string, MetadataValue>
* @phpstan-type SwitchTierPayload array{
* license_key: string,
* product_slug: string,
* from_tier: string,
* to_tier: string,
* site_limit?: int,
* expiration_date?: string,
* purchase_date?: string,
* grants?: MetadataMap,
* metadata?: MetadataMap
* }
*/
final class SwitchTier
{
public string $licenseKey;
public string $productSlug;
public string $fromTier;
public string $toTier;
public ?int $siteLimit;
public ?string $expirationDate;
public ?string $purchaseDate;
/**
* @var MetadataMap|null
*/
public ?array $grants;
/**
* @var MetadataMap|null
*/
public ?array $metadata;
/**
* @param MetadataMap|null $grants
* @param MetadataMap|null $metadata
*/
public function __construct(
string $licenseKey,
string $productSlug,
string $fromTier,
string $toTier,
?int $siteLimit = null,
?string $expirationDate = null,
?string $purchaseDate = null,
?array $grants = null,
?array $metadata = null
) {
$this->licenseKey = $licenseKey;
$this->productSlug = $productSlug;
$this->fromTier = $fromTier;
$this->toTier = $toTier;
$this->siteLimit = $siteLimit;
$this->expirationDate = $expirationDate;
$this->purchaseDate = $purchaseDate;
$this->grants = $grants;
$this->metadata = $metadata;
}
/**
* @return SwitchTierPayload
*/
public function toArray(): array {
return array_filter([
'license_key' => $this->licenseKey,
'product_slug' => $this->productSlug,
'from_tier' => $this->fromTier,
'to_tier' => $this->toTier,
'site_limit' => $this->siteLimit,
'expiration_date' => $this->expirationDate,
'purchase_date' => $this->purchaseDate,
'grants' => $this->grants,
'metadata' => $this->metadata,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,50 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement\ValueObjects\UpsertProduct;
/**
* Represents an upsert entitlements request payload.
*
* @phpstan-import-type UpsertProductPayload from UpsertProduct
* @phpstan-type UpsertPayload array{
* identity_id: string,
* license_key?: string,
* products: list<UpsertProductPayload>
* }
*/
final class Upsert
{
public string $identityId;
public ?string $licenseKey;
/**
* @var UpsertProduct[]
*/
public array $products;
/**
* @param UpsertProduct[] $products
*/
public function __construct(string $identityId, array $products, ?string $licenseKey = null) {
$this->identityId = $identityId;
$this->products = $products;
$this->licenseKey = $licenseKey;
}
/**
* @return UpsertPayload
*/
public function toArray(): array {
return array_filter([
'identity_id' => $this->identityId,
'license_key' => $this->licenseKey,
'products' => array_map(
static fn (UpsertProduct $product): array => $product->toArray(),
$this->products
),
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,100 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement\ValueObjects;
/**
* Represents one entitlement mutation inside an upsert request.
*
* @phpstan-type MetadataValue string|int|float|bool|null|array<int, string|int|float|bool|null>
* @phpstan-type MetadataMap array<string, MetadataValue>
* @phpstan-type UpsertProductPayload array{
* product_slug: string,
* tier?: string,
* site_limit?: int,
* expiration_date?: string,
* purchase_date?: string,
* status?: string,
* grants?: MetadataMap,
* metadata?: MetadataMap
* }
*/
final class UpsertProduct
{
public string $productSlug;
public ?string $tier;
/**
* Maximum allowed site activations for this entitlement.
*/
public ?int $siteLimit;
/**
* Entitlement expiration date in a format accepted by the API, including RFC3339 UTC `Z`, RFC3339 with an explicit offset, or MySQL DATETIME.
*/
public ?string $expirationDate;
/**
* Purchase date in a format accepted by the API, including RFC3339 UTC `Z`, RFC3339 with an explicit offset, or MySQL DATETIME.
*/
public ?string $purchaseDate;
/**
* Target entitlement status, e.g. `active`, `suspended`, or `cancelled`.
*/
public ?string $status;
/**
* Grants payload stored by the API, typically including a `capabilities` list.
*
* @var MetadataMap|null
*/
public ?array $grants;
/**
* Arbitrary metadata persisted with the entitlement.
*
* @var MetadataMap|null
*/
public ?array $metadata;
/**
* @param MetadataMap|null $grants
* @param MetadataMap|null $metadata
*/
public function __construct(
string $productSlug,
?string $tier = null,
?int $siteLimit = null,
?string $expirationDate = null,
?string $purchaseDate = null,
?string $status = null,
?array $grants = null,
?array $metadata = null
) {
$this->productSlug = $productSlug;
$this->tier = $tier;
$this->siteLimit = $siteLimit;
$this->expirationDate = $expirationDate;
$this->purchaseDate = $purchaseDate;
$this->status = $status;
$this->grants = $grants;
$this->metadata = $metadata;
}
/**
* @return UpsertProductPayload
*/
public function toArray(): array {
return array_filter([
'product_slug' => $this->productSlug,
'tier' => $this->tier,
'site_limit' => $this->siteLimit,
'expiration_date' => $this->expirationDate,
'purchase_date' => $this->purchaseDate,
'status' => $this->status,
'grants' => $this->grants,
'metadata' => $this->metadata,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,63 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License;
/**
* Represents a license activation request payload.
*
* @phpstan-type ActivatePayload array{
* license_key: string,
* product_slug: string,
* tier: string,
* domain: string
* }
*/
final class Activate
{
/**
* License key being activated.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Product identifier to activate.
*
* @example plugin-pro
*/
public string $productSlug;
/**
* Entitlement tier being activated.
*
* @example pro
*/
public string $tier;
/**
* Site domain where the license is being activated.
*
* @example example.com
*/
public string $domain;
public function __construct(string $licenseKey, string $productSlug, string $tier, string $domain) {
$this->licenseKey = $licenseKey;
$this->productSlug = $productSlug;
$this->tier = $tier;
$this->domain = $domain;
}
/**
* @return ActivatePayload
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'product_slug' => $this->productSlug,
'tier' => $this->tier,
'domain' => $this->domain,
];
}
}

View File

@@ -0,0 +1,50 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias\ValueObjects\ImportAlias;
/**
* Represents an alias import request payload.
*
* @phpstan-import-type ImportAliasPayload from ImportAlias
* @phpstan-type ImportAliasesPayload array{
* identity_id: string,
* aliases: list<ImportAliasPayload>
* }
*/
final class ImportAliases
{
/**
* Identity identifier that owns the aliases.
*
* @example identity_123
*/
public string $identityId;
/**
* @var ImportAlias[]
*/
public array $aliases;
/**
* @param ImportAlias[] $aliases
*/
public function __construct(string $identityId, array $aliases) {
$this->identityId = $identityId;
$this->aliases = $aliases;
}
/**
* @return ImportAliasesPayload
*/
public function toArray(): array {
return [
'identity_id' => $this->identityId,
'aliases' => array_map(
static fn (ImportAlias $alias): array => $alias->toArray(),
$this->aliases
),
];
}
}

View File

@@ -0,0 +1,62 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias;
use InvalidArgumentException;
/**
* Represents an alias removal request payload.
*
* @phpstan-type RemoveAliasesPayload array{
* license_key?: string,
* identity_id?: string,
* alias_key?: string
* }
*/
final class RemoveAliases
{
/**
* License key identifier.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public ?string $licenseKey;
/**
* Customer identity identifier.
*
* @example identity_123
*/
public ?string $identityId;
/**
* Specific alias key to remove. Omit to remove all aliases.
*
* @example LEGACY-KEY-123
*/
public ?string $aliasKey;
/**
* @throws InvalidArgumentException
*/
public function __construct(?string $licenseKey = null, ?string $identityId = null, ?string $aliasKey = null) {
if ($licenseKey === null && $identityId === null) {
throw new InvalidArgumentException('Either licenseKey or identityId is required.');
}
$this->licenseKey = $licenseKey;
$this->identityId = $identityId;
$this->aliasKey = $aliasKey;
}
/**
* @return RemoveAliasesPayload
*/
public function toArray(): array {
return array_filter([
'license_key' => $this->licenseKey,
'identity_id' => $this->identityId,
'alias_key' => $this->aliasKey,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,43 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias\ValueObjects;
/**
* Represents one alias import item.
*
* @phpstan-type ImportAliasPayload array{
* key: string,
* product_slug?: string
* }
*/
final class ImportAlias
{
/**
* Legacy alias key to import.
*
* @example LEGACY-KEY-123
*/
public string $key;
/**
* Optional product scope for the alias.
*
* @example plugin-pro
*/
public ?string $productSlug;
public function __construct(string $key, ?string $productSlug = null) {
$this->key = $key;
$this->productSlug = $productSlug;
}
/**
* @return ImportAliasPayload
*/
public function toArray(): array {
return array_filter([
'key' => $this->key,
'product_slug' => $this->productSlug,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,53 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License;
/**
* Represents a license deactivation request payload.
*
* @phpstan-type DeactivatePayload array{
* license_key: string,
* product_slug: string,
* domain: string
* }
*/
final class Deactivate
{
/**
* License key being deactivated.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Product identifier to deactivate.
*
* @example plugin-pro
*/
public string $productSlug;
/**
* Site domain where the license is being deactivated.
*
* @example example.com
*/
public string $domain;
public function __construct(string $licenseKey, string $productSlug, string $domain) {
$this->licenseKey = $licenseKey;
$this->productSlug = $productSlug;
$this->domain = $domain;
}
/**
* @return DeactivatePayload
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'product_slug' => $this->productSlug,
'domain' => $this->domain,
];
}
}

View File

@@ -0,0 +1,57 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License;
/**
* Represents a license activation deletion request payload.
*
* @phpstan-type DeleteActivationPayload array{
* license_key: string,
* product_slug: string,
* domain: string
* }
*/
final class DeleteActivation
{
/**
* License key whose activation is being deleted.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public string $licenseKey;
/**
* Product identifier whose activation is being deleted.
*
* @example plugin-pro
*/
public string $productSlug;
/**
* Site domain whose activation is being deleted.
*
* @example example.com
*/
public string $domain;
public function __construct(
string $licenseKey,
string $productSlug,
string $domain
) {
$this->licenseKey = $licenseKey;
$this->productSlug = $productSlug;
$this->domain = $domain;
}
/**
* @return DeleteActivationPayload
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'product_slug' => $this->productSlug,
'domain' => $this->domain,
];
}
}

View File

@@ -0,0 +1,52 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License;
use InvalidArgumentException;
/**
* Represents a license reference identified by license key or identity ID.
*
* @phpstan-type LicenseReferencePayload array{
* license_key?: string,
* identity_id?: string
* }
*/
final class LicenseReference
{
/**
* License key identifier.
*
* @example LWSW-8H9F-5UKA-VR3B-D7SQ-BP9N
*/
public ?string $licenseKey;
/**
* Customer identity identifier.
*
* @example identity_123
*/
public ?string $identityId;
/**
* @throws InvalidArgumentException
*/
public function __construct(?string $licenseKey = null, ?string $identityId = null) {
if ($licenseKey === null && $identityId === null) {
throw new InvalidArgumentException('Either licenseKey or identityId is required.');
}
$this->licenseKey = $licenseKey;
$this->identityId = $identityId;
}
/**
* @return LicenseReferencePayload
*/
public function toArray(): array {
return array_filter([
'license_key' => $this->licenseKey,
'identity_id' => $this->identityId,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,95 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Listing;
/**
* Defines the query parameters for listing licenses.
*
* Filters:
* - `search` performs a broad text search across listable license fields.
* - `identityId` narrows results to a specific external customer identity.
* - `status` applies the server-side license status filter.
* - `productSlug` and `tier` limit results to matching products.
* - `aliasKey` narrows results to licenses with a matching alias.
* - `domain` narrows results to licenses with an exact active activation on that domain.
*
* Cursor pagination:
* - `startingAfter` requests the next page after a known item ID.
* - `endingBefore` requests the previous page before a known item ID.
* - `limit` controls the page size and defaults to the API default of 10.
*/
final class ListRequest
{
public ?string $search;
public ?string $identityId;
public ?string $status;
public ?string $productSlug;
public ?string $tier;
public ?int $startingAfter;
public ?int $endingBefore;
public int $limit;
public ?string $aliasKey;
public ?string $domain;
public function __construct(
?string $search = null,
?string $identityId = null,
?string $status = null,
?string $productSlug = null,
?string $tier = null,
?int $startingAfter = null,
?int $endingBefore = null,
int $limit = 10,
?string $aliasKey = null,
?string $domain = null
) {
$this->search = $search;
$this->identityId = $identityId;
$this->status = $status;
$this->productSlug = $productSlug;
$this->tier = $tier;
$this->startingAfter = $startingAfter;
$this->endingBefore = $endingBefore;
$this->limit = $limit;
$this->aliasKey = $aliasKey;
$this->domain = $domain;
}
/**
* @return array{
* search?: string,
* identity_id?: string,
* status?: string,
* product_slug?: string,
* tier?: string,
* alias_key?: string,
* domain?: string,
* starting_after?: int,
* ending_before?: int,
* limit: int
* }
*/
public function toQuery(): array {
return array_filter([
'search' => $this->search,
'identity_id' => $this->identityId,
'status' => $this->status,
'product_slug' => $this->productSlug,
'tier' => $this->tier,
'alias_key' => $this->aliasKey,
'domain' => $this->domain,
'starting_after' => $this->startingAfter,
'ending_before' => $this->endingBefore,
'limit' => $this->limit,
], static fn ($value): bool => $value !== null);
}
}

View File

@@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License;
/**
* Represents a regenerate-key request payload.
*
* @phpstan-type RegenerateKeyPayload array{
* identity_id: string
* }
*/
final class RegenerateKey
{
/**
* Identity identifier whose license key should be regenerated.
*
* @example identity_123
*/
public string $identityId;
public function __construct(string $identityId) {
$this->identityId = $identityId;
}
/**
* @return RegenerateKeyPayload
*/
public function toArray(): array {
return [
'identity_id' => $this->identityId,
];
}
}

View File

@@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Token;
/**
* Represents a token creation request payload.
*
* @phpstan-type CreateTokenPayload array{
* license_key: string,
* domain: string
* }
*/
final class Create
{
public string $licenseKey;
public string $domain;
public function __construct(string $licenseKey, string $domain) {
$this->licenseKey = $licenseKey;
$this->domain = $domain;
}
/**
* @return CreateTokenPayload
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'domain' => $this->domain,
];
}
}

View File

@@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Token;
/**
* Represents a token revocation request payload.
*
* @phpstan-type RevokeTokenPayload array{
* license_key: string,
* domain: string
* }
*/
final class Revoke
{
public string $licenseKey;
public string $domain;
public function __construct(string $licenseKey, string $domain) {
$this->licenseKey = $licenseKey;
$this->domain = $domain;
}
/**
* @return RevokeTokenPayload
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'domain' => $this->domain,
];
}
}

View File

@@ -0,0 +1,45 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsLedgerResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsPoolsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsQuotasResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\EntitlementsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\LicensesResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\ProductsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\TokensResource;
/**
* Provides immutable auth-state rebinding for auth-bound resource views.
*
* @mixin CreditsLedgerResource
* @mixin CreditsPoolsResource
* @mixin CreditsQuotasResource
* @mixin CreditsResource
* @mixin EntitlementsResource
* @mixin LicensesResource
* @mixin ProductsResource
* @mixin TokensResource
*/
trait RebindsAuthState
{
/**
* Returns the current resource when the auth state is unchanged, or a rebound
* resource view when a different auth state is requested.
*/
public function withAuthState(AuthState $authState): self {
if ($this->authState === $authState) {
return $this;
}
return $this->rebindWithAuthState($authState);
}
/**
* Rebuilds the concrete resource with the provided auth state.
*/
abstract protected function rebindWithAuthState(AuthState $authState): self;
}

View File

@@ -0,0 +1,38 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsLedgerResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsPoolsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsQuotasResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit\CreditsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\EntitlementsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\LicensesResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\ProductsResource;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\TokensResource;
/**
* Provides immutable request-header rebinding for resource views.
*
* @mixin CreditsLedgerResource
* @mixin CreditsPoolsResource
* @mixin CreditsQuotasResource
* @mixin CreditsResource
* @mixin EntitlementsResource
* @mixin LicensesResource
* @mixin ProductsResource
* @mixin TokensResource
*/
trait RebindsRequestHeaderCollection
{
public function withRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
if ($this->requestHeaderCollection === $requestHeaderCollection) {
return $this;
}
return $this->rebindWithRequestHeaderCollection($requestHeaderCollection);
}
abstract protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self;
}

View File

@@ -0,0 +1,38 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use Generator;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\ListLedgerEntries;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\LedgerPage;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the credits ledger resource surface.
*/
interface CreditsLedgerResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(ListLedgerEntries $request): LedgerPage;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*
* @return Generator<int, LedgerPage, mixed, void>
*/
public function pages(ListLedgerEntries $request): Generator;
}

View File

@@ -0,0 +1,57 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\CreatePool;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\DeletePool as DeletePoolRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\UpdatePool;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\DeletePool;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\PoolCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\CreditPool;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the credits pools resource surface.
*/
interface CreditsPoolsResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(string $licenseKey, bool $active = false): PoolCollection;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function create(CreatePool $request): CreditPool;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function update(UpdatePool $request): CreditPool;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function delete(DeletePoolRequest $request): DeletePool;
}

View File

@@ -0,0 +1,46 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\SetQuota;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\DeleteQuota;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\QuotaCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\SiteQuota;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the credits quotas resource surface.
*/
interface CreditsQuotasResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(string $licenseKey): QuotaCollection;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function set(SetQuota $request): SiteQuota;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function delete(string $licenseKey, string $domain, string $creditType): DeleteQuota;
}

View File

@@ -0,0 +1,74 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\RecordUsage as RecordUsageRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\Refund as RefundRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\BalanceCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\RecordUsage;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\Refund;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the root credits resource surface.
*/
interface CreditsResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function balance(string $licenseKey, string $domain, ?string $creditType = null, ?string $sort = null): BalanceCollection;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function recordUsage(RecordUsageRequest $request): RecordUsage;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function refund(RefundRequest $request): Refund;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function pools(): CreditsPoolsResourceInterface;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function quotas(): CreditsQuotasResourceInterface;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function ledger(): CreditsLedgerResourceInterface;
}

View File

@@ -0,0 +1,77 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement\SwitchTier;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement\Upsert;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Cancel;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Delete;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Suspend;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\SwitchTier as SwitchTierResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Unsuspend;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Upsert as UpsertResponse;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the entitlements resource surface.
*/
interface EntitlementsResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function upsert(Upsert $request): UpsertResponse;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function switchTier(SwitchTier $request): SwitchTierResponse;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function suspend(string $licenseKey, string $productSlug, string $tier): Suspend;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function unsuspend(string $licenseKey, string $productSlug, string $tier): Unsuspend;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function cancel(string $licenseKey, string $productSlug, string $tier, ?string $reason = null): Cancel;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function delete(string $licenseKey, string $productSlug, string $tier): Delete;
}

View File

@@ -0,0 +1,145 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use Generator;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Activate;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias\ImportAliases;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias\RemoveAliases;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Deactivate;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\DeleteActivation;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\LicenseReference;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Listing\ListRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\RegenerateKey;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Activate as ActivateResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias\ImportAliases as ImportAliasesResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias\RemoveAliases as RemoveAliasesResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Deactivate as DeactivateResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\DeleteActivation as DeleteActivationResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Listing\Listing;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\RegenerateKey as RegenerateKeyResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\StatusChange;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Validate;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the licenses resource surface.
*/
interface LicensesResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(ListRequest $request): Listing;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*
* @return Generator<int, Listing, mixed, void>
*/
public function pages(ListRequest $request): Generator;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function activate(Activate $request): ActivateResponse;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function deactivate(Deactivate $request): DeactivateResponse;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function deleteActivation(DeleteActivation $request): DeleteActivationResponse;
/**
* @param list<string> $productSlugs
*
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function validate(string $licenseKey, array $productSlugs, string $domain): Validate;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function suspend(LicenseReference $request): StatusChange;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function reinstate(LicenseReference $request): StatusChange;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function ban(LicenseReference $request): StatusChange;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function regenerateKey(RegenerateKey $request): RegenerateKeyResponse;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function importAliases(ImportAliases $request): ImportAliasesResponse;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function removeAliases(RemoveAliases $request): RemoveAliasesResponse;
}

View File

@@ -0,0 +1,25 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Product\Catalog;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the products resource surface.
*/
interface ProductsResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function catalog(string $licenseKey, ?string $domain = null): Catalog;
}

View File

@@ -0,0 +1,55 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Token\Create as CreateRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Token\Revoke as RevokeRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Token\Auth;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Token\TokenList;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Token\ValueObjects\TokenItem;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Defines the tokens resource surface.
*/
interface TokensResourceInterface
{
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(string $licenseKey): TokenList;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function create(CreateRequest $request): TokenItem;
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function revoke(RevokeRequest $request): TokenItem;
/**
* @throws ApiErrorExceptionInterface
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function auth(string $licenseKey, string $token, string $domain): Auth;
}

View File

@@ -0,0 +1,145 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit;
use Generator;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\ListLedgerEntries;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsLedgerResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\LedgerPage;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the credits ledger API resource.
*
* @phpstan-import-type ListLedgerEntriesQuery from ListLedgerEntries
* @phpstan-type LedgerEntryPayload array{
* id: int,
* pool_id: int,
* entitlement_id_at_event: int,
* tier_at_event: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* entry_type: string,
* amount: int,
* period_start: string|null,
* idempotency_key: string,
* created_at: string
* }
* @phpstan-type LedgerPagePayload array{
* entries: list<LedgerEntryPayload>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* }
*/
final class CreditsLedgerResource implements CreditsLedgerResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(ListLedgerEntries $request): LedgerPage {
/** @var ListLedgerEntriesQuery $query */
$query = $request->toQuery();
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/credits/ledger'),
$query,
null,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var LedgerPagePayload $result */
return LedgerPage::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*
* @return Generator<int, LedgerPage, mixed, void>
*/
public function pages(ListLedgerEntries $request): Generator {
$page = $this->list($request);
while (true) {
yield $page;
if ($page->links->next === null) {
return;
}
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->fromPaginationLink($page->links->next),
[],
null,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var LedgerPagePayload $result */
$page = LedgerPage::from($result);
}
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self($this->requestExecutor, $this->apiUriFactory, $authState, $this->requestHeaderCollection);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self($this->requestExecutor, $this->apiUriFactory, $this->authState, $requestHeaderCollection);
}
}

View File

@@ -0,0 +1,178 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ApiResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\CreatePool;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\DeletePool as DeletePoolRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\UpdatePool;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsPoolsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\DeletePool;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\PoolCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\CreditPool;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the credits pools API resource.
*
* @phpstan-import-type CreatePoolPayload from CreatePool
* @phpstan-import-type UpdatePoolPayload from UpdatePool
* @phpstan-import-type DeletePoolPayload from DeletePoolRequest
* @phpstan-type PoolPayload array{
* pool_id: int,
* credit_type: string,
* credits_total: int,
* credits_used: int,
* overage_limit: ?int,
* priority: int,
* period: string,
* first_period_start: ?string,
* expires_at: ?string,
* is_expired: bool
* }
* @phpstan-type PoolCollectionPayload array{
* pools: array<int|string, PoolPayload>
* }
* @phpstan-type DeletePoolResponsePayload array{
* deleted: bool,
* pool_id: int
* }
*/
final class CreditsPoolsResource implements CreditsPoolsResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(string $licenseKey, bool $active = false): PoolCollection {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/credits/pools'),
[
'license_key' => $licenseKey,
'active' => $active,
],
null,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var PoolCollectionPayload $result */
return PoolCollection::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function create(CreatePool $request): CreditPool {
/** @var CreatePoolPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/credits/pools'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var PoolPayload $result */
return CreditPool::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function update(UpdatePool $request): CreditPool {
/** @var UpdatePoolPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'PATCH',
$this->apiUriFactory->make('/credits/pools'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var PoolPayload $result */
return CreditPool::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function delete(DeletePoolRequest $request): DeletePool {
/** @var DeletePoolPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'DELETE',
$this->apiUriFactory->make('/credits/pools'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var DeletePoolResponsePayload $result */
return DeletePool::from($result);
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self($this->requestExecutor, $this->apiUriFactory, $authState, $this->requestHeaderCollection);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self($this->requestExecutor, $this->apiUriFactory, $this->authState, $requestHeaderCollection);
}
}

View File

@@ -0,0 +1,146 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ApiResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\SetQuota;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsQuotasResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\DeleteQuota;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\QuotaCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\SiteQuota;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the credits quotas API resource.
*
* @phpstan-import-type SetQuotaPayload from \LiquidWeb\LicensingApiClient\Requests\Credit\SetQuota
* @phpstan-type SiteQuotaPayload array{
* domain: string,
* credit_type: string,
* quota: ?int,
* period: string,
* first_period_start: ?string,
* is_blocked: bool,
* is_uncapped: bool
* }
* @phpstan-type QuotaCollectionPayload array{
* quotas: list<SiteQuotaPayload>
* }
* @phpstan-type DeleteQuotaPayload array{
* deleted: bool
* }
*/
final class CreditsQuotasResource implements CreditsQuotasResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(string $licenseKey): QuotaCollection {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/credits/quotas'),
[
'license_key' => $licenseKey,
],
null,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var QuotaCollectionPayload $result */
return QuotaCollection::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function set(SetQuota $request): SiteQuota {
/** @var SetQuotaPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/credits/quotas'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var SiteQuotaPayload $result */
return SiteQuota::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function delete(string $licenseKey, string $domain, string $creditType): DeleteQuota {
$result = $this->requestExecutor->executeJson(
'DELETE',
$this->apiUriFactory->make('/credits/quotas'),
[],
[
'license_key' => $licenseKey,
'domain' => $domain,
'credit_type' => $creditType,
],
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var DeleteQuotaPayload $result */
return DeleteQuota::from($result);
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self($this->requestExecutor, $this->apiUriFactory, $authState, $this->requestHeaderCollection);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self($this->requestExecutor, $this->apiUriFactory, $this->authState, $requestHeaderCollection);
}
}

View File

@@ -0,0 +1,240 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Credit;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\ApiResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\RecordUsage as RecordUsageRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Credit\Refund as RefundRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsLedgerResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsPoolsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsQuotasResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\CreditsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\BalanceCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\RecordUsage;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\Refund;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the credits API resource.
*
* @phpstan-type BalancePayload array{
* credits: list<array{
* credit_type: string,
* remaining: int,
* site_quota: int|null,
* site_used: int,
* site_remaining: int,
* aggregate_total: int,
* aggregate_used: int,
* aggregate_remaining: int,
* aggregate_overage: int,
* pools: list<array{
* pool_id: int,
* pool_remaining: int,
* priority: int,
* period: string,
* resets_on: string|null,
* expires_at: string|null,
* credits_total?: int,
* credits_used?: int,
* overage?: int,
* overage_limit?: int|null
* }>
* }>
* }
* @phpstan-import-type RecordUsagePayload from RecordUsageRequest
* @phpstan-import-type RefundPayload from RefundRequest
* @phpstan-type RecordUsageResponsePayload array{
* credits_used: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<array-key, int>
* }
* @phpstan-type RefundResponsePayload array{
* credits_refunded: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<array-key, int>
* }
*/
final class CreditsResource implements CreditsResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
private CreditsPoolsResource $pools;
private CreditsQuotasResource $quotas;
private CreditsLedgerResource $ledger;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection,
CreditsPoolsResource $pools,
CreditsQuotasResource $quotas,
CreditsLedgerResource $ledger
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
$this->pools = $pools;
$this->quotas = $quotas;
$this->ledger = $ledger;
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function balance(string $licenseKey, string $domain, ?string $creditType = null, ?string $sort = null): BalanceCollection {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/credits'),
array_filter([
'license_key' => $licenseKey,
'domain' => $domain,
'credit_type' => $creditType,
'sort' => $sort,
], static fn ($value): bool => $value !== null),
null,
$this->authState->optionalToken(),
$this->requestHeaderCollection->all()
);
/** @var BalancePayload $result */
return BalanceCollection::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function recordUsage(RecordUsageRequest $request): RecordUsage {
/** @var RecordUsagePayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/credits/usage'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->merge([
'X-Idempotency-Key' => $request->idempotencyKey,
])
);
/** @var RecordUsageResponsePayload $result */
return RecordUsage::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function refund(RefundRequest $request): Refund {
/** @var RefundPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/credits/refunds'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->merge([
'X-Idempotency-Key' => $request->idempotencyKey,
])
);
/** @var RefundResponsePayload $result */
return Refund::from($result);
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function pools(): CreditsPoolsResourceInterface {
return $this->pools;
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function quotas(): CreditsQuotasResourceInterface {
return $this->quotas;
}
/**
* @throws ApiResponseException
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function ledger(): CreditsLedgerResourceInterface {
return $this->ledger;
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self(
$this->requestExecutor,
$this->apiUriFactory,
$authState,
$this->requestHeaderCollection,
$this->pools->withAuthState($authState),
$this->quotas->withAuthState($authState),
$this->ledger->withAuthState($authState)
);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self(
$this->requestExecutor,
$this->apiUriFactory,
$this->authState,
$requestHeaderCollection,
$this->pools->withRequestHeaderCollection($requestHeaderCollection),
$this->quotas->withRequestHeaderCollection($requestHeaderCollection),
$this->ledger->withRequestHeaderCollection($requestHeaderCollection)
);
}
}

View File

@@ -0,0 +1,240 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestBuilder;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement\SwitchTier as SwitchTierRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Entitlement\Upsert as UpsertRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\EntitlementsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Cancel;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Delete;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Suspend;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\SwitchTier as SwitchTierResponse;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Unsuspend;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\Upsert as UpsertResponse;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the entitlements API resource.
*
* @phpstan-import-type JsonObject from RequestBuilder
* @phpstan-type EntitlementStatusPayload array{
* product_slug: string,
* tier: string,
* status: string
* }
* @phpstan-type UpsertPayload array{
* license_key: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string
* }>
* }
* @phpstan-type DeletePayload array{
* deleted: bool
* }
* @phpstan-type SwitchTierPayload array{
* product_slug: string,
* from_tier: string,
* to_tier: string,
* status: string,
* site_limit: int,
* active_count: int,
* over_limit: bool
* }
*/
final class EntitlementsResource implements EntitlementsResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function upsert(UpsertRequest $request): UpsertResponse {
/** @var JsonObject $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/entitlements'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var UpsertPayload $result */
return UpsertResponse::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function switchTier(SwitchTierRequest $request): SwitchTierResponse {
/** @var JsonObject $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/entitlements/switch-tier'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var SwitchTierPayload $result */
return SwitchTierResponse::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function suspend(string $licenseKey, string $productSlug, string $tier): Suspend {
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/entitlements/suspend'),
[],
[
'license_key' => $licenseKey,
'product_slug' => $productSlug,
'tier' => $tier,
],
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var EntitlementStatusPayload $result */
return Suspend::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function unsuspend(string $licenseKey, string $productSlug, string $tier): Unsuspend {
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/entitlements/unsuspend'),
[],
[
'license_key' => $licenseKey,
'product_slug' => $productSlug,
'tier' => $tier,
],
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var EntitlementStatusPayload $result */
return Unsuspend::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function cancel(string $licenseKey, string $productSlug, string $tier, ?string $reason = null): Cancel {
$body = array_filter([
'license_key' => $licenseKey,
'product_slug' => $productSlug,
'tier' => $tier,
'reason' => $reason,
], static fn ($value): bool => $value !== null);
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/entitlements/cancel'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var EntitlementStatusPayload $result */
return Cancel::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function delete(string $licenseKey, string $productSlug, string $tier): Delete {
$result = $this->requestExecutor->executeJson(
'DELETE',
$this->apiUriFactory->make('/entitlements'),
[],
[
'license_key' => $licenseKey,
'product_slug' => $productSlug,
'tier' => $tier,
],
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var DeletePayload $result */
return Delete::from($result);
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self($this->requestExecutor, $this->apiUriFactory, $authState, $this->requestHeaderCollection);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self($this->requestExecutor, $this->apiUriFactory, $this->authState, $requestHeaderCollection);
}
}

View File

@@ -0,0 +1,471 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources;
use Generator;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Activate as ActivateRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias\ImportAliases as ImportAliasesRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Alias\RemoveAliases as RemoveAliasesRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Deactivate as DeactivateRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\DeleteActivation as DeleteActivationRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\LicenseReference;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\Listing\ListRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\License\RegenerateKey as RegenerateKeyRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\LicensesResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Activate;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias\ImportAliases;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias\RemoveAliases;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Deactivate;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\DeleteActivation;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Listing\Listing;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\RegenerateKey;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\StatusChange;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Validate;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the licenses API resource.
*
* @phpstan-type ActivationDomainPayload array{
* activated_at: string,
* deactivated_at: string|null,
* is_active: bool,
* is_production: bool
* }
* @phpstan-type ActivationDomainsPayload array<string, ActivationDomainPayload>
* @phpstan-type ValidatePayload array{
* license: array{license_key: string, status: string}|null,
* domain: string,
* is_production: bool,
* products: list<array{
* product_slug: string,
* status: string,
* is_valid: bool,
* entitlement: array{
* tier: string,
* site_limit: int,
* active_count: int,
* available: int,
* over_limit: bool,
* excess_activations: int,
* expiration_date: string,
* status: string,
* capabilities: list<string>
* }|null,
* activation: array{
* domain: string,
* activated_at: string
* }|null,
* available_entitlements?: list<array{
* tier: string,
* site_limit: int,
* active_count: int,
* available: int,
* over_limit: bool,
* excess_activations: int,
* capabilities: list<string>,
* status: string,
* expires: string
* }>
* }>
* }
* @phpstan-type ListingPayload array{
* licenses: list<array{
* license_key: string,
* identity_id: string,
* status: string,
* created_at: string,
* updated_at: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* }
* }>,
* aliases: list<array{alias_key: string, product_slug: string|null}>
* }>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* }
* @phpstan-import-type ActivatePayload from ActivateRequest
* @phpstan-import-type DeactivatePayload from DeactivateRequest
* @phpstan-import-type DeleteActivationPayload from DeleteActivationRequest
* @phpstan-import-type LicenseReferencePayload from LicenseReference
* @phpstan-import-type RegenerateKeyPayload from RegenerateKeyRequest
* @phpstan-import-type ImportAliasesPayload from ImportAliasesRequest
* @phpstan-import-type RemoveAliasesPayload from RemoveAliasesRequest
* @phpstan-type ActivateResponsePayload array{
* status: string,
* is_valid: bool,
* is_production: bool,
* license: array{license_key: string, status: string}|null,
* entitlement: array{
* product_slug: string,
* tier: string,
* site_limit: int,
* active_count: int,
* available: int,
* over_limit: bool,
* excess_activations: int,
* expiration_date: string,
* status: string,
* capabilities: list<string>
* }|null,
* activation: array{
* domain: string,
* activated_at: string
* }|null
* }
* @phpstan-type DeactivateResponsePayload array{deactivated: bool}
* @phpstan-type DeleteActivationResponsePayload array{deleted: bool}
* @phpstan-type StatusChangePayload array{license_key: string, status: string}
* @phpstan-type RegenerateKeyResponsePayload array{license_key: string}
* @phpstan-type ImportAliasesResponsePayload array{
* imported: list<array{alias_key: string, product_slug?: string|null}>
* }
* @phpstan-type RemoveAliasesResponsePayload array{removed: int}
*/
final class LicensesResource implements LicensesResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function activate(ActivateRequest $request): Activate {
/** @var ActivatePayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/licenses/activate'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var ActivateResponsePayload $result */
return Activate::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function deactivate(DeactivateRequest $request): Deactivate {
/** @var DeactivatePayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/licenses/deactivate'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var DeactivateResponsePayload $result */
return Deactivate::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function deleteActivation(DeleteActivationRequest $request): DeleteActivation {
/** @var DeleteActivationPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'DELETE',
$this->apiUriFactory->make('/licenses/activation'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var DeleteActivationResponsePayload $result */
return DeleteActivation::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(ListRequest $request): Listing {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/licenses'),
$request->toQuery(),
null,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var ListingPayload $result */
return Listing::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*
* @return Generator<int, Listing, mixed, void>
*/
public function pages(ListRequest $request): Generator {
$page = $this->list($request);
while (true) {
yield $page;
if ($page->links->next === null) {
return;
}
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->fromPaginationLink($page->links->next),
[],
null,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var ListingPayload $result */
$page = Listing::from($result);
}
}
/**
* @param list<string> $productSlugs
*
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function validate(string $licenseKey, array $productSlugs, string $domain): Validate {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/licenses/validate'),
[
'license_key' => $licenseKey,
'product_slugs' => $productSlugs,
'domain' => $domain,
],
null,
$this->authState->optionalToken(),
$this->requestHeaderCollection->all()
);
/** @var ValidatePayload $result */
return Validate::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function suspend(LicenseReference $request): StatusChange {
return $this->changeLicenseStatus('/licenses/suspend', $request);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function reinstate(LicenseReference $request): StatusChange {
return $this->changeLicenseStatus('/licenses/reinstate', $request);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function ban(LicenseReference $request): StatusChange {
return $this->changeLicenseStatus('/licenses/ban', $request);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function regenerateKey(RegenerateKeyRequest $request): RegenerateKey {
/** @var RegenerateKeyPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/licenses/regenerate-key'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var RegenerateKeyResponsePayload $result */
return RegenerateKey::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function importAliases(ImportAliasesRequest $request): ImportAliases {
/** @var ImportAliasesPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/licenses/aliases'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var ImportAliasesResponsePayload $result */
return ImportAliases::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function removeAliases(RemoveAliasesRequest $request): RemoveAliases {
/** @var RemoveAliasesPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'DELETE',
$this->apiUriFactory->make('/licenses/aliases'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var RemoveAliasesResponsePayload $result */
return RemoveAliases::from($result);
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self($this->requestExecutor, $this->apiUriFactory, $authState, $this->requestHeaderCollection);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self($this->requestExecutor, $this->apiUriFactory, $this->authState, $requestHeaderCollection);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
private function changeLicenseStatus(string $path, LicenseReference $request): StatusChange {
/** @var LicenseReferencePayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make($path),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var StatusChangePayload $result */
return StatusChange::from($result);
}
}

View File

@@ -0,0 +1,105 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\ProductsResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Product\Catalog;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the products API resource.
*
* @phpstan-type ActivationDomainPayload array{
* activated_at: string,
* deactivated_at: string|null,
* is_active: bool,
* is_production: bool
* }
* @phpstan-type ActivationDomainsPayload array<string, ActivationDomainPayload>
* @phpstan-type CatalogPayload array{
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* },
* activated_here?: bool,
* validation_status?: string,
* is_valid?: bool
* }>
* }
*/
final class ProductsResource implements ProductsResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function catalog(string $licenseKey, ?string $domain = null): Catalog {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/products'),
array_filter([
'license_key' => $licenseKey,
'domain' => $domain,
], static fn($value): bool => $value !== null),
null,
$this->authState->optionalToken(),
$this->requestHeaderCollection->all()
);
/** @var CatalogPayload $result */
return Catalog::from($result);
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self($this->requestExecutor, $this->apiUriFactory, $authState, $this->requestHeaderCollection);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self($this->requestExecutor, $this->apiUriFactory, $this->authState, $requestHeaderCollection);
}
}

View File

@@ -0,0 +1,169 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources;
use JsonException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\Contracts\ApiErrorExceptionInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\MissingAuthenticationException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\AuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\Factories\ApiUriFactory;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestExecutor;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Http\RequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Token\Create as CreateRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Requests\Token\Revoke as RevokeRequest;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsAuthState;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Concerns\RebindsRequestHeaderCollection;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Resources\Contracts\TokensResourceInterface;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Token\Auth;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Token\TokenList;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Token\ValueObjects\TokenItem;
use KadenceWP\KadenceBlocks\Psr\Http\Client\ClientExceptionInterface;
/**
* Provides operations for the tokens API resource.
*
* @phpstan-import-type CreateTokenPayload from CreateRequest
* @phpstan-import-type RevokeTokenPayload from RevokeRequest
* @phpstan-import-type TokenItemPayload from TokenItem
* @phpstan-type CreateResponsePayload TokenItemPayload
* @phpstan-type RevokeResponsePayload TokenItemPayload
* @phpstan-type AuthResponsePayload array{authorized: bool}
* @phpstan-type TokenListPayload array{
* tokens: list<array{
* id: int,
* token: string,
* license_id: int,
* domain: string,
* is_revoked: bool,
* created_at: string,
* updated_at: string
* }>
* }
*/
final class TokensResource implements TokensResourceInterface
{
use RebindsAuthState;
use RebindsRequestHeaderCollection;
private RequestExecutor $requestExecutor;
private ApiUriFactory $apiUriFactory;
private AuthState $authState;
private RequestHeaderCollection $requestHeaderCollection;
public function __construct(
RequestExecutor $requestExecutor,
ApiUriFactory $apiUriFactory,
AuthState $authState,
RequestHeaderCollection $requestHeaderCollection
) {
$this->requestExecutor = $requestExecutor;
$this->apiUriFactory = $apiUriFactory;
$this->authState = $authState;
$this->requestHeaderCollection = $requestHeaderCollection;
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function list(string $licenseKey): TokenList {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/tokens'),
['license_key' => $licenseKey],
null,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var TokenListPayload $result */
return TokenList::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function create(CreateRequest $request): TokenItem {
/** @var CreateTokenPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'POST',
$this->apiUriFactory->make('/tokens/create'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var CreateResponsePayload $result */
return TokenItem::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws MissingAuthenticationException
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function revoke(RevokeRequest $request): TokenItem {
/** @var RevokeTokenPayload $body */
$body = $request->toArray();
$result = $this->requestExecutor->executeJson(
'PUT',
$this->apiUriFactory->make('/tokens/revoke'),
[],
$body,
$this->authState->requiredToken(),
$this->requestHeaderCollection->all()
);
/** @var RevokeResponsePayload $result */
return TokenItem::from($result);
}
/**
* @throws ApiErrorExceptionInterface
* @throws UnexpectedResponseException
* @throws ClientExceptionInterface
* @throws JsonException
*/
public function auth(string $licenseKey, string $token, string $domain): Auth {
$result = $this->requestExecutor->executeJson(
'GET',
$this->apiUriFactory->make('/tokens/auth'),
[
'license_key' => $licenseKey,
'token' => $token,
'domain' => $domain,
],
null,
$this->authState->optionalToken(),
$this->requestHeaderCollection->all()
);
/** @var AuthResponsePayload $result */
return Auth::from($result);
}
protected function rebindWithAuthState(AuthState $authState): self {
return new self($this->requestExecutor, $this->apiUriFactory, $authState, $this->requestHeaderCollection);
}
protected function rebindWithRequestHeaderCollection(RequestHeaderCollection $requestHeaderCollection): self {
return new self($this->requestExecutor, $this->apiUriFactory, $this->authState, $requestHeaderCollection);
}
}

View File

@@ -0,0 +1,27 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts;
/**
* Response/value objects implement this interface to provide structured API data.
*
* @template TArray of array
*/
interface Response
{
/**
* Map raw attributes to the response object.
*
* @param array<string, mixed> $attributes
*
* @return static
*/
public static function from(array $attributes): self;
/**
* Return the array representation of the response object.
*
* @return TArray
*/
public function toArray(): array;
}

View File

@@ -0,0 +1,91 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\BalanceEntry;
/**
* Represents the credit balance response across one or more credit types.
*
* @implements Response<array{
* credits: list<array{
* credit_type: string,
* remaining: int,
* site_quota: int|null,
* site_used: int,
* site_remaining: int,
* aggregate_total: int,
* aggregate_used: int,
* aggregate_remaining: int,
* aggregate_overage: int,
* pools: list<array{
* pool_id: int,
* pool_remaining: int,
* priority: int,
* period: string,
* resets_on: string|null,
* expires_at: string|null,
* credits_total?: int,
* credits_used?: int,
* overage?: int,
* overage_limit?: int|null
* }>
* }>
* }>
*/
final class BalanceCollection implements Response
{
/** @var list<BalanceEntry> */
public array $credits;
/**
* @param list<BalanceEntry> $credits
*/
private function __construct(array $credits) {
$this->credits = $credits;
}
/**
* @param array{
* credits: list<array{
* credit_type: string,
* remaining: int,
* site_quota: int|null,
* site_used: int,
* site_remaining: int,
* aggregate_total: int,
* aggregate_used: int,
* aggregate_remaining: int,
* aggregate_overage: int,
* pools: list<array{
* pool_id: int,
* pool_remaining: int,
* priority: int,
* period: string,
* resets_on: string|null,
* expires_at: string|null,
* credits_total?: int,
* credits_used?: int,
* overage?: int,
* overage_limit?: int|null
* }>
* }>
* } $attributes
*/
public static function from(array $attributes): self {
return new self(array_map(
static fn (array $credit): BalanceEntry => BalanceEntry::from($credit),
$attributes['credits']
));
}
public function toArray(): array {
return [
'credits' => array_map(
static fn (BalanceEntry $credit): array => $credit->toArray(),
$this->credits
),
];
}
}

View File

@@ -0,0 +1,42 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a credit pool deletion response.
*
* @implements Response<array{deleted: bool, pool_id: int}>
*/
final class DeletePool implements Response
{
public bool $deleted;
public int $poolId;
private function __construct(bool $deleted, int $poolId) {
$this->deleted = $deleted;
$this->poolId = $poolId;
}
/**
* @param array{deleted: bool, pool_id: int} $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['deleted'],
$attributes['pool_id']
);
}
/**
* @return array{deleted: bool, pool_id: int}
*/
public function toArray(): array {
return [
'deleted' => $this->deleted,
'pool_id' => $this->poolId,
];
}
}

View File

@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a successful quota deletion.
*
* @implements Response<array{deleted: bool}>
*/
final class DeleteQuota implements Response
{
public bool $deleted;
private function __construct(bool $deleted) {
$this->deleted = $deleted;
}
/**
* @param array{deleted: bool} $attributes
*/
public static function from(array $attributes): self {
return new self($attributes['deleted']);
}
/**
* @return array{deleted: bool}
*/
public function toArray(): array {
return [
'deleted' => $this->deleted,
];
}
}

View File

@@ -0,0 +1,148 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\LedgerEntry;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\ValueObjects\PageMeta;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\ValueObjects\PaginationLinks;
/**
* Represents a cursor-paginated credits ledger response.
*
* @implements Response<array{
* entries: list<array{
* id: int,
* pool_id: int,
* entitlement_id_at_event: int,
* tier_at_event: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* entry_type: string,
* amount: int,
* period_start: string|null,
* idempotency_key: string,
* created_at: string
* }>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* }>
*/
final class LedgerPage implements Response
{
/**
* @var list<LedgerEntry>
*/
public array $entries;
public PaginationLinks $links;
public PageMeta $page;
/**
* @param list<LedgerEntry> $entries
*/
private function __construct(array $entries, PaginationLinks $links, PageMeta $page) {
$this->entries = $entries;
$this->links = $links;
$this->page = $page;
}
/**
* @param array{
* entries: list<array{
* id: int,
* pool_id: int,
* entitlement_id_at_event: int,
* tier_at_event: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* entry_type: string,
* amount: int,
* period_start: string|null,
* idempotency_key: string,
* created_at: string
* }>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
array_map(
static fn (array $entry): LedgerEntry => LedgerEntry::from($entry),
$attributes['entries']
),
PaginationLinks::from($attributes['links']),
PageMeta::from($attributes['meta']['page'])
);
}
/**
* @return array{
* entries: list<array{
* id: int,
* pool_id: int,
* entitlement_id_at_event: int,
* tier_at_event: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* entry_type: string,
* amount: int,
* period_start: string|null,
* idempotency_key: string,
* created_at: string
* }>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* }
*/
public function toArray(): array {
return [
'entries' => array_map(
static fn (LedgerEntry $entry): array => $entry->toArray(),
$this->entries
),
'links' => $this->links->toArray(),
'meta' => [
'page' => $this->page->toArray(),
],
];
}
}

View File

@@ -0,0 +1,89 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\CreditPool;
/**
* Represents a keyed collection of managed credit pools.
*
* @implements Response<array{
* pools: array<int, array{
* pool_id: int,
* credit_type: string,
* credits_total: int,
* credits_used: int,
* overage_limit: ?int,
* priority: int,
* period: string,
* first_period_start: ?string,
* expires_at: ?string,
* is_expired: bool
* }>
* }>
*/
final class PoolCollection implements Response
{
/**
* @var array<int, CreditPool>
*/
public array $pools;
/**
* @param array<int, CreditPool> $pools
*/
private function __construct(array $pools) {
$this->pools = $pools;
}
/**
* @param array{
* pools: array<int|string, array{
* pool_id: int,
* credit_type: string,
* credits_total: int,
* credits_used: int,
* overage_limit: ?int,
* priority: int,
* period: string,
* first_period_start: ?string,
* expires_at: ?string,
* is_expired: bool
* }>
* } $attributes
*/
public static function from(array $attributes): self {
$pools = [];
foreach ($attributes['pools'] as $poolId => $pool) {
$pools[(int) $poolId] = CreditPool::from($pool);
}
return new self($pools);
}
/**
* @return array{
* pools: array<int, array{
* pool_id: int,
* credit_type: string,
* credits_total: int,
* credits_used: int,
* overage_limit: ?int,
* priority: int,
* period: string,
* first_period_start: ?string,
* expires_at: ?string,
* is_expired: bool
* }>
* }
*/
public function toArray(): array {
$pools = array_map(static fn ($pool) => $pool->toArray(), $this->pools);
return [
'pools' => $pools,
];
}
}

View File

@@ -0,0 +1,78 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects\SiteQuota;
/**
* Represents a collection of site quotas.
*
* @implements Response<array{
* quotas: list<array{
* domain: string,
* credit_type: string,
* quota: ?int,
* period: string,
* first_period_start: ?string,
* is_blocked: bool,
* is_uncapped: bool
* }>
* }>
*/
final class QuotaCollection implements Response
{
/**
* @var list<SiteQuota>
*/
public array $quotas;
/**
* @param list<SiteQuota> $quotas
*/
private function __construct(array $quotas) {
$this->quotas = $quotas;
}
/**
* @param array{
* quotas: list<array{
* domain: string,
* credit_type: string,
* quota: ?int,
* period: string,
* first_period_start: ?string,
* is_blocked: bool,
* is_uncapped: bool
* }>
* } $attributes
*/
public static function from(array $attributes): self {
return new self(array_map(
static fn (array $quota): SiteQuota => SiteQuota::from($quota),
$attributes['quotas']
));
}
/**
* @return array{
* quotas: list<array{
* domain: string,
* credit_type: string,
* quota: ?int,
* period: string,
* first_period_start: ?string,
* is_blocked: bool,
* is_uncapped: bool
* }>
* }
*/
public function toArray(): array {
return [
'quotas' => array_map(
static fn (SiteQuota $quota): array => $quota->toArray(),
$this->quotas
),
];
}
}

View File

@@ -0,0 +1,79 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a successful credit usage response.
*
* @implements Response<array{
* credits_used: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<array-key, int>
* }>
*/
final class RecordUsage implements Response
{
public int $creditsUsed;
public int $poolRemaining;
public ?int $siteRemaining;
/**
* @var array<int, int>
*/
public array $poolBreakdown;
/**
* @param array<int, int> $poolBreakdown
*/
private function __construct(int $creditsUsed, int $poolRemaining, ?int $siteRemaining, array $poolBreakdown) {
$this->creditsUsed = $creditsUsed;
$this->poolRemaining = $poolRemaining;
$this->siteRemaining = $siteRemaining;
$this->poolBreakdown = $poolBreakdown;
}
/**
* @param array{
* credits_used: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<array-key, int>
* } $attributes
*/
public static function from(array $attributes): self {
$poolBreakdown = [];
foreach ($attributes['pool_breakdown'] as $poolId => $creditsUsed) {
$poolBreakdown[(int) $poolId] = $creditsUsed;
}
return new self(
$attributes['credits_used'],
$attributes['pool_remaining'],
$attributes['site_remaining'],
$poolBreakdown
);
}
/**
* @return array{
* credits_used: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<int, int>
* }
*/
public function toArray(): array {
return [
'credits_used' => $this->creditsUsed,
'pool_remaining' => $this->poolRemaining,
'site_remaining' => $this->siteRemaining,
'pool_breakdown' => $this->poolBreakdown,
];
}
}

View File

@@ -0,0 +1,79 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a successful credit refund response.
*
* @implements Response<array{
* credits_refunded: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<array-key, int>
* }>
*/
final class Refund implements Response
{
public int $creditsRefunded;
public int $poolRemaining;
public ?int $siteRemaining;
/**
* @var array<int, int>
*/
public array $poolBreakdown;
/**
* @param array<int, int> $poolBreakdown
*/
private function __construct(int $creditsRefunded, int $poolRemaining, ?int $siteRemaining, array $poolBreakdown) {
$this->creditsRefunded = $creditsRefunded;
$this->poolRemaining = $poolRemaining;
$this->siteRemaining = $siteRemaining;
$this->poolBreakdown = $poolBreakdown;
}
/**
* @param array{
* credits_refunded: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<array-key, int>
* } $attributes
*/
public static function from(array $attributes): self {
$poolBreakdown = [];
foreach ($attributes['pool_breakdown'] as $poolId => $creditsRefunded) {
$poolBreakdown[(int) $poolId] = $creditsRefunded;
}
return new self(
$attributes['credits_refunded'],
$attributes['pool_remaining'],
$attributes['site_remaining'],
$poolBreakdown
);
}
/**
* @return array{
* credits_refunded: int,
* pool_remaining: int,
* site_remaining: int|null,
* pool_breakdown: array<int, int>
* }
*/
public function toArray(): array {
return [
'credits_refunded' => $this->creditsRefunded,
'pool_remaining' => $this->poolRemaining,
'site_remaining' => $this->siteRemaining,
'pool_breakdown' => $this->poolBreakdown,
];
}
}

View File

@@ -0,0 +1,144 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents the credit balance for a single credit type.
*
* @implements Response<array{
* credit_type: string,
* remaining: int,
* site_quota: int|null,
* site_used: int,
* site_remaining: int,
* aggregate_total: int,
* aggregate_used: int,
* aggregate_remaining: int,
* aggregate_overage: int,
* pools: list<array{
* pool_id: int,
* pool_remaining: int,
* priority: int,
* period: string,
* resets_on: string|null,
* expires_at: string|null,
* credits_total?: int,
* credits_used?: int,
* overage?: int,
* overage_limit?: int|null
* }>
* }>
*/
final class BalanceEntry implements Response
{
public string $creditType;
public int $remaining;
public ?int $siteQuota;
public int $siteUsed;
public int $siteRemaining;
public int $aggregateTotal;
public int $aggregateUsed;
public int $aggregateRemaining;
public int $aggregateOverage;
/** @var list<PoolBalance> */
public array $pools;
/**
* @param list<PoolBalance> $pools
*/
private function __construct(
string $creditType,
int $remaining,
?int $siteQuota,
int $siteUsed,
int $siteRemaining,
int $aggregateTotal,
int $aggregateUsed,
int $aggregateRemaining,
int $aggregateOverage,
array $pools
) {
$this->creditType = $creditType;
$this->remaining = $remaining;
$this->siteQuota = $siteQuota;
$this->siteUsed = $siteUsed;
$this->siteRemaining = $siteRemaining;
$this->aggregateTotal = $aggregateTotal;
$this->aggregateUsed = $aggregateUsed;
$this->aggregateRemaining = $aggregateRemaining;
$this->aggregateOverage = $aggregateOverage;
$this->pools = $pools;
}
/**
* @param array{
* credit_type: string,
* remaining: int,
* site_quota: int|null,
* site_used: int,
* site_remaining: int,
* aggregate_total: int,
* aggregate_used: int,
* aggregate_remaining: int,
* aggregate_overage: int,
* pools: list<array{
* pool_id: int,
* pool_remaining: int,
* priority: int,
* period: string,
* resets_on: string|null,
* expires_at: string|null,
* credits_total?: int,
* credits_used?: int,
* overage?: int,
* overage_limit?: int|null
* }>
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['credit_type'],
$attributes['remaining'],
$attributes['site_quota'],
$attributes['site_used'],
$attributes['site_remaining'],
$attributes['aggregate_total'],
$attributes['aggregate_used'],
$attributes['aggregate_remaining'],
$attributes['aggregate_overage'],
array_map(
static fn (array $pool): PoolBalance => PoolBalance::from($pool),
$attributes['pools']
)
);
}
public function toArray(): array {
return [
'credit_type' => $this->creditType,
'remaining' => $this->remaining,
'site_quota' => $this->siteQuota,
'site_used' => $this->siteUsed,
'site_remaining' => $this->siteRemaining,
'aggregate_total' => $this->aggregateTotal,
'aggregate_used' => $this->aggregateUsed,
'aggregate_remaining' => $this->aggregateRemaining,
'aggregate_overage' => $this->aggregateOverage,
'pools' => array_map(
static fn (PoolBalance $pool): array => $pool->toArray(),
$this->pools
),
];
}
}

View File

@@ -0,0 +1,133 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents one managed credit pool entry.
*
* @implements Response<array{
* pool_id: int,
* credit_type: string,
* credits_total: int,
* credits_used: int,
* overage_limit: ?int,
* priority: int,
* period: string,
* first_period_start: ?string,
* expires_at: ?string,
* is_expired: bool
* }>
*/
final class CreditPool implements Response
{
use InteractsWithDateTime;
public int $poolId;
public string $creditType;
public int $creditsTotal;
public int $creditsUsed;
public ?int $overageLimit;
public int $priority;
public string $period;
public ?DateTimeImmutable $firstPeriodStart;
public ?DateTimeImmutable $expiresAt;
public bool $isExpired;
private function __construct(
int $poolId,
string $creditType,
int $creditsTotal,
int $creditsUsed,
?int $overageLimit,
int $priority,
string $period,
?DateTimeImmutable $firstPeriodStart,
?DateTimeImmutable $expiresAt,
bool $isExpired
) {
$this->poolId = $poolId;
$this->creditType = $creditType;
$this->creditsTotal = $creditsTotal;
$this->creditsUsed = $creditsUsed;
$this->overageLimit = $overageLimit;
$this->priority = $priority;
$this->period = $period;
$this->firstPeriodStart = $firstPeriodStart;
$this->expiresAt = $expiresAt;
$this->isExpired = $isExpired;
}
/**
* @param array{
* pool_id: int,
* credit_type: string,
* credits_total: int,
* credits_used: int,
* overage_limit: ?int,
* priority: int,
* period: string,
* first_period_start: ?string,
* expires_at: ?string,
* is_expired: bool
* } $attributes
*
* @throws UnexpectedResponseException
*/
public static function from(array $attributes): self {
return new self(
$attributes['pool_id'],
$attributes['credit_type'],
$attributes['credits_total'],
$attributes['credits_used'],
$attributes['overage_limit'],
$attributes['priority'],
$attributes['period'],
self::parseNullableDateTime($attributes['first_period_start']),
self::parseNullableDateTime($attributes['expires_at']),
$attributes['is_expired']
);
}
/**
* @return array{
* pool_id: int,
* credit_type: string,
* credits_total: int,
* credits_used: int,
* overage_limit: ?int,
* priority: int,
* period: string,
* first_period_start: ?string,
* expires_at: ?string,
* is_expired: bool
* }
*/
public function toArray(): array {
return [
'pool_id' => $this->poolId,
'credit_type' => $this->creditType,
'credits_total' => $this->creditsTotal,
'credits_used' => $this->creditsUsed,
'overage_limit' => $this->overageLimit,
'priority' => $this->priority,
'period' => $this->period,
'first_period_start' => $this->firstPeriodStart ? $this->formatDateTime($this->firstPeriodStart) : null,
'expires_at' => $this->expiresAt ? $this->formatDateTime($this->expiresAt) : null,
'is_expired' => $this->isExpired,
];
}
}

View File

@@ -0,0 +1,148 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents one credits ledger entry.
*
* @implements Response<array{
* id: int,
* pool_id: int,
* entitlement_id_at_event: int,
* tier_at_event: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* entry_type: string,
* amount: int,
* period_start: string|null,
* idempotency_key: string,
* created_at: string
* }>
*/
final class LedgerEntry implements Response
{
use InteractsWithDateTime;
public int $id;
public int $poolId;
public int $entitlementIdAtEvent;
public string $tierAtEvent;
public string $domain;
public string $productSlug;
public string $creditType;
public string $entryType;
public int $amount;
public ?DateTimeImmutable $periodStart;
public string $idempotencyKey;
public DateTimeImmutable $createdAt;
private function __construct(
int $id,
int $poolId,
int $entitlementIdAtEvent,
string $tierAtEvent,
string $domain,
string $productSlug,
string $creditType,
string $entryType,
int $amount,
?DateTimeImmutable $periodStart,
string $idempotencyKey,
DateTimeImmutable $createdAt
) {
$this->id = $id;
$this->poolId = $poolId;
$this->entitlementIdAtEvent = $entitlementIdAtEvent;
$this->tierAtEvent = $tierAtEvent;
$this->domain = $domain;
$this->productSlug = $productSlug;
$this->creditType = $creditType;
$this->entryType = $entryType;
$this->amount = $amount;
$this->periodStart = $periodStart;
$this->idempotencyKey = $idempotencyKey;
$this->createdAt = $createdAt;
}
/**
* @param array{
* id: int,
* pool_id: int,
* entitlement_id_at_event: int,
* tier_at_event: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* entry_type: string,
* amount: int,
* period_start: string|null,
* idempotency_key: string,
* created_at: string
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['id'],
$attributes['pool_id'],
$attributes['entitlement_id_at_event'],
$attributes['tier_at_event'],
$attributes['domain'],
$attributes['product_slug'],
$attributes['credit_type'],
$attributes['entry_type'],
$attributes['amount'],
$attributes['period_start'] ? self::parseDateTime($attributes['period_start']) : null,
$attributes['idempotency_key'],
self::parseDateTime($attributes['created_at'])
);
}
/**
* @return array{
* id: int,
* pool_id: int,
* entitlement_id_at_event: int,
* tier_at_event: string,
* domain: string,
* product_slug: string,
* credit_type: string,
* entry_type: string,
* amount: int,
* period_start: string|null,
* idempotency_key: string,
* created_at: string
* }
*/
public function toArray(): array {
return [
'id' => $this->id,
'pool_id' => $this->poolId,
'entitlement_id_at_event' => $this->entitlementIdAtEvent,
'tier_at_event' => $this->tierAtEvent,
'domain' => $this->domain,
'product_slug' => $this->productSlug,
'credit_type' => $this->creditType,
'entry_type' => $this->entryType,
'amount' => $this->amount,
'period_start' => $this->periodStart ? $this->periodStart->format('Y-m-d\TH:i:s\Z') : null,
'idempotency_key' => $this->idempotencyKey,
'created_at' => $this->createdAt->format('Y-m-d\TH:i:s\Z'),
];
}
}

View File

@@ -0,0 +1,127 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents one pool entry in a credit balance response.
*
* @implements Response<array{
* pool_id: int,
* pool_remaining: int,
* priority: int,
* period: string,
* resets_on: string|null,
* expires_at: string|null,
* credits_total?: int,
* credits_used?: int,
* overage?: int,
* overage_limit?: int|null
* }>
*/
final class PoolBalance implements Response
{
use InteractsWithDateTime;
public int $poolId;
public int $poolRemaining;
public int $priority;
public string $period;
public ?DateTimeImmutable $resetsOn;
public ?DateTimeImmutable $expiresAt;
public ?int $creditsTotal;
public ?int $creditsUsed;
public ?int $overage;
public ?int $overageLimit;
private function __construct(
int $poolId,
int $poolRemaining,
int $priority,
string $period,
?DateTimeImmutable $resetsOn,
?DateTimeImmutable $expiresAt,
?int $creditsTotal = null,
?int $creditsUsed = null,
?int $overage = null,
?int $overageLimit = null
) {
$this->poolId = $poolId;
$this->poolRemaining = $poolRemaining;
$this->priority = $priority;
$this->period = $period;
$this->resetsOn = $resetsOn;
$this->expiresAt = $expiresAt;
$this->creditsTotal = $creditsTotal;
$this->creditsUsed = $creditsUsed;
$this->overage = $overage;
$this->overageLimit = $overageLimit;
}
/**
* @param array{
* pool_id: int,
* pool_remaining: int,
* priority: int,
* period: string,
* resets_on: string|null,
* expires_at: string|null,
* credits_total?: int,
* credits_used?: int,
* overage?: int,
* overage_limit?: int|null
* } $attributes
*
* @throws UnexpectedResponseException
*/
public static function from(array $attributes): self {
return new self(
$attributes['pool_id'],
$attributes['pool_remaining'],
$attributes['priority'],
$attributes['period'],
self::parseNullableDateTime($attributes['resets_on']),
self::parseNullableDateTime($attributes['expires_at']),
$attributes['credits_total'] ?? null,
$attributes['credits_used'] ?? null,
$attributes['overage'] ?? null,
$attributes['overage_limit'] ?? null
);
}
public function toArray(): array {
$data = [
'pool_id' => $this->poolId,
'pool_remaining' => $this->poolRemaining,
'priority' => $this->priority,
'period' => $this->period,
'resets_on' => $this->resetsOn ? $this->formatDateTime($this->resetsOn) : null,
'expires_at' => $this->expiresAt ? $this->formatDateTime($this->expiresAt) : null,
];
$data = array_merge($data, array_filter([
'credits_total' => $this->creditsTotal,
'credits_used' => $this->creditsUsed,
'overage' => $this->overage,
], static fn ($value): bool => $value !== null));
if ($this->overageLimit !== null || array_key_exists('overage', $data)) {
$data['overage_limit'] = $this->overageLimit;
}
return $data;
}
}

View File

@@ -0,0 +1,106 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Credit\ValueObjects;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Exceptions\UnexpectedResponseException;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents one site quota entry.
*
* @implements Response<array{
* domain: string,
* credit_type: string,
* quota: ?int,
* period: string,
* first_period_start: ?string,
* is_blocked: bool,
* is_uncapped: bool
* }>
*/
final class SiteQuota implements Response
{
use InteractsWithDateTime;
public string $domain;
public string $creditType;
public ?int $quota;
public string $period;
public ?DateTimeImmutable $firstPeriodStart;
public bool $isBlocked;
public bool $isUncapped;
private function __construct(
string $domain,
string $creditType,
?int $quota,
string $period,
?DateTimeImmutable $firstPeriodStart,
bool $isBlocked,
bool $isUncapped
) {
$this->domain = $domain;
$this->creditType = $creditType;
$this->quota = $quota;
$this->period = $period;
$this->firstPeriodStart = $firstPeriodStart;
$this->isBlocked = $isBlocked;
$this->isUncapped = $isUncapped;
}
/**
* @param array{
* domain: string,
* credit_type: string,
* quota: ?int,
* period: string,
* first_period_start: ?string,
* is_blocked: bool,
* is_uncapped: bool
* } $attributes
*
* @throws UnexpectedResponseException
*/
public static function from(array $attributes): self {
return new self(
$attributes['domain'],
$attributes['credit_type'],
$attributes['quota'],
$attributes['period'],
self::parseNullableDateTime($attributes['first_period_start']),
$attributes['is_blocked'],
$attributes['is_uncapped']
);
}
/**
* @return array{
* domain: string,
* credit_type: string,
* quota: ?int,
* period: string,
* first_period_start: ?string,
* is_blocked: bool,
* is_uncapped: bool
* }
*/
public function toArray(): array {
return [
'domain' => $this->domain,
'credit_type' => $this->creditType,
'quota' => $this->quota,
'period' => $this->period,
'first_period_start' => $this->firstPeriodStart ? $this->formatDateTime($this->firstPeriodStart) : null,
'is_blocked' => $this->isBlocked,
'is_uncapped' => $this->isUncapped,
];
}
}

View File

@@ -0,0 +1,52 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a cancelled entitlement response payload.
*
* @implements Response<array{
* product_slug: string,
* tier: string,
* status: string
* }>
*/
final class Cancel implements Response
{
public string $productSlug;
public string $tier;
public string $status;
private function __construct(string $productSlug, string $tier, string $status) {
$this->productSlug = $productSlug;
$this->tier = $tier;
$this->status = $status;
}
/**
* @param array{
* product_slug: string,
* tier: string,
* status: string
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['product_slug'],
$attributes['tier'],
$attributes['status']
);
}
public function toArray(): array {
return [
'product_slug' => $this->productSlug,
'tier' => $this->tier,
'status' => $this->status,
];
}
}

View File

@@ -0,0 +1,37 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a successful entitlement deletion.
*
* @implements Response<array{deleted: bool}>
*/
final class Delete implements Response
{
public bool $deleted;
private function __construct(bool $deleted) {
$this->deleted = $deleted;
}
/**
* @param array{deleted: bool} $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['deleted']
);
}
/**
* @return array{deleted: bool}
*/
public function toArray(): array {
return [
'deleted' => $this->deleted,
];
}
}

View File

@@ -0,0 +1,52 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a suspended entitlement response payload.
*
* @implements Response<array{
* product_slug: string,
* tier: string,
* status: string
* }>
*/
final class Suspend implements Response
{
public string $productSlug;
public string $tier;
public string $status;
private function __construct(string $productSlug, string $tier, string $status) {
$this->productSlug = $productSlug;
$this->tier = $tier;
$this->status = $status;
}
/**
* @param array{
* product_slug: string,
* tier: string,
* status: string
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['product_slug'],
$attributes['tier'],
$attributes['status']
);
}
public function toArray(): array {
return [
'product_slug' => $this->productSlug,
'tier' => $this->tier,
'status' => $this->status,
];
}
}

View File

@@ -0,0 +1,88 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents an entitlement tier switch response payload.
*
* @implements Response<array{
* product_slug: string,
* from_tier: string,
* to_tier: string,
* status: string,
* site_limit: int,
* active_count: int,
* over_limit: bool
* }>
*/
final class SwitchTier implements Response
{
public string $productSlug;
public string $fromTier;
public string $toTier;
public string $status;
public int $siteLimit;
public int $activeCount;
public bool $overLimit;
private function __construct(
string $productSlug,
string $fromTier,
string $toTier,
string $status,
int $siteLimit,
int $activeCount,
bool $overLimit
) {
$this->productSlug = $productSlug;
$this->fromTier = $fromTier;
$this->toTier = $toTier;
$this->status = $status;
$this->siteLimit = $siteLimit;
$this->activeCount = $activeCount;
$this->overLimit = $overLimit;
}
/**
* @param array{
* product_slug: string,
* from_tier: string,
* to_tier: string,
* status: string,
* site_limit: int,
* active_count: int,
* over_limit: bool
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['product_slug'],
$attributes['from_tier'],
$attributes['to_tier'],
$attributes['status'],
$attributes['site_limit'],
$attributes['active_count'],
$attributes['over_limit']
);
}
public function toArray(): array {
return [
'product_slug' => $this->productSlug,
'from_tier' => $this->fromTier,
'to_tier' => $this->toTier,
'status' => $this->status,
'site_limit' => $this->siteLimit,
'active_count' => $this->activeCount,
'over_limit' => $this->overLimit,
];
}
}

View File

@@ -0,0 +1,52 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents an unsuspended entitlement response payload.
*
* @implements Response<array{
* product_slug: string,
* tier: string,
* status: string
* }>
*/
final class Unsuspend implements Response
{
public string $productSlug;
public string $tier;
public string $status;
private function __construct(string $productSlug, string $tier, string $status) {
$this->productSlug = $productSlug;
$this->tier = $tier;
$this->status = $status;
}
/**
* @param array{
* product_slug: string,
* tier: string,
* status: string
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['product_slug'],
$attributes['tier'],
$attributes['status']
);
}
public function toArray(): array {
return [
'product_slug' => $this->productSlug,
'tier' => $this->tier,
'status' => $this->status,
];
}
}

View File

@@ -0,0 +1,57 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\ValueObjects\UpsertProduct;
/**
* Represents an entitlement upsert response payload.
*
* @phpstan-import-type ResponseProductPayload from UpsertProduct
*
* @implements Response<array{
* license_key: string,
* products: list<ResponseProductPayload>
* }>
*/
final class Upsert implements Response
{
public string $licenseKey;
/**
* @var UpsertProduct[]
*/
public array $products;
/**
* @param UpsertProduct[] $products
*/
private function __construct(string $licenseKey, array $products) {
$this->licenseKey = $licenseKey;
$this->products = $products;
}
/**
* @param array{license_key: string, products: list<ResponseProductPayload>} $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['license_key'],
array_map(
static fn (array $product): UpsertProduct => UpsertProduct::from($product),
$attributes['products']
)
);
}
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'products' => array_map(
static fn (UpsertProduct $product): array => $product->toArray(),
$this->products
),
];
}
}

View File

@@ -0,0 +1,58 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Entitlement\ValueObjects;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents one product result inside an entitlement upsert response.
*
* @phpstan-type ResponseProductPayload array{
* product_slug: string,
* tier: string,
* status: string
* }
*
* @implements Response<array{
* product_slug: string,
* tier: string,
* status: string
* }>
*/
final class UpsertProduct implements Response
{
public string $productSlug;
public string $tier;
public string $status;
private function __construct(string $productSlug, string $tier, string $status) {
$this->productSlug = $productSlug;
$this->tier = $tier;
$this->status = $status;
}
/**
* @param array{
* product_slug: string,
* tier: string,
* status: string
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['product_slug'],
$attributes['tier'],
$attributes['status']
);
}
public function toArray(): array {
return [
'product_slug' => $this->productSlug,
'tier' => $this->tier,
'status' => $this->status,
];
}
}

View File

@@ -0,0 +1,58 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a standard API business error response.
*
* @implements Response<array{
* code?: string|null,
* message?: string|null,
* status_code?: int|null,
* statusCode?: int|null
* }>
*/
final class ErrorResponse implements Response
{
public ?string $code;
public ?string $message;
public ?int $statusCode;
private function __construct(
?string $code,
?string $message,
?int $statusCode
) {
$this->code = $code;
$this->message = $message;
$this->statusCode = $statusCode;
}
/**
* @param array{
* code?: string|null,
* message?: string|null,
* status_code?: int|null,
* statusCode?: int|null
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['code'] ?? null,
$attributes['message'] ?? null,
$attributes['statusCode'] ?? $attributes['status_code'] ?? null
);
}
public function toArray(): array {
return [
'code' => $this->code,
'message' => $this->message,
'status_code' => $this->statusCode,
];
}
}

View File

@@ -0,0 +1,115 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\ValueObjects\Activation;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\ValueObjects\ActivationEntitlement;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\ValueObjects\LicenseSummary;
/**
* Represents a license activation response.
*
* @implements Response<array{
* status: string,
* is_valid: bool,
* is_production: bool,
* license: array{license_key: string, status: string}|null,
* entitlement: array{
* product_slug: string,
* tier: string,
* site_limit: int,
* active_count: int,
* available: int,
* over_limit: bool,
* excess_activations: int,
* expiration_date: string,
* status: string,
* capabilities: list<string>
* }|null,
* activation: array{
* domain: string,
* activated_at: string
* }|null
* }>
*/
final class Activate implements Response
{
public string $status;
public bool $isValid;
public bool $isProduction;
public ?LicenseSummary $license;
public ?ActivationEntitlement $entitlement;
public ?Activation $activation;
private function __construct(
string $status,
bool $isValid,
bool $isProduction,
?LicenseSummary $license,
?ActivationEntitlement $entitlement,
?Activation $activation
) {
$this->status = $status;
$this->isValid = $isValid;
$this->isProduction = $isProduction;
$this->license = $license;
$this->entitlement = $entitlement;
$this->activation = $activation;
}
/**
* @param array{
* status: string,
* is_valid: bool,
* is_production?: bool,
* license: array{license_key: string, status: string}|null,
* entitlement: array{
* product_slug: string,
* tier: string,
* site_limit: int,
* active_count: int,
* available: int,
* over_limit: bool,
* excess_activations: int,
* expiration_date: string,
* status: string,
* capabilities: list<string>
* }|null,
* activation: array{
* domain: string,
* activated_at: string
* }|null
* } $attributes
*/
public static function from(array $attributes): self {
$license = $attributes['license'] ?? null;
$entitlement = $attributes['entitlement'] ?? null;
$activation = $attributes['activation'] ?? null;
return new self(
$attributes['status'],
$attributes['is_valid'],
$attributes['is_production'] ?? true,
$license ? LicenseSummary::from($license) : null,
$entitlement ? ActivationEntitlement::from($entitlement) : null,
$activation ? Activation::from($activation) : null
);
}
public function toArray(): array {
return [
'status' => $this->status,
'is_valid' => $this->isValid,
'is_production' => $this->isProduction,
'license' => $this->license ? $this->license->toArray() : null,
'entitlement' => $this->entitlement ? $this->entitlement->toArray() : null,
'activation' => $this->activation ? $this->activation->toArray() : null,
];
}
}

View File

@@ -0,0 +1,56 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias\ValueObjects\ImportedAlias;
/**
* Represents an alias import response.
*
* @implements Response<array{
* imported: list<array{alias_key: string, product_slug?: string|null}>
* }>
*/
final class ImportAliases implements Response
{
/**
* @var ImportedAlias[]
*/
public array $imported;
/**
* @param ImportedAlias[] $imported
*/
private function __construct(array $imported) {
$this->imported = $imported;
}
/**
* @param array{
* imported: list<array{alias_key: string, product_slug?: string|null}>
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
array_map(
static fn (array $alias): ImportedAlias => ImportedAlias::from($alias),
$attributes['imported']
)
);
}
/**
* @return array{
* imported: list<array{alias_key: string, product_slug: string|null}>
* }
*/
public function toArray(): array {
return [
'imported' => array_map(
static fn (ImportedAlias $alias): array => $alias->toArray(),
$this->imported
),
];
}
}

View File

@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents an alias removal response.
*
* @implements Response<array{removed: int}>
*/
final class RemoveAliases implements Response
{
public int $removed;
private function __construct(int $removed) {
$this->removed = $removed;
}
/**
* @param array{removed: int} $attributes
*/
public static function from(array $attributes): self {
return new self($attributes['removed']);
}
/**
* @return array{removed: int}
*/
public function toArray(): array {
return [
'removed' => $this->removed,
];
}
}

View File

@@ -0,0 +1,42 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias\ValueObjects;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents one imported license alias.
*
* @implements Response<array{alias_key: string, product_slug: string|null}>
*/
final class ImportedAlias implements Response
{
public string $aliasKey;
public ?string $productSlug;
private function __construct(string $aliasKey, ?string $productSlug) {
$this->aliasKey = $aliasKey;
$this->productSlug = $productSlug;
}
/**
* @param array{alias_key: string, product_slug?: string|null} $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['alias_key'],
$attributes['product_slug'] ?? null
);
}
/**
* @return array{alias_key: string, product_slug: string|null}
*/
public function toArray(): array {
return [
'alias_key' => $this->aliasKey,
'product_slug' => $this->productSlug,
];
}
}

View File

@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a license deactivation response.
*
* @implements Response<array{deactivated: bool}>
*/
final class Deactivate implements Response
{
public bool $deactivated;
private function __construct(bool $deactivated) {
$this->deactivated = $deactivated;
}
/**
* @param array{deactivated: bool} $attributes
*/
public static function from(array $attributes): self {
return new self($attributes['deactivated']);
}
/**
* @return array{deactivated: bool}
*/
public function toArray(): array {
return [
'deactivated' => $this->deactivated,
];
}
}

View File

@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
/**
* Represents a license activation deletion response.
*
* @implements Response<array{deleted: bool}>
*/
final class DeleteActivation implements Response
{
public bool $deleted;
private function __construct(bool $deleted) {
$this->deleted = $deleted;
}
/**
* @param array{deleted: bool} $attributes
*/
public static function from(array $attributes): self {
return new self($attributes['deleted']);
}
/**
* @return array{deleted: bool}
*/
public function toArray(): array {
return [
'deleted' => $this->deleted,
];
}
}

View File

@@ -0,0 +1,177 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Listing;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Listing\ValueObjects\LicenseListItem;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\ValueObjects\PageMeta;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\ValueObjects\PaginationLinks;
/**
* Represents a cursor-paginated license listing.
*
* @phpstan-type ActivationDomainPayload array{
* activated_at: string,
* deactivated_at: string|null,
* is_active: bool,
* is_production: bool
* }
* @phpstan-type ActivationDomainsPayload array<string, ActivationDomainPayload>
*
* @implements Response<array{
* licenses: list<array{
* license_key: string,
* identity_id: string,
* status: string,
* created_at: string,
* updated_at: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* }
* }>,
* aliases: list<array{alias_key: string, product_slug: string|null}>
* }>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* }>
*/
final class Listing implements Response
{
/**
* @var LicenseListItem[]
*/
public array $licenses;
public PaginationLinks $links;
public PageMeta $page;
/**
* @param LicenseListItem[] $licenses
*/
private function __construct(array $licenses, PaginationLinks $links, PageMeta $page) {
$this->licenses = $licenses;
$this->links = $links;
$this->page = $page;
}
/**
* @param array{
* licenses: list<array{
* license_key: string,
* identity_id: string,
* status: string,
* created_at: string,
* updated_at: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* }
* }>,
* aliases: list<array{alias_key: string, product_slug?: string|null}>
* }>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
array_map(static fn (array $license): LicenseListItem => LicenseListItem::from($license), $attributes['licenses']),
PaginationLinks::from($attributes['links']),
PageMeta::from($attributes['meta']['page'])
);
}
/**
* @return array{
* licenses: list<array{
* license_key: string,
* identity_id: string,
* status: string,
* created_at: string,
* updated_at: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* }
* }>,
* aliases: list<array{alias_key: string, product_slug: string|null}>
* }>,
* links: array{
* first: string,
* last: string|null,
* prev: string|null,
* next: string|null
* },
* meta: array{
* page: array{
* total: int,
* limit: int,
* max_size: int
* }
* }
* }
*/
public function toArray(): array {
return [
'licenses' => array_map(
static fn (LicenseListItem $license): array => $license->toArray(),
$this->licenses
),
'links' => $this->links->toArray(),
'meta' => [
'page' => $this->page->toArray(),
],
];
}
}

View File

@@ -0,0 +1,163 @@
<?php declare(strict_types=1);
namespace KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Listing\ValueObjects;
use DateTimeImmutable;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Concerns\InteractsWithDateTime;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\Contracts\Response;
use KadenceWP\KadenceBlocks\LiquidWeb\LicensingApiClient\Responses\License\Alias\ValueObjects\ImportedAlias;
/**
* Represents a single license in a cursor-paginated listing.
*
* @phpstan-type ActivationDomainPayload array{
* activated_at: string,
* deactivated_at: string|null,
* is_active: bool,
* is_production: bool
* }
* @phpstan-type ActivationDomainsPayload array<string, ActivationDomainPayload>
*
* @implements Response<array{
* license_key: string,
* identity_id: string,
* status: string,
* created_at: string,
* updated_at: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* }
* }>,
* aliases: list<array{alias_key: string, product_slug: string|null}>
* }>
*/
final class LicenseListItem implements Response
{
use InteractsWithDateTime;
public string $licenseKey;
public string $identityId;
public string $status;
public DateTimeImmutable $createdAt;
public DateTimeImmutable $updatedAt;
public ListedProductCollection $products;
/**
* @var ImportedAlias[]
*/
public array $aliases;
/**
* @param ImportedAlias[] $aliases
*/
private function __construct(
string $licenseKey,
string $identityId,
string $status,
DateTimeImmutable $createdAt,
DateTimeImmutable $updatedAt,
ListedProductCollection $products,
array $aliases
) {
$this->licenseKey = $licenseKey;
$this->identityId = $identityId;
$this->status = $status;
$this->createdAt = $createdAt;
$this->updatedAt = $updatedAt;
$this->products = $products;
$this->aliases = $aliases;
}
/**
* @param array{
* license_key: string,
* identity_id: string,
* status: string,
* created_at: string,
* updated_at: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* }
* }>,
* aliases: list<array{alias_key: string, product_slug?: string|null}>
* } $attributes
*/
public static function from(array $attributes): self {
return new self(
$attributes['license_key'],
$attributes['identity_id'],
$attributes['status'],
self::parseDateTime($attributes['created_at']),
self::parseDateTime($attributes['updated_at']),
ListedProductCollection::from($attributes['products']),
array_map(
static fn (array $alias): ImportedAlias => ImportedAlias::from($alias),
$attributes['aliases']
)
);
}
/**
* @return array{
* license_key: string,
* identity_id: string,
* status: string,
* created_at: string,
* updated_at: string,
* products: list<array{
* product_slug: string,
* tier: string,
* status: string,
* expires: string,
* capabilities: list<string>,
* activations: array{
* site_limit: int,
* active_count: int,
* over_limit: bool,
* excess_activations: int,
* domains: ActivationDomainsPayload
* }
* }>,
* aliases: list<array{alias_key: string, product_slug: string|null}>
* }
*/
public function toArray(): array {
return [
'license_key' => $this->licenseKey,
'identity_id' => $this->identityId,
'status' => $this->status,
'created_at' => $this->formatDateTime($this->createdAt),
'updated_at' => $this->formatDateTime($this->updatedAt),
'products' => $this->products->toArray(),
'aliases' => array_map(
static fn (ImportedAlias $alias): array => $alias->toArray(),
$this->aliases
),
];
}
}

Some files were not shown because too many files have changed in this diff Show More