npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@elgin-white/sail-desktop-agent

v0.0.1-beta.0

Published

FDC3 Desktop Agent implementation for Sail

Readme

FDC3 Sail Desktop Agent

A pure, transport-agnostic FDC3 Desktop Agent implementation that supports the complete Desktop Agent Communication Protocol (DACP) specification.

Overview

This package provides a production-ready FDC3 Desktop Agent that manages application instances, channels, intents, and private channels according to the FDC3 2.2 specification.

Key Features:

  • Full FDC3 2.2 Compliance: All mandatory Desktop Agent APIs implemented
  • Transport Agnostic: Core has zero transport dependencies - works with any message transport
  • Environment Agnostic: Runs in browser, Node.js, Web Worker, or any JavaScript runtime
  • WCP Support: Full Web Connection Protocol (WCP1-6) implementation for browser apps
  • Flexible Deployment: Same code runs locally, on server, or in worker
  • Type Safety: Built with TypeScript and Zod validation

Architecture

The package follows a clean three-layer architecture:

┌─────────────────────────────────────────────────────────────────────────┐
│  Browser Apps (iframes)                                                 │
│  Using @finos/fdc3-get-agent                                           │
│  fdc3.raiseIntent(), fdc3.broadcast(), etc.                            │
└────────────────────────────────┬────────────────────────────────────────┘
                                 │ MessagePort (WCP)
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  WCPConnector (Browser only)                                            │
│  - Handles WCP1-3 handshake with iframe apps                           │
│  - Manages MessagePorts per app                                         │
│  - Bridges to Transport                                                 │
└────────────────────────────────┬────────────────────────────────────────┘
                                 │ Transport (swappable)
                                 ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  DesktopAgent (runs anywhere)                                           │
│  - Pure FDC3 logic, zero environment dependencies                       │
│  - DACP message handlers                                                │
│  - State registries (apps, channels, intents)                          │
└─────────────────────────────────────────────────────────────────────────┘

Directory Structure

packages/sail-desktop-agent/
├── src/
│   ├── core/                      # Pure FDC3 Desktop Agent (environment-agnostic)
│   │   ├── sail-desktop-agent.ts       # Main DesktopAgent class
│   │   ├── handlers/              # DACP message handlers
│   │   │   └── dacp/              # All FDC3 operation handlers
│   │   ├── state/                 # State registries
│   │   │   ├── app-instance-registry.ts
│   │   │   ├── intent-registry.ts
│   │   │   ├── channel-context-registry.ts
│   │   │   └── ...
│   │   ├── interfaces/            # Transport & AppLauncher interfaces
│   │   └── app-directory/         # FDC3 App Directory management
│   ├── browser/                   # Browser-specific code
│   │   ├── browser-sail-desktop-agent.ts  # Factory functions
│   │   └── wcp/                   # WCP implementation
│   │       ├── wcp-connector.ts   # WCP1-6 protocol handler
│   │       └── message-port-transport.ts
│   └── transports/                # Transport implementations
│       └── in-memory-transport.ts # For same-process communication
└── test/                          # Cucumber BDD tests

Installation

npm install @finos/fdc3-sail-desktop-agent

Quick Start

Browser Mode (Desktop Agent in same window)

Use when Desktop Agent runs in the browser alongside your UI:

import { createBrowserDesktopAgent } from "@finos/fdc3-sail-desktop-agent/browser"

const { desktopAgent, wcpConnector, start, stop } = createBrowserDesktopAgent({
  wcpOptions: {
    // Return false for Sail-controlled UI (recommended)
    getIntentResolverUrl: () => false,
    getChannelSelectorUrl: () => false,
  },
  appDirectories: ["https://example.com/apps.json"],
})

// Start Desktop Agent and WCP Connector
start()

// Apps in iframes can now connect via fdc3.getAgent()

Server Mode (Desktop Agent on server)

Use when Desktop Agent runs on a Node.js server:

// Browser client
import { createWCPClient } from "@finos/fdc3-sail-desktop-agent/browser"
import { SocketIOClientTransport } from "@finos/sail-platform-api"

const transport = new SocketIOClientTransport({
  url: "wss://your-server.com",
  auth: { userId: "user123" },
})

const { wcpConnector, start } = createWCPClient({
  transport,
  wcpOptions: {
    getIntentResolverUrl: () => false,
    getChannelSelectorUrl: () => false,
  },
})

start()
// Apps connect via WCP, messages flow to server
// Server
import { DesktopAgent } from "@finos/fdc3-sail-desktop-agent"
import { SocketIOServerTransport } from "@finos/sail-platform-api"

const transport = new SocketIOServerTransport(io, userId)
const agent = new DesktopAgent({ transport })
agent.start()

Worker Mode (Desktop Agent in Web Worker)

Use when Desktop Agent runs in a Web Worker for isolation:

// Main thread
import { createWCPClient } from "@finos/fdc3-sail-desktop-agent/browser"
import { WebWorkerTransport } from "@finos/sail-platform-api"

const worker = new Worker("sail-desktop-agent-worker.js")
const transport = new WebWorkerTransport(worker)

const { wcpConnector, start } = createWCPClient({ transport })
start()

