Skip to content

feat(notifications): mark-read flows (PR 2/7)#513

Open
sarthak688 wants to merge 4 commits into
feat/notifications-sdkfrom
feat/notifications-mark-read
Open

feat(notifications): mark-read flows (PR 2/7)#513
sarthak688 wants to merge 4 commits into
feat/notifications-sdkfrom
feat/notifications-mark-read

Conversation

@sarthak688

Copy link
Copy Markdown

PR 2/7 in the Notification SDK stack. Stacked on top of #512.

Adds the three mark-read methods on the Notifications service. All hit the same UpdateRead OData action endpoint; markAllRead uses the server-side forceAllRead flag.

Methods Added

Layer Method Signature
Service notifications.markRead() markRead(tenantId: string, notificationIds: string[]): Promise<NotificationUpdateReadResponse>
Service notifications.markUnread() markUnread(tenantId: string, notificationIds: string[]): Promise<NotificationUpdateReadResponse>
Service notifications.markAllRead() markAllRead(tenantId: string): Promise<NotificationMarkAllReadResponse>

Endpoint Called

Method HTTP Endpoint OAuth Scope
markRead() / markUnread() / markAllRead() POST notificationservice_/notificationserviceapi/odata/v1/NotificationEntry/UiPath.NotificationService.Api.UpdateRead NotificationService
  • markRead and markUnread delegate to a private updateRead(tenantId, ids, read) helper to share the POST body construction.
  • markAllRead sends { notifications: [], forceAllRead: true } — the server reads all notifications for the acting user regardless of the empty array.
  • All three carry @track(...) telemetry decorators.

Example Usage

import { Notifications } from '@uipath/uipath-typescript/notifications';

const notifications = new Notifications(sdk);
const tenantId = '<tenant-guid>';

await notifications.markRead(tenantId, ['<notificationId-1>', '<notificationId-2>']);
await notifications.markUnread(tenantId, ['<notificationId>']);
await notifications.markAllRead(tenantId);

API Response vs SDK Response

These methods don't return entity data — they wrap the API's empty 200 in an OperationResponse<T> for consistency with other SDK mutation methods:

Method SDK Response
markRead / markUnread { success: true, data: { notificationIds, read } }
markAllRead { success: true, data: { all: true, read: true } }

Sample SDK Response

notifications.markRead(tenantId, [''])
{
  "success": true,
  "data": {
    "notificationIds": ["9a3b0db5-9b8b-44a7-9b6a-08de0a17b4e2"],
    "read": true
  }
}

Verification

Check Status
npm run typecheck ✅ clean
npm run lint ✅ 0 warnings, 0 errors
npm run test:unit ✅ 10 tests in notification suite (up from 4)

Files

Area Files
Endpoint constants src/utils/constants/endpoints/notification.ts (UPDATE_READ)
Models src/models/notification/notifications.models.ts (response types + ServiceModel methods)
Service src/services/notification/notifications.ts (methods + private updateRead helper)
Unit tests tests/unit/services/notification/notifications.test.ts (+6 tests)
Integration tests tests/integration/shared/notification/notifications.integration.test.ts (+2 tests)
Docs docs/oauth-scopes.md

PR Stack

# Branch Status
1 feat/notifications-sdk #512
2 feat/notifications-mark-read (this PR)
3 feat/notifications-delete upcoming
4 feat/subscriptions-sdk upcoming
5 feat/subscriptions-topic-updates upcoming
6 feat/subscriptions-publisher-updates upcoming
7 feat/subscriptions-mode-reset upcoming

🤖 Generated with Claude Code

sarthak688 and others added 2 commits June 12, 2026 11:52
Establishes the notification service module with the inbox listing
endpoint. Routes at the organization level via NOTIFICATION_BASE
(URL-traversal trick to bypass the tenant segment). tenantId is taken
as a positional argument and forwarded via X-UIPATH-Internal-TenantId.

Foundation included for follow-up PRs that add the remaining inbox and
subscription methods on top of this branch:
  - @uipath/uipath-typescript/notifications subpath in package.json + rollup
  - NOTIFICATION_BASE, NOTIFICATION_ENDPOINTS scaffold
  - test infra (NOTIFICATION_TEST_TENANT_ID env var, test-config,
    unified-setup registration, notification mock factories, constants)
  - oauth-scopes + pagination + mkdocs nav entries

Methods: getAll (paginated OData listing with $top/$skip/$count,
filter, orderby; transformFn drops 8 internal/transport fields).

Tests: 4 unit + 4 integration (skipped when NOTIFICATION_TEST_TENANT_ID
is not set).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…llRead)

