chore: standardize protocol

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-02-14 11:45:34 -05:00
parent 169b7b4c91
commit fefa0a0384
18 changed files with 3090 additions and 1239 deletions
+27 -54
View File
@@ -1,10 +1,10 @@
/**
* Collection-related type definitions for Mail Manager
* Collection type definitions
*/
import type { SourceSelector } from './common';
import type { ListFilter, ListSort, SourceSelector } from './common';
/**
* Collection interface (mailbox/folder)
* Collection information
*/
export interface CollectionInterface {
provider: string;
@@ -22,41 +22,29 @@ export interface CollectionBaseProperties {
version: number;
}
/**
* Immutable collection properties (computed by server)
*/
export interface CollectionImmutableProperties extends CollectionBaseProperties {
total?: number;
unread?: number;
role?: string | null;
}
/**
* Mutable collection properties (can be modified by user)
*/
export interface CollectionMutableProperties extends CollectionBaseProperties {
label: string;
rank?: number;
subscribed?: boolean;
}
/**
* Full collection properties (what server returns)
*/
export interface CollectionPropertiesInterface extends CollectionMutableProperties, CollectionImmutableProperties {}
/**
* Collection list request
* Collection list
*/
export interface CollectionListRequest {
sources?: SourceSelector;
filter?: any;
sort?: any;
filter?: ListFilter;
sort?: ListSort;
}
/**
* Collection list response
*/
export interface CollectionListResponse {
[providerId: string]: {
[serviceId: string]: {
@@ -66,15 +54,23 @@ export interface CollectionListResponse {
}
/**
* Collection extant request
* Collection fetch
*/
export interface CollectionFetchRequest {
provider: string;
service: string | number;
collection: string | number;
}
export interface CollectionFetchResponse extends CollectionInterface {}
/**
* Collection extant
*/
export interface CollectionExtantRequest {
sources: SourceSelector;
}
/**
* Collection extant response
*/
export interface CollectionExtantResponse {
[providerId: string]: {
[serviceId: string]: {
@@ -84,21 +80,7 @@ export interface CollectionExtantResponse {
}
/**
* Collection fetch request
*/
export interface CollectionFetchRequest {
provider: string;
service: string | number;
collection: string | number;
}
/**
* Collection fetch response
*/
export interface CollectionFetchResponse extends CollectionInterface {}
/**
* Collection create request
* Collection create
*/
export interface CollectionCreateRequest {
provider: string;
@@ -107,42 +89,33 @@ export interface CollectionCreateRequest {
properties: CollectionMutableProperties;
}
/**
* Collection create response
*/
export interface CollectionCreateResponse extends CollectionInterface {}
/**
* Collection modify request
* Collection modify
*/
export interface CollectionModifyRequest {
export interface CollectionUpdateRequest {
provider: string;
service: string | number;
identifier: string | number;
properties: CollectionMutableProperties;
}
/**
* Collection modify response
*/
export interface CollectionModifyResponse extends CollectionInterface {}
export interface CollectionUpdateResponse extends CollectionInterface {}
/**
* Collection destroy request
* Collection delete
*/
export interface CollectionDestroyRequest {
export interface CollectionDeleteRequest {
provider: string;
service: string | number;
identifier: string | number;
options?: {
force?: boolean; // Whether to force destroy even if collection is not empty
recursive?: boolean; // Whether to destroy child collections/items as well
force?: boolean; // Whether to force delete even if collection is not empty
recursive?: boolean; // Whether to delete child collections/items as well
};
}
/**
* Collection destroy response
*/
export interface CollectionDestroyResponse {
export interface CollectionDeleteResponse {
success: boolean;
}
+82 -19
View File
@@ -1,5 +1,5 @@
/**
* Common types shared across Mail Manager services
* Common types shared across provider, service, collection, and entity request and responses.
*/
/**
@@ -44,8 +44,19 @@ export interface ApiErrorResponse {
export type ApiResponse<T = any> = ApiSuccessResponse<T> | ApiErrorResponse;
/**
* Source selector structure for hierarchical resource selection
* Structure: Provider -> Service -> Collection -> Message
* Selector for targeting specific providers, services, collections, or entities in list or extant operations.
*
* Example usage:
* {
* "provider1": true, // Select all services/collections/entities under provider1
* "provider2": {
* "serviceA": true, // Select all collections/entities under serviceA of provider2
* "serviceB": {
* "collectionX": true, // Select all entities under collectionX of serviceB of provider2
* "collectionY": [1, 2, 3] // Select entities with identifiers 1, 2, and 3 under collectionY of serviceB of provider2
* }
* }
* }
*/
export type SourceSelector = {
[provider: string]: boolean | ServiceSelector;
@@ -56,38 +67,90 @@ export type ServiceSelector = {
};
export type CollectionSelector = {
[collection: string | number]: boolean | MessageSelector;
[collection: string | number]: boolean | EntitySelector;
};
export type MessageSelector = (string | number)[];
export type EntitySelector = (string | number)[];
/**
* Filter condition for building complex queries
* Filter comparison for list operations
*/
export interface FilterCondition {
field: string;
operator: string;
value: any;
}
export const ListFilterComparisonOperator = {
EQ: 1, // Equal
NEQ: 2, // Not Equal
GT: 4, // Greater Than
LT: 8, // Less Than
GTE: 16, // Greater Than or Equal
LTE: 32, // Less Than or Equal
IN: 64, // In Array
NIN: 128, // Not In Array
LIKE: 256, // Like
NLIKE: 512, // Not Like
} as const;
export type ListFilterComparisonOperator = typeof ListFilterComparisonOperator[keyof typeof ListFilterComparisonOperator];
/**
* Filter criteria for list operations
* Filter conjunction for list operations
*/
export const ListFilterConjunctionOperator = {
NONE: '',
AND: 'AND',
OR: 'OR',
} as const;
export type ListFilterConjunctionOperator = typeof ListFilterConjunctionOperator[keyof typeof ListFilterConjunctionOperator];
/**
* Filter condition for list operations
*
* Tuple format: [value, comparator?, conjunction?]
*/
export type ListFilterCondition = [
string | number | boolean | string[] | number[],
ListFilterComparisonOperator?,
ListFilterConjunctionOperator?
];
/**
* Filter for list operations
*
* Values can be:
* - Simple primitives (string | number | boolean) for default equality comparison
* - ListFilterCondition tuple for explicit comparator/conjunction
*
* Examples:
* - Simple usage: { name: "John" }
* - With comparator: { age: [25, ListFilterComparisonOperator.GT] }
* - With conjunction: { age: [25, ListFilterComparisonOperator.GT, ListFilterConjunctionOperator.AND] }
* - With array value for IN operator: { status: [["active", "pending"], ListFilterComparisonOperator.IN] }
*/
export interface ListFilter {
[key: string]: any;
[attribute: string]: string | number | boolean | ListFilterCondition;
}
/**
* Sort options for list operations
* Sort for list operations
*
* Values can be:
* - true for ascending
* - false for descending
*/
export interface ListSort {
[key: string]: boolean;
[attribute: string]: boolean;
}
/**
* Range specification for pagination/limiting results
* Range for list operations
*
* Values can be:
* - relative based on item identifier
* - absolute based on item count
*/
export interface ListRange {
start: number;
limit: number;
}
type: 'tally';
anchor: 'relative' | 'absolute';
position: string | number;
tally: number;
}
+57 -87
View File
@@ -1,11 +1,11 @@
/**
* Entity type definitions for mail
* Entity type definitions
*/
import type { SourceSelector } from './common';
import type { SourceSelector, ListFilter, ListSort, ListRange } from './common';
import type { MessageInterface } from './message';
/**
* Entity wrapper with metadata
* Entity definition
*/
export interface EntityInterface<T = MessageInterface> {
provider: string;
@@ -19,18 +19,15 @@ export interface EntityInterface<T = MessageInterface> {
}
/**
* Entity list request
* Entity list
*/
export interface EntityListRequest {
sources?: SourceSelector;
filter?: any;
sort?: any;
range?: { start: number; limit: number };
filter?: ListFilter;
sort?: ListSort;
range?: ListRange;
}
/**
* Entity list response
*/
export interface EntityListResponse {
[providerId: string]: {
[serviceId: string]: {
@@ -42,68 +39,38 @@ export interface EntityListResponse {
}
/**
* Entity delta request
*/
export interface EntityDeltaRequest {
sources: SourceSelector;
}
/**
* Entity delta response
*/
export interface EntityDeltaResponse {
[providerId: string]: {
[serviceId: string]: {
[collectionId: string]: {
signature: string;
created?: EntityInterface<MessageInterface>[];
modified?: EntityInterface<MessageInterface>[];
deleted?: string[];
};
};
};
}
/**
* Entity extant request
*/
export interface EntityExtantRequest {
sources: SourceSelector;
}
/**
* Entity extant response
*/
export interface EntityExtantResponse {
[providerId: string]: {
[serviceId: string]: {
[collectionId: string]: {
[messageId: string]: boolean;
};
};
};
}
/**
* Entity fetch request
* Entity fetch
*/
export interface EntityFetchRequest {
provider: string;
service: string | number;
collection: string | number;
identifiers: (string | number)[];
properties?: string[];
}
/**
* Entity fetch response
*/
export interface EntityFetchResponse {
entities: EntityInterface<MessageInterface>[];
[identifier: string]: EntityInterface<MessageInterface>;
}
/**
* Entity create request
* Entity extant
*/
export interface EntityExtantRequest {
sources: SourceSelector;
}
export interface EntityExtantResponse {
[providerId: string]: {
[serviceId: string]: {
[collectionId: string]: {
[identifier: string]: boolean;
};
};
};
}
/**
* Entity create
*/
export interface EntityCreateRequest<T = MessageInterface> {
provider: string;
@@ -112,17 +79,12 @@ export interface EntityCreateRequest<T = MessageInterface> {
properties: T;
}
/**
* Entity create response
*/
export interface EntityCreateResponse<T = MessageInterface> {
entity: EntityInterface<T>;
}
export interface EntityCreateResponse<T = MessageInterface> extends EntityInterface<T> {}
/**
* Entity modify request
* Entity update
*/
export interface EntityModifyRequest<T = MessageInterface> {
export interface EntityUpdateRequest<T = MessageInterface> {
provider: string;
service: string | number;
collection: string | number;
@@ -130,35 +92,46 @@ export interface EntityModifyRequest<T = MessageInterface> {
properties: T;
}
/**
* Entity modify response
*/
export interface EntityModifyResponse<T = MessageInterface> {
success: boolean;
entity?: EntityInterface<T>;
}
export interface EntityUpdateResponse<T = MessageInterface> extends EntityInterface<T> {}
/**
* Entity destroy request
* Entity delete
*/
export interface EntityDestroyRequest {
export interface EntityDeleteRequest {
provider: string;
service: string | number;
collection: string | number;
identifier: string | number;
}
/**
* Entity destroy response
*/
export interface EntityDestroyResponse {
export interface EntityDeleteResponse {
success: boolean;
}
/**
* Entity send request
* Entity delta
*/
export interface EntitySendRequest {
export interface EntityDeltaRequest {
sources: SourceSelector;
}
export interface EntityDeltaResponse {
[providerId: string]: false | {
[serviceId: string]: false | {
[collectionId: string]: false | {
signature: string;
additions: (string | number)[];
modifications: (string | number)[];
deletions: (string | number)[];
};
};
};
}
/**
* Entity transmit
*/
export interface EntityTransmitRequest {
message: {
from?: string;
to: string[];
@@ -181,10 +154,7 @@ export interface EntitySendRequest {
};
}
/**
* Entity send response
*/
export interface EntitySendResponse {
export interface EntityTransmitResponse {
id: string;
status: 'queued' | 'sent';
}
+3 -12
View File
@@ -29,41 +29,32 @@ export interface ProviderInterface {
}
/**
* Provider list request
* Provider list
*/
export interface ProviderListRequest {
sources?: SourceSelector;
}
/**
* Provider list response
*/
export interface ProviderListResponse {
[identifier: string]: ProviderInterface;
}
/**
* Provider fetch request
* Provider fetch
*/
export interface ProviderFetchRequest {
identifier: string;
}
/**
* Provider fetch response
*/
export interface ProviderFetchResponse extends ProviderInterface {}
/**
* Provider extant request
* Provider extant
*/
export interface ProviderExtantRequest {
sources: SourceSelector;
}
/**
* Provider extant response
*/
export interface ProviderExtantResponse {
[identifier: string]: boolean;
}
+95 -102
View File
@@ -1,7 +1,7 @@
/**
* Service-related type definitions
* Service type definitions
*/
import type { SourceSelector } from './common';
import type { SourceSelector, ListFilterComparisonOperator } from './common';
/**
* Service capabilities
@@ -9,29 +9,29 @@ import type { SourceSelector } from './common';
export interface ServiceCapabilitiesInterface {
// Collection capabilities
CollectionList?: boolean;
CollectionListFilter?: boolean | { [field: string]: string };
CollectionListSort?: boolean | string[];
CollectionListFilter?: ServiceListFilterCollection;
CollectionListSort?: ServiceListSortCollection;
CollectionExtant?: boolean;
CollectionFetch?: boolean;
CollectionCreate?: boolean;
CollectionModify?: boolean;
CollectionUpdate?: boolean;
CollectionDelete?: boolean;
// Message capabilities
EntityList?: boolean;
EntityListFilter?: boolean | { [field: string]: string };
EntityListSort?: boolean | string[];
EntityListRange?: boolean | { tally?: string[] };
EntityListFilter?: ServiceListFilterEntity;
EntityListSort?: ServiceListSortEntity;
EntityListRange?: ServiceListRange;
EntityDelta?: boolean;
EntityExtant?: boolean;
EntityFetch?: boolean;
EntityCreate?: boolean;
EntityModify?: boolean;
EntityUpdate?: boolean;
EntityDelete?: boolean;
EntityMove?: boolean;
EntityCopy?: boolean;
// Send capability
EntityTransmit?: boolean;
[key: string]: boolean | object | string[] | undefined;
[key: string]: boolean | object | string | string[] | undefined;
}
/**
@@ -52,15 +52,12 @@ export interface ServiceInterface {
}
/**
* Service list request
* Service list
*/
export interface ServiceListRequest {
sources?: SourceSelector;
}
/**
* Service list response
*/
export interface ServiceListResponse {
[provider: string]: {
[identifier: string]: ServiceInterface;
@@ -68,15 +65,22 @@ export interface ServiceListResponse {
}
/**
* Service extant request
* Service fetch
*/
export interface ServiceFetchRequest {
provider: string;
identifier: string | number;
}
export interface ServiceFetchResponse extends ServiceInterface {}
/**
* Service extant
*/
export interface ServiceExtantRequest {
sources: SourceSelector;
}
/**
* Service extant response
*/
export interface ServiceExtantResponse {
[provider: string]: {
[identifier: string]: boolean;
@@ -84,45 +88,17 @@ export interface ServiceExtantResponse {
}
/**
* Service fetch request
*/
export interface ServiceFetchRequest {
provider: string;
identifier: string | number;
}
/**
* Service fetch response
*/
export interface ServiceFetchResponse extends ServiceInterface {}
/**
* Service find by address request
*/
export interface ServiceFindByAddressRequest {
address: string;
}
/**
* Service find by address response
*/
export interface ServiceFindByAddressResponse extends ServiceInterface {}
/**
* Service create request
* Service create
*/
export interface ServiceCreateRequest {
provider: string;
data: Partial<ServiceInterface>;
}
/**
* Service create response
*/
export interface ServiceCreateResponse extends ServiceInterface {}
/**
* Service update request
* Service update
*/
export interface ServiceUpdateRequest {
provider: string;
@@ -130,29 +106,20 @@ export interface ServiceUpdateRequest {
data: Partial<ServiceInterface>;
}
/**
* Service update response
*/
export interface ServiceUpdateResponse extends ServiceInterface {}
/**
* Service delete request
* Service delete
*/
export interface ServiceDeleteRequest {
provider: string;
identifier: string | number;
}
/**
* Service delete response
*/
export interface ServiceDeleteResponse {}
// ==================== Discovery Types ====================
/**
* Service discovery request - NEW VERSION
* Supports identity-based discovery with optional hints
* Service discovery
*/
export interface ServiceDiscoverRequest {
identity: string; // Email address or domain
@@ -161,42 +128,36 @@ export interface ServiceDiscoverRequest {
secret?: string; // Optional: password/token for credential validation
}
/**
* Service discovery response - NEW VERSION
* Provider-keyed map of discovered service locations
*/
export interface ServiceDiscoverResponse {
[provider: string]: ServiceLocation; // Uses existing ServiceLocation discriminated union
}
/**
* Discovery status tracking for real-time UI updates
* Used by store to track per-provider discovery progress
* Service connection test
*/
export interface ProviderDiscoveryStatus {
export interface ServiceTestRequest {
provider: string;
status: 'pending' | 'discovering' | 'success' | 'failed';
location?: ServiceLocation;
error?: string;
metadata?: {
host?: string;
port?: number;
protocol?: string;
};
// For existing service
identifier?: string | number | null;
// For fresh configuration
location?: ServiceLocation | null;
identity?: ServiceIdentity | null;
}
// ==================== Service Testing Types ====================
export interface ServiceTestResponse {
success: boolean;
message: string;
}
/**
* Base service location interface
* Service location - Base
*/
export interface ServiceLocationBase {
type: 'URI' | 'SOCKET_SOLE' | 'SOCKET_SPLIT' | 'FILE';
}
/**
* URI-based service location for API and web services
* Used by: JMAP, Gmail API, etc.
* Service location - URI-based type
*/
export interface ServiceLocationUri extends ServiceLocationBase {
type: 'URI';
@@ -209,8 +170,7 @@ export interface ServiceLocationUri extends ServiceLocationBase {
}
/**
* Single socket-based service location
* Used by: services using a single host/port combination
* Service location - Single socket-based type (combined inbound/outbound configuration)
*/
export interface ServiceLocationSocketSole extends ServiceLocationBase {
type: 'SOCKET_SOLE';
@@ -222,8 +182,7 @@ export interface ServiceLocationSocketSole extends ServiceLocationBase {
}
/**
* Split socket-based service location
* Used by: traditional IMAP/SMTP configurations
* Service location - Split socket-based type (separate inbound/outbound configurations)
*/
export interface ServiceLocationSocketSplit extends ServiceLocationBase {
type: 'SOCKET_SPLIT';
@@ -240,8 +199,7 @@ export interface ServiceLocationSocketSplit extends ServiceLocationBase {
}
/**
* File-based service location
* Used by: local file system providers
* Service location - File-based type (e.g., for local mail delivery or Unix socket)
*/
export interface ServiceLocationFile extends ServiceLocationBase {
type: 'FILE';
@@ -249,7 +207,7 @@ export interface ServiceLocationFile extends ServiceLocationBase {
}
/**
* Discriminated union of all service location types
* Service location types
*/
export type ServiceLocation =
| ServiceLocationUri
@@ -257,24 +215,22 @@ export type ServiceLocation =
| ServiceLocationSocketSplit
| ServiceLocationFile;
// ==================== Service Identity Types ====================
/**
* Base service identity interface
* Service identity - base
*/
export interface ServiceIdentityBase {
type: 'NA' | 'BA' | 'TA' | 'OA' | 'CC';
}
/**
* No authentication
* Service identity - No authentication
*/
export interface ServiceIdentityNone extends ServiceIdentityBase {
type: 'NA';
}
/**
* Basic authentication (username/password)
* Service identity - Basic authentication type
*/
export interface ServiceIdentityBasic extends ServiceIdentityBase {
type: 'BA';
@@ -324,21 +280,58 @@ export type ServiceIdentity =
| ServiceIdentityCertificate;
/**
* Service connection test request
* List filter specification format
*
* Format: "type:length:defaultComparator:supportedComparators"
*
* Examples:
* - "s:200:256:771" = String field, max 200 chars, default LIKE, supports EQ|NEQ|LIKE|NLIKE
* - "a:10:64:192" = Array field, max 10 items, default IN, supports IN|NIN
* - "i:0:1:31" = Integer field, default EQ, supports EQ|NEQ|GT|LT|GTE|LTE
*
* Type codes:
* - s = string
* - i = integer
* - b = boolean
* - a = array
*
* Comparator values are bitmasks that can be combined
*/
export interface ServiceTestRequest {
provider: string;
// For existing service
identifier?: string | number | null;
// For fresh configuration
location?: ServiceLocation | null;
identity?: ServiceIdentity | null;
export type ServiceListFilterCollection = {
'label'?: string;
'rank'?: string;
[attribute: string]: string | undefined;
};
export type ServiceListFilterEntity = {
'*'?: string;
'from'?: string;
'to'?: string;
'cc'?: string;
'bcc'?: string;
'subject'?: string;
'body'?: string;
'before'?: string;
'after'?: string;
'min'?: string;
'max'?: string;
[attribute: string]: string | undefined;
}
/**
* Service connection test response
* Service list sort specification
*/
export interface ServiceTestResponse {
success: boolean;
message: string;
export type ServiceListSortCollection = ("label" | "rank" | string)[];
export type ServiceListSortEntity = ("from" | "to" | "subject" | "received" | "sent" | "size" | string)[];
export type ServiceListRange = {
'tally'?: string[];
};
export interface ServiceListFilterDefinition {
type: 'string' | 'integer' | 'date' | 'boolean' | 'array';
length: number;
defaultComparator: ListFilterComparisonOperator;
supportedComparators: ListFilterComparisonOperator[];
}