Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d9541d1
Context Clearing
kemerava Sep 27, 2024
77e2b61
Apply suggestions from code review
kemerava Oct 4, 2024
a2c348e
Changelog and fixing the name of the field
kemerava Oct 4, 2024
60456c3
Merge remote-tracking branch 'origin/main' into feature/context-clearing
kemerava Dec 11, 2024
768f50d
Adding conformance tests
kemerava Dec 11, 2024
acac1a0
Apply suggestions from code review
kemerava Jan 31, 2025
a4106fe
Merge remote-tracking branch 'origin/main' into feature/context-clearing
kemerava Mar 21, 2025
4e2bc61
Merge branch 'main' into feature/context-clearing
kriswest Apr 17, 2025
c66f420
Merge remote-tracking branch 'origin/main' into feature/context-clearing
kemerava May 8, 2025
cdeea6a
Adding addEventListener for listening on clearing context
kemerava May 8, 2025
1ad0c4a
Clearing context tests
kemerava May 8, 2025
a732bcc
Fixing package-lock.json
kemerava May 14, 2025
9c79048
Making build pass
kemerava Jun 20, 2025
04507e0
Merge remote-tracking branch 'origin/main' into feature/context-clearing
kemerava Jul 9, 2025
e21ec30
Adding the event for the contextCleared
kemerava Jul 9, 2025
90c8fab
npm
kemerava Jul 9, 2025
c63e1d4
PR review changes
kemerava Jul 9, 2025
b953954
Merge remote-tracking branch 'origin/main' into feature/context-clearing
kemerava Jul 25, 2025
bc5c98c
Update CHANGELOG.md
kemerava Jul 25, 2025
c572444
Merge branch 'feature/context-clearing' of https://github.com/kemerav…
kemerava Jul 25, 2025
90a06e3
Update website/docs/api/ref/Channel.md
kemerava Jul 25, 2025
ac73c5c
Updating based on reviews
kemerava Jul 25, 2025
6d22fb3
Typo
kemerava Jul 25, 2025
a7e5c4b
Update lang
kemerava Jul 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions docs/api/ref/Channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface Channel {
broadcast(context: Context): Promise<void>;
getCurrentContext(contextType?: string): Promise<Context|null>;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
clearContext(contextType?: string): Promise<void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should require an explicit null argument (contextType: string | null) to clear all types - which would match addContectListener or stick with this (matching getCurrentContext). Either works of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it makes sense to keep it closer to getCurrentContext, because they seem most related to me, but happy to hear any thoughts/suggestions.

Copy link
Contributor

@kriswest kriswest Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a historical reason for addContextListener having an explicit null argument, the contextType argument was originally optional so the handler argument could be either first or second (when a type was specified). This was NOT good in practice so we moved to an explicit null argument and deprecated the single argument override:
https://fdc3.finos.org/docs/2.0/api/ref/DesktopAgent#addcontextlistener-deprecated

We don't have that problem here, so I agree its fine as is (matching getCurrentContext).


//deprecated functions
/**
Expand All @@ -57,6 +58,7 @@ interface IChannel: IIntentResult
Task Broadcast(IContext context);
Task<IContext?> GetCurrentContext(string? contextType);
Task<IListener> AddContextListener<T>(string? contextType, ContextHandler<T> handler) where T : IContext;
Task ClearContext(string? contextType);
}
```

Expand Down Expand Up @@ -431,6 +433,99 @@ catch (Exception ex)
- [`broadcast`](#broadcast)
- [`addContextListener`](#addcontextlistener)

### `clearContext`

<Tabs groupId="lang">
<TabItem value="ts" label="TypeScript/JavaScript">

```ts
public clearContext(contextType?: string): Promise<void>;
```

</TabItem>
<TabItem value="dotnet" label=".NET">

```csharp
Task ClearContext(string? contextType);
```

</TabItem>
</Tabs>

Used to clear the specified context type if provided, otherwise, clear all contexts. Desktop Agent MUST update internal context. Any future calls to [`getCurrentContext`](#getcurrentcontext) and any new joiners on that channel (through [`joinUserChannel`](DesktopAgent#joinUserChannel) or [`addContextListener`](DesktopAgent#addContextListener)) will not receive anything for specified context type or all contexts accordingly.
Desktop Agent MUST update all channel listeners subscribed to the [`fdc3.nothing`](../../context/ref/Nothing.md/#nothing) type. If `contextType` is provided, then `subType` will be specified, otherwise, it is ommitted.


**Examples:**

Without specifying a context type:

<Tabs groupId="lang">
<TabItem value="ts" label="TypeScript/JavaScript">

```ts
try {
const context = await channel.clearContext();
} catch (err: ChannelError) {
// handle error
}
```

</TabItem>
<TabItem value="dotnet" label=".NET">

```csharp
try
{
var context = await channel.ClearContext();
}
catch (Exception ex)
{
// handle error
}
```

</TabItem>
</Tabs>

Specifying a context type:

<Tabs groupId="lang">
<TabItem value="ts" label="TypeScript/JavaScript">

```ts
try {
const contact = await channel.clearContext('fdc3.contact');
} catch (err: ChannelError) {
// handler error
}
```

</TabItem>
<TabItem value="dotnet" label=".NET">

```csharp
try
{
var context = await channel.ClearContext("fdc3.contact");
}
catch (Exception ex)
{
// handle error
}
```

</TabItem>
</Tabs>


**See also:**

- [`getCurrentContext`](#getcurrentcontext)
- [`addContextListener`](DesktopAgent#addContextListener)
- [`joinUserChannel`](DesktopAgent#joinUserChannel)
- [`fdc3.nothing`](../../context/ref/Nothing.md/#nothing)

## Deprecated Functions

### `addContextListener` (deprecated)
Expand Down
7 changes: 5 additions & 2 deletions docs/api/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ When raising an intent a specific context is provided as input. The type of the

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 `IntentHandler` or in an App Directory).
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 `IntentHandler` or in an App Directory). This type is also used when the context is cleared for the channel. If the optional context type is provided when performing [`clearContext`](ref/Channel.md#clearcontext), that type will be recorded in the field `subType` of [`fdc3.nothing`](../context/ref/Nothing) context type.

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.

Expand Down Expand Up @@ -585,7 +585,7 @@ Apps can join *User channels*. An app can only be joined to one User channel at

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.

When an app joins a User channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel.
When an app joins a User channel, or adds a context listener when already joined to a channel, it will automatically receive the current context for that channel, unless the context was cleared through [`clearContext`](ref/Channel.md#clearcontext).

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.

Expand Down Expand Up @@ -830,6 +830,9 @@ The [Context specification](../context/spec#assumptions) recommends that complex

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.

### Context clearning on channels
Channel interface provides the ability to [`clearContext`](ref/Channel.md#clearcontext) on the channel, either for the specific context type, if provided, or for all contexts on that channel. If provided, the specified type will be recorded in the `subType` field of the [`fdc3.nothing`](../context/ref/Nothing) context type. Once cleared, any subsequent new joiners on the channel, new context listeners on the context or calls to [`getCurrentContext`](ref/Channel.md#getcurrentcontext) will not return anything to the caller.

### Originating App Metadata

Optional metadata about each context message received, including the app that originated the message, SHOULD be provided by the desktop agent implementation to registered context handlers on all types of channel. As this metadata is optional, apps making use of it MUST handle cases where it is not provided.
7 changes: 6 additions & 1 deletion schemas/context/nothing.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
"properties": {
"type": {
"const": "fdc3.nothing"
},
"subtype": {
"type": "string",
"description": "A subtype of the context type. This can be used to provide a specific context which should be cleared, if ommitted, all contexts will be cleared"
}
}
},
{ "$ref": "context.schema.json#/definitions/BaseContext" }
],
"examples": [
{
"type": "fdc3.nothing"
"type": "fdc3.nothing",
"subtype": "fdc3.timeRange"
}
]
}
9 changes: 9 additions & 0 deletions src/api/Channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ export interface Channel {
*/
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;

/**
* Provides the ability to clear context from the channel. Subsequent connection to this channel or calls to get current context will not return anything (accounting for contextType if specified).
*
* If a `contextType` is provided, only contexts of that type will be cleared.
*
* If no `contextType` is provided, all contexts will be cleared.
*/
clearContext(contextType?: string): Promise<void>;

/**
* @deprecated use `addContextListener(null, handler)` instead of `addContextListener(handler)`.
*/
Expand Down