Adds the three read-state mutation methods on top of the foundation
established in feat/notifications-sdk. All three POST to the
NotificationEntry.UpdateRead OData action; markAllRead uses the
server-side forceAllRead flag.

Adds UPDATE_READ endpoint constant and per-method telemetry decorators.

Tests: 6 additional unit tests + 2 integration tests (mark/unmark
round-trip + markAllRead).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
});

it('should propagate errors', async () => {
mockApiClient.post.mockRejectedValue(createMockError(TEST_CONSTANTS.ERROR_MESSAGE));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

markUnread operates on specific notification IDs — the same pattern as markRead, whose error test correctly uses NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND (line 129). Per agent_docs/rules.md: "Use domain-specific error constants for entity-specific method tests; Generic TEST_CONSTANTS.ERROR_MESSAGE is acceptable for collection methods like getAll."

Suggested change
mockApiClient.post.mockRejectedValue(createMockError(TEST_CONSTANTS.ERROR_MESSAGE));
mockApiClient.post.mockRejectedValue(createMockError(NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND));

Line 162 needs the matching .rejects.toThrow(NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND) change too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in a59c3f6 — switched both error tests to NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND.

});

it('should propagate errors', async () => {
mockApiClient.post.mockRejectedValue(createMockError(TEST_CONSTANTS.ERROR_MESSAGE));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

markAllRead is a mutation on domain entities — for consistency with markRead and the corrected markUnread, use the domain-specific error constant here too.

Suggested change
mockApiClient.post.mockRejectedValue(createMockError(TEST_CONSTANTS.ERROR_MESSAGE));
mockApiClient.post.mockRejectedValue(createMockError(NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND));

Line 185 needs the matching .rejects.toThrow(NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND) change too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed in a59c3f6 — switched both error tests to NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND.

@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review findings

2 inline comments + 1 general note

Inline comments

  • notifications.test.ts:158markUnread error test uses TEST_CONSTANTS.ERROR_MESSAGE instead of domain-specific NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND, inconsistent with the markRead error test directly above it.
  • notifications.test.ts:181 — same issue for markAllRead.

General note — stale class JSDoc

src/services/notification/notifications.ts lines 38–39 still reads:

Further inbox operations (mark-read, delete) land in follow-up PRs.

Since mark-read is being shipped in this PR, update it to:

Further inbox operations (delete) land in follow-up PRs.

(The line is outside the diff so GitHub won't accept an inline comment on it.)

…markAllRead tests

Matches the pattern in the parallel markRead test and the convention
in agent_docs/rules.md ("Use domain-specific error constants for
entity-specific method tests").

Addresses review comments on PR #513.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Stale class-level JSDoc in src/services/notification/notifications.ts (outside the diff — raised in the prior review summary but not yet addressed)

Line ~41 currently reads:

Further inbox operations (mark-read, delete) land in follow-up PRs.

Since markRead, markUnread, and markAllRead ship in this PR, the comment should read:

Further inbox operations (delete) land in follow-up PRs.

@sarthak688

Copy link
Copy Markdown
Author

All findings addressed in the latest commit on this branch. Inline reply threads are resolved with commit references.

…opes entries

NotificationService uses an internal scope. Tag markRead, markUnread,
and markAllRead @internal in both the ServiceModel interface and the
service class so TypeDoc hides them from generated SDK API docs.
Remove their entries from docs/oauth-scopes.md (external-only).

Addresses reviewer feedback on PR #512 (same treatment applied here).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sarthak688 added a commit that referenced this pull request Jun 12, 2026
…s entries

Same treatment as PR #512 / #513 — tag deleteNotifications, deleteAll
@internal in models + service, drop their oauth-scopes entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Two issues remain after the latest commit — both outside the diff so inline comments aren't possible.


1. Stale class-level JSDoc in src/services/notification/notifications.ts (lines 38–39)

This was flagged twice in earlier review comments but was not fixed. The comment still reads:

Further inbox operations (mark-read, delete) land in follow-up PRs.

Since markRead, markUnread, and markAllRead all ship in this PR, it should read:

Further inbox operations (delete) land in follow-up PRs.

2. Missing OAuth scope entries in docs/oauth-scopes.md

Per agent_docs/rules.md: "When adding methods, update docs/oauth-scopes.md with required OAuth scopes. NEVER skip this."

The Notifications section only covers getAll(). The three new methods need entries:

Method OAuth Scope
markRead() NotificationService
markUnread() NotificationService
markAllRead() NotificationService

@sarthak688 sarthak688 force-pushed the feat/notifications-sdk branch 10 times, most recently from 35d8ef4 to 32c58a9 Compare June 16, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant