Skip to content

Commit 2f0d37c

Browse files
sarthak688claude
andcommitted
feat(subscriptions): add Subscriptions service foundation + read methods [internal]
Adds the Subscriptions service on top of the notifications module, rebased onto current main. Read methods (getAll, getPublishers, getSupportedChannels) against the usersubscriptionservice API; all tagged @internal (NotificationService scope is internal), so no oauth-scopes or mkdocs nav entries are added. getAll returns the full subscription state (SubscriptionGetResponse); getPublishers returns the discovery-only catalogue (SubscriptionGetPublishersResponse) whose base shapes (SubscriptionPublisherBase, SubscriptionTopicBase) the full SubscriptionPublisher and SubscriptionTopic extend — matching the backend's distinct populated field sets. Adds the NotificationMode delivery-channel enum (InApp/Email/Slack/Teams) to notifications.types.ts, shared by the subscription channel responses. Tests: 8 unit tests + integration tests (skipped without tenant config). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8a069eb commit 2f0d37c

12 files changed

Lines changed: 827 additions & 6 deletions

File tree

src/models/notification/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
2-
* Notification models barrel export.
2+
* Notification & Subscription models barrel export.
33
*/
44

55
export * from './notifications.types';
66
export * from './notifications.models';
7+
export * from './subscriptions.types';
8+
export * from './subscriptions.models';

src/models/notification/notifications.types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ export enum NotificationCategory {
3131
Fatal = 'Fatal',
3232
}
3333

