chore: standardize protocol
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
+217
-79
@@ -10,27 +10,31 @@ import type {
|
||||
ServiceLocation,
|
||||
SourceSelector,
|
||||
ServiceIdentity,
|
||||
ServiceInterface,
|
||||
} from '../types'
|
||||
|
||||
export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
// State
|
||||
const _services = ref<Record<string, ServiceObject>>({})
|
||||
const transceiving = ref(false)
|
||||
const lastTestResult = ref<any>(null)
|
||||
|
||||
// Getters
|
||||
/**
|
||||
* Get count of services in store
|
||||
*/
|
||||
const count = computed(() => Object.keys(_services.value).length)
|
||||
|
||||
/**
|
||||
* Check if any services are present in store
|
||||
*/
|
||||
const has = computed(() => count.value > 0)
|
||||
|
||||
/**
|
||||
* Get services as an array
|
||||
* @returns Array of service objects
|
||||
* Get all services present in store
|
||||
*/
|
||||
const services = computed(() => Object.values(_services.value))
|
||||
|
||||
/**
|
||||
* Get services grouped by provider
|
||||
* @returns Services grouped by provider ID
|
||||
* Get all services present in store grouped by provider
|
||||
*/
|
||||
const servicesByProvider = computed(() => {
|
||||
const groups: Record<string, ServiceObject[]> = {}
|
||||
@@ -45,9 +49,60 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
return groups
|
||||
})
|
||||
|
||||
// Actions
|
||||
/**
|
||||
* Retrieve for all or specific services
|
||||
* Get a specific service from store, with optional retrieval
|
||||
*
|
||||
* @param provider - provider identifier
|
||||
* @param identifier - service identifier
|
||||
* @param retrieve - Retrieve behavior: true = fetch if missing or refresh, false = cache only
|
||||
*
|
||||
* @returns Service object or null
|
||||
*/
|
||||
function service(provider: string, identifier: string | number, retrieve: boolean = false): ServiceObject | null {
|
||||
const key = identifierKey(provider, identifier)
|
||||
if (retrieve === true && !_services.value[key]) {
|
||||
console.debug(`[Mail Manager][Store] - Force fetching service "${key}"`)
|
||||
fetch(provider, identifier)
|
||||
}
|
||||
|
||||
return _services.value[key] || null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a service from store matching a given address, with optional retrieval
|
||||
*
|
||||
* @param address - email address to match against primary and secondary addresses
|
||||
* @param retrieve - Retrieve behavior: true = fetch if missing, false = cache only
|
||||
*
|
||||
* @returns Service object or null
|
||||
*/
|
||||
function serviceForAddress(address: string, retrieve: boolean = false): ServiceObject | null {
|
||||
const service = Object.values(_services.value).find(s => s.primaryAddress === address || s.secondaryAddresses?.includes(address))
|
||||
|
||||
if (retrieve === true && !service) {
|
||||
console.debug(`[Mail Manager][Store] - No service found for address "${address}", discovery may be needed`)
|
||||
|
||||
// TODO: Implement retrieving service by address
|
||||
}
|
||||
|
||||
return service || null
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique key for a service
|
||||
*/
|
||||
function identifierKey(provider: string, identifier: string | number | null): string {
|
||||
return `${provider}:${identifier ?? ''}`
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
/**
|
||||
* Retrieve all or specific services, optionally filtered by source selector
|
||||
*
|
||||
* @param sources - optional source selector
|
||||
*
|
||||
* @returns Promise with service object list keyed by provider and service identifier
|
||||
*/
|
||||
async function list(sources?: SourceSelector): Promise<Record<string, ServiceObject>> {
|
||||
transceiving.value = true
|
||||
@@ -55,20 +110,21 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
const response = await serviceService.list({ sources })
|
||||
|
||||
// Flatten nested structure: provider-id: { service-id: object } -> "provider-id:service-id": object
|
||||
const flattened: Record<string, ServiceObject> = {}
|
||||
const services: Record<string, ServiceObject> = {}
|
||||
Object.entries(response).forEach(([_providerId, providerServices]) => {
|
||||
Object.entries(providerServices).forEach(([_serviceId, serviceObj]) => {
|
||||
const key = `${serviceObj.provider}:${serviceObj.identifier}`
|
||||
flattened[key] = serviceObj
|
||||
const key = identifierKey(serviceObj.provider, serviceObj.identifier)
|
||||
services[key] = serviceObj
|
||||
})
|
||||
})
|
||||
|
||||
console.debug('[Mail Manager](Store) - Successfully retrieved', Object.keys(flattened).length, 'services')
|
||||
// Merge retrieved services into state
|
||||
_services.value = { ..._services.value, ...services }
|
||||
|
||||
_services.value = flattened
|
||||
return flattened
|
||||
console.debug('[Mail Manager][Store] - Successfully retrieved', Object.keys(services).length, 'services')
|
||||
return services
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager](Store) - Failed to retrieve services:', error)
|
||||
console.error('[Mail Manager][Store] - Failed to retrieve services:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
@@ -76,14 +132,26 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific service
|
||||
* Retrieve a specific service by provider and identifier
|
||||
*
|
||||
* @param provider - provider identifier
|
||||
* @param identifier - service identifier
|
||||
*
|
||||
* @returns Promise with service object
|
||||
*/
|
||||
async function fetch(provider: string, identifier: string | number): Promise<ServiceObject> {
|
||||
transceiving.value = true
|
||||
try {
|
||||
return await serviceService.fetch({ provider, identifier })
|
||||
const service = await serviceService.fetch({ provider, identifier })
|
||||
|
||||
// Merge fetched service into state
|
||||
const key = identifierKey(service.provider, service.identifier)
|
||||
_services.value[key] = service
|
||||
|
||||
console.debug('[Mail Manager][Store] - Successfully fetched service:', key)
|
||||
return service
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager](Store) - Failed to fetch service:', error)
|
||||
console.error('[Mail Manager][Store] - Failed to fetch service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
@@ -91,9 +159,117 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover service configuration
|
||||
* Retrieve service availability status for a given source selector
|
||||
*
|
||||
* @returns Array of discovered services sorted by provider
|
||||
* @param sources - source selector to check availability for
|
||||
*
|
||||
* @returns Promise with service availability status
|
||||
*/
|
||||
async function extant(sources: SourceSelector) {
|
||||
transceiving.value = true
|
||||
try {
|
||||
const response = await serviceService.extant({ sources })
|
||||
|
||||
console.debug('[Mail Manager][Store] - Successfully checked', sources ? Object.keys(sources).length : 0, 'services')
|
||||
return response
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager][Store] - Failed to check services:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new service with given provider and data
|
||||
*
|
||||
* @param provider - provider identifier for the new service
|
||||
* @param data - partial service data for creation
|
||||
*
|
||||
* @returns Promise with created service object
|
||||
*/
|
||||
async function create(provider: string, data: Partial<ServiceInterface>): Promise<ServiceObject> {
|
||||
transceiving.value = true
|
||||
try {
|
||||
const service = await serviceService.create({ provider, data })
|
||||
|
||||
// Merge created service into state
|
||||
const key = identifierKey(service.provider, service.identifier)
|
||||
_services.value[key] = service
|
||||
|
||||
console.debug('[Mail Manager][Store] - Successfully created service:', key)
|
||||
return service
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager][Store] - Failed to create service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing service with given provider, identifier, and data
|
||||
*
|
||||
* @param provider - provider identifier for the service to update
|
||||
* @param identifier - service identifier for the service to update
|
||||
* @param data - partial service data for update
|
||||
*
|
||||
* @returns Promise with updated service object
|
||||
*/
|
||||
async function update(provider: string, identifier: string | number, data: Partial<ServiceInterface>): Promise<ServiceObject> {
|
||||
transceiving.value = true
|
||||
try {
|
||||
const service = await serviceService.update({ provider, identifier, data })
|
||||
|
||||
// Merge updated service into state
|
||||
const key = identifierKey(service.provider, service.identifier)
|
||||
_services.value[key] = service
|
||||
|
||||
console.debug('[Mail Manager][Store] - Successfully updated service:', key)
|
||||
return service
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager][Store] - Failed to update service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a service by provider and identifier
|
||||
*
|
||||
* @param provider - provider identifier for the service to delete
|
||||
* @param identifier - service identifier for the service to delete
|
||||
*
|
||||
* @returns Promise with deletion result
|
||||
*/
|
||||
async function remove(provider: string, identifier: string | number): Promise<any> {
|
||||
transceiving.value = true
|
||||
try {
|
||||
await serviceService.delete({ provider, identifier })
|
||||
|
||||
// Remove deleted service from state
|
||||
const key = identifierKey(provider, identifier)
|
||||
delete _services.value[key]
|
||||
|
||||
console.debug('[Mail Manager][Store] - Successfully deleted service:', key)
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager][Store] - Failed to delete service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover services based on provided parameters
|
||||
*
|
||||
* @param identity - optional service identity for discovery
|
||||
* @param secret - optional secret for discovery
|
||||
* @param location - optional location for discovery
|
||||
* @param provider - optional provider identifier for discovery
|
||||
*
|
||||
* @returns Promise with list of discovered service objects
|
||||
*/
|
||||
async function discover(
|
||||
identity: string,
|
||||
@@ -105,16 +281,27 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
|
||||
try {
|
||||
const services = await serviceService.discover({identity, secret, location, provider})
|
||||
console.debug('[Mail Manager](Store) - Successfully discovered', services.length, 'services')
|
||||
|
||||
console.debug('[Mail Manager][Store] - Successfully discovered', services.length, 'services')
|
||||
return services
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager](Store) - Failed to discover service:', error)
|
||||
console.error('[Mail Manager][Store] - Failed to discover service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test service connectivity and configuration
|
||||
*
|
||||
* @param provider - provider identifier for the service to test
|
||||
* @param identifier - optional service identifier for testing existing service
|
||||
* @param location - optional service location for testing new configuration
|
||||
* @param identity - optional service identity for testing new configuration
|
||||
*
|
||||
* @return Promise with test results
|
||||
*/
|
||||
async function test(
|
||||
provider: string,
|
||||
identifier?: string | number | null,
|
||||
@@ -124,62 +311,11 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
transceiving.value = true
|
||||
try {
|
||||
const response = await serviceService.test({ provider, identifier, location, identity })
|
||||
lastTestResult.value = response
|
||||
|
||||
console.debug('[Mail Manager][Store] - Successfully tested service:', provider, identifier || location)
|
||||
return response
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager](Store) - Failed to test service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function create(provider: string, data: any) {
|
||||
transceiving.value = true
|
||||
try {
|
||||
const serviceObj = await serviceService.create({ provider, data })
|
||||
|
||||
// Add to store with composite key
|
||||
const key = `${serviceObj.provider}:${serviceObj.identifier}`
|
||||
_services.value[key] = serviceObj
|
||||
|
||||
return serviceObj
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager](Store) - Failed to create service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function update(provider: string, identifier: string | number, data: any) {
|
||||
transceiving.value = true
|
||||
try {
|
||||
const serviceObj = await serviceService.update({ provider, identifier, data })
|
||||
|
||||
// Update in store with composite key
|
||||
const key = `${serviceObj.provider}:${serviceObj.identifier}`
|
||||
_services.value[key] = serviceObj
|
||||
|
||||
return serviceObj
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager](Store) - Failed to update service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function remove(provider: string, identifier: string | number) {
|
||||
transceiving.value = true
|
||||
try {
|
||||
await serviceService.delete({ provider, identifier })
|
||||
|
||||
// Remove from store using composite key
|
||||
const key = `${provider}:${identifier}`
|
||||
delete _services.value[key]
|
||||
} catch (error: any) {
|
||||
console.error('[Mail Manager](Store) - Failed to delete service:', error)
|
||||
console.error('[Mail Manager][Store] - Failed to test service:', error)
|
||||
throw error
|
||||
} finally {
|
||||
transceiving.value = false
|
||||
@@ -190,7 +326,6 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
return {
|
||||
// State (readonly)
|
||||
transceiving: readonly(transceiving),
|
||||
lastTestResult: readonly(lastTestResult),
|
||||
// Getters
|
||||
count,
|
||||
has,
|
||||
@@ -198,12 +333,15 @@ export const useServicesStore = defineStore('mailServicesStore', () => {
|
||||
servicesByProvider,
|
||||
|
||||
// Actions
|
||||
service,
|
||||
serviceForAddress,
|
||||
list,
|
||||
fetch,
|
||||
discover,
|
||||
test,
|
||||
extant,
|
||||
create,
|
||||
update,
|
||||
delete: remove,
|
||||
discover,
|
||||
test,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user