-
Notifications
You must be signed in to change notification settings - Fork 0
Services Events and Diagnostics
ForsettiContext is the safe runtime bridge given to modules during start(context:) and stop(context:). It exposes service resolution, eventing, module messaging, logging, and routing without exposing host internals. Runtime-created module contexts are scoped to the active module ID and granted capabilities.
flowchart LR
Module["Module"] --> Context["ForsettiContext"]
Context --> Services["ForsettiServiceProviding"]
Context --> Events["ForsettiEventBus"]
Context --> Logger["ForsettiLogger"]
Context --> Router["OverlayRouting"]
Context --> Guard["ModuleCommunicationGuard"]
Services are registered by protocol type in ForsettiServiceContainer.
let services = ForsettiServiceContainer()
services.register(NetworkingService.self, service: URLSessionNetworkingService())
services.register(StorageService.self, service: UserDefaultsStorageService())| Service Protocol | Default Platform Adapter or Role |
|---|---|
NetworkingService |
URLSessionNetworkingService |
StorageService |
UserDefaultsStorageService |
SecureStorageService |
KeychainSecureStorageService |
FileExportService |
LocalFileExportService |
TelemetryService |
NoopTelemetryService |
SharedDatabaseService |
Host adapter or service module with defaultModuleRole: "shared_database". |
AuthenticationService |
Host adapter or service module with defaultModuleRole: "authentication". |
DiagnosticsService |
Host adapter or service module with defaultModuleRole: "diagnostics". |
APIService |
Host adapter or service module with defaultModuleRole: "api". |
SecurityService |
Host adapter or service module with defaultModuleRole: "security". |
sequenceDiagram
participant ModuleA as Module A
participant Context as ForsettiContext
participant Bus as InMemoryEventBus
participant ModuleB as Module B
ModuleB->>Context: subscribeToFrameworkEvents(type)
Context->>Bus: subscribe(eventType)
ModuleA->>Context: publishEvent(type, payload)
Context->>Bus: publish(event)
Bus-->>ModuleB: handler(event)
InMemoryEventBus dispatches events to handlers registered for the exact event type.
Scoped contexts always publish with the bound module ID, even if module code attempts to pass a different source ID.
Module messaging is intentionally guarded. The default guard rejects empty IDs, self-relay, empty event types, and the reserved forsetti.internal. event namespace.
flowchart TD
A["sendModuleMessage"] --> B["DefaultModuleCommunicationGuard"]
B --> C{"Allowed?"}
C -- no --> D["Log blocked communication and throw"]
C -- yes --> E["Add _forsetti.targetModuleID to payload"]
E --> F["Publish event"]
F --> G["Subscriber receives only matching targetModuleID"]
ForsettiModuleLogger enriches module logs with moduleID metadata.
| API | Use |
|---|---|
debug |
Diagnostic details useful during development. |
info |
Lifecycle and normal operation events. |
warning |
Recoverable problems or skipped work. |
error |
Failed operations with optional Error details. |
flowchart LR
Symptom["Runtime symptom"] --> Logs["Check ForsettiLogger output"]
Logs --> Manifest["Check manifest fields"]
Manifest --> Compatibility["Check compatibility report"]
Compatibility --> Entitlement["Check entitlement state"]
Entitlement --> Registry["Check ModuleRegistry entry point"]
Registry --> Tests["Add regression test"]
- Modules resolve protocols, not concrete host implementations.
- Host apps decide which services are registered.
- Modules can resolve only services covered by their granted capabilities.
- Sensitive storage should use
KeychainSecureStorageServicein production; in-memory secure storage is an explicit test/debug adapter. - Telemetry should remain host-governed so privacy and analytics policy stay centralized. Service resolution is capability-scoped for module contexts:
| Service Protocol | Required Capability |
|---|---|
NetworkingService |
networking |
StorageService |
storage |
SecureStorageService |
secure_storage |
FileExportService |
file_export |
TelemetryService |
telemetry |
SharedDatabaseService |
shared_database |
AuthenticationService |
authentication |
DiagnosticsService |
diagnostics |
APIService |
api |
SecurityService |
security |
Unknown service protocols are denied by default.
flowchart TD
Provider["Service module manifest"] --> Role["defaultModuleRole"]
Role --> Discovery["Discovery records provider role"]
Consumer["Consumer module manifest"] --> Requirement["runtimeRequirements.dataIsolation.requiredDefaultRoles"]
Requirement --> Activation["Activation checks provider availability"]
Discovery --> Activation
Activation -- available --> Start["Consumer starts"]
Activation -- missing --> Block["unsatisfiedRuntimeRequirement"]
Provider roles make shared services explicit without forcing consumers to know concrete module implementations.