From 1cf75c282df7d5b64a4696cf1d29db13cd2f8b90 Mon Sep 17 00:00:00 2001 From: Kris West Date: Thu, 19 May 2022 15:10:24 +0100 Subject: [PATCH 1/8] Allow an App to retrieve its own metadata through getInfo() --- CHANGELOG.md | 1 + docs/api/ref/DesktopAgent.md | 137 ++++++++++++++++++------------ docs/api/ref/Metadata.md | 20 ++++- docs/api/spec.md | 97 ++++++++++++++------- src/api/ImplementationMetadata.ts | 5 ++ 5 files changed, 172 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 863dc38ac..e13ab93ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Added details of FDC3's existing versioning and deprecation policies to the FDC3 compliance page ([#539](https://github.com/finos/FDC3/pull/539)) * Added a new experimental features policy, which exempts features designated as experimental from the versioning and deprecation policies, to the FDC3 compliance page ([#549](https://github.com/finos/FDC3/pull/549)) * Add `IntentDeliveryFailed` to the `ResolveError` enumeration to be used when delivery of an intent and context to a targetted app or instance fails. ([#601](https://github.com/finos/FDC3/pull/601)) +* Added the current app's `AppMetadata` to the `ImplementationMetadata` returned by `fdc3.getInfo()` allowing an app to retrieve its own metadata, according to the desktop agent ([#726](https://github.com/finos/FDC3/pull/726)) ### Changed * Consolidated `Listener` documentation with other types ([#404](https://github.com/finos/FDC3/pull/404)) diff --git a/docs/api/ref/DesktopAgent.md b/docs/api/ref/DesktopAgent.md index ab0b6e1f6..dc3c2ea34 100644 --- a/docs/api/ref/DesktopAgent.md +++ b/docs/api/ref/DesktopAgent.md @@ -68,11 +68,13 @@ addContextListener(contextType: string | null, handler: ContextHandler): Promise */ addContextListener(handler: ContextHandler): Promise; ``` -Adds a listener for incoming context broadcasts from the Desktop Agent. If the consumer is only interested in a context of a particular type, they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types. + +Adds a listener for incoming context broadcasts from the Desktop Agent. If the consumer is only interested in a context of a particular type, they can specify that type. If the consumer is able to receive context of any type or will inspect types received, then they can pass `null` as the `contextType` parameter to receive all context types. Context broadcasts are only received from apps that are joined to the same User Channel as the listening application, hence, if the application is not currently joined to a User Channel no broadcasts will be received. If this function is called after the app has already joined a channel and the channel already contains context that would be passed to the context listener, then it will be called immediately with that context. #### Examples + ```js // any context const listener = await fdc3.addContextListener(null, context => { ... }); @@ -82,12 +84,11 @@ const contactListener = await fdc3.addContextListener('fdc3.contact', contact => ``` #### See also + * [`Listener`](Types#listener) * [`Context`](Types#context) * [`ContextHandler`](Types#contexthandler) - - ### `addIntentListener` ```ts @@ -140,13 +141,12 @@ fdc3.addIntentListener("QuoteStream", async (context) => { ``` #### See also + * [`PrivateChannel`](PrivateChannel) * [`Listener`](Types#listener) * [`Context`](Types#context) * [`IntentHandler`](Types#intenthandler) - - ### `broadcast` ```ts @@ -160,6 +160,7 @@ DesktopAgent implementations should ensure that context messages broadcast to a If you are working with complex context types composed of other simpler types (as recommended by the [Context Data specification](../../context/spec#assumptions)) then you should broadcast each individual type (starting with the simpler types, followed by the complex type) that you want other apps to be able to respond to. Doing so allows applications to filter the context types they receive by adding listeners for specific context types. #### Example + ```js const instrument = { type: 'fdc3.instrument', @@ -170,7 +171,9 @@ const instrument = { fdc3.broadcast(instrument); ``` + #### See also + * [addContextListener](#addcontextlistener) ### `findInstances` @@ -186,6 +189,7 @@ If there are no instances of the specified application the returned promise shou If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration. ### Example + ```js // Retrieve a list of instances of an application let instances = await fdc3.findInstances({name: "MyApp"}); @@ -194,7 +198,6 @@ let instances = await fdc3.findInstances({name: "MyApp"}); let resolution = fdc3.raiseIntent("ViewInstrument", context, instances[0]); ``` - ### `findIntent` ```ts @@ -210,7 +213,9 @@ This can be used to raise the intent against a specific app or app instance. If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration. Result types may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. + #### Examples + I know 'StartChat' exists as a concept, and want to know which apps can resolve it: ```js @@ -243,6 +248,7 @@ const appIntent = await fdc3.findIntent("StartChat"); ``` An optional input context object and/or `resultType` argument may be specified, which the resolver MUST use to filter the returned applications such that each supports the specified input and result types. + ```js const appIntent = await fdc3.findIntent("StartChat", contact); @@ -268,6 +274,7 @@ const appIntent = await fdc3.findIntent("QuoteStream", instrument, "channel"`. If intent resolution to an app returning a channel is requested, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. #### Example + I have a context object, and I want to know what I can do with it, hence, I look for intents and apps to resolve them... - + ```js const appIntents = await fdc3.findIntentsByContext(context); @@ -334,18 +342,17 @@ await fdc3.raiseIntent(startChat.intent.name, context, selectedApp); ``` #### See also + * [`findIntent()`](#findintent) * [`ResolveError`](Errors#resolveerror) - - ### `getCurrentChannel` ```ts getCurrentChannel() : Promise; ``` -Optional function that returns the `Channel` object for the current User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the desktop agent, rather than calling this function directly. +Optional function that returns the `Channel` object for the current User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the desktop agent, rather than calling this function directly. Returns `null` if the app is not joined to a channel. @@ -357,9 +364,8 @@ let current = await fdc3.getCurrentChannel(); ``` #### See also -* [`Channel`](Channel) - +* [`Channel`](Channel) ### `getInfo` @@ -367,7 +373,7 @@ let current = await fdc3.getCurrentChannel(); getInfo(): Promise; ``` -Retrieves information about the FDC3 Desktop Agent implementation, such as the implemented version of the FDC3 specification and the name of the implementation provider. +Retrieves information about the FDC3 Desktop Agent implementation, including the supported version of the FDC3 specification, the name of the provider of the implementation, its own version number and the metadata of the calling application according to the Desktop Agent. Returns an [`ImplementationMetadata`](Metadata#implementationmetadata) object. This metadata object can be used to vary the behavior of an application based on the version supported by the Desktop Agent and for logging purposes. @@ -383,8 +389,18 @@ if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), "1.2")) { } ``` +The `ImplementationMetadata` object returned also includes the metadata for the calling application, according to the desktop agent. This allows the application to retrieve its own `appId`, `instanceId` and other details, e.g.: + +```js +let implMetadata = await fdc3.getInfo(); +let {appId, instanceId} = impleMetadata.appMetadata; + +``` + #### See also + * [`ImplementationMetadata`](Metadata#implementationmetadata) +* [`AppMetadata`](Metadata#appmetadata) ### `getOrCreateChannel` @@ -408,14 +424,15 @@ catch (err){ ``` #### See also -* [`Channel`](Channel) + +* [`Channel`](Channel) ### `createPrivateChannel` ```ts createPrivateChannel(): Promise; ``` - + Returns a `Channel` with an auto-generated identity that is intended for private communication between applications. Primarily used to create channels that will be returned to other applications via an IntentResolution for a raised intent. If the `PrivateChannel` cannot be created, the returned promise MUST be rejected with an error string from the [`ChannelError`](Errors#channelerror) enumeration. @@ -423,50 +440,52 @@ If the `PrivateChannel` cannot be created, the returned promise MUST be rejected The `PrivateChannel` type is provided to support synchronisation of data transmitted over returned channels, by allowing both parties to listen for events denoting subscription and unsubscription from the returned channel. `PrivateChannels` are only retrievable via raising an intent. It is intended that Desktop Agent implementations: -- SHOULD restrict external apps from listening or publishing on this channel. -- MUST prevent `PrivateChannels` from being retrieved via fdc3.getOrCreateChannel. -- MUST provide the `id` value for the channel as required by the `Channel` interface. +* SHOULD restrict external apps from listening or publishing on this channel. +* MUST prevent `PrivateChannels` from being retrieved via fdc3.getOrCreateChannel. +* MUST provide the `id` value for the channel as required by the `Channel` interface. #### Example ```js fdc3.addIntentListener("QuoteStream", async (context) => { - const channel = await fdc3.createPrivateChannel(); - const symbol = context.id.ticker; - - // This gets called when the remote side adds a context listener - const addContextListener = channel.onAddContextListener((contextType) => { - // broadcast price quotes as they come in from our quote feed - feed.onQuote(symbol, (price) => { - channel.broadcast({ type: "price", price}); - }); - }); - - // This gets called when the remote side calls Listener.unsubscribe() - const unsubscriberListener = channel.onUnsubscribe((contextType) => { - feed.stop(symbol); - }); - - // This gets called if the remote side closes - const disconnectListener = channel.onDisconnect(() => { - feed.stop(symbol); - }); - - return channel; + const channel = await fdc3.createPrivateChannel(); + const symbol = context.id.ticker; + + // This gets called when the remote side adds a context listener + const addContextListener = channel.onAddContextListener((contextType) => { + // broadcast price quotes as they come in from our quote feed + feed.onQuote(symbol, (price) => { + channel.broadcast({ type: "price", price}); + }); + }); + + // This gets called when the remote side calls Listener.unsubscribe() + const unsubscriberListener = channel.onUnsubscribe((contextType) => { + feed.stop(symbol); + }); + + // This gets called if the remote side closes + const disconnectListener = channel.onDisconnect(() => { + feed.stop(symbol); + }); + + return channel; }); ``` #### See also -* [`PrivateChannel`](PrivateChannel) -* [`raiseIntent`](#raiseintent) -* [`addIntentListener`](#addintentlistener) + +* [`PrivateChannel`](PrivateChannel) +* [`raiseIntent`](#raiseintent) +* [`addIntentListener`](#addintentlistener) ### `getUserChannels` + ```ts getUserChannels() : Promise>; ``` -Retrieves a list of the User Channels available for the app to join. +Retrieves a list of the User Channels available for the app to join. #### Example @@ -476,9 +495,11 @@ const redChannel = userChannels.find(c => c.id === 'red'); ``` #### See also + * [`Channel`](Channel) ### `getSystemChannels` + ```ts /** * @deprecated Use `getUserChannels` instead. @@ -487,7 +508,9 @@ getSystemChannels() : Promise>; ``` Alias to the [`getUserChannels`](#getuserchannels) function provided for backwards compatibility with version 1.1 & 1.2 of the FDC3 standard. + #### See also + * [`getUserChannels`](#getuserchannels) ### `joinUserChannel` @@ -498,7 +521,7 @@ joinUserChannel(channelId: string) : Promise; Optional function that joins the app to the specified User channel. In most cases, applications SHOULD be joined to channels via UX provided to the application by the desktop agent, rather than calling this function directly. -If an app is joined to a channel, all `fdc3.broadcast` calls will go to the channel, and all listeners assigned via `fdc3.addContextListener` will listen on the channel. +If an app is joined to a channel, all `fdc3.broadcast` calls will go to the channel, and all listeners assigned via `fdc3.addContextListener` will listen on the channel. If the channel already contains context that would be passed to context listeners added via `fdc3.addContextListener` then those listeners will be called immediately with that context. @@ -518,9 +541,10 @@ const channels = await fdc3.getUserChannels(); fdc3.joinUserChannel(selectedChannel.id); ``` + #### See also -* [`getUserChannels`](#getuserchannels) +* [`getUserChannels`](#getuserchannels) ### `joinChannel` @@ -530,11 +554,12 @@ fdc3.joinUserChannel(selectedChannel.id); */ joinChannel(channelId: string) : Promise; ``` + Alias to the [`joinUserChannel`](#joinuserchannel) function provided for backwards compatibility with version 1.1 & 1.2 of the FDC3 standard. #### See also -* [`joinUserChannel`](#joinuserchannel) +* [`joinUserChannel`](#joinuserchannel) ### `leaveCurrentChannel` @@ -560,8 +585,6 @@ redChannel.addContextListener(null, channelListener); ``` - - ### `open` ```ts @@ -581,6 +604,7 @@ Returns an [`AppMetadata`](Metadata#appmetadata) object with the `instanceId` fi If opening errors, it returns an `Error` with a string from the [`OpenError`](Errors#openerror) enumeration. #### Example + ```js // Open an app without context, using the app name let instanceMetadata = await fdc3.open('myApp'); @@ -594,6 +618,7 @@ let instanceMetadata = await fdc3.open(appMetadata, context); ``` #### See also + * [`Context`](Types#context) * [`TargetApp`](Types#targetapp) * [`AppMetadata`](Metadata#appmetadata) @@ -604,7 +629,8 @@ let instanceMetadata = await fdc3.open(appMetadata, context); ```ts raiseIntent(intent: string, context: Context, app?: TargetApp): Promise; ``` -Raises a specific intent for resolution against apps registered with the desktop agent. + +Raises a specific intent for resolution against apps registered with the desktop agent. The desktop agent MUST resolve the correct app to target based on the provided intent name and context data. If multiple matching apps are found, a method for resolving the intent to a target app, such as presenting the user with a resolver UI allowing them to pick an app, SHOULD be provided. Alternatively, the specific app or app instance to target can also be provided. A list of valid target applications and instances can be retrieved via [`findIntent`](DesktopAgent#findintent). @@ -613,7 +639,7 @@ If a target app for the intent cannot be found with the criteria provided or the If you wish to raise an intent without a context, use the `fdc3.nothing` context type. This type exists so that apps can explicitly declare support for raising an intent without context. -Returns an [`IntentResolution`](Metadata#intentresolution) object with details of the app instance that was selected (or started) to respond to the intent. +Returns an [`IntentResolution`](Metadata#intentresolution) object with details of the app instance that was selected (or started) to respond to the intent. Issuing apps may optionally wait on the promise that is returned by the `getResult()` member of the IntentResolution. This promise will resolve when the _receiving app's_ intent handler function returns and resolves a promise. The Desktop Agent resolves the issuing app's promise with the Context object or Channel that is provided as resolution by the receiving app. The Desktop Agent MUST reject the issuing app's promise, with a string from the [`ResultError`](Errors#resulterror) enumeration, if: (1) the intent handling function's returned promise rejects, (2) the intent handling function doesn't return a promise, or (3) the returned promise resolves to an invalid type. @@ -649,7 +675,9 @@ try { console.error(`${resolution.source} returned a result error: ${error}`); } ``` + #### See also + * [`Context`](Types#context) * [`TargetApp`](Types#targetapp) * [`IntentResult`](Types#intentresult) @@ -665,14 +693,14 @@ raiseIntentForContext(context: Context, app?: TargetApp): Promise; } ``` + An interface that represents the binding of an intent to apps, returned as part of intent disocvery. For each intent, it reference the applications that support that intent. #### See also + * [`AppMetadata`](#appmetadata) * [`IntentMetadata`](#intentmetadata) * [`DesktopAgent.findIntent`](DesktopAgent#findintent) @@ -72,12 +74,12 @@ Optionally, extra information from the app directory can be returned, to aid in In situations where a desktop agent connects to multiple app directories or multiple versions of the same app exists in a single app directory, it may be necessary to specify `appId` or `version` to target applications that share the same name. #### See also + * [`AppIntent.apps`](#appintent) * [`Icon`](Types#icon) * [`DesktopAgent.findIntent`](DesktopAgent#findintent) * [`DesktopAgent.raiseIntent`](DesktopAgent#raiseintent) - ## `DisplayMetadata` ```ts @@ -100,6 +102,7 @@ interface DisplayMetadata { A desktop agent (typically for _system_ channels) may want to provide additional information about how a channel can be represented in a UI. A common use case is for color linking. #### See also + * [`Channel`](Channel) * [`DesktopAgent.getUserChannels`](DesktopAgent#getuserchannels) @@ -111,16 +114,23 @@ interface ImplementationMetadata { * The string must be a numeric semver version, e.g. 1.2 or 1.2.1. */ readonly fdc3Version: string; + /** The name of the provider of the FDC3 Desktop Agent Implementation (e.g. Finsemble, Glue42, OpenFin etc.). */ readonly provider: string; + /** The version of the provider of the FDC3 Desktop Agent Implementation (e.g. 5.3.0). */ readonly providerVersion?: string; + + /** The calling application instance's own metadata, according to the Desktop Agent (MUST include at least the `appId` and `instanceId`). */ + readonly appMetadata: AppMetadata; } ``` -Metadata relating to the FDC3 [DesktopAgent](DesktopAgent) object and its provider, including the supported version of the FDC3 specification and the name of the provider of the implementation. +Metadata relating to the FDC3 [DesktopAgent](DesktopAgent) object and its provider, including the supported version of the FDC3 specification, the name of the provider of the implementation, its own version number and the metadata of the calling application according to the Desktop Agent. #### See also + +* [`AppMetadata`](#appmetadata) * [`DesktopAgent.getInfo`](DesktopAgent#getinfo) ## `IntentMetadata` @@ -136,8 +146,8 @@ interface IntentMetadata { The interface used to describe an intent within the platform. - #### See also + * [`AppIntent.intent`](#appintent) ## `IntentResolution` @@ -182,6 +192,7 @@ interface IntentResolution { IntentResolution provides a standard format for data returned upon resolving an intent. #### Examples + ```js //resolve a "Chain" type intent let resolution = await agent.raiseIntent("intentName", context); @@ -199,7 +210,7 @@ catch (err) { ... } //resolve a "Client-Service" type intent with a data or channel response let resolution = await agent.raiseIntent("intentName", context); try { - const result = await resolution.getResult(); + const result = await resolution.getResult(); if (result && result.broadcast) { //detect whether the result is Context or a Channel console.log(`${resolution.source} returned a channel with id ${result.id}`); } else if (result){ @@ -213,6 +224,7 @@ try { ``` #### See also + * [`DesktopAgent.raiseIntent`](DesktopAgent#raiseintent) * [`DesktopAgent.raiseIntentForContext`](DesktopAgent#raiseintentforcontext) * [`TargetApp`](Types#targetapp) diff --git a/docs/api/spec.md b/docs/api/spec.md index f1812b2f4..5e84edeab 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -9,7 +9,9 @@ The role of FDC3 API is to establish a baseline interface for interoperability b The following sections examine the API's use-cases and core concepts. The APIs a fully defined in both subsequent pages of this Part and a full set of TypeScript definitions in the [src](https://github.com/finos/FDC3/tree/master/src/api) directory of the [FDC3 GitHub repository](https://github.com/finos/FDC3/). ## Components + ### Desktop Agent + A Desktop Agent is a desktop component (or aggregate of components) that serves as a launcher and message router (broker) for applications in its domain. A Desktop Agent can be connected to one or more App Directories and will use directories for application identity and discovery. Typically, a Desktop Agent will contain the proprietary logic of a given platform, handling functionality like explicit application interop workflows where security, consistency, and implementation requirements are proprietary. Examples of Desktop Agents include: @@ -23,17 +25,21 @@ Examples of Desktop Agents include: An FDC3-compliant Desktop Agent exposes an FDC3 standard API to applications they have launched. When an App is launched by a Desktop Agent and is given access to the Agent's API to interoperate, it is running in that Desktop Agent's *context*. ### Application + An application is any endpoint on the desktop that is: + - Registered with/known by a Desktop Agent - Launchable by a Desktop Agent - Addressable by a Desktop Agent -Examples of End Points include: +Examples of endpoint include: + - Native Applications - Web Applications - Headless “services” running on the desktop ## Desktop Agent Implementation + The FDC3 API specification consists of interfaces. It is expected that each Desktop Agent will implement these interfaces. A typical implemention would provide instantiable classes for the following interfaces: - [`DesktopAgent`](ref/DesktopAgent) @@ -57,6 +63,7 @@ Other interfaces defined in the spec are not critical to define as concrete type - [`TargetApp`](ref/Types#targetapp) ### API Access + The FDC3 API can be made available to an application through a number of different methods. In the case of web applications, a Desktop Agent MUST provide the FDC3 API via a global accessible as `window.fdc3`. Implementors MAY additionally make the API available through modules, imports, or other means. The global `window.fdc3` must only be available after the API is ready to use. To enable applications to avoid using the API before it is ready, implementors MUST provide a global `fdc3Ready` event that is fired when the API is ready for use. Implementations should first check for the existence of the FDC3 API and add a listener for this event if it is not found: @@ -74,11 +81,13 @@ if (window.fdc3) { ``` ### Standards vs. Implementation + ![Desktop Agent - Standards Schematic](assets/api-1.png) The surface area of FDC3 standardization (shown in *white* above) itself is quite small in comparison to the extent of a typical desktop agent implementation (in *grey*). For example: + - workspace management - user identity and SSO - entitlements @@ -87,6 +96,7 @@ For example: Are all areas of functionality that any feature complete desktop agent would implement, but are not currently areas considered for standardization under FDC3. ### Inter-Agent Communication + A goal of FDC3 standards is that applications running in different Desktop Agent contexts on the same desktop would be able to interoperate. And that one Desktop Agent context would be able to discover and launch an application in another Desktop Application context. ![Desktop Agent - Interop](assets/api-2.png) @@ -98,6 +108,7 @@ An actual connection protocol between Desktop Agents is not currently available ## Functional Use Cases ### Retrieve Metadata about the Desktop Agent implementation + From version 1.2 of the FDC3 specification, Desktop Agent implementations MUST provide a `fdc3.getInfo()` function to allow apps to retrieve information about the version of the FDC3 specification supported by a Desktop Agent implementation and the name of the implementation provider. This metadata can be used to vary the behavior of an application based on the version supported by the Desktop Agent, e.g.: ```js @@ -110,12 +121,21 @@ if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), '1.2')) { } ``` +The `ImplementationMetadata` object returned also includes the metadata for the calling application, according to the desktop agent. This allows the application to retrieve its own `appId`, `instanceId` and other details, e.g.: + +```js +let implMetadata = await fdc3.getInfo(); +let {appId, instanceId} = impleMetadata.appMetadata; + +``` + ### Open an Application by Name -Linking from one application to another is a critical basic workflow that the web revolutionized via the hyperlink. Supporting semantic addressing of applications across different technologies and platform domains greatly reduces friction in linking different applications into a single workflow. +Linking from one application to another is a critical basic workflow that the web revolutionized via the hyperlink. Supporting semantic addressing of applications across different technologies and platform domains greatly reduces friction in linking different applications into a single workflow. ### Requesting Functionality From Another App -Often, we want to link from one app to another to dynamically create a workflow. Enabling this without requiring prior knowledge between apps is a key goal of FDC3 and is implemented via the raising of [intents](../intents/spec), which represent a desired action, to be performed with a [context](../context/spec) supplied as input. + +Often, we want to link from one app to another to dynamically create a workflow. Enabling this without requiring prior knowledge between apps is a key goal of FDC3 and is implemented via the raising of [intents](../intents/spec), which represent a desired action, to be performed with a [context](../context/spec) supplied as input. Intents provide a way for an app to request functionality from another app and defer the discovery and launching of the destination app to the Desktop Agent. There are multiple models for interop that intents can support. @@ -124,23 +144,27 @@ Intents provide a way for an app to request functionality from another app and d - **Remote API**: An app wants to remote an entire API that it owns to another App. In this case, the API for the App cannot be standardized. However, the FDC3 API can address how an App connects to another App in order to get access to a proprietary API. ### Send/broadcast Context + On the financial desktop, applications often want to broadcast [context](../context/spec) to any number of applications. Context sharing needs to support different groupings of applications, which is supported via the concept of 'channels', over which context is broadcast and received by other applications listening to the channel. In some cases, an application may want to communicate with a single application or service and to prevent other applications from participating in the communication. For single transactions, this can instead be implemented via a raised intent, which will be delivered to a single application that can, optionally, respond with data. Alternatively, it may instead respond with a [`Channel`](ref/Channel) or [`PrivateChannel`](ref/PrivateChannel) over which a stream of responses or a dialog can be supported. ## Raising Intents -Raising an Intent is a method for an application to request functionality from another application and, if desired, defer the discovery and launching of the destination app to the Desktop Agent. + +Raising an Intent is a method for an application to request functionality from another application and, if desired, defer the discovery and launching of the destination app to the Desktop Agent. ### Intents and Context + When raising an intent a specific context is provided as input. The type of the provided context may determine which applications can resolve the intent. -A context type may also be associated with multiple intents. For example, an `fdc3.instrument` could be associated with `ViewChart`, `ViewNews`, `ViewAnalysis` or other intents. +A context type may also be associated with multiple intents. For example, an `fdc3.instrument` could be associated with `ViewChart`, `ViewNews`, `ViewAnalysis` or other intents. To raise an Intent without a context, use the [`fdc3.nothing`](../context/ref/Nothing) context type. This type exists so that applications can explicitly declare that they support raising an intent without a context (when registering an Intent listener or in an App Directory). As an alternative to raising a specific intent, you may also raise an unspecified intent with a known context allowing the Desktop Agent or the user (if the intent is ambiguous) to select the appropriate intent and then to raise it with the specified context for resolution. ### Intent Results + An optional [`IntentResult`](ref/Types#intentresult) may also be returned as output by an application handling an intent. Results maybe either a single `Context` object, or a `Channel` that may be used to send a stream of responses. The [`PrivateChannel`](ref/PrivateChannel) type is provided to support synchronisation of data transmitted over returned channels, by allowing both parties to listen for events denoting subscription and unsubscription from the returned channel. `PrivateChannels` are only retrievable via [raising an intent](ref/DesktopAgent#raiseintent). For example, an application handling a `CreateOrder` intent might return a context representing the order and including an ID, allowing the application that raised the intent to make further calls using that ID. @@ -148,6 +172,7 @@ For example, an application handling a `CreateOrder` intent might return a conte An optional result type is also supported when programmatically resolving an intent via [`findIntent`](ref/DesktopAgent#findintent) or [`findIntentByContext`](ref/DesktopAgent#findintentbycontext). ### Resolvers + Successful delivery of an intent depends first upon the Desktop Agent's ability to "resolve the intent" (i.e. map the intent to a specific App instance). Where the target application is ambiguous (because there is more than one application that could resolve the intent and context) Desktop Agents may resolve intents by any suitable methodology. A common method is to display a UI that allows the user to pick the desired App from a list of those that will accept the intent and context. Alternatively, the app issuing the intent may proactively handle resolution by calling [`findIntent`](ref/DesktopAgent#findintent) or [`findIntentByContext`](ref/DesktopAgent#findintentbycontext) and then raise the intent with a specific target application, e.g.: ```js @@ -189,22 +214,26 @@ const appIntents = await fdc3.findIntentByContext(context); await fdc3.raiseIntent(appIntent[0].intent, context, appIntent[0].apps[0]); ``` -Result context types requested are represented by their type name. A channel may be requested by passing the string `"channel"` or a channel that returns a specific type via the syntax `"channel"`, e.g. `"channel"`. Requesting intent resolution to an app returning a channel MUST include apps that are registered as returning a channel with a specific type. +Result context types requested are represented by their type name. A channel may be requested by passing the string `"channel"` or a channel that returns a specific type via the syntax `"channel"`, e.g. `"channel"`. Requesting intent resolution to an app returning a channel MUST include apps that are registered as returning a channel with a specific type. ### Intent Resolution + Raising an intent will return a Promise-type object that will resolve/reject based on a number of factors. #### Resolve + - Intent was resolved unambiguously and the receiving app was launched successfully (if necessary). - Intent was ambiguous, a resolution was chosen by the end user, and the chosen application was launched successfully. #### Reject + - No app matching the intent and context (if specified) was found. - A match was found, but the receiving app failed to launch. - The intent was ambiguous and the resolver experienced an error. #### Resolution Object -If the raising of the intent resolves (or rejects), a standard [`IntentResolution`](ref/Metadata#intentresolution) object will be passed into the resolver function with details of the application that resolved the intent and the means to access any results subsequently returned. + +If the raising of the intent resolves (or rejects), a standard [`IntentResolution`](ref/Metadata#intentresolution) object will be passed into the resolver function with details of the application that resolved the intent and the means to access any results subsequently returned. For example, to raise a specific intent: @@ -228,6 +257,7 @@ catch (err){ ... } ``` Use metadata about the resolving app instance to target a further intent + ```js try { const resolution = await fdc3.raiseIntent('StageOrder', context); @@ -240,6 +270,7 @@ catch (err) { ... } ``` Raise an intent and retrieve either data or a channel from the IntentResolution: + ```js let resolution = await agent.raiseIntent("intentName", context); try { @@ -258,50 +289,53 @@ try { ``` ### Register an Intent Handler + Applications need to let the system know the intents they can support. Typically, this is done via registration with an [App Directory](../app-directory/spec). It is also possible for intents to be registered at the application level as well to support ad-hoc registration which may be helpful at development time. Although dynamic registration is not part of this specification, a Desktop Agent agent may choose to support any number of registration paths. When an instance of an application is launched, it is expected to add an [`IntentHandler`](ref/Types#intenthandler) function to the desktop agent for each intent it has registered by calling the [`fdc3.addIntentListener`](ref/DesktopAgent#addintentlistener) function of the Desktop Agent. Doing so allows the Desktop Agent to pass incoming intents and contexts to that instance of the application. Hence, if the application instance was spawned in response to the raised intent, then the Desktop Agent must wait for the relevant intent listener to be added by that instance, before it can deliver the intent and context to it. In order to facilitate accurate error responses, calls to `fdc3.raiseIntent` should not return an `IntentResolution` until the intent handler has been added and the intent delivered to the target app. #### Compliance with Intent Standards + Intents represent a contract with expected behaviour if an app asserts that it supports the intent. Where this contract is enforceable by schema (for example, return object types), the FDC3 API implementation SHOULD enforce compliance and return an error if the interface is not met. It is expected that App Directories SHOULD also curate listed apps and ensure that they are complying with declared intents. - ## Context Channels Context channels allows a set of apps to share a stateful piece of data between them, and be alerted when it changes. Use cases for channels include color linking between applications to automate the sharing of context and topic based pub/sub such as theme. ### Types of Channel + There are three types of channels, which have different visibility and discoverability semantics: -1. **_User channels_**, which: - * facilitate the creation of user-controlled context links between applications (often via the selection of a color channel), - * are created and named by the desktop agent, - * are discoverable (via the [`getUserChannels()`](ref/DesktopAgent#getuserchannels) API call), - * can be 'joined' (via the [`joinUserChannel()`](ref/DesktopAgent#joinuserchannel) API call). +1. ***User channels***, which: + - facilitate the creation of user-controlled context links between applications (often via the selection of a color channel), + - are created and named by the desktop agent, + - are discoverable (via the [`getUserChannels()`](ref/DesktopAgent#getuserchannels) API call), + - can be 'joined' (via the [`joinUserChannel()`](ref/DesktopAgent#joinuserchannel) API call). > **Note:** Prior to FDC3 2.0, 'user' channels were known as 'system' channels. They were renamed in FDC3 2.0 to reflect their intended usage, rather than the fact that they are created by system (which could also create 'app' channels). > **Note:** Earlier versions of FDC3 included the concept of a 'global' system channel which was deprecated in FDC3 1.2 and removed in FDC3 2.0. -2. **_App channels_**, which: - * facilitate developer controlled messaging between applications, - * are created and named by applications (via the [`getOrCreateChannel()`](ref/DesktopAgent#getorcreatechannel) API call), - * are not discoverable, - * are interacted with via the [Channel API](ref/Channel) (accessed via the desktop agent [`getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API call) +2. ***App channels***, which: + - facilitate developer controlled messaging between applications, + - are created and named by applications (via the [`getOrCreateChannel()`](ref/DesktopAgent#getorcreatechannel) API call), + - are not discoverable, + - are interacted with via the [Channel API](ref/Channel) (accessed via the desktop agent [`getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API call) -3. **_Private_** channels, which: - * facilitate private communication between two parties, - * have an auto-generated identity and can only be retrieved via a raised intent. +3. ***Private*** channels, which: + - facilitate private communication between two parties, + - have an auto-generated identity and can only be retrieved via a raised intent. Channels are interacted with via `broadcast` and `addContextListener` functions, allowing an application to send and receive Context objects via the channel. For User channels, these functions are provided on the Desktop Agent, e.g. [`fdc3.broadcast(context)`](ref/DesktopAgent#broadcast), and apply to channels joined via [`fdc3.joinUserChannel`](ref/DesktopAgent#joinuserchannel). For App channels, a channel object must be retrieved, via [`fdc3.getOrCreateChannel(channelName)`](ref/DesktopAgent#getorcreatechannel), which provides the functions, i.e. [`myChannel.broadcast(context)`](ref/Channel#broadcast) and [`myChannel.addContextListener(context)`](ref/Channel#addcontextlistener). For `PrivateChannels`, a channel object must also be retrieved, but via an intent raised with [`fdc3.raiseIntent(intent, context)`](ref/DesktopAgent#raiseintent) and returned as an [`IntentResult`](ref/Types#intentresult). Channel implementations SHOULD ensure that context messages broadcast by an application on a channel are not delivered back to that same application if they are also listening on the channel. ### Joining User Channels -Apps can join _User channels_. An app can only be joined to one User channel at a time. + +Apps can join *User channels*. An app can only be joined to one User channel at a time. When an app is joined to a User channel, calls to [`fdc3.broadcast`](ref/DesktopAgent#broadcast) will be routed to that channel and listeners added through [`fdc3.addContextListener`](ref/DesktopAgent#addcontextlistener) will receive context broadcasts from other apps also joined to that channel. If an app is not joined to a User channel [`fdc3.broadcast`](ref/DesktopAgent#broadcast) will be a no-op and handler functions added with [`fdc3.addContextListener`](ref/DesktopAgent#addcontextlistener) will not receive any broadcasts. However, apps can still choose to listen and broadcast to specific channels (both User and App channels) via the methods on the [`Channel`](ref/Channel) class. @@ -309,11 +343,12 @@ When an app joins a User channel, or adds a context listener when already joined It is possible that a call to join a User channel could be rejected. If for example, the desktop agent wanted to implement controls around what data apps can access. -Joining channels in FDC3 is intended to be a behavior initiated by the end user. For example: by color linking or apps being grouped in the same workspace. Most of the time, it is expected that apps will be joined to a channel by mechanisms outside of the app. To support programmatic management of joined channels and the implementation of channel selector UIs other than those provided outside of the app, Desktop Agent implementations MAY provide [`fdc3.joinChannel()`](ref/DesktopAgent#joinchannel), [`fdc3.getCurrentChannel()](ref/DesktopAgent#getcurrentchannel) and [`fdc3.leaveCurrentChannel()`](ref/DesktopAgent#leavecurrentchannel) functions and if they do, MUST do so as defined in the [Desktop Agent API reference](ref/DesktopAgent). +Joining channels in FDC3 is intended to be a behavior initiated by the end user. For example: by color linking or apps being grouped in the same workspace. Most of the time, it is expected that apps will be joined to a channel by mechanisms outside of the app. To support programmatic management of joined channels and the implementation of channel selector UIs other than those provided outside of the app, Desktop Agent implementations MAY provide [`fdc3.joinChannel()`](ref/DesktopAgent#joinchannel), [`fdc3.getCurrentChannel()](ref/DesktopAgent#getcurrentchannel) and [`fdc3.leaveCurrentChannel()`](ref/DesktopAgent#leavecurrentchannel) functions and if they do, MUST do so as defined in the [Desktop Agent API reference](ref/DesktopAgent). There SHOULD always be a clear UX indicator of what channel an app is joined to. #### Examples + To find a User channel, one calls: ```js @@ -335,9 +370,11 @@ Channel implementations SHOULD ensure that context messages broadcast by an appl > Prior to FDC3 2.0, 'user' channels were known as 'system' channels. They were renamed in FDC 2.0 to reflect their intended usage, rather than the fact that they are created by system (which could also create 'app' channels). The `joinChannel` function was also renamed to `joinUserChannel` to clarify that it is only intended to be used to join 'user', rather than 'app', channels. ### Direct Listening and Broadcast on Channels -While joining User channels (using fdc3.joinUserChannel) automates a lot of the channel behaviour for an app, it has the limitation that an app can only be 'joined' to one channel at a time. However, an app may instead retrieve a `Channel` Object via the [`fdc3.getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API, or by raising an intent that returns a channel. The `Channel` object may then be used to listen to and broadcast on that channel directly using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs. This is especially useful for working with dynamic _App Channels_. FDC3 imposes no restriction on adding context listeners or broadcasting to multiple channels. + +While joining User channels (using fdc3.joinUserChannel) automates a lot of the channel behaviour for an app, it has the limitation that an app can only be 'joined' to one channel at a time. However, an app may instead retrieve a `Channel` Object via the [`fdc3.getOrCreateChannel`](ref/DesktopAgent#getorcreatechannel) API, or by raising an intent that returns a channel. The `Channel` object may then be used to listen to and broadcast on that channel directly using the [`Channel.addContextListener`](ref/Channel#addcontextlistener) and the [`Channel.broadcast`](ref/Channel#broadcast) APIs. This is especially useful for working with dynamic *App Channels*. FDC3 imposes no restriction on adding context listeners or broadcasting to multiple channels. ### App Channels + App Channels are topics dynamically created by applications connected via FDC3. For example, an app may` create a channel to broadcast to others data or status specific to that app. To get (or create) a channel reference, then interact with it: @@ -375,17 +412,17 @@ if another application broadcasts to "my_custom_channel" (by retrieving it and b ### Private Channels -`PrivateChannels` are created to support the return of a stream of responses from a raised intent, or private dialog between two applications. +`PrivateChannels` are created to support the return of a stream of responses from a raised intent, or private dialog between two applications. It is intended that Desktop Agent implementations: - * - SHOULD restrict external apps from listening or publishing on this channel. - * - MUST prevent `PrivateChannels` from being retrieved via `fdc3.getOrCreateChannel`. - * - MUST provide the `id` value for the channel as required by the `Channel` interface. + - - SHOULD restrict external apps from listening or publishing on this channel. + - - MUST prevent `PrivateChannels` from being retrieved via `fdc3.getOrCreateChannel`. + - - MUST provide the `id` value for the channel as required by the `Channel` interface. The `PrivateChannel` type also supports synchronisation of data transmitted over returned channels. They do so by extending the `Channel` interface with event handlers which provide information on the connection state of both parties, ensuring that desktop agents do not need to queue or retain messages that are broadcast before a context listener is added and that applications are able to stop broadcasting messages when the other party has disconnected. ### Broadcasting and listening for multiple context types -The [Context specification](../../context/spec#assumptions) recommends that complex context objects are defined using simpler context types for particular fields. For example, a `Position` is composed of an `Instrument` and a holding amount. This leads to situations where an application may be able to receive or respond to context objects that are embedded in a more complex type, but not the more complex type itself. For example, a pricing chart might respond to an `Instrument` but doesn't know how to handle a `Position`. -To facilitate context linking in such situations it is recommended that applications `broadcast` each context type that other apps (listening on a User Channel or App Channel) may wish to process, starting with the simpler types, followed by the complex type. Doing so allows applications to filter the context types they receive by adding listeners for specific context types - but requires that the application broadcasting context make multiple broadcast calls in quick succession when sharing its context. +The [Context specification](../../context/spec#assumptions) recommends that complex context objects are defined using simpler context types for particular fields. For example, a `Position` is composed of an `Instrument` and a holding amount. This leads to situations where an application may be able to receive or respond to context objects that are embedded in a more complex type, but not the more complex type itself. For example, a pricing chart might respond to an `Instrument` but doesn't know how to handle a `Position`. +To facilitate context linking in such situations it is recommended that applications `broadcast` each context type that other apps (listening on a User Channel or App Channel) may wish to process, starting with the simpler types, followed by the complex type. Doing so allows applications to filter the context types they receive by adding listeners for specific context types - but requires that the application broadcasting context make multiple broadcast calls in quick succession when sharing its context. diff --git a/src/api/ImplementationMetadata.ts b/src/api/ImplementationMetadata.ts index ba68d867a..0de0eedda 100644 --- a/src/api/ImplementationMetadata.ts +++ b/src/api/ImplementationMetadata.ts @@ -3,6 +3,8 @@ * Copyright FINOS FDC3 contributors - see NOTICE file */ +import { AppMetadata } from './AppMetadata'; + /** * Metadata relating to the FDC3 Desktop Agent implementation and its provider. */ @@ -17,4 +19,7 @@ export interface ImplementationMetadata { /** The version of the provider of the FDC3 Desktop Agent Implementation (e.g. 5.3.0). */ readonly providerVersion?: string; + + /** The calling application instance's own metadata, according to the Desktop Agent (MUST include at least the `appId` and `instanceId`). */ + readonly appMetadata: AppMetadata; } From 48615dc13c0b29dca25b10f28460576c85aeaa06 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 20 May 2022 12:06:19 +0100 Subject: [PATCH 2/8] Apply suggestions from code review Co-authored-by: Hugh Troeger --- CHANGELOG.md | 2 +- docs/api/ref/DesktopAgent.md | 20 ++++++++++---------- docs/api/ref/Metadata.md | 4 ++-- docs/api/spec.md | 22 +++++++++++----------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e13ab93ef..953e6a453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Added details of FDC3's existing versioning and deprecation policies to the FDC3 compliance page ([#539](https://github.com/finos/FDC3/pull/539)) * Added a new experimental features policy, which exempts features designated as experimental from the versioning and deprecation policies, to the FDC3 compliance page ([#549](https://github.com/finos/FDC3/pull/549)) * Add `IntentDeliveryFailed` to the `ResolveError` enumeration to be used when delivery of an intent and context to a targetted app or instance fails. ([#601](https://github.com/finos/FDC3/pull/601)) -* Added the current app's `AppMetadata` to the `ImplementationMetadata` returned by `fdc3.getInfo()` allowing an app to retrieve its own metadata, according to the desktop agent ([#726](https://github.com/finos/FDC3/pull/726)) +* Added the current app's `AppMetadata` to the `ImplementationMetadata` returned by `fdc3.getInfo()` allowing an app to retrieve its own metadata, according to the Desktop Agent ([#726](https://github.com/finos/FDC3/pull/726)) ### Changed * Consolidated `Listener` documentation with other types ([#404](https://github.com/finos/FDC3/pull/404)) diff --git a/docs/api/ref/DesktopAgent.md b/docs/api/ref/DesktopAgent.md index dc3c2ea34..e1513e407 100644 --- a/docs/api/ref/DesktopAgent.md +++ b/docs/api/ref/DesktopAgent.md @@ -212,7 +212,7 @@ This can be used to raise the intent against a specific app or app instance. If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration. -Result types may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. +Result types may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the Desktop Agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. #### Examples @@ -290,7 +290,7 @@ A promise resolving to all the intents, their metadata and metadata about the ap If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration. -The optional `resultType` argument may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. +The optional `resultType` argument may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the Desktop Agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. #### Example @@ -352,7 +352,7 @@ await fdc3.raiseIntent(startChat.intent.name, context, selectedApp); getCurrentChannel() : Promise; ``` -Optional function that returns the `Channel` object for the current User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the desktop agent, rather than calling this function directly. +Optional function that returns the `Channel` object for the current User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the Desktop Agent, rather than calling this function directly. Returns `null` if the app is not joined to a channel. @@ -389,11 +389,11 @@ if (fdc3.getInfo && versionIsAtLeast(await fdc3.getInfo(), "1.2")) { } ``` -The `ImplementationMetadata` object returned also includes the metadata for the calling application, according to the desktop agent. This allows the application to retrieve its own `appId`, `instanceId` and other details, e.g.: +The `ImplementationMetadata` object returned also includes the metadata for the calling application, according to the Desktop Agent. This allows the application to retrieve its own `appId`, `instanceId` and other details, e.g.: ```js -let implMetadata = await fdc3.getInfo(); -let {appId, instanceId} = impleMetadata.appMetadata; +let implementationMetadata = await fdc3.getInfo(); +let {appId, instanceId} = implementationMetadata.appMetadata; ``` @@ -519,7 +519,7 @@ Alias to the [`getUserChannels`](#getuserchannels) function provided for backwar joinUserChannel(channelId: string) : Promise; ``` -Optional function that joins the app to the specified User channel. In most cases, applications SHOULD be joined to channels via UX provided to the application by the desktop agent, rather than calling this function directly. +Optional function that joins the app to the specified User channel. In most cases, applications SHOULD be joined to channels via UX provided to the application by the Desktop Agent, rather than calling this function directly. If an app is joined to a channel, all `fdc3.broadcast` calls will go to the channel, and all listeners assigned via `fdc3.addContextListener` will listen on the channel. @@ -630,9 +630,9 @@ let instanceMetadata = await fdc3.open(appMetadata, context); raiseIntent(intent: string, context: Context, app?: TargetApp): Promise; ``` -Raises a specific intent for resolution against apps registered with the desktop agent. +Raises a specific intent for resolution against apps registered with the Desktop Agent. -The desktop agent MUST resolve the correct app to target based on the provided intent name and context data. If multiple matching apps are found, a method for resolving the intent to a target app, such as presenting the user with a resolver UI allowing them to pick an app, SHOULD be provided. +The Desktop Agent MUST resolve the correct app to target based on the provided intent name and context data. If multiple matching apps are found, a method for resolving the intent to a target app, such as presenting the user with a resolver UI allowing them to pick an app, SHOULD be provided. Alternatively, the specific app or app instance to target can also be provided. A list of valid target applications and instances can be retrieved via [`findIntent`](DesktopAgent#findintent). If a target app for the intent cannot be found with the criteria provided or the user either closes the resolver UI or otherwise cancels resolution, an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration is returned. If a specific target `app` parameter was set, but either the app or app instance is not available then the `ResolveError.TargetAppUnavailable` or `ResolveError.TargetInstanceUnavailable` errors MUST be returned. @@ -693,7 +693,7 @@ raiseIntentForContext(context: Context, app?: TargetApp): Promise Date: Fri, 20 May 2022 13:40:37 +0100 Subject: [PATCH 3/8] Ensure preview deploys --- website/static/schemas/next/app-directory.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/static/schemas/next/app-directory.yaml b/website/static/schemas/next/app-directory.yaml index e7261c4c6..bece799ed 100644 --- a/website/static/schemas/next/app-directory.yaml +++ b/website/static/schemas/next/app-directory.yaml @@ -378,7 +378,7 @@ components: type: string description: >- A comma separated list of the types of contexts the intent offered by the application can process, - where the first part of the context type is the namespace e.g."fdc3.contact", "org.symphony.contact" + where the first part of the context type is the namespace e.g."fdc3.contact, org.symphony.contact" resultType: type: string description: >- From 818c8adb176e45a7aa547834232abf15372c368a Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 20 May 2022 14:09:47 +0100 Subject: [PATCH 4/8] fixing test --- test/Methods.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/Methods.test.ts b/test/Methods.test.ts index 04c40533f..3584de0d2 100644 --- a/test/Methods.test.ts +++ b/test/Methods.test.ts @@ -376,6 +376,7 @@ describe('test version comparison functions', () => { const metaOneTwo: ImplementationMetadata = { fdc3Version: '1.2', provider: 'test', + appMetadata: { appId: 'dummy', name: 'dummy' }, }; expect(versionIsAtLeast(metaOneTwo, '1.1')).toBe(true); expect(versionIsAtLeast(metaOneTwo, '1.2')).toBe(true); @@ -385,6 +386,7 @@ describe('test version comparison functions', () => { const metaOneTwoOne: ImplementationMetadata = { fdc3Version: '1.2.1', provider: 'test', + appMetadata: { appId: 'dummy', name: 'dummy' }, }; expect(versionIsAtLeast(metaOneTwoOne, '1.1')).toBe(true); expect(versionIsAtLeast(metaOneTwoOne, '1.2')).toBe(true); From c0fa57ae625f60a4f3ad482425d4334378909b71 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 27 May 2022 18:13:29 +0100 Subject: [PATCH 5/8] Update docs/api/ref/DesktopAgent.md --- docs/api/ref/DesktopAgent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/ref/DesktopAgent.md b/docs/api/ref/DesktopAgent.md index 42fcfdfad..d63a1e3b5 100644 --- a/docs/api/ref/DesktopAgent.md +++ b/docs/api/ref/DesktopAgent.md @@ -281,7 +281,7 @@ A promise resolving to all the intents, their metadata and metadata about the ap If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration. -The optional `resultType` argument may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the Desktop Agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. +The optional `resultType` argument may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. #### Example From 75ce676d37ab3d02a2759905441f015b0bcbc7d8 Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 27 May 2022 18:19:08 +0100 Subject: [PATCH 6/8] don't regress capitalisation of desktop agent --- docs/api/ref/DesktopAgent.md | 12 ++++++------ docs/api/ref/Metadata.md | 4 ++-- docs/api/spec.md | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/api/ref/DesktopAgent.md b/docs/api/ref/DesktopAgent.md index d63a1e3b5..81317c61c 100644 --- a/docs/api/ref/DesktopAgent.md +++ b/docs/api/ref/DesktopAgent.md @@ -203,7 +203,7 @@ This can be used to raise the intent against a specific app or app instance. If the resolution fails, the promise will return an `Error` with a string from the [`ResolveError`](Errors#resolveerror) enumeration. -Result types may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the Desktop Agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. +Result types may be a type name, the string `"channel"` (which indicates that the app will return a channel) or a string indicating a channel that returns a specific type, e.g. `"channel"`. If intent resolution to an app returning a channel is requested, the desktop agent MUST include both apps that are registered as returning a channel and those registered as returning a channel with a specific type in the response. #### Examples @@ -343,7 +343,7 @@ await fdc3.raiseIntent(startChat.intent.name, context, selectedApp); getCurrentChannel() : Promise; ``` -Optional function that returns the `Channel` object for the current User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the Desktop Agent, rather than calling this function directly. +Optional function that returns the `Channel` object for the current User channel membership. In most cases, an application's membership of channels SHOULD be managed via UX provided to the application by the desktop agent, rather than calling this function directly. Returns `null` if the app is not joined to a channel. @@ -364,7 +364,7 @@ let current = await fdc3.getCurrentChannel(); getInfo(): Promise; ``` -Retrieves information about the FDC3 Desktop Agent implementation, including the supported version of the FDC3 specification, the name of the provider of the implementation, its own version number and the metadata of the calling application according to the Desktop Agent. +Retrieves information about the FDC3 Desktop Agent implementation, including the supported version of the FDC3 specification, the name of the provider of the implementation, its own version number and the metadata of the calling application according to the desktop agent. Returns an [`ImplementationMetadata`](Metadata#implementationmetadata) object. This metadata object can be used to vary the behavior of an application based on the version supported by the Desktop Agent and for logging purposes. @@ -496,7 +496,7 @@ const redChannel = userChannels.find(c => c.id === 'red'); joinUserChannel(channelId: string) : Promise; ``` -Optional function that joins the app to the specified User channel. In most cases, applications SHOULD be joined to channels via UX provided to the application by the Desktop Agent, rather than calling this function directly. +Optional function that joins the app to the specified User channel. In most cases, applications SHOULD be joined to channels via UX provided to the application by the desktop agent, rather than calling this function directly. If an app is joined to a channel, all `fdc3.broadcast` calls will go to the channel, and all listeners assigned via `fdc3.addContextListener` will listen on the channel. @@ -594,7 +594,7 @@ raiseIntent(intent: string, context: Context, app?: AppIdentifier): Promise Date: Fri, 27 May 2022 18:19:37 +0100 Subject: [PATCH 7/8] Update docs/api/spec.md --- docs/api/spec.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/spec.md b/docs/api/spec.md index 5d7f01bf5..26edc5bb4 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -93,7 +93,7 @@ For example: - entitlements - UX of application resolution -Are all areas of functionality that any feature-complete Desktop Agent would implement, but are not currently areas considered for standardization under FDC3. +Are all areas of functionality that any feature-complete desktop agent would implement, but are not currently areas considered for standardization under FDC3. ### Inter-Agent Communication From 968002de6936a35df74dc3c5c79f2e389bfa93df Mon Sep 17 00:00:00 2001 From: Kris West Date: Fri, 27 May 2022 18:20:09 +0100 Subject: [PATCH 8/8] Update docs/api/spec.md --- docs/api/spec.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/spec.md b/docs/api/spec.md index 26edc5bb4..b51739b4b 100644 --- a/docs/api/spec.md +++ b/docs/api/spec.md @@ -292,7 +292,7 @@ try { Applications need to let the system know the intents they can support. Typically, this is done via registration with an [App Directory](../app-directory/spec). It is also possible for intents to be registered at the application level as well to support ad-hoc registration which may be helpful at development time. Although dynamic registration is not part of this specification, a Desktop Agent agent may choose to support any number of registration paths. -When an instance of an application is launched, it is expected to add an [`IntentHandler`](ref/Types#intenthandler) function to the Desktop Agent for each intent it has registered by calling the [`fdc3.addIntentListener`](ref/DesktopAgent#addintentlistener) function of the Desktop Agent. Doing so allows the Desktop Agent to pass incoming intents and contexts to that instance of the application. Hence, if the application instance was spawned in response to the raised intent, then the Desktop Agent must wait for the relevant intent listener to be added by that instance before it can deliver the intent and context to it. In order to facilitate accurate error responses, calls to `fdc3.raiseIntent` should not return an `IntentResolution` until the intent handler has been added and the intent delivered to the target app. +When an instance of an application is launched, it is expected to add an [`IntentHandler`](ref/Types#intenthandler) function to the desktop agent for each intent it has registered by calling the [`fdc3.addIntentListener`](ref/DesktopAgent#addintentlistener) function of the Desktop Agent. Doing so allows the Desktop Agent to pass incoming intents and contexts to that instance of the application. Hence, if the application instance was spawned in response to the raised intent, then the Desktop Agent must wait for the relevant intent listener to be added by that instance before it can deliver the intent and context to it. In order to facilitate accurate error responses, calls to `fdc3.raiseIntent` should not return an `IntentResolution` until the intent handler has been added and the intent delivered to the target app. #### Compliance with Intent Standards