chore: code cleanup
All checks were successful
Build Test / test (pull_request) Successful in 48s
JS Unit Tests / test (pull_request) Successful in 51s
PHP Unit Tests / test (pull_request) Successful in 1m3s

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-02-19 00:16:33 -05:00
parent 6716e507c4
commit e5eeeeb546
8 changed files with 211 additions and 331 deletions

View File

@@ -14,8 +14,6 @@ use KTXC\Http\Response\JsonResponse;
use KTXC\SessionIdentity;
use KTXC\SessionTenant;
use KTXF\Controller\ControllerAbstract;
use KTXF\Mail\Entity\Message;
use KTXF\Mail\Queue\SendOptions;
use KTXF\Resource\Selector\SourceSelector;
use KTXF\Routing\Attributes\AuthenticatedRoute;
use KTXM\MailManager\Manager;
@@ -30,7 +28,6 @@ use Throwable;
*/
class DefaultController extends ControllerAbstract {
// Error message constants
private const ERR_MISSING_PROVIDER = 'Missing parameter: provider';
private const ERR_MISSING_IDENTIFIER = 'Missing parameter: identifier';
private const ERR_MISSING_SERVICE = 'Missing parameter: service';
@@ -38,7 +35,7 @@ class DefaultController extends ControllerAbstract {
private const ERR_MISSING_DATA = 'Missing parameter: data';
private const ERR_MISSING_SOURCES = 'Missing parameter: sources';
private const ERR_MISSING_IDENTIFIERS = 'Missing parameter: identifiers';
private const ERR_MISSING_MESSAGE = 'Missing parameter: message';
private const ERR_INVALID_OPERATION = 'Invalid operation: ';
private const ERR_INVALID_PROVIDER = 'Invalid parameter: provider must be a string';
private const ERR_INVALID_SERVICE = 'Invalid parameter: service must be a string';
private const ERR_INVALID_IDENTIFIER = 'Invalid parameter: identifier must be a string';
@@ -46,7 +43,6 @@ class DefaultController extends ControllerAbstract {
private const ERR_INVALID_SOURCES = 'Invalid parameter: sources must be an array';
private const ERR_INVALID_IDENTIFIERS = 'Invalid parameter: identifiers must be an array';
private const ERR_INVALID_DATA = 'Invalid parameter: data must be an array';
private const ERR_INVALID_MESSAGE = 'Invalid parameter: message must be an array';
public function __construct(
private readonly SessionTenant $tenantIdentity,
@@ -59,23 +55,21 @@ class DefaultController extends ControllerAbstract {
* Main API endpoint for mail operations
*
* Single operation:
* { "version": 1, "transaction": "tx-1", "operation": "message.send", "data": {...} }
*
* Batch operations:
* { "version": 1, "transaction": "tx-1", "operations": [
* {"id": "op1", "operation": "message.send", "data": {...}},
* {"id": "op2", "operation": "message.destroy", "data": {"collection": "#op1.draftId"}}
* ]}
* {
* "version": 1,
* "transaction": "tx-1",
* "operation": "entity.create",
* "data": {...}
* }
*
* @return JsonResponse
*/
*/
#[AuthenticatedRoute('/v1', name: 'mail.manager.v1', methods: ['POST'])]
public function index(
int $version,
string $transaction,
string|null $operation = null,
array|null $data = null,
array|null $operations = null,
int $version,
string $transaction,
string|null $operation = null,
array|null $data = null,
string|null $user = null
): JsonResponse {
@@ -84,7 +78,7 @@ class DefaultController extends ControllerAbstract {
$userId = $this->userIdentity->identifier();
try {
// Single operation mode
if ($operation !== null) {
$result = $this->processOperation($tenantId, $userId, $operation, $data ?? [], []);
return new JsonResponse([
@@ -96,21 +90,10 @@ class DefaultController extends ControllerAbstract {
], JsonResponse::HTTP_OK);
}
// Batch operations mode
if ($operations !== null && is_array($operations)) {
$results = $this->processBatch($tenantId, $userId, $operations);
return new JsonResponse([
'version' => $version,
'transaction' => $transaction,
'status' => 'success',
'operations' => $results
], JsonResponse::HTTP_OK);
}
throw new InvalidArgumentException('Either operation or operations must be provided');
throw new InvalidArgumentException('Operation must be provided');
} catch (Throwable $t) {
$this->logger->error('Error processing mail manager request', ['exception' => $t]);
$this->logger->error('Error processing request', ['exception' => $t]);
return new JsonResponse([
'version' => $version,
'transaction' => $transaction,
@@ -124,105 +107,10 @@ class DefaultController extends ControllerAbstract {
}
}
/**
* Process batch operations with result references
*/
private function processBatch(string $tenantId, string $userId, array $operations): array {
$results = [];
$resultMap = []; // Store results by operation ID for references
foreach ($operations as $index => $op) {
$opId = $op['id'] ?? "op{$index}";
$operation = $op['operation'] ?? null;
$data = $op['data'] ?? [];
if ($operation === null) {
$results[] = [
'id' => $opId,
'status' => 'error',
'data' => ['message' => 'Missing operation name']
];
continue;
}
try {
// Resolve result references in data (e.g., "#op1.id")
$data = $this->resolveReferences($data, $resultMap);
$result = $this->processOperation($tenantId, $userId, $operation, $data, $resultMap);
$results[] = [
'id' => $opId,
'operation' => $operation,
'status' => 'success',
'data' => $result
];
// Store result for future references
$resultMap[$opId] = $result;
} catch (Throwable $t) {
$this->logger->warning('Batch operation failed', [
'operation' => $operation,
'opId' => $opId,
'error' => $t->getMessage()
]);
$results[] = [
'id' => $opId,
'operation' => $operation,
'status' => 'error',
'data' => [
'code' => $t->getCode(),
'message' => $t->getMessage()
]
];
}
}
return $results;
}
/**
* Resolve result references in operation data
*
* Transforms "#op1.id" into the actual value from previous operation results
*/
private function resolveReferences(mixed $data, array $resultMap): mixed {
if (is_string($data) && str_starts_with($data, '#')) {
// Parse reference like "#op1.id" or "#op1.collection.id"
$parts = explode('.', substr($data, 1));
$opId = array_shift($parts);
if (!isset($resultMap[$opId])) {
throw new InvalidArgumentException("Reference to undefined operation: #{$opId}");
}
$value = $resultMap[$opId];
foreach ($parts as $key) {
if (is_array($value) && isset($value[$key])) {
$value = $value[$key];
} elseif (is_object($value) && isset($value->$key)) {
$value = $value->$key;
} else {
throw new InvalidArgumentException("Invalid reference path: {$data}");
}
}
return $value;
}
if (is_array($data)) {
return array_map(fn($item) => $this->resolveReferences($item, $resultMap), $data);
}
return $data;
}
/**
* Process a single operation
*/
private function processOperation(string $tenantId, string $userId, string $operation, array $data, array $resultMap): mixed {
private function processOperation(string $tenantId, string $userId, string $operation, array $data): mixed {
return match ($operation) {
// Provider operations
'provider.list' => $this->providerList($tenantId, $userId, $data),
@@ -261,7 +149,7 @@ class DefaultController extends ControllerAbstract {
'entity.copy' => throw new InvalidArgumentException('Operation not implemented: ' . $operation),
'entity.transmit' => $this->entityTransmit($tenantId, $userId, $data),
default => throw new InvalidArgumentException('Unknown operation: ' . $operation)
default => throw new InvalidArgumentException(self::ERR_INVALID_OPERATION . $operation)
};
}
@@ -279,6 +167,18 @@ class DefaultController extends ControllerAbstract {
}
private function providerFetch(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['identifier'])) {
throw new InvalidArgumentException(self::ERR_MISSING_IDENTIFIER);
}
if (!is_string($data['identifier'])) {
throw new InvalidArgumentException(self::ERR_INVALID_IDENTIFIER);
}
return $this->mailManager->providerFetch($tenantId, $userId, $data['identifier']);
}
private function providerExtant(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['sources'])) {
@@ -294,18 +194,6 @@ class DefaultController extends ControllerAbstract {
}
private function providerFetch(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['identifier'])) {
throw new InvalidArgumentException(self::ERR_MISSING_IDENTIFIER);
}
if (!is_string($data['identifier'])) {
throw new InvalidArgumentException(self::ERR_INVALID_IDENTIFIER);
}
return $this->mailManager->providerFetch($tenantId, $userId, $data['identifier']);
}
// ==================== Service Operations =====================
private function serviceList(string $tenantId, string $userId, array $data): mixed {
@@ -320,20 +208,6 @@ class DefaultController extends ControllerAbstract {
}
private function serviceExtant(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['sources'])) {
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
}
if (!is_array($data['sources'])) {
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
}
$sources = new SourceSelector();
$sources->jsonDeserialize($data['sources']);
return $this->mailManager->serviceExtant($tenantId, $userId, $sources);
}
private function serviceFetch(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['provider'])) {
@@ -352,41 +226,18 @@ class DefaultController extends ControllerAbstract {
return $this->mailManager->serviceFetch($tenantId, $userId, $data['provider'], $data['identifier']);
}
private function serviceDiscover(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['identity']) || empty($data['identity']) || !is_string($data['identity'])) {
throw new InvalidArgumentException(self::ERR_INVALID_DATA);
}
$provider = $data['provider'] ?? null;
$identity = $data['identity'];
$location = $data['location'] ?? null;
$secret = $data['secret'] ?? null;
private function serviceExtant(string $tenantId, string $userId, array $data): mixed {
return $this->mailManager->serviceDiscover($tenantId, $userId, $provider, $identity, $location, $secret);
}
private function serviceTest(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['provider'])) {
throw new InvalidArgumentException(self::ERR_MISSING_PROVIDER);
}
if (!is_string($data['provider'])) {
throw new InvalidArgumentException(self::ERR_INVALID_PROVIDER);
}
if (!isset($data['identifier']) && !isset($data['location']) && !isset($data['identity'])) {
throw new InvalidArgumentException('Either a service identifier or location and identity must be provided for service test');
}
return $this->mailManager->serviceTest(
$tenantId,
$userId,
$data['provider'],
$data['identifier'] ?? null,
$data['location'] ?? null,
$data['identity'] ?? null,
);
if (!isset($data['sources'])) {
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
}
if (!is_array($data['sources'])) {
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
}
$sources = new SourceSelector();
$sources->jsonDeserialize($data['sources']);
return $this->mailManager->serviceExtant($tenantId, $userId, $sources);
}
private function serviceCreate(string $tenantId, string $userId, array $data): mixed {
@@ -462,6 +313,43 @@ class DefaultController extends ControllerAbstract {
);
}
private function serviceTest(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['provider'])) {
throw new InvalidArgumentException(self::ERR_MISSING_PROVIDER);
}
if (!is_string($data['provider'])) {
throw new InvalidArgumentException(self::ERR_INVALID_PROVIDER);
}
if (!isset($data['identifier']) && !isset($data['location']) && !isset($data['identity'])) {
throw new InvalidArgumentException('Either a service identifier or location and identity must be provided for service test');
}
return $this->mailManager->serviceTest(
$tenantId,
$userId,
$data['provider'],
$data['identifier'] ?? null,
$data['location'] ?? null,
$data['identity'] ?? null,
);
}
private function serviceDiscover(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['identity']) || empty($data['identity']) || !is_string($data['identity'])) {
throw new InvalidArgumentException(self::ERR_INVALID_DATA);
}
$provider = $data['provider'] ?? null;
$identity = $data['identity'];
$location = $data['location'] ?? null;
$secret = $data['secret'] ?? null;
return $this->mailManager->serviceDiscover($tenantId, $userId, $provider, $identity, $location, $secret);
}
// ==================== Collection Operations ====================
private function collectionList(string $tenantId, string $userId, array $data): mixed {
@@ -640,34 +528,6 @@ class DefaultController extends ControllerAbstract {
}
private function entityDelta(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['sources'])) {
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
}
if (!is_array($data['sources'])) {
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
}
$sources = new SourceSelector();
$sources->jsonDeserialize($data['sources']);
return $this->mailManager->entityDelta($tenantId, $userId, $sources);
}
private function entityExtant(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['sources'])) {
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
}
if (!is_array($data['sources'])) {
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
}
$sources = new SourceSelector();
$sources->jsonDeserialize($data['sources']);
return $this->mailManager->entityExtant($tenantId, $userId, $sources);
}
private function entityFetch(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['provider'])) {
throw new InvalidArgumentException(self::ERR_MISSING_PROVIDER);
@@ -704,6 +564,34 @@ class DefaultController extends ControllerAbstract {
);
}
private function entityExtant(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['sources'])) {
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
}
if (!is_array($data['sources'])) {
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
}
$sources = new SourceSelector();
$sources->jsonDeserialize($data['sources']);
return $this->mailManager->entityExtant($tenantId, $userId, $sources);
}
private function entityDelta(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['sources'])) {
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
}
if (!is_array($data['sources'])) {
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
}
$sources = new SourceSelector();
$sources->jsonDeserialize($data['sources']);
return $this->mailManager->entityDelta($tenantId, $userId, $sources);
}
private function entityTransmit(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['provider'])) {
throw new InvalidArgumentException(self::ERR_MISSING_PROVIDER);

View File

@@ -38,8 +38,7 @@ use Psr\Log\LoggerInterface;
/**
* Mail Manager
*
* Provides unified mail sending across multiple providers with context-aware
* service discovery and queued delivery support.
* Provides unified mail sending across multiple providers
*/
class Manager {
@@ -63,6 +62,25 @@ class Manager {
return $this->providerManager->providers(ProviderBaseInterface::TYPE_MAIL, $filter);
}
/**
* Retrieve specific provider for specific user
*
* @param string $tenantId tenant identifier
* @param string $userId user identifier
* @param string $provider provider identifier
*
* @return ProviderBaseInterface
* @throws InvalidArgumentException
*/
public function providerFetch(string $tenantId, string $userId, string $provider): ProviderBaseInterface {
// retrieve provider
$providers = $this->providerList($tenantId, $userId, new SourceSelector([$provider => true]));
if (!isset($providers[$provider])) {
throw new InvalidArgumentException("Provider '$provider' not found");
}
return $providers[$provider];
}
/**
* Confirm which providers are available
*
@@ -83,25 +101,6 @@ class Manager {
return $responseData;
}
/**
* Retrieve specific provider for specific user
*
* @param string $tenantId tenant identifier
* @param string $userId user identifier
* @param string $provider provider identifier
*
* @return ProviderBaseInterface
* @throws InvalidArgumentException
*/
public function providerFetch(string $tenantId, string $userId, string $provider): ProviderBaseInterface {
// retrieve provider
$providers = $this->providerList($tenantId, $userId, new SourceSelector([$provider => true]));
if (!isset($providers[$provider])) {
throw new InvalidArgumentException("Provider '$provider' not found");
}
return $providers[$provider];
}
/**
* Retrieve available services for specific user
*
@@ -124,6 +123,27 @@ class Manager {
return $responseData;
}
/**
* Retrieve service for specific user
*
* @param string $tenantId tenant identifier
* @param string $userId user identifier
* @param string $providerId provider identifier
* @param string|int $serviceId service identifier
*
* @return ServiceBaseInterface
* @throws InvalidArgumentException
*/
public function serviceFetch(string $tenantId, string $userId, string $providerId, string|int $serviceId): ServiceBaseInterface {
// retrieve provider and service
$service = $this->providerFetch($tenantId, $userId, $providerId)->serviceFetch($tenantId, $userId, $serviceId);
if ($service === null) {
throw new InvalidArgumentException("Service '$serviceId' not found for provider '$providerId'");
}
// retrieve services
return $service;
}
/**
* Confirm which services are available
*
@@ -151,27 +171,6 @@ class Manager {
return $responseData;
}
/**
* Retrieve service for specific user
*
* @param string $tenantId tenant identifier
* @param string $userId user identifier
* @param string $providerId provider identifier
* @param string|int $serviceId service identifier
*
* @return ServiceBaseInterface
* @throws InvalidArgumentException
*/
public function serviceFetch(string $tenantId, string $userId, string $providerId, string|int $serviceId): ServiceBaseInterface {
// retrieve provider and service
$service = $this->providerFetch($tenantId, $userId, $providerId)->serviceFetch($tenantId, $userId, $serviceId);
if ($service === null) {
throw new InvalidArgumentException("Service '$serviceId' not found for provider '$providerId'");
}
// retrieve services
return $service;
}
/**
* Find a service that handles a specific email address
*
@@ -764,54 +763,26 @@ class Manager {
return $responseData;
}
/**
* Get message delta/changes
* Fetch specific messages
*
* @since 2025.05.01
*
* @param string $tenantId Tenant identifier
* @param string|null $userId User identifier for context
* @param SourceSelector $sources Message sources with signatures
* @param string $providerId Provider identifier
* @param string|int $serviceId Service identifier
* @param string|int $collectionId Collection identifier
* @param array<string|int> $identifiers Message identifiers
*
* @return array<string, array<string|int, array<string|int, array>>> Delta grouped by provider/service/collection
* @return array<string|int, IMessageBase> Messages indexed by ID
*/
public function entityDelta(string $tenantId, string $userId, SourceSelector $sources): array {
// confirm that sources are provided
if ($sources === null) {
$sources = new SourceSelector([]);
}
// retrieve providers
$providers = $this->providerList($tenantId, $userId, $sources);
$providersRequested = $sources->identifiers();
$providersUnavailable = array_diff($providersRequested, array_keys($providers));
// initialize response with unavailable providers
$responseData = array_fill_keys($providersUnavailable, false);
// iterate through available providers
foreach ($providers as $provider) {
$serviceSelector = $sources[$provider->identifier()];
$servicesRequested = $serviceSelector instanceof ServiceSelector ? $serviceSelector->identifiers() : [];
/** @var ServiceBaseInterface[] $services */
$services = $provider->serviceList($tenantId, $userId, $servicesRequested);
$servicesUnavailable = array_diff($servicesRequested, array_keys($services));
if ($servicesUnavailable !== []) {
$responseData[$provider->identifier()] = array_fill_keys($servicesUnavailable, false);
}
// iterate through available services
foreach ($services as $service) {
$collectionSelector = $serviceSelector[$service->identifier()];
$collectionsRequested = $collectionSelector instanceof CollectionSelector ? $collectionSelector->identifiers() : [];
if ($collectionsRequested === []) {
$responseData[$provider->identifier()][$service->identifier()] = false;
continue;
}
foreach ($collectionsRequested as $collection) {
$entitySelector = $collectionSelector[$collection] ?? null;
$responseData[$provider->identifier()][$service->identifier()][$collection] = $service->entityDelta($collection, $entitySelector);
}
}
}
return $responseData;
public function entityFetch(string $tenantId, ?string $userId, string $providerId, string|int $serviceId, string|int $collectionId, array $identifiers): array {
$service = $this->serviceFetch($tenantId, $userId, $providerId, $serviceId);
// retrieve collection
return $service->entityFetch($collectionId, ...$identifiers);
}
/**
@@ -889,24 +860,52 @@ class Manager {
}
/**
* Fetch specific messages
* Get message delta/changes
*
* @since 2025.05.01
*
* @param string $tenantId Tenant identifier
* @param string|null $userId User identifier for context
* @param string $providerId Provider identifier
* @param string|int $serviceId Service identifier
* @param string|int $collectionId Collection identifier
* @param array<string|int> $identifiers Message identifiers
* @param SourceSelector $sources Message sources with signatures
*
* @return array<string|int, IMessageBase> Messages indexed by ID
* @return array<string, array<string|int, array<string|int, array>>> Delta grouped by provider/service/collection
*/
public function entityFetch(string $tenantId, ?string $userId, string $providerId, string|int $serviceId, string|int $collectionId, array $identifiers): array {
$service = $this->serviceFetch($tenantId, $userId, $providerId, $serviceId);
// retrieve collection
return $service->entityFetch($collectionId, ...$identifiers);
public function entityDelta(string $tenantId, string $userId, SourceSelector $sources): array {
// confirm that sources are provided
if ($sources === null) {
$sources = new SourceSelector([]);
}
// retrieve providers
$providers = $this->providerList($tenantId, $userId, $sources);
$providersRequested = $sources->identifiers();
$providersUnavailable = array_diff($providersRequested, array_keys($providers));
// initialize response with unavailable providers
$responseData = array_fill_keys($providersUnavailable, false);
// iterate through available providers
foreach ($providers as $provider) {
$serviceSelector = $sources[$provider->identifier()];
$servicesRequested = $serviceSelector instanceof ServiceSelector ? $serviceSelector->identifiers() : [];
/** @var ServiceBaseInterface[] $services */
$services = $provider->serviceList($tenantId, $userId, $servicesRequested);
$servicesUnavailable = array_diff($servicesRequested, array_keys($services));
if ($servicesUnavailable !== []) {
$responseData[$provider->identifier()] = array_fill_keys($servicesUnavailable, false);
}
// iterate through available services
foreach ($services as $service) {
$collectionSelector = $serviceSelector[$service->identifier()];
$collectionsRequested = $collectionSelector instanceof CollectionSelector ? $collectionSelector->identifiers() : [];
if ($collectionsRequested === []) {
$responseData[$provider->identifier()][$service->identifier()] = false;
continue;
}
foreach ($collectionsRequested as $collection) {
$entitySelector = $collectionSelector[$collection] ?? null;
$responseData[$provider->identifier()][$service->identifier()][$collection] = $service->entityDelta($collection, $entitySelector);
}
}
}
return $responseData;
}
/**

View File

@@ -1,13 +1,7 @@
/**
* Central export point for all Mail Manager models
*/
export { CollectionObject } from './collection';
export { EntityObject } from './entity';
export { ProviderObject } from './provider';
export { ServiceObject } from './service';
// Identity models
export {
Identity,
IdentityNone,
@@ -16,8 +10,6 @@ export {
IdentityOAuth,
IdentityCertificate
} from './identity';
// Location models
export {
Location,
LocationUri,

View File

@@ -5,21 +5,21 @@
import type {
ServiceListRequest,
ServiceListResponse,
ServiceExtantRequest,
ServiceExtantResponse,
ServiceFetchRequest,
ServiceFetchResponse,
ServiceDiscoverRequest,
ServiceDiscoverResponse,
ServiceTestRequest,
ServiceTestResponse,
ServiceInterface,
ServiceExtantRequest,
ServiceExtantResponse,
ServiceCreateResponse,
ServiceCreateRequest,
ServiceUpdateResponse,
ServiceUpdateRequest,
ServiceDeleteResponse,
ServiceDeleteRequest,
ServiceDiscoverRequest,
ServiceDiscoverResponse,
ServiceTestRequest,
ServiceTestResponse,
ServiceInterface,
} from '../types/service';
import { useIntegrationStore } from '@KTXC/stores/integrationStore';
import { transceivePost } from './transceive';

4
src/stores/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export { useCollectionsStore } from './collectionsStore';
export { useEntitiesStore } from './entitiesStore';
export { useProvidersStore } from './providersStore';
export { useServicesStore } from './servicesStore';

View File

@@ -1,7 +1,3 @@
/**
* Central export point for all Mail Manager types
*/
export type * from './collection';
export type * from './common';
export type * from './entity';

View File

@@ -11,8 +11,8 @@ export interface ProviderCapabilitiesInterface {
ServiceFetch?: boolean;
ServiceExtant?: boolean;
ServiceCreate?: boolean;
ServiceModify?: boolean;
ServiceDestroy?: boolean;
ServiceUpdate?: boolean;
ServiceDelete?: boolean;
ServiceDiscover?: boolean;
ServiceTest?: boolean;
[key: string]: boolean | object | string[] | undefined;

View File

@@ -16,6 +16,7 @@ export interface ServiceCapabilitiesInterface {
CollectionCreate?: boolean;
CollectionUpdate?: boolean;
CollectionDelete?: boolean;
CollectionMove?: boolean;
// Message capabilities
EntityList?: boolean;
EntityListFilter?: ServiceListFilterEntity;