feat(notifications): mark-read flows (PR 2/7)#513
Conversation
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)); |
There was a problem hiding this comment.
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."
| 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.
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
markAllRead is a mutation on domain entities — for consistency with markRead and the corrected markUnread, use the domain-specific error constant here too.
| 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.
There was a problem hiding this comment.
Addressed in a59c3f6 — switched both error tests to NOTIFICATION_TEST_CONSTANTS.ERROR_NOTIFICATION_NOT_FOUND.
Review findings2 inline comments + 1 general note Inline comments
General note — stale class JSDoc
Since mark-read is being shipped in this PR, update it to: (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>
|
Stale class-level JSDoc in Line ~41 currently reads: Since |
|
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>
|
Two issues remain after the latest commit — both outside the diff so inline comments aren't possible. 1. Stale class-level JSDoc in
|
| Method | OAuth Scope |
|---|---|
markRead() |
NotificationService |
markUnread() |
NotificationService |
markAllRead() |
NotificationService |
35d8ef4 to
32c58a9
Compare
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
UpdateReadOData action endpoint;markAllReaduses the server-sideforceAllReadflag.Methods Added
notifications.markRead()markRead(tenantId: string, notificationIds: string[]): Promise<NotificationUpdateReadResponse>notifications.markUnread()markUnread(tenantId: string, notificationIds: string[]): Promise<NotificationUpdateReadResponse>notifications.markAllRead()markAllRead(tenantId: string): Promise<NotificationMarkAllReadResponse>Endpoint Called
markRead()/markUnread()/markAllRead()notificationservice_/notificationserviceapi/odata/v1/NotificationEntry/UiPath.NotificationService.Api.UpdateReadNotificationServicemarkReadandmarkUnreaddelegate to a privateupdateRead(tenantId, ids, read)helper to share the POST body construction.markAllReadsends{ notifications: [], forceAllRead: true }— the server reads all notifications for the acting user regardless of the empty array.@track(...)telemetry decorators.Example Usage
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: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
npm run typechecknpm run lintnpm run test:unitFiles
src/utils/constants/endpoints/notification.ts(UPDATE_READ)src/models/notification/notifications.models.ts(response types + ServiceModel methods)src/services/notification/notifications.ts(methods + privateupdateReadhelper)tests/unit/services/notification/notifications.test.ts(+6 tests)tests/integration/shared/notification/notifications.integration.test.ts(+2 tests)docs/oauth-scopes.mdPR Stack
feat/notifications-sdkfeat/notifications-mark-read(this PR)feat/notifications-deletefeat/subscriptions-sdkfeat/subscriptions-topic-updatesfeat/subscriptions-publisher-updatesfeat/subscriptions-mode-reset🤖 Generated with Claude Code