feat(subscriptions): topic-level updates (PR 5/7)#517
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>
Adds the two delete methods. Both POST to the NotificationEntry.DeleteBulk OData action; deleteAll uses the server-side deleteAll flag. Preserves the API spec's misspelling `notifcationIds` in the request body — the server expects that exact (mistyped) key. Tests: 4 additional unit tests. No integration tests — these destructively mutate the inbox with no SDK-level undo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the SubscriptionService class alongside the existing NotificationService. Both services live under @uipath/uipath-typescript/notifications as discrete classes (no shared state). Subscription endpoints route through the same notificationservice_ base via the URL-traversal trick. Methods: getAll, getPublishers, getSupportedChannels — the three read-side methods that return user subscription state and tenant channel availability. Mutation methods land in follow-up PRs. Adds SUBSCRIPTION_ENDPOINTS scaffold (3 read URLs), subscription model types (SubscriptionPublisher, SubscriptionTopic, SubscriptionMode, SupportedChannel, AllowedMode, options types), subscription test infrastructure (mock factories), Subscriptions section in oauth-scopes and mkdocs nav, and Subscriptions registration in unified-setup. Tests: 8 unit + 4 integration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…gory) Adds the two topic/category-scoped subscription writes. Each entry in the payload sets the subscription state for a single (topic, mode) or (category, mode) pair. UPDATE_TOPIC reuses the same URL as GET_ALL — POST vs GET differentiates. Adds TopicSubscriptionUpdate and CategorySubscriptionUpdate types, response types, oauth-scopes entries, and unit + integration tests (updateTopic round-trip; updateCategory unit-only because it needs richer tenant fixtures). 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.
The updateCategory error test uses the generic TEST_CONSTANTS.ERROR_MESSAGE while the parallel updateTopic error test (line 174) correctly uses NOTIFICATION_TEST_CONSTANTS.ERROR_SUBSCRIPTION_INVALID. Per conventions, TEST_CONSTANTS.ERROR_MESSAGE is only acceptable for collection methods like getAll — mutation methods should use domain-specific error constants.
| it('should propagate errors', async () => { | |
| mockApiClient.post.mockRejectedValue(createMockError(TEST_CONSTANTS.ERROR_MESSAGE)); | |
| it('should propagate errors', async () => { | |
| mockApiClient.post.mockRejectedValue(createMockError(NOTIFICATION_TEST_CONSTANTS.ERROR_SUBSCRIPTION_INVALID)); |
There was a problem hiding this comment.
Addressed in a2057e0 — switched to NOTIFICATION_TEST_CONSTANTS.ERROR_SUBSCRIPTION_INVALID.
| notificationMode: NotificationMode.InApp, | ||
| }, | ||
| ]) | ||
| ).rejects.toThrow(TEST_CONSTANTS.ERROR_MESSAGE); |
There was a problem hiding this comment.
| ).rejects.toThrow(TEST_CONSTANTS.ERROR_MESSAGE); | |
| ).rejects.toThrow(NOTIFICATION_TEST_CONSTANTS.ERROR_SUBSCRIPTION_INVALID); |
There was a problem hiding this comment.
Addressed in a2057e0 — switched to NOTIFICATION_TEST_CONSTANTS.ERROR_SUBSCRIPTION_INVALID.
|
Review findings (1 issue): New finding posted:
|
…ory test Matches the parallel updateTopic error test on the same suite. Addresses review comment on PR #517. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
All findings addressed in the latest commit on this branch. Inline reply threads are resolved with commit references. |
…scopes entries Same internal-scope treatment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1d382c9 to
18c7fcb
Compare
PR 5/7 in the Notification SDK stack. Stacked on top of #516.
Adds the topic-scoped subscription writes. Each method takes an array of update entries, letting callers batch many subscription toggles into one request.
Methods Added
subscriptions.updateTopic()updateTopic(tenantId: string, subscriptions: TopicSubscriptionUpdate[]): Promise<SubscriptionUpdateTopicResponse>subscriptions.updateCategory()updateCategory(tenantId: string, subscriptions: CategorySubscriptionUpdate[]): Promise<SubscriptionUpdateCategoryResponse>Endpoints Called
updateTopic()notificationservice_/usersubscriptionservice/api/v1/UserSubscriptionNotificationServiceupdateCategory()notificationservice_/usersubscriptionservice/api/v1/UserSubscription/CategorySubscriptionNotificationServiceUPDATE_TOPICreuses the same URL asGET_ALL— POST vs GET differentiates the operation. Documented inline in the endpoint constants.updateTopicsends{ userSubscriptions: [...] };updateCategorysends{ categorySubscriptions: [...] }.(topicId|publisherId, isSubscribed, notificationMode)triple.Example Usage
API Response vs SDK Response
updateTopic{ success: true, data: { subscriptions } }(echoes input)updateCategory{ success: true, data: { subscriptions } }(echoes input)Verification
npm run typechecknpm run lintnpm run test:unitIntegration:
updateTopicround-trip — flip a non-mandatory topic's mode, then restore.updateCategoryis unit-only because it needs richer tenant fixtures (multi-topic category coverage).Files
src/utils/constants/endpoints/notification.ts(UPDATE_TOPIC,UPDATE_CATEGORY)src/models/notification/subscriptions.types.ts(TopicSubscriptionUpdate,CategorySubscriptionUpdate)src/models/notification/subscriptions.models.ts(response types + ServiceModel methods)src/services/notification/subscriptions.tstests/unit/services/notification/subscriptions.test.ts(+4 tests)tests/integration/shared/notification/subscriptions.integration.test.ts(+1 round-trip test)tests/utils/constants/notification.ts(ERROR_SUBSCRIPTION_INVALID)docs/oauth-scopes.mdPR Stack
feat/notifications-sdkfeat/notifications-mark-readfeat/notifications-deletefeat/subscriptions-sdkfeat/subscriptions-topic-updates(this PR)feat/subscriptions-publisher-updatesfeat/subscriptions-mode-reset🤖 Generated with Claude Code