Skip to content

Commit

Permalink
Merge pull request #17 from finos-labs/conformance
Browse files Browse the repository at this point in the history
Conformance
  • Loading branch information
robmoffat authored Jun 11, 2024
2 parents 4242e9c + 32bcd4e commit f8109b0
Show file tree
Hide file tree
Showing 67 changed files with 2,789 additions and 1,160 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ packages/testing/tsconfig.tsbuildinfo
**/coverage
.nyc_output
packages/da-server/generated
**/cucumber-report.html
14 changes: 14 additions & 0 deletions .release-it.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"git": {
"commitMessage": "chore: release v${version}"
},
"github": {
"release": false
},
"npm": {
"release": true
},
"publishConfig": {
"registry": "https://registry.npmjs.org"
}
}
83 changes: 47 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# FDC3 For The Web
# FDC3 For The Web

This is a minimal proof-of-concept for FDC3 For the Web.

Expand All @@ -12,6 +12,7 @@ This is a minimal proof-of-concept for FDC3 For the Web.
```
1. From the Command Line:
```
yarn install
yarn workspaces foreach --all install
Expand All @@ -20,48 +21,49 @@ This is a minimal proof-of-concept for FDC3 For the Web.
yarn dev
```
2. Point browser at http://localhost:8080/da/
2. Point browser at http://localhost:8080/da/
3. This is your dummy desktop agent, which has various apps you can launch.
3. This is your dummy desktop agent, which has various apps you can launch.
4. Launch the apps, press the button, watch messages pass between them.
4. Launch the apps, press the button, watch messages pass between them.
## What This Project Contains
The project is divided into several different yarn workspaces:
- `da-proxy`:
- `src`: This is an implementation of a client-side, typescript desktop agent proxy that communicates to a server backend using the APIs/JSON Schema defined in [Agent Bridging](https://fdc3.finos.org/docs/next/agent-bridging/spec). It is expected that we would standardize this and add to the FDC3 NPM module.
- `test`: This is some cucumber/gherkin tests that exercise the functionality in `src`. These are written to be language-agnostic so that we can use the same Gherkin feature files to test .net, Java, Python APIs too. These can be run with `yarn build`
- `da-proxy`:
- `src`: This is an implementation of a client-side, typescript desktop agent proxy that communicates to a server backend using the APIs/JSON Schema defined in [Agent Bridging](https://fdc3.finos.org/docs/next/agent-bridging/spec). It is expected that we would standardize this and add to the FDC3 NPM module.
- `test`: This is some cucumber/gherkin tests that exercise the functionality in `src`. These are written to be language-agnostic so that we can use the same Gherkin feature files to test .net, Java, Python APIs too. These can be run with `yarn build`
- `client`: This exports the `getClientAPI()` function which can be used to retrieve a desktop agent API via the web.
- `da-server`:
- `client`: This exports the `getClientAPI()` function which can be used to retrieve a desktop agent API via the web.
- `src`: A minimal implementation of the desktop-agent bridging protocol for handling messages between multiple connected sources.
- `test`: This is some cucumber/gherkin tests that exercise the functionality in `src`. These can be run with `yarn build`
- `da-server`:
- `src`: A minimal implementation of the desktop-agent bridging protocol for handling messages between multiple connected sources.
- `test`: This is some cucumber/gherkin tests that exercise the functionality in `src`. These can be run with `yarn build`
- `common` : Common APIs and functionality used by both `client` and `server`
- `common` : Common APIs and functionality used by both `client` and `server`
- `demo` : A bare-bones desktop agent implementation with a few apps that use WebFDC3. See: https://static.swimlanes.io/6bb69f2c9acdc0656f5f3b098d40518e.png for how this works. Basically, the implementation here is that it uses iframes approach and a server-side websocket to relay messages.
- `demo` : A bare-bones desktop agent implementation with a few apps that use WebFDC3. See: https://static.swimlanes.io/6bb69f2c9acdc0656f5f3b098d40518e.png for how this works. Basically, the implementation here is that it uses iframes approach and a server-side websocket to relay messages.
- `fdc3-workbench`: The FDC3 Workbench app from https://github.com/FDC3/toolbox/workbench, ported to use WebFDC3. Start with `yarn dev` and invoke from `demo`
- `fdc3-workbench`: The FDC3 Workbench app from https://github.com/FDC3/toolbox/workbench, ported to use WebFDC3. Start with `yarn dev` and invoke from `demo`
## Configuring the client
`getClientAPI` (in `index.ts`): Called (with options) by an FDC3 App to retrieve the API. This retrieves `details` from the desktop agent and initialises a `DesktopAgent` API implementation, returning it in a promise. There are various options available:
`getClientAPI` (in `index.ts`): Called (with options) by an FDC3 App to retrieve the API. This retrieves `details` from the desktop agent and initialises a `DesktopAgent` API implementation, returning it in a promise. There are various options available:
- `strategies`: This allows plugable strategies for getting the DA. Two exist:
- `electron-event` which waits for `window.fdc3` to be set and
- `post-message` which fires a post message up to the opening window/iframe (or whatever is set in the `frame` option) asking for details of how to construct a `DesktopAgent` API implementation.
- `frame` : when _not_ using a loaded iframe, you can begin communicating with a port on a particular frame. By default, opener or window, but you can pick something else if you want.
- `strategies`: This allows plugable strategies for getting the DA. Two exist:
- `electron-event` which waits for `window.fdc3` to be set and
- `post-message` which fires a post message up to the opening window/iframe (or whatever is set in the `frame` option) asking for details of how to construct a `DesktopAgent` API implementation.
- `frame` : when _not_ using a loaded iframe, you can begin communicating with a port on a particular frame. By default, opener or window, but you can pick something else if you want.
## Configuring Server
- **For the desktop agent**: `supply` (in `server/supply.ts`): Called by the desktop agent on startup, allows it to supply FDC3 APIs to apps when they ask for one via the `post-message` strategy. This takes the following parameters:
- A `checker`, which checks the origin window for the API request. It should be a window that the Desktop Agent is aware of.
- A `detailsResolver`s, which returns a map of properties to send to the API requestor (the app) that should be used to instantiate the API.
- A `portResolver` which is responsible for providing a `MessagePort` for the server and client to communicate over.
- **For the desktop agent**: `supply` (in `server/supply.ts`): Called by the desktop agent on startup, allows it to supply FDC3 APIs to apps when they ask for one via the `post-message` strategy. This takes the following parameters:
- A `checker`, which checks the origin window for the API request. It should be a window that the Desktop Agent is aware of.
- A `detailsResolver`s, which returns a map of properties to send to the API requestor (the app) that should be used to instantiate the API.
- A `portResolver` which is responsible for providing a `MessagePort` for the server and client to communicate over.
## Notes
Expand All @@ -71,15 +73,15 @@ The project is divided into several different yarn workspaces:
## Cross-Origin
- This supports cross-origin when using post message without iframes. (at least on my machine!) you can configure hostnames in `dummy-desktop-agent.ts` to try this out.
- This supports cross-origin when using post message without iframes. (at least on my machine!) you can configure hostnames in `dummy-desktop-agent.ts` to try this out.
- However, using the iframe mode (you can see this in the demo) will fail as chrome has restricted the SharedWorker when used with iframes (even of the same origin).
## TO-DO
- Fallback strategy in case FDC3 API isn't available (currently promise never resolves)
- Sanitisation of response from the Desktop Agent
- Handing of fdc3Ready
- Handling on intents, open, finishing test cases for `da` / `testing`
- Fallback strategy in case FDC3 API isn't available (currently promise never resolves)
- Sanitisation of response from the Desktop Agent
- Handing of fdc3Ready
- Handling on intents, open, finishing test cases for `da` / `testing`
## Troubleshooting
Expand All @@ -89,18 +91,27 @@ The project is divided into several different yarn workspaces:
- Desktop Agent Briding needs extending with types from `fdc3-common/index.ts`
- Move exchange into client, instead of common.
- How does the da-server tell the da-proxy about the channel metadata? We need a message to get the list of user channels from the server.
- How does the da-server tell the da-proxy about the channel metadata? We need a message to get the list of user channels from the server.
- How does the da-server decide on a desktop agent name (maybe it just has one?)
- AppChecker / AppDetailsResolver / AppPortResolver - this is all too complex.
= fdc3Ready timeout
= fdc3Ready timeout
- get it to work without desktop agent window running
- use cookie for the da id.
- add server tests for intent resolution choice
- handle disconnections from the server / update running apps
- test intent resolvers on different domains
- we shoulnd't be using meta for routing - check this.
- factor out test codes into module
- handle setting connected on the server context.
## Idea
Do we need to send a post-message to the server, if we have cookies? Couldn't we just hold the DA ID and the
address of the embed page in the cookie? Problem is, the cookie is scoped to the DA...
Do we need to send a post-message to the server, if we have cookies? Couldn't we just hold the DA ID and the
address of the embed page in the cookie? Problem is, the cookie is scoped to the DA...
## Releasing
```
yarn npm login
yarn workspaces foreach --all version 0.0.10 (or whatever)
yarn workspaces foreach --all npm publish --access=public

