refactor: front end

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-03-28 12:47:21 -04:00
parent 28e5cce23a
commit ccb781f933
38 changed files with 4909 additions and 2897 deletions

View File

@@ -1,262 +0,0 @@
/**
* File Manager API Types - Request and Response interfaces
*/
import type { SourceSelector, FilterCondition, SortCondition, RangeCondition, ApiResponse } from '@/types/common';
import type { ProviderRecord } from '@/types/provider';
import type { ServiceInterface, ServiceRecord } from '@/types/service';
import type { FileCollection, FileEntity, FileNode } from '@/types/node';
// ==================== Provider Types ====================
export type ProviderListResponse = ApiResponse<ProviderRecord>;
export interface ProviderExtantRequest {
sources: SourceSelector;
}
export type ProviderExtantResponse = ApiResponse<Record<string, boolean>>;
// ==================== Service Types ====================
export type ServiceListResponse = ApiResponse<ServiceRecord>;
export interface ServiceExtantRequest {
sources: SourceSelector;
}
export type ServiceExtantResponse = ApiResponse<Record<string, boolean>>;
export interface ServiceFetchRequest {
provider: string;
identifier: string;
}
export type ServiceFetchResponse = ApiResponse<ServiceInterface>;
// ==================== Collection Types ====================
export interface CollectionListRequest {
provider: string;
service: string;
location?: string | null;
filter?: FilterCondition[] | null;
sort?: SortCondition[] | null;
}
export type CollectionListResponse = ApiResponse<FileCollection[]>;
export interface CollectionExtantRequest {
provider: string;
service: string;
identifier: string;
}
export type CollectionExtantResponse = ApiResponse<{ extant: boolean }>;
export interface CollectionFetchRequest {
provider: string;
service: string;
identifier: string;
}
export type CollectionFetchResponse = ApiResponse<FileCollection>;
export interface CollectionCreateRequest {
provider: string;
service: string;
location?: string | null;
data: Partial<FileCollection>;
options?: Record<string, unknown>;
}
export type CollectionCreateResponse = ApiResponse<FileCollection>;
export interface CollectionModifyRequest {
provider: string;
service: string;
identifier: string;
data: Partial<FileCollection>;
}
export type CollectionModifyResponse = ApiResponse<FileCollection>;
export interface CollectionDestroyRequest {
provider: string;
service: string;
identifier: string;
}
export type CollectionDestroyResponse = ApiResponse<{ success: boolean }>;
export interface CollectionCopyRequest {
provider: string;
service: string;
identifier: string;
location?: string | null;
}
export type CollectionCopyResponse = ApiResponse<FileCollection>;
export interface CollectionMoveRequest {
provider: string;
service: string;
identifier: string;
location?: string | null;
}
export type CollectionMoveResponse = ApiResponse<FileCollection>;
// ==================== Entity Types ====================
export interface EntityListRequest {
provider: string;
service: string;
collection: string;
filter?: FilterCondition[] | null;
sort?: SortCondition[] | null;
range?: RangeCondition | null;
}
export type EntityListResponse = ApiResponse<FileEntity[]>;
export interface EntityDeltaRequest {
provider: string;
service: string;
collection: string;
signature: string;
detail?: 'ids' | 'full';
}
export interface EntityDeltaResult {
added: string[] | FileEntity[];
modified: string[] | FileEntity[];
removed: string[];
signature: string;
}
export type EntityDeltaResponse = ApiResponse<EntityDeltaResult>;
export interface EntityExtantRequest {
provider: string;
service: string;
collection: string;
identifiers: string[];
}
export type EntityExtantResponse = ApiResponse<Record<string, boolean>>;
export interface EntityFetchRequest {
provider: string;
service: string;
collection: string;
identifiers: string[];
}
export type EntityFetchResponse = ApiResponse<FileEntity[]>;
export interface EntityReadRequest {
provider: string;
service: string;
collection: string;
identifier: string;
}
export interface EntityReadResult {
content: string | null;
encoding: 'base64';
}
export type EntityReadResponse = ApiResponse<EntityReadResult>;
export interface EntityCreateRequest {
provider: string;
service: string;
collection?: string | null;
data: Partial<FileEntity>;
options?: Record<string, unknown>;
}
export type EntityCreateResponse = ApiResponse<FileEntity>;
export interface EntityModifyRequest {
provider: string;
service: string;
collection?: string | null;
identifier: string;
data: Partial<FileEntity>;
}
export type EntityModifyResponse = ApiResponse<FileEntity>;
export interface EntityDestroyRequest {
provider: string;
service: string;
collection?: string | null;
identifier: string;
}
export type EntityDestroyResponse = ApiResponse<{ success: boolean }>;
export interface EntityCopyRequest {
provider: string;
service: string;
collection?: string | null;
identifier: string;
destination?: string | null;
}
export type EntityCopyResponse = ApiResponse<FileEntity>;
export interface EntityMoveRequest {
provider: string;
service: string;
collection?: string | null;
identifier: string;
destination?: string | null;
}
export type EntityMoveResponse = ApiResponse<FileEntity>;
export interface EntityWriteRequest {
provider: string;
service: string;
collection?: string | null;
identifier: string;
content: string;
encoding?: 'base64';
}
export type EntityWriteResponse = ApiResponse<{ bytesWritten: number }>;
// ==================== Node Types (Unified/Recursive) ====================
export interface NodeListRequest {
provider: string;
service: string;
location?: string | null;
recursive?: boolean;
filter?: FilterCondition[] | null;
sort?: SortCondition[] | null;
range?: RangeCondition | null;
}
export type NodeListResponse = ApiResponse<FileNode[]>;
export interface NodeDeltaRequest {
provider: string;
service: string;
location?: string | null;
signature: string;
recursive?: boolean;
detail?: 'ids' | 'full';
}
export interface NodeDeltaResult {
added: string[] | FileNode[];
modified: string[] | FileNode[];
removed: string[];
signature: string;
}
export type NodeDeltaResponse = ApiResponse<NodeDeltaResult>;

