diff --git a/CHANGELOG.md b/CHANGELOG.md index e414e7982..86ab40d93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * The supported platforms page in the FDC3 documentation was moved into the API section as the information it provides all relates to FDC3 Desktop Agent API implementations. ([#1108](https://github.com/finos/FDC3/pull/1108)) * FDC3 apps are now encouraged to instantiate their FDC3 interface (DesktopAgent) using the `getAgent()` function provided by the `@finos/fdc3` module. This will allow apps to interoperate in either traditional Preload DAs (i.e. Electron) as well as the new Browser-Resident DAs. ([#1191](https://github.com/finos/FDC3/pull/1191)) * `ContextType` and `Intent` (`string`) types were created for use in DesktopAgent API signatures - they are unions of standardized values and `string`, enabling autocomplete/IntelliSense in IDEs when working with the FDC3 API. ([#1139](https://github.com/finos/FDC3/pull/1139)) +* SessionStorage use by `getAgent` was updated to scope the stored data by `window.name` and the app's `identityUrl`. ([#1442](https://github.com/finos/FDC3/pull/1442)) ### Deprecated diff --git a/docs/api/ref/GetAgent.md b/docs/api/ref/GetAgent.md index 5e8626346..5e8e00b5b 100644 --- a/docs/api/ref/GetAgent.md +++ b/docs/api/ref/GetAgent.md @@ -61,7 +61,7 @@ A small number of arguments are accepted that can affect the behavior of `getAge * * @property {number} timeoutMs Number of milliseconds to allow for an FDC3 * implementation to be found before calling the failover function or - * rejecting (default 750). Note that the timeout is cancelled as soon as a + * rejecting (default 1000). Note that the timeout is cancelled as soon as a * Desktop Agent is detected. There may be additional set-up steps to perform * which will happen outside the timeout. * @@ -159,11 +159,34 @@ Failover functions MUST be asynchronous and MUST resolve to one of the following ## Persisted Connection Data -The `getAgent()` function uses [`SessionStorage`](https://html.spec.whatwg.org/multipage/webstorage.html) ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)) to persist information on an instance of an app under the key `"FDC3-Desktop-Agent-Details"` and how it connected to a Desktop Agent in order to ensure a consistent connection type and `instanceId` when reconnecting after navigation or refresh events. Applications are not expected to interact with this information directly, rather it is set and used by the `getAgent()` implementation. +The `getAgent()` function uses [`SessionStorage`](https://html.spec.whatwg.org/multipage/webstorage.html) ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)) to persist information on an instance of an app and how it connected to a Desktop Agent in order to ensure a consistent connection type and `instanceId` when reconnecting after navigation or refresh events. -The details persisted conform to the following type: +:::warning +Apps do not need to and SHOULD NOT interact with data persisted in SessionStorage by `getAgent` directly, rather it is set and used by the `getAgent()` implementation. +::: + +SessionStorage is used as for persistence as it is scoped to a single browser window and the current origin, ensuring apps in different windows or on different origins access different storage. However, as multiple iframes from the same-domain embedded within a window can share a SessionStorage instance, and multiple applications can be hosted on the same origin and be navigated to and from within a window, additional scoping is applied. + +To differentiate storage for multiple iframes the name of the browsing context (`window.name`) is used to generate the key used in SessionStorage by concatenating the string `"FDC3-Desktop-Agent-Details-"` with `window.name`. The `window.name` remains stable during same-origin navigation and is persisted by the browser in its [session history](https://html.spec.whatwg.org/multipage/nav-history-apis.html#nav-traversal-apis) and is appropriate for scoping to a particular browsing context (window or iframe). Desktop Agents should assign a unique name to each window and iframe when they are created to facilitate such scoping. If no name is assigned, then the `getAgent` will assign a UUID as a unique name for that browsing context. + +The data persisted is structured as an object conforming to the `SessionStorageFormat` type below, with the `identityUrl` of the app used as the key (if no `identityUrl` is provided the `actualUrl` is used instead), with the value conforming to the `DesktopAgentDetails` type. Hence, the data might be retrieved as follows: ```ts +const sessionData: SessionStorageFormat = sessionStorage.get("FDC3-Desktop-Agent-Details-myWindowName"); +const agentDetails: DesktopAgentDetails = sessionData["myApIdentityUrl"]; +``` + +### Type Definitions + +```ts +/** Type representing the format of data stored by `getAgent` + * in Session Storage. The `identityUrl` of each app is used + * as the key. */ +type SessionStorageFormat = { + /** */ + [key: string]: DesktopAgentDetails +} + /** Type representing data on the Desktop Agent that an app * connected to that is persisted by the getAgent function * to be used when re-connecting (after a navigation or @@ -232,4 +255,8 @@ enum WebDesktopAgentType { * function that was passed by the application. */ Failover = "FAILOVER" } + +const DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX = 'fdc3-desktop-agent-details'; + +const DEFAULT_TIMEOUT_MS = 1000; ``` diff --git a/src/api/GetAgent.ts b/src/api/GetAgent.ts index bd5dbf800..08e2b1378 100644 --- a/src/api/GetAgent.ts +++ b/src/api/GetAgent.ts @@ -44,7 +44,7 @@ export type GetAgentType = (params?: GetAgentParams) => Promise; * * @property {number} timeoutMs Number of milliseconds to allow for an FDC3 * implementation to be found before calling the failover function or - * rejecting (default 750). Note that the timeout is cancelled as soon as a + * rejecting (default 1000). Note that the timeout is cancelled as soon as a * Desktop Agent is detected. There may be additional set-up steps to perform * which will happen outside the timeout. * @@ -91,6 +91,14 @@ type GetAgentParams = { failover?: (args: GetAgentParams) => Promise; }; +/** Type representing the format of data stored by `getAgent` + * in Session Storage. The `identityUrl` of each app is used + * as the key. */ +export type SessionStorageFormat = { + /** */ + [key: string]: DesktopAgentDetails +} + /** Type representing data on the Desktop Agent that an app * connected to that is persisted by the getAgent function * to be used when re-connecting (after a navigation or @@ -159,3 +167,7 @@ export enum WebDesktopAgentType { * function that was passed by the application. */ Failover = 'FAILOVER', } + +export const DESKTOP_AGENT_SESSION_STORAGE_KEY_PREFIX = 'fdc3-desktop-agent-details'; + +export const DEFAULT_TIMEOUT_MS = 1000; \ No newline at end of file