```
14 changes: 11 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
{
"name": "@finos/web-fdc3",
"name": "@kite9/web-fdc3",
"private": true,
"version": "0.0.0",
"version": "0.0.30",
"workspaces": [
"packages/*"
],
"scripts": {
"build": "yarn workspaces foreach --all run build"
"clean": "yarn workspaces foreach --all run clean",
"build": "yarn workspaces foreach --all run build",
"test": "yarn workspaces foreach --all run test"
},
"packageManager": "[email protected]",
"devDependencies": {
"typescript": "^5.3.2"
},
"publishConfig": {
"registry": "https://registry.npmjs.org"
},
"dependencies": {
"rimraf": "^5.0.7"
}
}
19 changes: 13 additions & 6 deletions packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
{
"name": "client",
"main": "src/index.ts",
"version": "0.0.0",
"name": "@kite9/client",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"version": "0.0.30",
"scripts": {
"build": "tsc -b"
"build": "tsc --module es2022",
"clean": "rimraf dist; rimraf cucumber-report.html; rimraf coverage"
},
"files": [
"dist"
],
"license": "Apache-2.0",
"dependencies": {
"@finos/fdc3": "^2.1.0-beta.4",
"@kite9/da-proxy": "workspace:*",
"@kite9/fdc3-common": "workspace:*",
"@types/uuid": "^9.0.7",
"da-proxy": "workspace:*",
"fdc3-common": "workspace:*",
"uuid": "^9.0.1"
},
"devDependencies": {
"rimraf": "^5.0.7",
"typescript": "^5.3.2"
}
}
5 changes: 3 additions & 2 deletions packages/client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { DesktopAgent } from '@finos/fdc3'
import { Options } from 'fdc3-common';
import { Options } from '@kite9/fdc3-common';
import postMessage from './strategies/post-message'
//import electronEvent from './strategies/electron-event'

export const DEFAULT_OPTIONS: Options = {
setWindowGlobal: false,
fireFdc3Ready: false,
strategies: [postMessage], //, electronEvent],
frame: window.opener ?? window.parent
frame: window.opener ?? window.parent,
middlewares: []
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AppIntent, IntentResult } from "@finos/fdc3";
import { Messaging } from "da-proxy";
import { IntentResolver, SingleAppIntent, IntentResolutionChoiceAgentResponse } from "fdc3-common";
import { Messaging } from "@kite9/da-proxy";
import { IntentResolver, SingleAppIntent, IntentResolutionChoiceAgentResponse } from "@kite9/fdc3-common";

/**
* Works with the desktop agent to provide a resolution to the intent choices.
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/messaging/MessagePortMessaging.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AppIdentifier } from "@finos/fdc3"
import { AbstractMessaging } from "da-proxy"
import { RegisterableListener } from "da-proxy/src/listeners/RegisterableListener"
import { exchangePostMessage } from "fdc3-common"
import { AbstractMessaging } from "@kite9/da-proxy"
import { RegisterableListener } from "@kite9/da-proxy/src/listeners/RegisterableListener"
import { exchangePostMessage } from "@kite9/fdc3-common"
import { v4 as uuidv4 } from "uuid"

export class MessagePortMessaging extends AbstractMessaging {
Expand Down
11 changes: 9 additions & 2 deletions packages/client/src/messaging/message-port.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DesktopAgent } from "@finos/fdc3";
import { BasicDesktopAgent, DefaultChannelSupport, DefaultAppSupport, DefaultIntentSupport, DefaultChannel, DefaultHandshakeSupport } from "da-proxy";
import { APIResponseMessage, FDC3_PORT_TRANSFER_RESPONSE_TYPE, FDC3_PORT_TRANSFER_REQUEST_TYPE, Options, exchangeForMessagePort, APIResponseMessageParentWindow, APIResponseMessageIFrame } from "fdc3-common"
import { BasicDesktopAgent, DefaultChannelSupport, DefaultAppSupport, DefaultIntentSupport, DefaultChannel, DefaultHandshakeSupport } from "@kite9/da-proxy";
import { APIResponseMessage, FDC3_PORT_TRANSFER_RESPONSE_TYPE, Options, exchangeForMessagePort, APIResponseMessageIFrame } from "@kite9/fdc3-common"
import { MessagePortMessaging } from "./MessagePortMessaging";
import { DesktopAgentIntentResolver } from "../intent-resolution/DesktopAgentIntentResolver";

Expand Down Expand Up @@ -72,6 +72,13 @@ function buildUserChannelState(messaging: MessagePortMessaging) {
new DefaultChannel(messaging, "one", "user", {
color: "red",
name: "THE RED CHANNEL"
}),
new DefaultChannel(messaging, "two", "user", {
color: "blue",
name: "THE BLUE CHANNEL"
}), new DefaultChannel(messaging, "two", "user", {
color: "green",
name: "THE GREEN CHANNEL"
})
]
}
4 changes: 2 additions & 2 deletions packages/client/src/strategies/electron-event.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DesktopAgent, fdc3Ready } from "@finos/fdc3";
import { Loader, Options } from "fdc3-common";
import { Loader, Options } from "@kite9/fdc3-common";

/**
* This approach will resolve the loader promise if the fdc3Ready event occurs.
Expand All @@ -11,7 +11,7 @@ const loader: Loader = (_options: Options) => {
fdc3Ready().then(() => {
resolve(window.fdc3);
})

});

return out;
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/strategies/post-message.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DesktopAgent } from '@finos/fdc3'
import { APIResponseMessage, Loader, Options, FDC3_API_RESPONSE_MESSAGE_TYPE, FDC3_API_REQUEST_MESSAGE_TYPE } from 'fdc3-common'
import { APIResponseMessage, Loader, Options, FDC3_API_RESPONSE_MESSAGE_TYPE, FDC3_API_REQUEST_MESSAGE_TYPE } from '@kite9/fdc3-common'
import { messagePortInit } from '../messaging/message-port';

const loader: Loader = (options: Options) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.root.json",
"compilerOptions": {
"rootDir": "src",
"rootDirs": [ "src", "test" ],
"outDir": "dist",
},
"include": [
Expand Down
2 changes: 1 addition & 1 deletion packages/da-proxy/cucumber.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
default:
format:
- html:dist/cucumber-report.html
- html:cucumber-report.html
- "@cucumber/pretty-formatter"
paths:
- test/features/*.feature
Expand Down
19 changes: 13 additions & 6 deletions packages/da-proxy/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
{
"name": "da-proxy",
"main": "src/index.ts",
"name": "@kite9/da-proxy",
"version": "0.0.30",
"files": [
"dist"
],
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"scripts": {
"build": "nyc --reporter=lcov --reporter=text cucumber-js",
"b2": "tsx cucumber-js"
"build": "tsc --module es2022",
"test": "tsc; nyc --reporter=lcov --reporter=text cucumber-js",
"clean": "rimraf dist; rimraf cucumber-report.html; rimraf coverage; rimraf .nyc_output; rimraf node_modules"
},
"dependencies": {
"@finos/fdc3": "^2.1.0-beta.6",
"tsx": "^4.7.1"
"@kite9/fdc3-common": "workspace:*"
},
"devDependencies": {
"@cucumber/cucumber": "10.3.1",
Expand All @@ -25,12 +31,13 @@
"eslint-plugin-import": "2.22.1",
"eslint-plugin-prettier": "3.3.1",
"expect": "^29.7.0",
"fdc3-common": "workspace:*",
"is-ci": "2.0.0",
"jsonpath-plus": "^7.2.0",
"nyc": "15.1.0",
"prettier": "2.2.1",
"rimraf": "^5.0.7",
"ts-node": "^10.9.2",
"tsx": "^4.7.1",
"typescript": "^5.3.2",
"uuid": "^9.0.1"
}
Expand Down
Loading

0 comments on commit f8109b0

Please sign in to comment.