150
src/types/collection.ts Normal file
View File

@@ -0,0 +1,150 @@
/**
* Collection type definitions
*/
import type { ListFilter, ListSort, SourceSelector } from './common';
export interface CollectionModelInterface extends Omit<CollectionInterface, '@type' | 'created' | 'modified'> {
created: Date | null;
modified: Date | null;
}
/**
* Collection information
*/
export interface CollectionInterface {
'@type': string;
schema: number;
provider: string;
service: string | number;
collection: string | number | null;
identifier: string | number;
signature: string | null;
created: string | null;
modified: string | null;
properties: CollectionPropertiesInterface;
}
export type CollectionContentTypes = 'file' | 'folder';
export interface CollectionBaseProperties {
}
export interface CollectionImmutableProperties extends CollectionBaseProperties {
content: CollectionContentTypes[];
}
export interface CollectionMutableProperties extends CollectionBaseProperties {
owner: string;
label: string;
}
export interface CollectionPropertiesInterface extends CollectionMutableProperties, CollectionImmutableProperties {}
/**
* Collection list
*/
export interface CollectionListRequest {
sources?: SourceSelector;
filter?: ListFilter;
sort?: ListSort;
}
export interface CollectionListResponse {
[providerId: string]: {
[serviceId: string]: {
[collectionId: string]: CollectionInterface;
};
};
}
/**
* 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;
}
export interface CollectionExtantResponse {
[providerId: string]: {
[serviceId: string]: {
[collectionId: string]: boolean;
};
};
}
/**
* Collection create
*/
export interface CollectionCreateRequest {
provider: string;
service: string | number;
collection?: string | number | null; // Parent Collection Identifier
properties: CollectionMutableProperties;
}
export interface CollectionCreateResponse extends CollectionInterface {}
/**
* Collection modify
*/
export interface CollectionUpdateRequest {
provider: string;
service: string | number;
identifier: string | number;
properties: CollectionMutableProperties;
}
export interface CollectionUpdateResponse extends CollectionInterface {}
/**
* Collection delete
*/
export interface CollectionDeleteRequest {
provider: string;
service: string | number;
identifier: string | number;
options?: {
force?: boolean; // Whether to force delete even if collection is not empty
};
}
export interface CollectionDeleteResponse {
success: boolean;
}
/**
* Collection copy
*/
export interface CollectionCopyRequest {
provider: string;
service: string;
identifier: string;
location?: string | null;
}
export interface CollectionCopyResponse extends CollectionInterface {}
/**
* Collection move
*/
export interface CollectionMoveRequest {
provider: string;
service: string;
identifier: string;
location?: string | null;
}
export interface CollectionMoveResponse extends CollectionInterface {}