34+
/**
35+
* Notification delivery channel.
36+
*
37+
* `InApp` is always implicitly enabled (it is not returned by `getSupportedChannels()`);
38+
* the others must be checked via `Subscriptions.getSupportedChannels()`.
39+
*/
40+
export enum NotificationMode {
41+
/** Real-time in-app push. Always available. */
42+
InApp = 'InApp',
43+
/** Email delivery. */
44+
Email = 'Email',
45+
/** Slack delivery. */
46+
Slack = 'Slack',
47+
/** Microsoft Teams delivery. */
48+
Teams = 'Teams',
49+
}
50+
3451
/**
3552
* Notification entry as returned by `GET /odata/v1/NotificationEntry`.
3653
*
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* Subscription service model — public response shapes and the ServiceModel interface
3+
* that drives generated API documentation.
4+
*/
5+
6+
import type {
7+
SubscriptionGetAllOptions,
8+
SubscriptionGetPublishersOptions,
9+
SubscriptionGetPublishersResponse,
10+
SubscriptionGetResponse,
11+
SubscriptionGetSupportedChannelsResponse,
12+
} from './subscriptions.types';
13+
14+
/**
15+
* Public surface of the Subscriptions service. JSDoc on this interface drives
16+
* the generated API reference documentation.
17+
*
18+
* Every method takes the tenant GUID as the first argument, which the SDK
19+
* forwards to the subscription API on each call.
20+
*/
21+
export interface SubscriptionServiceModel {
22+
/**
23+
* Gets the current user's subscription preferences, optionally filtered to a set of
24+
* publisher names.
25+
*
26+
* Returns the full list of publishers (their topics, channels, and current subscription
27+
* state) the user has access to. Use {@link SubscriptionGetAllOptions.publishers} to
28+
* narrow to specific publishers.
29+
*
30+
* @param tenantId - Tenant GUID
31+
* @param options - Optional publisher-name filter
32+
* @returns Full subscription state for the matched publishers
33+
* {@link SubscriptionGetResponse}
34+
*
35+
* @example Basic usage
36+
* ```typescript
37+
* import { Subscriptions } from '@uipath/uipath-typescript/notifications';
38+
*
39+
* const subscriptions = new Subscriptions(sdk);
40+
* const { publishers } = await subscriptions.getAll('<tenantId>');
41+
* ```
42+
*
43+
* @example Filter to specific publishers
44+
* ```typescript
45+
* const { publishers } = await subscriptions.getAll('<tenantId>', {
46+
* publishers: ['Orchestrator', 'Actions'],
47+
* });
48+
* ```
49+
* @internal
50+
*/
51+
getAll(tenantId: string, options?: SubscriptionGetAllOptions): Promise<SubscriptionGetResponse>;
52+
53+
/**
54+
* Lists available publishers and their topics, regardless of the user's current subscription.
55+
*
56+
* Used for discovery — pair with {@link getAll} to inspect what's subscribable.
57+
*
58+
* Note: the response from this endpoint carries only identity/discovery fields on
59+
* publishers and topics (no subscription state). Use {@link getAll} to inspect state.
60+
*
61+
* @param tenantId - Tenant GUID
62+
* @param options - Optional publisher-name filter
63+
* @returns Publishers and their full topic catalogue (discovery fields only)
64+
* {@link SubscriptionGetPublishersResponse}
65+
*
66+
* @example Basic usage
67+
* ```typescript
68+
* const { publishers } = await subscriptions.getPublishers('<tenantId>');
69+
* ```
70+
*
71+
* @example Filter to a single publisher
72+
* ```typescript
73+
* const { publishers } = await subscriptions.getPublishers('<tenantId>', { name: 'Orchestrator' });
74+
* ```
75+
* @internal
76+
*/
77+
getPublishers(tenantId: string, options?: SubscriptionGetPublishersOptions): Promise<SubscriptionGetPublishersResponse>;
78+
79+
/**
80+
* Gets the notification channels supported in the current tenant.
81+
*
82+
* Check the `isEnabled` field on each {@link SupportedChannel} before attempting to subscribe to a
83+
* channel — disabled channels will be rejected by the server.
84+
*
85+
* Note: `InApp` is always available and is not included in the response.
86+
*
87+
* @param tenantId - Tenant GUID
88+
* @returns Supported channels with enabled status
89+
* {@link SubscriptionGetSupportedChannelsResponse}
90+
*
91+
* @example
92+
* ```typescript
93+
* import { NotificationMode } from '@uipath/uipath-typescript/notifications';
94+
*
95+
* const { channels } = await subscriptions.getSupportedChannels('<tenantId>');
96+
* const slack = channels.find(c => c.name === NotificationMode.Slack);
97+
* if (slack?.isEnabled) {
98+
* // safe to subscribe to Slack
99+
* }
100+
* ```
101+
* @internal
102+
*/
103+
getSupportedChannels(tenantId: string): Promise<SubscriptionGetSupportedChannelsResponse>;
104+
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/**
2+
* Subscription service types — request/response shapes for user subscription preferences.
3+
*/
4+
5+
import { NotificationCategory, NotificationMode } from './notifications.types';
6+
7+
/**
8+
* Status of a notification mode (channel) for a publisher — whether the user has
9+
* activated this channel.
10+
*/
11+
export interface AllowedMode {
12+
/** Notification channel. */
13+
name: NotificationMode;
14+
/** Whether the user has activated this channel for the publisher. */
15+
isActive: boolean;
16+
}
17+
18+
/**
19+
* Per-mode subscription state for a topic.
20+
*/
21+
export interface SubscriptionMode {
22+
/** Notification channel. */
23+
name: NotificationMode;
24+
/** Whether the user is subscribed to this topic via this channel. */
25+
isSubscribed: boolean;
26+
/** Whether the topic is subscribed by default via this channel. */
27+
isSubscribedByDefault: boolean;
28+
}
29+
30+
/**
31+
* Base topic shape — identity/discovery fields only, with no subscription state.
32+
*/
33+
export interface SubscriptionTopicBase {
34+
/** Topic GUID. */
35+
id: string;
36+
/** Stable topic identifier (e.g. `Process.JobExecution.Faulted`). */
37+
name: string;
38+
/** Human-readable topic name. */
39+
displayName: string | null;
40+
/** Topic description. */
41+
description: string | null;
42+
/** Topic group name. */
43+
group: string | null;
44+
}
45+
46+
/**
47+
* A topic that the user can subscribe to, with full subscription state — as returned by `getAll()`.
48+
*/
49+
export interface SubscriptionTopic extends SubscriptionTopicBase {
50+
/** Severity category. Only populated on `getAll()`. */
51+
category?: NotificationCategory;
52+
/** Parent topic group name. Often `null`. */
53+
parentGroup?: string | null;
54+
/** Whether the user is currently subscribed to this topic. Only populated on `getAll()`. */
55+
isSubscribed?: boolean;
56+
/** Whether the topic is mandatory — cannot be unsubscribed. Only populated on `getAll()`. */
57+
isMandatory?: boolean;
58+
/** Whether the topic should be visible in the user-facing subscription UI. */
59+
isVisible?: boolean;
60+
/** Whether the topic is subscribed by default for new users. */
61+
isDefault?: boolean;
62+
/** Whether notifications for this topic can be batched. */
63+
isAllowedToBeDispatchedInBatch?: boolean;
64+
/** Whether the topic is marked as infrequent (lower-priority delivery). */
65+
isInfrequent?: boolean;
66+
/** Number of days notifications for this topic are retained. */
67+
retentionDays?: number;
68+
/** Display ordering hint. */
69+
orderingSequence?: number;
70+
/** Per-channel subscription state. Only populated on `getAll()`. */
71+
modes?: SubscriptionMode[];
72+
}
73+
74+
/**
75+
* An entity reference used in publisher / topic-group subscription requests.
76+
*/
77+
export interface SubscriptionEntity {
78+
/** Entity GUID. */
79+
id?: string;
80+
/** Entity name. */
81+
name?: string;
82+
/** Entity type. */
83+
type?: string;
84+
/** Parent name (e.g. folder name for a sub-folder). */
85+
parentName?: string;
86+
/** Whether the user is subscribed to notifications for this entity. */
87+
isSubscribed?: boolean;
88+
}
89+
90+
/**
91+
* Group of entities that belong to a topic group.
92+
*/
93+
export interface TopicGroupEntity {
94+
/** Topic group name. */
95+
name?: string;
96+
/** Entities belonging to this group. */
97+
entities?: SubscriptionEntity[];
98+
}
99+
100+
/**
101+
* Entity types supported by a topic group.
102+
*/
103+
export interface TopicGroupEntityType {
104+
/** Topic group name. */
105+
name?: string;
106+
/** Entity type names. */
107+
entityTypes?: string[];
108+
}
109+
110+
/**
111+
* Base publisher shape — identity/discovery fields and the topic catalogue, with no subscription state.
112+
*/
113+
export interface SubscriptionPublisherBase {
114+
/** Publisher GUID. */
115+
id: string;
116+
/** Stable publisher name (e.g. `Orchestrator`, `Actions`). */
117+
name: string;
118+
/** Human-readable publisher name. */
119+
displayName: string | null;
120+
/** Topics published under this publisher. */
121+
topics: SubscriptionTopicBase[];
122+
}
123+
124+
/**
125+
* A publisher with its topics, channels, and subscription state — as returned by `getAll()`.
126+
*/
127+
export interface SubscriptionPublisher extends SubscriptionPublisherBase {
128+
/** Topics published under this publisher, with full per-topic subscription state. */
129+
topics: SubscriptionTopic[];
130+
/** URL to navigate to when a publisher notification is clicked. */
131+
redirectionUrl?: string | null;
132+
/** Number of days notifications from this publisher are retained. */
133+
retentionDays?: number;
134+
/** Whether notifications from this publisher are included in summary digests. */
135+
addToSummary?: boolean;
136+
/** Whether the user has opted in to receive notifications from this publisher. */
137+
isUserOptin?: boolean;
138+
/** Channels available for this publisher and their activation state. */
139+
modes?: AllowedMode[];
140+
/** Entities (e.g. folders) that the publisher exposes. */
141+
entities?: SubscriptionEntity[];
142+
/** Entity types the publisher exposes. */
143+
entityTypes?: string[];
144+
/** Topic-group entity sets. */
145+
topicGroupEntities?: TopicGroupEntity[];
146+
/** Topic-group entity types. */
147+
topicGroupEntityTypes?: TopicGroupEntityType[];
148+
}
149+
150+
/**
151+
* Channel availability returned by `getSupportedChannels()`.
152+
*
153+
* Note: `InApp` is never returned — it is always implicitly available.
154+
*/
155+
export interface SupportedChannel {
156+
/** Notification channel. */
157+
name: NotificationMode;
158+
/** Whether the channel is enabled for the current tenant. */
159+
isEnabled: boolean;
160+
}
161+
162+
/**
163+
* Options for `Subscriptions.getAll()`.
164+
*/
165+
export interface SubscriptionGetAllOptions {
166+
/** Filter to specific publisher names. When omitted, all publishers are returned. */
167+
publishers?: string[];
168+
}
169+
170+
/**
171+
* Options for `Subscriptions.getPublishers()`.
172+
*/
173+
export interface SubscriptionGetPublishersOptions {
174+
/** Filter to a specific publisher name. When omitted, all publishers are returned. */
175+
name?: string;
176+
}
177+
178+
/**
179+
* Response from `getAll()` — publishers with their topics, channels, and full subscription state.
180+
*/
181+
export interface SubscriptionGetResponse {
182+
/** Publishers with their topics and subscription state. */
183+
publishers: SubscriptionPublisher[];
184+
}
185+
186+
/**
187+
* Response from `getPublishers()` — the publisher/topic discovery catalogue.
188+
*
189+
* Publishers and topics carry only identity/discovery fields (no subscription state);
190+
* use `getAll()` to inspect subscription state.
191+
*/
192+
export interface SubscriptionGetPublishersResponse {
193+
/** Publishers with their topic catalogue. */
194+
publishers: SubscriptionPublisherBase[];
195+
}
196+
197+
/**
198+
* Response from `getSupportedChannels()`.
199+
*/
200+
export interface SubscriptionGetSupportedChannelsResponse {
201+
/** Notification channels supported in the current tenant. `InApp` is not listed — it is always available. */
202+
channels: SupportedChannel[];
203+
}

src/services/notification/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,31 @@
33
*
44
* Provides access to the UiPath Notification platform from the perspective of an
55
* authenticated user (UserContext):
6-
* - `Notifications` — list operations on the user's inbox (further operations land in
7-
* follow-up PRs)
6+
* - `Notifications` — list / mark-read / delete operations on the user's inbox
7+
* - `Subscriptions` — read the user's notification preferences per publisher and topic
88
*
99
* Publishing (sending) notifications is a first-party service action and is NOT part of this module.
1010
*
1111
* @example
1212
* ```typescript
1313
* import { UiPath } from '@uipath/uipath-typescript/core';
14-
* import { Notifications } from '@uipath/uipath-typescript/notifications';
14+
* import { Notifications, Subscriptions } from '@uipath/uipath-typescript/notifications';
1515
*
1616
* const sdk = new UiPath(config);
1717
* await sdk.initialize();
1818
*
1919
* const notifications = new Notifications(sdk);
2020
* const unread = await notifications.getAll('<tenantId>', { filter: 'hasRead eq false' });
21+
*
22+
* const subscriptions = new Subscriptions(sdk);
23+
* const { publishers } = await subscriptions.getAll('<tenantId>');
2124
* ```
2225
*
2326
* @module
2427
*/
2528

2629
export { NotificationService as Notifications } from './notifications';
30+
export { SubscriptionService as Subscriptions } from './subscriptions';
2731

2832
// Models (types, enums, response shapes)
2933
export * from '../../models/notification';

0 commit comments

Comments
 (0)