Manual Composition (Advanced)

For full control over component setup:

import { DesktopAgent } from "@finos/fdc3-sail-desktop-agent"
import { WCPConnector } from "@finos/fdc3-sail-desktop-agent/browser"
import { createInMemoryTransportPair } from "@finos/fdc3-sail-desktop-agent/transports"

// Create linked transport pair
const [daTransport, wcpTransport] = createInMemoryTransportPair()

// Create Desktop Agent
const desktopAgent = new DesktopAgent({
  transport: daTransport,
  appLauncher: myAppLauncher,
  requestIntentResolution: myIntentResolver,
})

// Create WCP Connector
const wcpConnector = new WCPConnector(wcpTransport, {
  getIntentResolverUrl: () => false,
  getChannelSelectorUrl: () => false,
})

// Start both
desktopAgent.start()
wcpConnector.start()

FDC3 API Coverage

Context Management

  • broadcast() - Broadcast context to channel
  • addContextListener() - Listen for context on channels
  • getCurrentContext() - Get current context for channel

Channel Management

  • getCurrentChannel() - Get current user channel
  • joinUserChannel() - Join user channel
  • leaveCurrentChannel() - Leave current channel
  • getUserChannels() - Get available user channels
  • getOrCreateChannel() - Get or create app channel

Intent Management

  • raiseIntent() - Raise intent with optional target
  • raiseIntentForContext() - Raise intent by context type
  • addIntentListener() - Listen for specific intents
  • findIntent() - Find handlers for intent
  • findIntentsByContext() - Find intents for context type

App Management

  • getInfo() - Get desktop agent metadata
  • open() - Launch applications
  • findInstances() - Find running app instances
  • getAppMetadata() - Get app metadata from directory

Private Channels

  • createPrivateChannel() - Create private channels
  • Private channel context listeners
  • Private channel disconnect handling

Protocol Support

DACP (Desktop Agent Communication Protocol)

All FDC3 operations use DACP messages. The Desktop Agent handles:

Request Messages: broadcastRequest, raiseIntentRequest, addContextListenerRequest, joinUserChannelRequest, openRequest, findIntentRequest, etc.

Response Messages: Automatic response generation with proper error handling.

Event Messages: contextEvent, intentEvent, listenerEvent for async notifications.

WCP (Web Connection Protocol)

Browser app connection handshake:

  • WCP1Hello - App initiates connection
  • WCP3Handshake - Desktop Agent responds with MessagePort
  • WCP4ValidateAppIdentity - App validates identity
  • WCP5ValidateAppIdentityResponse - Desktop Agent confirms
  • WCP6Goodbye - App disconnects gracefully

Transport Interface

The Desktop Agent works with any transport implementing this interface:

interface Transport {
  send(message: unknown): void
  onMessage(handler: (message: unknown) => void): void
  onDisconnect(handler: () => void): void
  isConnected(): boolean
  getInstanceId(): string | null
  disconnect(): void
}

Built-in Transports:

  • InMemoryTransport - Same-process communication
  • MessagePortTransport - Browser MessagePort API

Platform SDK Transports:

  • SocketIOClientTransport - Browser to server
  • SocketIOServerTransport - Server-side Socket.IO

Testing

Running Tests

# Run Cucumber BDD tests
npm run test:cucumber --workspace=@finos/fdc3-sail-desktop-agent

# Run unit tests
npm run test --workspace=@finos/fdc3-sail-desktop-agent

# Type checking
npm run typecheck --workspace=@finos/fdc3-sail-desktop-agent

Test Architecture

Tests use a MockTransport that simulates DACP message flow:

// Tests send DACP messages directly to the transport
const message: RaiseIntentRequest = {
  type: 'raiseIntentRequest',
  meta: { source: { instanceId: 'app-1' }, ... },
  payload: { intent: 'ViewChart', context: {...} }
}

await mockTransport.receiveMessage(message)

// Verify responses
const responses = mockTransport.getMessagesByType('raiseIntentResponse')
expect(responses[0].payload.resolution).toBeDefined()

Development

Building

npm run build --workspace=@finos/fdc3-sail-desktop-agent

Key Design Principles

  1. Pure Core: DesktopAgent has zero browser/Node.js dependencies
  2. Transport Abstraction: All communication via Transport interface
  3. WCP in Browser Only: WCPConnector handles browser-specific concerns
  4. Message-Driven Cleanup: App disconnects flow through transport (WCP6Goodbye)

Adding New DACP Handlers

  1. Create handler in src/core/handlers/dacp/:
export function handleNewFeatureRequest(message: unknown, context: DACPHandlerContext): void {
  // Validate, process, send response
}
  1. Register in src/core/handlers/dacp/index.ts:
const handlerMap = {
  // ...existing handlers
  newFeatureRequest: newHandlers.handleNewFeatureRequest,
}
  1. Add Cucumber tests in test/features/ and test/step-definitions/.

Dependencies

Runtime

  • @finos/fdc3 - Official FDC3 types
  • @finos/fdc3-schema - FDC3 JSON schemas and type guards

Peer Dependencies

  • zod - Runtime validation (optional, for schema validation)

License

Apache-2.0

Related