View File

@@ -1,85 +1,156 @@
/**
* Common types for file manager
* Common types shared across provider, service, collection, and entity request and responses.
*/
/**
* Base API request envelope
*/
export interface ApiRequest<T = any> {
version: number;
transaction: string;
operation: string;
data: T;
user?: string;
}
/**
* Success response envelope
*/
export interface ApiSuccessResponse<T = any> {
version: number;
transaction: string;
operation: string;
status: 'success';
data: T;
}
/**
* Error response envelope
*/
export interface ApiErrorResponse {
version: number;
transaction: string;
operation: string;
status: 'error';
data: {
code: number;
message: string;
};
}
/**
* Combined response type
*/
export type ApiResponse<T = any> = ApiSuccessResponse<T> | ApiErrorResponse;
/**
* 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;
};
export type ServiceSelector = {
[service: string]: boolean;
[service: string]: boolean | CollectionSelector;
};
export const SortDirection = {
Ascending: 'asc',
Descending: 'desc'
export type CollectionSelector = {
[collection: string | number]: boolean | EntitySelector;
};
export type EntitySelector = (string | number)[];
/**
* Filter comparison for list operations
*/
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 SortDirection = typeof SortDirection[keyof typeof SortDirection];
export type ListFilterComparisonOperator = typeof ListFilterComparisonOperator[keyof typeof ListFilterComparisonOperator];
export const RangeType = {
Tally: 'tally',
Date: 'date'
/**
* Filter conjunction for list operations
*/
export const ListFilterConjunctionOperator = {
NONE: '',
AND: 'AND',
OR: 'OR',
} as const;
export type RangeType = typeof RangeType[keyof typeof RangeType];
export type ListFilterConjunctionOperator = typeof ListFilterConjunctionOperator[keyof typeof ListFilterConjunctionOperator];
export const RangeAnchorType = {
Absolute: 'absolute',
Relative: 'relative'
} as const;
/**
* Filter condition for list operations
*
* Tuple format: [value, comparator?, conjunction?]
*/
export type ListFilterCondition = [
string | number | boolean | string[] | number[],
ListFilterComparisonOperator?,
ListFilterConjunctionOperator?
];
export type RangeAnchorType = typeof RangeAnchorType[keyof typeof RangeAnchorType];
export const FilterOperator = {
Equals: 'eq',
NotEquals: 'ne',
GreaterThan: 'gt',
LessThan: 'lt',
GreaterThanOrEquals: 'gte',
LessThanOrEquals: 'lte',
Contains: 'contains',
StartsWith: 'startsWith',
EndsWith: 'endsWith',
In: 'in',
NotIn: 'notIn'
} as const;
export type FilterOperator = typeof FilterOperator[keyof typeof FilterOperator];
export interface FilterCondition {
attribute: string;
value: unknown;
operator?: FilterOperator;
/**
* 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 {
[attribute: string]: string | number | boolean | ListFilterCondition;
}
export interface SortCondition {
attribute: string;
direction: SortDirection;
/**
* Sort for list operations
*
* Values can be:
* - true for ascending
* - false for descending
*/
export interface ListSort {
[attribute: string]: boolean;
}
export interface RangeCondition {
type: RangeType;
anchor?: RangeAnchorType;
position?: string | number;
tally?: number;
}
export interface ApiRequest {
version: number;
transaction: string;
operation: string;
data?: Record<string, unknown>;
}
export interface ApiResponse<T = unknown> {
version: number;
transaction: string;
operation: string;
status: 'success' | 'error';
data?: T;
error?: {
code: number;
message: string;
};
}
/**
* Range for list operations
*
* Values can be:
* - relative based on item identifier
* - absolute based on item count
*/
export interface ListRange {
type: 'tally';
anchor: 'relative' | 'absolute';
position: string | number;
tally: number;
}

20
src/types/document.ts Normal file
View File

@@ -0,0 +1,20 @@
/**
* Document-related type definitions
*/
/**
* Document interface
*/
export interface DocumentModelInterface extends Omit<DocumentInterface, '@type' | 'label'> {
label: string | null;
}
export interface DocumentInterface {
'@type': string;
urid: string | null;
size: number;
label: string;
mime: string | null;
format: string | null;
encoding: string | null;
}

194
src/types/entity.ts Normal file
View File

@@ -0,0 +1,194 @@
/**
* Entity type definitions
*/
import type { ListFilter, ListRange, ListSort, SourceSelector } from './common';
import type { DocumentInterface, DocumentModelInterface } from './document';
/**
* Entity definition
*/
export interface EntityModelInterface extends Omit<EntityInterface<DocumentModelInterface>, '@type' | 'created' | 'modified'> {
created: Date | null;
modified: Date | null;
}
export interface EntityInterface<T = DocumentInterface> {
'@type': string;
schema: number;
provider: string;
service: string;
collection: string | number;
identifier: string | number;
signature: string | null;
created: string | null;
modified: string | null;
properties: T;
}
/**
* Entity list
*/
export interface EntityListRequest {
sources?: SourceSelector;
filter?: ListFilter;
sort?: ListSort;
range?: ListRange;
}
export interface EntityListResponse {
[providerId: string]: {
[serviceId: string]: {
[collectionId: string]: {
[identifier: string]: EntityInterface<DocumentInterface>;
};
};
};
}
/**
* Entity fetch
*/
export interface EntityFetchRequest {
provider: string;
service: string | number;
collection: string | number;
identifiers: (string | number)[];
}
export interface EntityFetchResponse {
[identifier: string]: EntityInterface<DocumentInterface>;
}
/**
* 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 = DocumentInterface> {
provider: string;
service: string | number;
collection: string | number;
properties: T;
options?: Record<string, unknown>;
}
export interface EntityCreateResponse<T = DocumentInterface> extends EntityInterface<T> {}
/**
* Entity update
*/
export interface EntityUpdateRequest<T = DocumentInterface> {
provider: string;
service: string | number;
collection: string | number;
identifier: string | number;
properties: T;
}
export interface EntityUpdateResponse<T = DocumentInterface> extends EntityInterface<T> {}
/**
* Entity delete
*/
export interface EntityDeleteRequest {
provider: string;
service: string | number;
collection: string | number;
identifier: string | number;
}
export interface EntityDeleteResponse {
success: boolean;
}
/**
* Entity delta
*/
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 copy
*/
export interface EntityCopyRequest {
provider: string;
service: string | number;
collection: string | number;
identifier: string | number;
destination?: string | null;
}
export interface EntityCopyResponse<T = DocumentInterface> extends EntityInterface<T> {}
/**
* Entity move
*/
export interface EntityMoveRequest {
provider: string;
service: string | number;
collection: string | number;
identifier: string | number;
destination?: string | null;
}
export interface EntityMoveResponse<T = DocumentInterface> extends EntityInterface<T> {}
/**
* Entity read content
*/
export interface EntityReadRequest {
provider: string;
service: string | number;
collection: string | number;
identifier: string | number;
}
export interface EntityReadResult {
content: string | null;
encoding: 'base64';
}
export type EntityReadResponse = EntityReadResult;
/**
* Entity write content
*/
export interface EntityWriteRequest {
provider: string;
service: string | number;
collection: string | number;
identifier: string | number;
content: string;
encoding?: 'base64';
}
export type EntityWriteResponse = { bytesWritten: number };

View File

@@ -1,9 +1,7 @@
/**
* File manager types barrel export
*/
export * from './common';
export * from './provider';
export * from './service';
export * from './node';
export * from './api';
export type * from './common';
export type * from './provider';
export type * from './service';
export type * from './collection';
export type * from './entity';
export type * from './document';
export type * from './node';

View File

@@ -1,65 +1,37 @@
/**
* Node types for file manager (collections and entities)
* Node types for combined operations
*/
export type NodeType = 'files.collection' | 'files.entity';
import type { CollectionInterface } from "./collection";
import type { ApiResponse, ListFilterCondition, ListRange, ListSort } from "./common";
import type { EntityInterface } from "./entity";
export interface NodeBase {
'@type': NodeType;
in: string | null;
id: string;
createdBy: string;
createdOn: string;
modifiedBy: string;
modifiedOn: string;
owner: string;
export interface NodeListRequest {
provider: string;
service: string;
location?: string | null;
recursive?: boolean;
filter?: ListFilterCondition | null;
sort?: ListSort | null;
range?: ListRange | null;
}
export type NodeListResponse = ApiResponse<CollectionInterface | EntityInterface>;
export interface NodeDeltaRequest {
provider: string;
service: string;
location?: string | null;
signature: string;
label: string;
recursive?: boolean;
detail?: 'ids' | 'full';
}
export interface FileCollection extends NodeBase {
'@type': 'files.collection';
}
export interface FileEntity extends NodeBase {
'@type': 'files.entity';
size: number;
mime: string;
format: string;
encoding: string;
}
export type FileNode = FileCollection | FileEntity;
export interface NodeListResult {
items: FileNode[];
total: number;
hasMore?: boolean;
}
export interface EntityListResult {
items: FileEntity[];
total: number;
hasMore?: boolean;
}
export interface CollectionListResult {
items: FileCollection[];
total: number;
hasMore?: boolean;
}
export interface DeltaResult {
added: FileNode[];
modified: FileNode[];
export interface NodeDeltaResult {
added: string[];
modified: string[];
removed: string[];
signature: string;
}
export function isFileCollection(node: FileNode): node is FileCollection {
return node['@type'] === 'files.collection';
}
export function isFileEntity(node: FileNode): node is FileEntity {
return node['@type'] === 'files.entity';
}
export type NodeDeltaResponse = ApiResponse<NodeDeltaResult>;

View File

@@ -1,49 +1,60 @@
/**
* Provider types for file manager
* Provider type definitions
*/
import type { SourceSelector } from "./common";
/**
* Provider capabilities
*/
export interface ProviderCapabilitiesInterface {
CollectionList?: boolean;
CollectionListFilter?: boolean | Record<string, string>;
CollectionListSort?: boolean | string[];
CollectionExtant?: boolean;
CollectionFetch?: boolean;
CollectionCreate?: boolean;
CollectionModify?: boolean;
CollectionDestroy?: boolean;
CollectionCopy?: boolean;
CollectionMove?: boolean;
EntityList?: boolean;
EntityListFilter?: boolean | Record<string, string>;
EntityListSort?: boolean | string[];
EntityListRange?: boolean | Record<string, string[]>;
EntityDelta?: boolean;
EntityExtant?: boolean;
EntityFetch?: boolean;
EntityRead?: boolean;
EntityReadStream?: boolean;
EntityReadChunk?: boolean;
EntityCreate?: boolean;
EntityModify?: boolean;
EntityDestroy?: boolean;
EntityCopy?: boolean;
EntityMove?: boolean;
EntityWrite?: boolean;
EntityWriteStream?: boolean;
EntityWriteChunk?: boolean;
NodeList?: boolean;
NodeListFilter?: boolean | Record<string, string>;
NodeListSort?: boolean | string[];
NodeListRange?: boolean | Record<string, string[]>;
NodeDelta?: boolean;
[key: string]: boolean | string[] | Record<string, string> | Record<string, string[]> | undefined;
ServiceList?: boolean;
ServiceFetch?: boolean;
ServiceExtant?: boolean;
ServiceCreate?: boolean;
ServiceUpdate?: boolean;
ServiceDelete?: boolean;
ServiceDiscover?: boolean;
ServiceTest?: boolean;
[key: string]: boolean | object | string[] | undefined;
}
/**
* Provider information
*/
export interface ProviderInterface {
'@type': string;
id: string;
identifier: string;
label: string;
capabilities: ProviderCapabilitiesInterface;
}
export type ProviderRecord = Record<string, ProviderInterface>;
/**
* Provider list
*/
export interface ProviderListRequest {
sources?: SourceSelector;
}
export interface ProviderListResponse {
[identifier: string]: ProviderInterface;
}
/**
* Provider fetch
*/
export interface ProviderFetchRequest {
identifier: string;
}
export interface ProviderFetchResponse extends ProviderInterface {}
/**
* Provider extant
*/
export interface ProviderExtantRequest {
sources: SourceSelector;
}
export interface ProviderExtantResponse {
[identifier: string]: boolean;
}

View File

@@ -1,13 +1,307 @@
/**
* Service types for file manager
* Service type definitions
*/
import type { SourceSelector, ListFilterComparisonOperator } from './common';
export interface ServiceInterface {
'@type': string;
id: string;
provider: string;
label: string;
rootId: string;
/**
* Service capabilities
*/
export interface ServiceCapabilitiesInterface {
// Collection capabilities
CollectionList?: boolean;
CollectionListFilter?: ServiceListFilterCollection;
CollectionListSort?: ServiceListSortCollection;
CollectionExtant?: boolean;
CollectionFetch?: boolean;
CollectionCreate?: boolean;
CollectionUpdate?: boolean;
CollectionDelete?: boolean;
CollectionCopy?: boolean;
CollectionMove?: boolean;
// Entity capabilities
EntityList?: boolean;
EntityListFilter?: ServiceListFilterEntity;
EntityListSort?: ServiceListSortEntity;
EntityListRange?: ServiceListRange;
EntityDelta?: boolean;
EntityExtant?: boolean;
EntityFetch?: boolean;
EntityCreate?: boolean;
EntityUpdate?: boolean;
EntityDelete?: boolean;
EntityMove?: boolean;
EntityCopy?: boolean;
EntityRead?: boolean;
EntityReadStream?: boolean;
EntityReadChunk?: boolean;
EntityWrite?: boolean;
EntityWriteStream?: boolean;
EntityWriteChunk?: boolean;
// Node capabilities
NodeList?: boolean;
NodeListFilter?: boolean | Record<string, string>;
NodeListSort?: boolean | string[];
NodeListRange?: boolean | Record<string, string[]>;
NodeDelta?: boolean;
[key: string]: boolean | object | string | string[] | undefined;
}
export type ServiceRecord = Record<string, ServiceInterface>;
/**
* Service information
*/
export interface ServiceInterface {
'@type': string;
provider: string;
identifier: string | number | null;
label: string | null;
enabled: boolean;
capabilities?: ServiceCapabilitiesInterface;
location?: ServiceLocation | null;
identity?: ServiceIdentity | null;
auxiliary?: Record<string, any>; // Provider-specific extension data
}
/**
* Service list
*/
export interface ServiceListRequest {
sources?: SourceSelector;
}
export interface ServiceListResponse {
[provider: string]: {
[identifier: string]: ServiceInterface;
};
}
/**
* Service fetch
*/
export interface ServiceFetchRequest {
provider: string;
identifier: string | number;
}
export interface ServiceFetchResponse extends ServiceInterface {}
/**
* Service extant
*/
export interface ServiceExtantRequest {
sources: SourceSelector;
}
export interface ServiceExtantResponse {
[provider: string]: {
[identifier: string]: boolean;
};
}
/**
* Service create
*/
export interface ServiceCreateRequest {
provider: string;
data: Partial<ServiceInterface>;
}
export interface ServiceCreateResponse extends ServiceInterface {}
/**
* Service update
*/
export interface ServiceUpdateRequest {
provider: string;
identifier: string | number;
data: Partial<ServiceInterface>;
}
export interface ServiceUpdateResponse extends ServiceInterface {}
/**
* Service delete
*/
export interface ServiceDeleteRequest {
provider: string;
identifier: string | number;
}
export interface ServiceDeleteResponse {}
/**
* Service discovery
*/
export interface ServiceDiscoverRequest {
identity: string; // Email address or domain
provider?: string; // Optional: specific provider ('jmap', 'smtp', etc.) or null for all
location?: string; // Optional: known hostname (bypasses DNS lookup)
secret?: string; // Optional: password/token for credential validation
}
export interface ServiceDiscoverResponse {
[provider: string]: ServiceLocation; // Uses existing ServiceLocation discriminated union
}
/**
* Service connection test
*/
export interface ServiceTestRequest {
provider: string;
// For existing service
identifier?: string | number | null;
// For fresh configuration
location?: ServiceLocation | null;
identity?: ServiceIdentity | null;
}
export interface ServiceTestResponse {
success: boolean;
message: string;
}
/**
* Service location - Base
*/
export interface ServiceLocationBase {
type: 'URI' | 'FILE';
}
/**
* Service location - URI-based type
*/
export interface ServiceLocationUri extends ServiceLocationBase {
type: 'URI';
scheme: string; // e.g., 'https', 'http'
host: string; // e.g., 'api.example.com'
port: number; // e.g., 443
path?: string; // e.g., '/v1/api'
verifyPeer?: boolean; // Verify SSL/TLS peer certificate
verifyHost?: boolean; // Verify SSL/TLS certificate host
}
/**
* Service location - File-based type (e.g., for local mail delivery or Unix socket)
*/
export interface ServiceLocationFile extends ServiceLocationBase {
type: 'FILE';
path: string; // File system path
}
/**
* Service location types
*/
export type ServiceLocation =
| ServiceLocationUri
| ServiceLocationFile;
/**
* Service identity - base
*/
export interface ServiceIdentityBase {
type: 'NA' | 'BA' | 'TA' | 'OA' | 'CC';
}
/**
* Service identity - No authentication
*/
export interface ServiceIdentityNone extends ServiceIdentityBase {
type: 'NA';
}
/**
* Service identity - Basic authentication type
*/
export interface ServiceIdentityBasic extends ServiceIdentityBase {
type: 'BA';
identity: string; // Username/email
secret: string; // Password
}
/**
* Token authentication (API key, static token)
*/
export interface ServiceIdentityToken extends ServiceIdentityBase {
type: 'TA';
token: string; // Authentication token/API key
}
/**
* OAuth authentication
*/
export interface ServiceIdentityOAuth extends ServiceIdentityBase {
type: 'OA';
accessToken: string; // Current access token
accessScope?: string[]; // Token scopes
accessExpiry?: number; // Unix timestamp when token expires
refreshToken?: string; // Refresh token for getting new access tokens
refreshLocation?: string; // Token refresh endpoint URL
}
/**
* Client certificate authentication (mTLS)
*/
export interface ServiceIdentityCertificate extends ServiceIdentityBase {
type: 'CC';
certificate: string; // X.509 certificate (PEM format or file path)
privateKey: string; // Private key (PEM format or file path)
passphrase?: string; // Optional passphrase for encrypted private key
}
/**
* Service identity configuration
* Discriminated union of all identity types
*/
export type ServiceIdentity =
| ServiceIdentityNone
| ServiceIdentityBasic
| ServiceIdentityToken
| ServiceIdentityOAuth
| ServiceIdentityCertificate;
/**
* 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 type ServiceListFilterCollection = {
'label'?: string;
[attribute: string]: string | undefined;
};
export type ServiceListFilterEntity = {
'text'?: string;
'label'?: string;
[attribute: string]: string | undefined;
}
/**
* Service list sort specification
*/
export type ServiceListSortCollection = ("label" | string)[];
export type ServiceListSortEntity = ( "label" | string)[];
export type ServiceListRange = {
'tally'?: string[];
};
export interface ServiceListFilterDefinition {
type: 'string' | 'integer' | 'date' | 'boolean' | 'array';
length: number;
defaultComparator: ListFilterComparisonOperator;
supportedComparators: ListFilterComparisonOperator[];
}