diff --git a/apps/api/src/app/subscribers-v2/dtos/get-subscriber-preferences.dto.ts b/apps/api/src/app/subscribers-v2/dtos/get-subscriber-preferences.dto.ts new file mode 100644 index 00000000000..8d9ada3ec06 --- /dev/null +++ b/apps/api/src/app/subscribers-v2/dtos/get-subscriber-preferences.dto.ts @@ -0,0 +1,48 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { PreferenceChannels } from '../../shared/dtos/preference-channels'; +import { Overrides } from '../../subscribers/dtos/get-subscriber-preferences-response.dto'; + +export class WorkflowInfoDto { + @ApiProperty({ description: 'Unique identifier of the workflow' }) + identifier: string; + + @ApiProperty({ description: 'Display name of the workflow' }) + name: string; +} + +export class GlobalPreferenceDto { + @ApiProperty({ description: 'Whether notifications are enabled globally' }) + enabled: boolean; + + @ApiProperty({ description: 'Channel-specific preference settings', type: PreferenceChannels }) + @Type(() => PreferenceChannels) + channels: PreferenceChannels; +} + +export class WorkflowPreferenceDto { + @ApiProperty({ description: 'Whether notifications are enabled for this workflow' }) + enabled: boolean; + + @ApiProperty({ description: 'Channel-specific preference settings for this workflow', type: PreferenceChannels }) + @Type(() => PreferenceChannels) + channels: PreferenceChannels; + + @ApiProperty({ description: 'List of preference overrides', type: [Overrides] }) + @Type(() => Overrides) + overrides: Overrides[]; + + @ApiProperty({ description: 'Workflow information', type: WorkflowInfoDto }) + @Type(() => WorkflowInfoDto) + workflow: WorkflowInfoDto; +} + +export class GetSubscriberPreferencesDto { + @ApiProperty({ description: 'Global preference settings', type: GlobalPreferenceDto }) + @Type(() => GlobalPreferenceDto) + global: GlobalPreferenceDto; + + @ApiProperty({ description: 'Workflow-specific preference settings', type: [WorkflowPreferenceDto] }) + @Type(() => WorkflowPreferenceDto) + workflows: WorkflowPreferenceDto[]; +} diff --git a/apps/api/src/app/subscribers-v2/dtos/index.ts b/apps/api/src/app/subscribers-v2/dtos/index.ts deleted file mode 100644 index 1a7a9765f95..00000000000 --- a/apps/api/src/app/subscribers-v2/dtos/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './list-subscribers-response.dto'; -export * from './list-subscribers-query.dto'; -export { CursorPaginationQueryDto } from './cursor-pagination-query.dto'; diff --git a/apps/api/src/app/subscribers-v2/e2e/get-subscriber-preferences.e2e.ts b/apps/api/src/app/subscribers-v2/e2e/get-subscriber-preferences.e2e.ts new file mode 100644 index 00000000000..026284d8bc5 --- /dev/null +++ b/apps/api/src/app/subscribers-v2/e2e/get-subscriber-preferences.e2e.ts @@ -0,0 +1,139 @@ +import { expect } from 'chai'; +import { randomBytes } from 'crypto'; +import { UserSession } from '@novu/testing'; +import { ChannelTypeEnum } from '@novu/shared'; +import { NotificationTemplateEntity } from '@novu/dal'; +import { + UpdateSubscriberGlobalPreferencesRequestDto, + UpdateSubscriberPreferenceRequestDto, + SubscriberResponseDto, +} from '@novu/api/models/components'; +import { Novu } from '@novu/api'; +import { expectSdkExceptionGeneric, initNovuClassSdk } from '../../shared/helpers/e2e/sdk/e2e-sdk.helper'; + +const v2Prefix = '/v2'; +let session: UserSession; + +describe('Get Subscriber Preferences - /subscribers/:subscriberId/preferences (GET) #novu-v2', () => { + let novuClient: Novu; + let subscriber: SubscriberResponseDto; + let workflow: NotificationTemplateEntity; + + beforeEach(async () => { + const uuid = randomBytes(4).toString('hex'); + session = new UserSession(); + await session.initialize(); + novuClient = initNovuClassSdk(session); + subscriber = await createSubscriberAndValidate(uuid); + workflow = await session.createTemplate({ + noFeedId: true, + }); + }); + + it('should fetch subscriber preferences with default values', async () => { + const response = await novuClient.subscribers.preferences.retrieve(subscriber.subscriberId); + + expect(response.result).to.have.property('global'); + expect(response.result).to.have.property('workflows'); + + const { global, workflows } = response.result; + + // Validate global preferences + expect(global).to.have.property('enabled'); + expect(global).to.have.property('channels'); + expect(global.enabled).to.be.true; + + // Validate workflows array + expect(workflows).to.be.an('array'); + expect(workflows).to.have.lengthOf(1); + }); + + it('should return 404 if subscriber does not exist', async () => { + const invalidSubscriberId = `non-existent-${randomBytes(2).toString('hex')}`; + const { error } = await expectSdkExceptionGeneric(() => + novuClient.subscribers.preferences.retrieve(invalidSubscriberId) + ); + + expect(error?.statusCode).to.equal(404); + }); + + it('should handle subscriber with modified workflow preferences', async () => { + // created workflow has 'email' and 'in-app' channels enabled by default + const workflowId = workflow._id; + + // disable email channel for this workflow + const enableEmailPreferenceData: UpdateSubscriberPreferenceRequestDto = { + channel: { + type: ChannelTypeEnum.EMAIL, + enabled: false, + }, + }; + + // TODO: replace with v2 endpoint when available + await session.testAgent + .patch(`/v1/subscribers/${subscriber.subscriberId}/preferences/${workflowId}`) + .send({ ...enableEmailPreferenceData }); + + const response = await session.testAgent.get(`${v2Prefix}/subscribers/${subscriber.subscriberId}/preferences`); + + const { global, workflows } = response.body.data; + + expect(response.statusCode).to.equal(200); + + expect(global.channels).to.deep.equal({ in_app: true, email: true }); + expect(workflows).to.have.lengthOf(1); + expect(workflows[0].channels).to.deep.equal({ in_app: true, email: false }); + expect(workflows[0].workflow).to.deep.equal({ name: workflow.name, identifier: workflow.triggers[0].identifier }); + }); + + it('should handle subscriber with modified global preferences', async () => { + // disable email channel globally + const enableGlobalEmailPreferenceData: UpdateSubscriberGlobalPreferencesRequestDto = { + preferences: [ + { + type: ChannelTypeEnum.EMAIL, + enabled: false, + }, + ], + }; + + // TODO: replace with v2 endpoint when available + await session.testAgent + .patch(`/v1/subscribers/${subscriber.subscriberId}/preferences`) + .send({ ...enableGlobalEmailPreferenceData }); + + const response = await session.testAgent.get(`${v2Prefix}/subscribers/${subscriber.subscriberId}/preferences`); + + const { global, workflows } = response.body.data; + + expect(response.statusCode).to.equal(200); + + expect(global.channels).to.deep.equal({ in_app: true, email: false }); + expect(workflows).to.have.lengthOf(1); + expect(workflows[0].channels).to.deep.equal({ in_app: true, email: false }); + expect(workflows[0].workflow).to.deep.equal({ name: workflow.name, identifier: workflow.triggers[0].identifier }); + }); +}); + +async function createSubscriberAndValidate(id: string = '') { + const payload = { + subscriberId: `test-subscriber-${id}`, + firstName: `Test ${id}`, + lastName: 'Subscriber', + email: `test-${id}@subscriber.com`, + phone: '+1234567890', + }; + + const res = await session.testAgent.post(`/v1/subscribers`).send(payload); + expect(res.status).to.equal(201); + + const subscriber = res.body.data; + + expect(subscriber.subscriberId).to.equal(payload.subscriberId); + expect(subscriber.firstName).to.equal(payload.firstName); + expect(subscriber.lastName).to.equal(payload.lastName); + expect(subscriber.email).to.equal(payload.email); + expect(subscriber.phone).to.equal(payload.phone); + + return subscriber; +} diff --git a/apps/api/src/app/subscribers-v2/subscribers.controller.ts b/apps/api/src/app/subscribers-v2/subscribers.controller.ts index 4906ad0694a..bdba72a084a 100644 --- a/apps/api/src/app/subscribers-v2/subscribers.controller.ts +++ b/apps/api/src/app/subscribers-v2/subscribers.controller.ts @@ -20,8 +20,10 @@ import { GetSubscriber } from './usecases/get-subscriber/get-subscriber.usecase' import { GetSubscriberCommand } from './usecases/get-subscriber/get-subscriber.command'; import { PatchSubscriber } from './usecases/patch-subscriber/patch-subscriber.usecase'; import { PatchSubscriberCommand } from './usecases/patch-subscriber/patch-subscriber.command'; +import { GetSubscriberPreferences } from './usecases/get-subscriber-preferences/get-subscriber-preferences.usecase'; +import { GetSubscriberPreferencesCommand } from './usecases/get-subscriber-preferences/get-subscriber-preferences.command'; import { ListSubscribersQueryDto } from './dtos/list-subscribers-query.dto'; -import { ListSubscribersResponseDto } from './dtos'; +import { ListSubscribersResponseDto } from './dtos/list-subscribers-response.dto'; import { SdkGroupName, SdkMethodName } from '../shared/framework/swagger/sdk.decorators'; import { DirectionEnum } from '../shared/dtos/base-responses'; import { PatchSubscriberRequestDto } from './dtos/patch-subscriber.dto'; @@ -29,6 +31,7 @@ import { SubscriberResponseDto } from '../subscribers/dtos'; import { RemoveSubscriberCommand } from './usecases/remove-subscriber/remove-subscriber.command'; import { RemoveSubscriber } from './usecases/remove-subscriber/remove-subscriber.usecase'; import { RemoveSubscriberResponseDto } from './dtos/remove-subscriber.dto'; +import { GetSubscriberPreferencesDto } from './dtos/get-subscriber-preferences.dto'; @Controller({ path: '/subscribers', version: '2' }) @UseInterceptors(ClassSerializerInterceptor) @@ -40,7 +43,8 @@ export class SubscribersController { private listSubscribersUsecase: ListSubscribersUseCase, private getSubscriberUsecase: GetSubscriber, private patchSubscriberUsecase: PatchSubscriber, - private removeSubscriberUsecase: RemoveSubscriber + private removeSubscriberUsecase: RemoveSubscriber, + private getSubscriberPreferencesUsecase: GetSubscriberPreferences ) {} @Get('') @@ -136,4 +140,27 @@ export class SubscribersController { }) ); } + + @Get('/:subscriberId/preferences') + @UserAuthentication() + @ExternalApiAccessible() + @ApiOperation({ + summary: 'Get subscriber preferences', + description: 'Get subscriber preferences', + }) + @ApiResponse(GetSubscriberPreferencesDto) + @SdkGroupName('Subscribers.Preferences') + @SdkMethodName('retrieve') + async getSubscriberPreferences( + @UserSession() user: UserSessionData, + @Param('subscriberId') subscriberId: string + ): Promise { + return await this.getSubscriberPreferencesUsecase.execute( + GetSubscriberPreferencesCommand.create({ + environmentId: user.environmentId, + organizationId: user.organizationId, + subscriberId, + }) + ); + } } diff --git a/apps/api/src/app/subscribers-v2/subscribers.module.ts b/apps/api/src/app/subscribers-v2/subscribers.module.ts index 9e6876c21d3..ea5fe4dc444 100644 --- a/apps/api/src/app/subscribers-v2/subscribers.module.ts +++ b/apps/api/src/app/subscribers-v2/subscribers.module.ts @@ -1,18 +1,44 @@ import { Module } from '@nestjs/common'; -import { SubscriberRepository } from '@novu/dal'; -import { SubscribersController } from './subscribers.controller'; +import { + NotificationTemplateRepository, + PreferencesRepository, + SubscriberRepository, + TopicSubscribersRepository, +} from '@novu/dal'; +import { + cacheService, + GetPreferences, + GetSubscriberGlobalPreference, + GetSubscriberPreference, + InvalidateCacheService, +} from '@novu/application-generic'; import { ListSubscribersUseCase } from './usecases/list-subscribers/list-subscribers.usecase'; import { GetSubscriber } from './usecases/get-subscriber/get-subscriber.usecase'; import { PatchSubscriber } from './usecases/patch-subscriber/patch-subscriber.usecase'; +import { GetSubscriberPreferences } from './usecases/get-subscriber-preferences/get-subscriber-preferences.usecase'; import { RemoveSubscriber } from './usecases/remove-subscriber/remove-subscriber.usecase'; -import { SharedModule } from '../shared/shared.module'; -import { PreferencesModule } from '../preferences/preferences.module'; +import { SubscribersController } from './subscribers.controller'; + +const USE_CASES = [ + ListSubscribersUseCase, + GetSubscriber, + PatchSubscriber, + RemoveSubscriber, + GetSubscriberPreferences, + GetSubscriberGlobalPreference, + GetSubscriberPreference, + GetPreferences, +]; -const USE_CASES = [ListSubscribersUseCase, GetSubscriber, PatchSubscriber, RemoveSubscriber]; +const DAL_MODELS = [ + SubscriberRepository, + NotificationTemplateRepository, + PreferencesRepository, + TopicSubscribersRepository, +]; @Module({ controllers: [SubscribersController], - imports: [SharedModule, PreferencesModule], - providers: [...USE_CASES, SubscriberRepository], + providers: [...USE_CASES, ...DAL_MODELS, cacheService, InvalidateCacheService], }) export class SubscribersModule {} diff --git a/apps/api/src/app/subscribers-v2/usecases/get-subscriber-preferences/get-subscriber-preferences.command.ts b/apps/api/src/app/subscribers-v2/usecases/get-subscriber-preferences/get-subscriber-preferences.command.ts new file mode 100644 index 00000000000..beda7d56af5 --- /dev/null +++ b/apps/api/src/app/subscribers-v2/usecases/get-subscriber-preferences/get-subscriber-preferences.command.ts @@ -0,0 +1,3 @@ +import { EnvironmentWithSubscriber } from '../../../shared/commands/project.command'; + +export class GetSubscriberPreferencesCommand extends EnvironmentWithSubscriber {} diff --git a/apps/api/src/app/subscribers-v2/usecases/get-subscriber-preferences/get-subscriber-preferences.usecase.ts b/apps/api/src/app/subscribers-v2/usecases/get-subscriber-preferences/get-subscriber-preferences.usecase.ts new file mode 100644 index 00000000000..d51a158fdef --- /dev/null +++ b/apps/api/src/app/subscribers-v2/usecases/get-subscriber-preferences/get-subscriber-preferences.usecase.ts @@ -0,0 +1,76 @@ +import { Injectable } from '@nestjs/common'; +import { + GetSubscriberGlobalPreference, + GetSubscriberGlobalPreferenceCommand, + GetSubscriberPreference, + GetSubscriberPreferenceCommand, +} from '@novu/application-generic'; +import { ISubscriberPreferenceResponse } from '@novu/shared'; +import { plainToInstance } from 'class-transformer'; +import { GetSubscriberPreferencesCommand } from './get-subscriber-preferences.command'; +import { + GetSubscriberPreferencesDto, + GlobalPreferenceDto, + WorkflowPreferenceDto, +} from '../../dtos/get-subscriber-preferences.dto'; + +@Injectable() +export class GetSubscriberPreferences { + constructor( + private getSubscriberGlobalPreference: GetSubscriberGlobalPreference, + private getSubscriberPreference: GetSubscriberPreference + ) {} + + async execute(command: GetSubscriberPreferencesCommand): Promise { + const globalPreference = await this.fetchGlobalPreference(command); + const workflowPreferences = await this.fetchWorkflowPreferences(command); + + return plainToInstance(GetSubscriberPreferencesDto, { + global: globalPreference, + workflows: workflowPreferences, + }); + } + + private async fetchGlobalPreference(command: GetSubscriberPreferencesCommand): Promise { + const { preference } = await this.getSubscriberGlobalPreference.execute( + GetSubscriberGlobalPreferenceCommand.create({ + organizationId: command.organizationId, + environmentId: command.environmentId, + subscriberId: command.subscriberId, + includeInactiveChannels: false, + }) + ); + + return { + enabled: preference.enabled, + channels: preference.channels, + }; + } + + private async fetchWorkflowPreferences(command: GetSubscriberPreferencesCommand) { + const subscriberWorkflowPreferences = await this.getSubscriberPreference.execute( + GetSubscriberPreferenceCommand.create({ + environmentId: command.environmentId, + subscriberId: command.subscriberId, + organizationId: command.organizationId, + includeInactiveChannels: false, + }) + ); + + return subscriberWorkflowPreferences.map(this.mapToWorkflowPreference); + } + + private mapToWorkflowPreference(subscriberWorkflowPreference: ISubscriberPreferenceResponse): WorkflowPreferenceDto { + const { preference, template } = subscriberWorkflowPreference; + + return { + enabled: preference.enabled, + channels: preference.channels, + overrides: preference.overrides, + workflow: { + identifier: template.triggers[0].identifier, + name: template.name, + }, + }; + } +} diff --git a/apps/api/src/app/subscribers-v2/usecases/list-subscribers/list-subscribers.usecase.ts b/apps/api/src/app/subscribers-v2/usecases/list-subscribers/list-subscribers.usecase.ts index 21c0bafd20b..2bf8c38b68b 100644 --- a/apps/api/src/app/subscribers-v2/usecases/list-subscribers/list-subscribers.usecase.ts +++ b/apps/api/src/app/subscribers-v2/usecases/list-subscribers/list-subscribers.usecase.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InstrumentUsecase } from '@novu/application-generic'; import { SubscriberRepository } from '@novu/dal'; import { ListSubscribersCommand } from './list-subscribers.command'; -import { ListSubscribersResponseDto } from '../../dtos'; +import { ListSubscribersResponseDto } from '../../dtos/list-subscribers-response.dto'; import { DirectionEnum } from '../../../shared/dtos/base-responses'; import { mapSubscriberEntityToDto } from './map-subscriber-entity-to.dto'; diff --git a/apps/api/src/app/subscribers/dtos/get-subscriber-preferences-response.dto.ts b/apps/api/src/app/subscribers/dtos/get-subscriber-preferences-response.dto.ts index 0b688d87a26..dfd1f6d9666 100644 --- a/apps/api/src/app/subscribers/dtos/get-subscriber-preferences-response.dto.ts +++ b/apps/api/src/app/subscribers/dtos/get-subscriber-preferences-response.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { ChannelTypeEnum, PreferenceOverrideSourceEnum } from '@novu/shared'; +import { ChannelTypeEnum, IPreferenceOverride, PreferenceOverrideSourceEnum } from '@novu/shared'; import { PreferenceChannels } from '../../shared/dtos/preference-channels'; class TemplateResponse { @@ -23,7 +23,7 @@ class TemplateResponse { critical: boolean; } -class Overrides { +export class Overrides implements IPreferenceOverride { @ApiProperty({ enum: ChannelTypeEnum, description: 'The channel type which is overridden', diff --git a/libs/application-generic/src/usecases/get-subscriber-global-preference/get-subscriber-global-preference.usecase.ts b/libs/application-generic/src/usecases/get-subscriber-global-preference/get-subscriber-global-preference.usecase.ts index b2b408358a6..d865f0d1b3f 100644 --- a/libs/application-generic/src/usecases/get-subscriber-global-preference/get-subscriber-global-preference.usecase.ts +++ b/libs/application-generic/src/usecases/get-subscriber-global-preference/get-subscriber-global-preference.usecase.ts @@ -1,10 +1,9 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, NotFoundException } from '@nestjs/common'; import { SubscriberEntity, SubscriberRepository } from '@novu/dal'; import { IPreferenceChannels, ChannelTypeEnum } from '@novu/shared'; import { GetSubscriberGlobalPreferenceCommand } from './get-subscriber-global-preference.command'; import { buildSubscriberKey, CachedEntity } from '../../services/cache'; -import { ApiException } from '../../utils/exceptions'; import { GetPreferences } from '../get-preferences'; import { GetSubscriberPreference } from '../get-subscriber-preference/get-subscriber-preference.usecase'; import { filteredPreference } from '../get-subscriber-template-preference/get-subscriber-template-preference.usecase'; @@ -111,7 +110,9 @@ export class GetSubscriberGlobalPreference { ); if (!subscriber) { - throw new ApiException(`Subscriber ${command.subscriberId} not found`); + throw new NotFoundException( + `Subscriber ${command.subscriberId} not found`, + ); } return subscriber; diff --git a/libs/internal-sdk/src/funcs/subscribersPreferencesRetrieve.ts b/libs/internal-sdk/src/funcs/subscribersPreferencesRetrieve.ts new file mode 100644 index 00000000000..2529ee3cf09 --- /dev/null +++ b/libs/internal-sdk/src/funcs/subscribersPreferencesRetrieve.ts @@ -0,0 +1,202 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { NovuCore } from "../core.js"; +import { encodeSimple } from "../lib/encodings.js"; +import * as M from "../lib/matchers.js"; +import { compactMap } from "../lib/primitives.js"; +import { safeParse } from "../lib/schemas.js"; +import { RequestOptions } from "../lib/sdks.js"; +import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js"; +import { pathToFunc } from "../lib/url.js"; +import { + ConnectionError, + InvalidRequestError, + RequestAbortedError, + RequestTimeoutError, + UnexpectedClientError, +} from "../models/errors/httpclienterrors.js"; +import * as errors from "../models/errors/index.js"; +import { SDKError } from "../models/errors/sdkerror.js"; +import { SDKValidationError } from "../models/errors/sdkvalidationerror.js"; +import * as operations from "../models/operations/index.js"; +import { Result } from "../types/fp.js"; + +/** + * Get subscriber preferences + * + * @remarks + * Get subscriber preferences + */ +export async function subscribersPreferencesRetrieve( + client: NovuCore, + subscriberId: string, + idempotencyKey?: string | undefined, + options?: RequestOptions, +): Promise< + Result< + operations.SubscribersControllerGetSubscriberPreferencesResponse, + | errors.ErrorDto + | errors.ErrorDto + | errors.ValidationErrorDto + | errors.ErrorDto + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + > +> { + const input: operations.SubscribersControllerGetSubscriberPreferencesRequest = + { + subscriberId: subscriberId, + idempotencyKey: idempotencyKey, + }; + + const parsed = safeParse( + input, + (value) => + operations + .SubscribersControllerGetSubscriberPreferencesRequest$outboundSchema + .parse(value), + "Input validation failed", + ); + if (!parsed.ok) { + return parsed; + } + const payload = parsed.value; + const body = null; + + const pathParams = { + subscriberId: encodeSimple("subscriberId", payload.subscriberId, { + explode: false, + charEncoding: "percent", + }), + }; + + const path = pathToFunc("/v2/subscribers/{subscriberId}/preferences")( + pathParams, + ); + + const headers = new Headers(compactMap({ + Accept: "application/json", + "idempotency-key": encodeSimple( + "idempotency-key", + payload["idempotency-key"], + { explode: false, charEncoding: "none" }, + ), + })); + + const securityInput = await extractSecurity(client._options.security); + const requestSecurity = resolveGlobalSecurity(securityInput); + + const context = { + operationID: "SubscribersController_getSubscriberPreferences", + oAuth2Scopes: [], + + resolvedSecurity: requestSecurity, + + securitySource: client._options.security, + retryConfig: options?.retries + || client._options.retryConfig + || { + strategy: "backoff", + backoff: { + initialInterval: 1000, + maxInterval: 30000, + exponent: 1.5, + maxElapsedTime: 3600000, + }, + retryConnectionErrors: true, + } + || { strategy: "none" }, + retryCodes: options?.retryCodes || ["408", "409", "429", "5XX"], + }; + + const requestRes = client._createRequest(context, { + security: requestSecurity, + method: "GET", + baseURL: options?.serverURL, + path: path, + headers: headers, + body: body, + timeoutMs: options?.timeoutMs || client._options.timeoutMs || -1, + }, options); + if (!requestRes.ok) { + return requestRes; + } + const req = requestRes.value; + + const doResult = await client._do(req, { + context, + errorCodes: [ + "400", + "401", + "403", + "404", + "405", + "409", + "413", + "414", + "415", + "422", + "429", + "4XX", + "500", + "503", + "5XX", + ], + retryConfig: context.retryConfig, + retryCodes: context.retryCodes, + }); + if (!doResult.ok) { + return doResult; + } + const response = doResult.value; + + const responseFields = { + HttpMeta: { Response: response, Request: req }, + }; + + const [result] = await M.match< + operations.SubscribersControllerGetSubscriberPreferencesResponse, + | errors.ErrorDto + | errors.ErrorDto + | errors.ValidationErrorDto + | errors.ErrorDto + | SDKError + | SDKValidationError + | UnexpectedClientError + | InvalidRequestError + | RequestAbortedError + | RequestTimeoutError + | ConnectionError + >( + M.json( + 200, + operations + .SubscribersControllerGetSubscriberPreferencesResponse$inboundSchema, + { hdrs: true, key: "Result" }, + ), + M.jsonErr(414, errors.ErrorDto$inboundSchema), + M.jsonErr( + [400, 401, 403, 404, 405, 409, 413, 415], + errors.ErrorDto$inboundSchema, + { hdrs: true }, + ), + M.jsonErr(422, errors.ValidationErrorDto$inboundSchema, { hdrs: true }), + M.fail(429), + M.jsonErr(500, errors.ErrorDto$inboundSchema, { hdrs: true }), + M.fail(503), + M.fail("4XX"), + M.fail("5XX"), + )(response, { extraFields: responseFields }); + if (!result.ok) { + return result; + } + + return result; +} diff --git a/libs/internal-sdk/src/models/components/getsubscriberpreferencesdto.ts b/libs/internal-sdk/src/models/components/getsubscriberpreferencesdto.ts new file mode 100644 index 00000000000..ff12360dba4 --- /dev/null +++ b/libs/internal-sdk/src/models/components/getsubscriberpreferencesdto.ts @@ -0,0 +1,90 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; +import { + GlobalPreferenceDto, + GlobalPreferenceDto$inboundSchema, + GlobalPreferenceDto$Outbound, + GlobalPreferenceDto$outboundSchema, +} from "./globalpreferencedto.js"; +import { + WorkflowPreferenceDto, + WorkflowPreferenceDto$inboundSchema, + WorkflowPreferenceDto$Outbound, + WorkflowPreferenceDto$outboundSchema, +} from "./workflowpreferencedto.js"; + +export type GetSubscriberPreferencesDto = { + /** + * Global preference settings + */ + global: GlobalPreferenceDto; + /** + * Workflow-specific preference settings + */ + workflows: Array; +}; + +/** @internal */ +export const GetSubscriberPreferencesDto$inboundSchema: z.ZodType< + GetSubscriberPreferencesDto, + z.ZodTypeDef, + unknown +> = z.object({ + global: GlobalPreferenceDto$inboundSchema, + workflows: z.array(WorkflowPreferenceDto$inboundSchema), +}); + +/** @internal */ +export type GetSubscriberPreferencesDto$Outbound = { + global: GlobalPreferenceDto$Outbound; + workflows: Array; +}; + +/** @internal */ +export const GetSubscriberPreferencesDto$outboundSchema: z.ZodType< + GetSubscriberPreferencesDto$Outbound, + z.ZodTypeDef, + GetSubscriberPreferencesDto +> = z.object({ + global: GlobalPreferenceDto$outboundSchema, + workflows: z.array(WorkflowPreferenceDto$outboundSchema), +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace GetSubscriberPreferencesDto$ { + /** @deprecated use `GetSubscriberPreferencesDto$inboundSchema` instead. */ + export const inboundSchema = GetSubscriberPreferencesDto$inboundSchema; + /** @deprecated use `GetSubscriberPreferencesDto$outboundSchema` instead. */ + export const outboundSchema = GetSubscriberPreferencesDto$outboundSchema; + /** @deprecated use `GetSubscriberPreferencesDto$Outbound` instead. */ + export type Outbound = GetSubscriberPreferencesDto$Outbound; +} + +export function getSubscriberPreferencesDtoToJSON( + getSubscriberPreferencesDto: GetSubscriberPreferencesDto, +): string { + return JSON.stringify( + GetSubscriberPreferencesDto$outboundSchema.parse( + getSubscriberPreferencesDto, + ), + ); +} + +export function getSubscriberPreferencesDtoFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GetSubscriberPreferencesDto$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GetSubscriberPreferencesDto' from JSON`, + ); +} diff --git a/libs/internal-sdk/src/models/components/globalpreferencedto.ts b/libs/internal-sdk/src/models/components/globalpreferencedto.ts new file mode 100644 index 00000000000..8bd0306fb97 --- /dev/null +++ b/libs/internal-sdk/src/models/components/globalpreferencedto.ts @@ -0,0 +1,82 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; +import { + PreferenceChannels, + PreferenceChannels$inboundSchema, + PreferenceChannels$Outbound, + PreferenceChannels$outboundSchema, +} from "./preferencechannels.js"; + +export type GlobalPreferenceDto = { + /** + * Whether notifications are enabled globally + */ + enabled: boolean; + /** + * Channel-specific preference settings + */ + channels: PreferenceChannels; +}; + +/** @internal */ +export const GlobalPreferenceDto$inboundSchema: z.ZodType< + GlobalPreferenceDto, + z.ZodTypeDef, + unknown +> = z.object({ + enabled: z.boolean(), + channels: PreferenceChannels$inboundSchema, +}); + +/** @internal */ +export type GlobalPreferenceDto$Outbound = { + enabled: boolean; + channels: PreferenceChannels$Outbound; +}; + +/** @internal */ +export const GlobalPreferenceDto$outboundSchema: z.ZodType< + GlobalPreferenceDto$Outbound, + z.ZodTypeDef, + GlobalPreferenceDto +> = z.object({ + enabled: z.boolean(), + channels: PreferenceChannels$outboundSchema, +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace GlobalPreferenceDto$ { + /** @deprecated use `GlobalPreferenceDto$inboundSchema` instead. */ + export const inboundSchema = GlobalPreferenceDto$inboundSchema; + /** @deprecated use `GlobalPreferenceDto$outboundSchema` instead. */ + export const outboundSchema = GlobalPreferenceDto$outboundSchema; + /** @deprecated use `GlobalPreferenceDto$Outbound` instead. */ + export type Outbound = GlobalPreferenceDto$Outbound; +} + +export function globalPreferenceDtoToJSON( + globalPreferenceDto: GlobalPreferenceDto, +): string { + return JSON.stringify( + GlobalPreferenceDto$outboundSchema.parse(globalPreferenceDto), + ); +} + +export function globalPreferenceDtoFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => GlobalPreferenceDto$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'GlobalPreferenceDto' from JSON`, + ); +} diff --git a/libs/internal-sdk/src/models/components/index.ts b/libs/internal-sdk/src/models/components/index.ts index b8374b20e00..5e9b78fa5e1 100644 --- a/libs/internal-sdk/src/models/components/index.ts +++ b/libs/internal-sdk/src/models/components/index.ts @@ -54,8 +54,10 @@ export * from "./feedresponsedto.js"; export * from "./fieldfilterpartdto.js"; export * from "./filtertopicsresponsedto.js"; export * from "./generatepreviewresponsedto.js"; +export * from "./getsubscriberpreferencesdto.js"; export * from "./getsubscriberpreferencesresponsedto.js"; export * from "./gettopicresponsedto.js"; +export * from "./globalpreferencedto.js"; export * from "./integrationresponsedto.js"; export * from "./listsubscribersresponsedto.js"; export * from "./markallmessageasrequestdto.js"; @@ -83,6 +85,7 @@ export * from "./notificationtriggervariable.js"; export * from "./notificationtriggervariableresponse.js"; export * from "./ordinalenum.js"; export * from "./ordinalvalueenum.js"; +export * from "./overrides.js"; export * from "./patchsubscriberrequestdto.js"; export * from "./preference.js"; export * from "./preferencechannels.js"; @@ -122,4 +125,6 @@ export * from "./updatesubscriberpreferenceglobalresponsedto.js"; export * from "./updatesubscriberpreferencerequestdto.js"; export * from "./updatesubscriberpreferenceresponsedto.js"; export * from "./updatesubscriberrequestdto.js"; +export * from "./workflowinfodto.js"; +export * from "./workflowpreferencedto.js"; export * from "./workflowresponse.js"; diff --git a/libs/internal-sdk/src/models/components/overrides.ts b/libs/internal-sdk/src/models/components/overrides.ts new file mode 100644 index 00000000000..0965f9bb062 --- /dev/null +++ b/libs/internal-sdk/src/models/components/overrides.ts @@ -0,0 +1,141 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { ClosedEnum } from "../../types/enums.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +/** + * The channel type which is overridden + */ +export const OverridesChannel = { + InApp: "in_app", + Email: "email", + Sms: "sms", + Chat: "chat", + Push: "push", +} as const; +/** + * The channel type which is overridden + */ +export type OverridesChannel = ClosedEnum; + +/** + * The source of overrides + */ +export const Source = { + Subscriber: "subscriber", + Template: "template", + WorkflowOverride: "workflowOverride", +} as const; +/** + * The source of overrides + */ +export type Source = ClosedEnum; + +export type Overrides = { + /** + * The channel type which is overridden + */ + channel: OverridesChannel; + /** + * The source of overrides + */ + source: Source; +}; + +/** @internal */ +export const OverridesChannel$inboundSchema: z.ZodNativeEnum< + typeof OverridesChannel +> = z.nativeEnum(OverridesChannel); + +/** @internal */ +export const OverridesChannel$outboundSchema: z.ZodNativeEnum< + typeof OverridesChannel +> = OverridesChannel$inboundSchema; + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace OverridesChannel$ { + /** @deprecated use `OverridesChannel$inboundSchema` instead. */ + export const inboundSchema = OverridesChannel$inboundSchema; + /** @deprecated use `OverridesChannel$outboundSchema` instead. */ + export const outboundSchema = OverridesChannel$outboundSchema; +} + +/** @internal */ +export const Source$inboundSchema: z.ZodNativeEnum = z + .nativeEnum(Source); + +/** @internal */ +export const Source$outboundSchema: z.ZodNativeEnum = + Source$inboundSchema; + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace Source$ { + /** @deprecated use `Source$inboundSchema` instead. */ + export const inboundSchema = Source$inboundSchema; + /** @deprecated use `Source$outboundSchema` instead. */ + export const outboundSchema = Source$outboundSchema; +} + +/** @internal */ +export const Overrides$inboundSchema: z.ZodType< + Overrides, + z.ZodTypeDef, + unknown +> = z.object({ + channel: OverridesChannel$inboundSchema, + source: Source$inboundSchema, +}); + +/** @internal */ +export type Overrides$Outbound = { + channel: string; + source: string; +}; + +/** @internal */ +export const Overrides$outboundSchema: z.ZodType< + Overrides$Outbound, + z.ZodTypeDef, + Overrides +> = z.object({ + channel: OverridesChannel$outboundSchema, + source: Source$outboundSchema, +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace Overrides$ { + /** @deprecated use `Overrides$inboundSchema` instead. */ + export const inboundSchema = Overrides$inboundSchema; + /** @deprecated use `Overrides$outboundSchema` instead. */ + export const outboundSchema = Overrides$outboundSchema; + /** @deprecated use `Overrides$Outbound` instead. */ + export type Outbound = Overrides$Outbound; +} + +export function overridesToJSON(overrides: Overrides): string { + return JSON.stringify(Overrides$outboundSchema.parse(overrides)); +} + +export function overridesFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => Overrides$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'Overrides' from JSON`, + ); +} diff --git a/libs/internal-sdk/src/models/components/triggereventtoallrequestdto.ts b/libs/internal-sdk/src/models/components/triggereventtoallrequestdto.ts index 66756d3ef5a..3c51b37b947 100644 --- a/libs/internal-sdk/src/models/components/triggereventtoallrequestdto.ts +++ b/libs/internal-sdk/src/models/components/triggereventtoallrequestdto.ts @@ -22,7 +22,7 @@ import { /** * This could be used to override provider specific configurations */ -export type Overrides = {}; +export type TriggerEventToAllRequestDtoOverrides = {}; /** * It is used to display the Avatar of the provided actor's subscriber id or actor object. @@ -56,7 +56,7 @@ export type TriggerEventToAllRequestDto = { /** * This could be used to override provider specific configurations */ - overrides?: Overrides | undefined; + overrides?: TriggerEventToAllRequestDtoOverrides | undefined; /** * A unique identifier for this transaction, we will generated a UUID if not provided. */ @@ -78,46 +78,55 @@ export type TriggerEventToAllRequestDto = { }; /** @internal */ -export const Overrides$inboundSchema: z.ZodType< - Overrides, +export const TriggerEventToAllRequestDtoOverrides$inboundSchema: z.ZodType< + TriggerEventToAllRequestDtoOverrides, z.ZodTypeDef, unknown > = z.object({}); /** @internal */ -export type Overrides$Outbound = {}; +export type TriggerEventToAllRequestDtoOverrides$Outbound = {}; /** @internal */ -export const Overrides$outboundSchema: z.ZodType< - Overrides$Outbound, +export const TriggerEventToAllRequestDtoOverrides$outboundSchema: z.ZodType< + TriggerEventToAllRequestDtoOverrides$Outbound, z.ZodTypeDef, - Overrides + TriggerEventToAllRequestDtoOverrides > = z.object({}); /** * @internal * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. */ -export namespace Overrides$ { - /** @deprecated use `Overrides$inboundSchema` instead. */ - export const inboundSchema = Overrides$inboundSchema; - /** @deprecated use `Overrides$outboundSchema` instead. */ - export const outboundSchema = Overrides$outboundSchema; - /** @deprecated use `Overrides$Outbound` instead. */ - export type Outbound = Overrides$Outbound; +export namespace TriggerEventToAllRequestDtoOverrides$ { + /** @deprecated use `TriggerEventToAllRequestDtoOverrides$inboundSchema` instead. */ + export const inboundSchema = + TriggerEventToAllRequestDtoOverrides$inboundSchema; + /** @deprecated use `TriggerEventToAllRequestDtoOverrides$outboundSchema` instead. */ + export const outboundSchema = + TriggerEventToAllRequestDtoOverrides$outboundSchema; + /** @deprecated use `TriggerEventToAllRequestDtoOverrides$Outbound` instead. */ + export type Outbound = TriggerEventToAllRequestDtoOverrides$Outbound; } -export function overridesToJSON(overrides: Overrides): string { - return JSON.stringify(Overrides$outboundSchema.parse(overrides)); +export function triggerEventToAllRequestDtoOverridesToJSON( + triggerEventToAllRequestDtoOverrides: TriggerEventToAllRequestDtoOverrides, +): string { + return JSON.stringify( + TriggerEventToAllRequestDtoOverrides$outboundSchema.parse( + triggerEventToAllRequestDtoOverrides, + ), + ); } -export function overridesFromJSON( +export function triggerEventToAllRequestDtoOverridesFromJSON( jsonString: string, -): SafeParseResult { +): SafeParseResult { return safeParse( jsonString, - (x) => Overrides$inboundSchema.parse(JSON.parse(x)), - `Failed to parse 'Overrides' from JSON`, + (x) => + TriggerEventToAllRequestDtoOverrides$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'TriggerEventToAllRequestDtoOverrides' from JSON`, ); } @@ -234,7 +243,8 @@ export const TriggerEventToAllRequestDto$inboundSchema: z.ZodType< > = z.object({ name: z.string(), payload: z.record(z.any()), - overrides: z.lazy(() => Overrides$inboundSchema).optional(), + overrides: z.lazy(() => TriggerEventToAllRequestDtoOverrides$inboundSchema) + .optional(), transactionId: z.string().optional(), actor: z.union([SubscriberPayloadDto$inboundSchema, z.string()]).optional(), tenant: z.union([TenantPayloadDto$inboundSchema, z.string()]).optional(), @@ -244,7 +254,7 @@ export const TriggerEventToAllRequestDto$inboundSchema: z.ZodType< export type TriggerEventToAllRequestDto$Outbound = { name: string; payload: { [k: string]: any }; - overrides?: Overrides$Outbound | undefined; + overrides?: TriggerEventToAllRequestDtoOverrides$Outbound | undefined; transactionId?: string | undefined; actor?: SubscriberPayloadDto$Outbound | string | undefined; tenant?: TenantPayloadDto$Outbound | string | undefined; @@ -258,7 +268,8 @@ export const TriggerEventToAllRequestDto$outboundSchema: z.ZodType< > = z.object({ name: z.string(), payload: z.record(z.any()), - overrides: z.lazy(() => Overrides$outboundSchema).optional(), + overrides: z.lazy(() => TriggerEventToAllRequestDtoOverrides$outboundSchema) + .optional(), transactionId: z.string().optional(), actor: z.union([SubscriberPayloadDto$outboundSchema, z.string()]).optional(), tenant: z.union([TenantPayloadDto$outboundSchema, z.string()]).optional(), diff --git a/libs/internal-sdk/src/models/components/workflowinfodto.ts b/libs/internal-sdk/src/models/components/workflowinfodto.ts new file mode 100644 index 00000000000..c80379c2be6 --- /dev/null +++ b/libs/internal-sdk/src/models/components/workflowinfodto.ts @@ -0,0 +1,74 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type WorkflowInfoDto = { + /** + * Unique identifier of the workflow + */ + identifier: string; + /** + * Display name of the workflow + */ + name: string; +}; + +/** @internal */ +export const WorkflowInfoDto$inboundSchema: z.ZodType< + WorkflowInfoDto, + z.ZodTypeDef, + unknown +> = z.object({ + identifier: z.string(), + name: z.string(), +}); + +/** @internal */ +export type WorkflowInfoDto$Outbound = { + identifier: string; + name: string; +}; + +/** @internal */ +export const WorkflowInfoDto$outboundSchema: z.ZodType< + WorkflowInfoDto$Outbound, + z.ZodTypeDef, + WorkflowInfoDto +> = z.object({ + identifier: z.string(), + name: z.string(), +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace WorkflowInfoDto$ { + /** @deprecated use `WorkflowInfoDto$inboundSchema` instead. */ + export const inboundSchema = WorkflowInfoDto$inboundSchema; + /** @deprecated use `WorkflowInfoDto$outboundSchema` instead. */ + export const outboundSchema = WorkflowInfoDto$outboundSchema; + /** @deprecated use `WorkflowInfoDto$Outbound` instead. */ + export type Outbound = WorkflowInfoDto$Outbound; +} + +export function workflowInfoDtoToJSON( + workflowInfoDto: WorkflowInfoDto, +): string { + return JSON.stringify(WorkflowInfoDto$outboundSchema.parse(workflowInfoDto)); +} + +export function workflowInfoDtoFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => WorkflowInfoDto$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'WorkflowInfoDto' from JSON`, + ); +} diff --git a/libs/internal-sdk/src/models/components/workflowpreferencedto.ts b/libs/internal-sdk/src/models/components/workflowpreferencedto.ts new file mode 100644 index 00000000000..8b288bff7e0 --- /dev/null +++ b/libs/internal-sdk/src/models/components/workflowpreferencedto.ts @@ -0,0 +1,108 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; +import { + Overrides, + Overrides$inboundSchema, + Overrides$Outbound, + Overrides$outboundSchema, +} from "./overrides.js"; +import { + PreferenceChannels, + PreferenceChannels$inboundSchema, + PreferenceChannels$Outbound, + PreferenceChannels$outboundSchema, +} from "./preferencechannels.js"; +import { + WorkflowInfoDto, + WorkflowInfoDto$inboundSchema, + WorkflowInfoDto$Outbound, + WorkflowInfoDto$outboundSchema, +} from "./workflowinfodto.js"; + +export type WorkflowPreferenceDto = { + /** + * Whether notifications are enabled for this workflow + */ + enabled: boolean; + /** + * Channel-specific preference settings for this workflow + */ + channels: PreferenceChannels; + /** + * List of preference overrides + */ + overrides: Array; + /** + * Workflow information + */ + workflow: WorkflowInfoDto; +}; + +/** @internal */ +export const WorkflowPreferenceDto$inboundSchema: z.ZodType< + WorkflowPreferenceDto, + z.ZodTypeDef, + unknown +> = z.object({ + enabled: z.boolean(), + channels: PreferenceChannels$inboundSchema, + overrides: z.array(Overrides$inboundSchema), + workflow: WorkflowInfoDto$inboundSchema, +}); + +/** @internal */ +export type WorkflowPreferenceDto$Outbound = { + enabled: boolean; + channels: PreferenceChannels$Outbound; + overrides: Array; + workflow: WorkflowInfoDto$Outbound; +}; + +/** @internal */ +export const WorkflowPreferenceDto$outboundSchema: z.ZodType< + WorkflowPreferenceDto$Outbound, + z.ZodTypeDef, + WorkflowPreferenceDto +> = z.object({ + enabled: z.boolean(), + channels: PreferenceChannels$outboundSchema, + overrides: z.array(Overrides$outboundSchema), + workflow: WorkflowInfoDto$outboundSchema, +}); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace WorkflowPreferenceDto$ { + /** @deprecated use `WorkflowPreferenceDto$inboundSchema` instead. */ + export const inboundSchema = WorkflowPreferenceDto$inboundSchema; + /** @deprecated use `WorkflowPreferenceDto$outboundSchema` instead. */ + export const outboundSchema = WorkflowPreferenceDto$outboundSchema; + /** @deprecated use `WorkflowPreferenceDto$Outbound` instead. */ + export type Outbound = WorkflowPreferenceDto$Outbound; +} + +export function workflowPreferenceDtoToJSON( + workflowPreferenceDto: WorkflowPreferenceDto, +): string { + return JSON.stringify( + WorkflowPreferenceDto$outboundSchema.parse(workflowPreferenceDto), + ); +} + +export function workflowPreferenceDtoFromJSON( + jsonString: string, +): SafeParseResult { + return safeParse( + jsonString, + (x) => WorkflowPreferenceDto$inboundSchema.parse(JSON.parse(x)), + `Failed to parse 'WorkflowPreferenceDto' from JSON`, + ); +} diff --git a/libs/internal-sdk/src/models/operations/index.ts b/libs/internal-sdk/src/models/operations/index.ts index c1e68e01829..40cb6b528ad 100644 --- a/libs/internal-sdk/src/models/operations/index.ts +++ b/libs/internal-sdk/src/models/operations/index.ts @@ -21,6 +21,7 @@ export * from "./notificationscontrollergetactivitystats.js"; export * from "./notificationscontrollergetnotification.js"; export * from "./notificationscontrollerlistnotifications.js"; export * from "./subscriberscontrollergetsubscriber.js"; +export * from "./subscriberscontrollergetsubscriberpreferences.js"; export * from "./subscriberscontrollerpatchsubscriber.js"; export * from "./subscriberscontrollerremovesubscriber.js"; export * from "./subscriberscontrollersearchsubscribers.js"; diff --git a/libs/internal-sdk/src/models/operations/subscriberscontrollergetsubscriberpreferences.ts b/libs/internal-sdk/src/models/operations/subscriberscontrollergetsubscriberpreferences.ts new file mode 100644 index 00000000000..241189aee47 --- /dev/null +++ b/libs/internal-sdk/src/models/operations/subscriberscontrollergetsubscriberpreferences.ts @@ -0,0 +1,183 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import * as z from "zod"; +import { remap as remap$ } from "../../lib/primitives.js"; +import { safeParse } from "../../lib/schemas.js"; +import { Result as SafeParseResult } from "../../types/fp.js"; +import * as components from "../components/index.js"; +import { SDKValidationError } from "../errors/sdkvalidationerror.js"; + +export type SubscribersControllerGetSubscriberPreferencesRequest = { + subscriberId: string; + /** + * A header for idempotency purposes + */ + idempotencyKey?: string | undefined; +}; + +export type SubscribersControllerGetSubscriberPreferencesResponse = { + headers: { [k: string]: Array }; + result: components.GetSubscriberPreferencesDto; +}; + +/** @internal */ +export const SubscribersControllerGetSubscriberPreferencesRequest$inboundSchema: + z.ZodType< + SubscribersControllerGetSubscriberPreferencesRequest, + z.ZodTypeDef, + unknown + > = z.object({ + subscriberId: z.string(), + "idempotency-key": z.string().optional(), + }).transform((v) => { + return remap$(v, { + "idempotency-key": "idempotencyKey", + }); + }); + +/** @internal */ +export type SubscribersControllerGetSubscriberPreferencesRequest$Outbound = { + subscriberId: string; + "idempotency-key"?: string | undefined; +}; + +/** @internal */ +export const SubscribersControllerGetSubscriberPreferencesRequest$outboundSchema: + z.ZodType< + SubscribersControllerGetSubscriberPreferencesRequest$Outbound, + z.ZodTypeDef, + SubscribersControllerGetSubscriberPreferencesRequest + > = z.object({ + subscriberId: z.string(), + idempotencyKey: z.string().optional(), + }).transform((v) => { + return remap$(v, { + idempotencyKey: "idempotency-key", + }); + }); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace SubscribersControllerGetSubscriberPreferencesRequest$ { + /** @deprecated use `SubscribersControllerGetSubscriberPreferencesRequest$inboundSchema` instead. */ + export const inboundSchema = + SubscribersControllerGetSubscriberPreferencesRequest$inboundSchema; + /** @deprecated use `SubscribersControllerGetSubscriberPreferencesRequest$outboundSchema` instead. */ + export const outboundSchema = + SubscribersControllerGetSubscriberPreferencesRequest$outboundSchema; + /** @deprecated use `SubscribersControllerGetSubscriberPreferencesRequest$Outbound` instead. */ + export type Outbound = + SubscribersControllerGetSubscriberPreferencesRequest$Outbound; +} + +export function subscribersControllerGetSubscriberPreferencesRequestToJSON( + subscribersControllerGetSubscriberPreferencesRequest: + SubscribersControllerGetSubscriberPreferencesRequest, +): string { + return JSON.stringify( + SubscribersControllerGetSubscriberPreferencesRequest$outboundSchema.parse( + subscribersControllerGetSubscriberPreferencesRequest, + ), + ); +} + +export function subscribersControllerGetSubscriberPreferencesRequestFromJSON( + jsonString: string, +): SafeParseResult< + SubscribersControllerGetSubscriberPreferencesRequest, + SDKValidationError +> { + return safeParse( + jsonString, + (x) => + SubscribersControllerGetSubscriberPreferencesRequest$inboundSchema.parse( + JSON.parse(x), + ), + `Failed to parse 'SubscribersControllerGetSubscriberPreferencesRequest' from JSON`, + ); +} + +/** @internal */ +export const SubscribersControllerGetSubscriberPreferencesResponse$inboundSchema: + z.ZodType< + SubscribersControllerGetSubscriberPreferencesResponse, + z.ZodTypeDef, + unknown + > = z.object({ + Headers: z.record(z.array(z.string())), + Result: components.GetSubscriberPreferencesDto$inboundSchema, + }).transform((v) => { + return remap$(v, { + "Headers": "headers", + "Result": "result", + }); + }); + +/** @internal */ +export type SubscribersControllerGetSubscriberPreferencesResponse$Outbound = { + Headers: { [k: string]: Array }; + Result: components.GetSubscriberPreferencesDto$Outbound; +}; + +/** @internal */ +export const SubscribersControllerGetSubscriberPreferencesResponse$outboundSchema: + z.ZodType< + SubscribersControllerGetSubscriberPreferencesResponse$Outbound, + z.ZodTypeDef, + SubscribersControllerGetSubscriberPreferencesResponse + > = z.object({ + headers: z.record(z.array(z.string())), + result: components.GetSubscriberPreferencesDto$outboundSchema, + }).transform((v) => { + return remap$(v, { + headers: "Headers", + result: "Result", + }); + }); + +/** + * @internal + * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module. + */ +export namespace SubscribersControllerGetSubscriberPreferencesResponse$ { + /** @deprecated use `SubscribersControllerGetSubscriberPreferencesResponse$inboundSchema` instead. */ + export const inboundSchema = + SubscribersControllerGetSubscriberPreferencesResponse$inboundSchema; + /** @deprecated use `SubscribersControllerGetSubscriberPreferencesResponse$outboundSchema` instead. */ + export const outboundSchema = + SubscribersControllerGetSubscriberPreferencesResponse$outboundSchema; + /** @deprecated use `SubscribersControllerGetSubscriberPreferencesResponse$Outbound` instead. */ + export type Outbound = + SubscribersControllerGetSubscriberPreferencesResponse$Outbound; +} + +export function subscribersControllerGetSubscriberPreferencesResponseToJSON( + subscribersControllerGetSubscriberPreferencesResponse: + SubscribersControllerGetSubscriberPreferencesResponse, +): string { + return JSON.stringify( + SubscribersControllerGetSubscriberPreferencesResponse$outboundSchema.parse( + subscribersControllerGetSubscriberPreferencesResponse, + ), + ); +} + +export function subscribersControllerGetSubscriberPreferencesResponseFromJSON( + jsonString: string, +): SafeParseResult< + SubscribersControllerGetSubscriberPreferencesResponse, + SDKValidationError +> { + return safeParse( + jsonString, + (x) => + SubscribersControllerGetSubscriberPreferencesResponse$inboundSchema.parse( + JSON.parse(x), + ), + `Failed to parse 'SubscribersControllerGetSubscriberPreferencesResponse' from JSON`, + ); +} diff --git a/libs/internal-sdk/src/react-query/index.ts b/libs/internal-sdk/src/react-query/index.ts index 6cd452c19bb..9410762018b 100644 --- a/libs/internal-sdk/src/react-query/index.ts +++ b/libs/internal-sdk/src/react-query/index.ts @@ -37,6 +37,7 @@ export * from "./subscribersNotificationsFeed.js"; export * from "./subscribersNotificationsUnseenCount.js"; export * from "./subscribersPatch.js"; export * from "./subscribersPreferencesList.js"; +export * from "./subscribersPreferencesRetrieve.js"; export * from "./subscribersPreferencesRetrieveByLevel.js"; export * from "./subscribersPreferencesUpdate.js"; export * from "./subscribersPreferencesUpdateGlobal.js"; diff --git a/libs/internal-sdk/src/react-query/subscribersPreferencesRetrieve.ts b/libs/internal-sdk/src/react-query/subscribersPreferencesRetrieve.ts new file mode 100644 index 00000000000..425349c8f72 --- /dev/null +++ b/libs/internal-sdk/src/react-query/subscribersPreferencesRetrieve.ts @@ -0,0 +1,170 @@ +/* + * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + */ + +import { + InvalidateQueryFilters, + QueryClient, + QueryFunctionContext, + QueryKey, + useQuery, + UseQueryResult, + useSuspenseQuery, + UseSuspenseQueryResult, +} from "@tanstack/react-query"; +import { NovuCore } from "../core.js"; +import { subscribersPreferencesRetrieve } from "../funcs/subscribersPreferencesRetrieve.js"; +import { combineSignals } from "../lib/primitives.js"; +import { RequestOptions } from "../lib/sdks.js"; +import * as operations from "../models/operations/index.js"; +import { unwrapAsync } from "../types/fp.js"; +import { useNovuContext } from "./_context.js"; +import { + QueryHookOptions, + SuspenseQueryHookOptions, + TupleToPrefixes, +} from "./_types.js"; + +export type SubscribersPreferencesRetrieveQueryData = + operations.SubscribersControllerGetSubscriberPreferencesResponse; + +/** + * Get subscriber preferences + * + * @remarks + * Get subscriber preferences + */ +export function useSubscribersPreferencesRetrieve( + subscriberId: string, + idempotencyKey?: string | undefined, + options?: QueryHookOptions, +): UseQueryResult { + const client = useNovuContext(); + return useQuery({ + ...buildSubscribersPreferencesRetrieveQuery( + client, + subscriberId, + idempotencyKey, + options, + ), + ...options, + }); +} + +/** + * Get subscriber preferences + * + * @remarks + * Get subscriber preferences + */ +export function useSubscribersPreferencesRetrieveSuspense( + subscriberId: string, + idempotencyKey?: string | undefined, + options?: SuspenseQueryHookOptions, +): UseSuspenseQueryResult { + const client = useNovuContext(); + return useSuspenseQuery({ + ...buildSubscribersPreferencesRetrieveQuery( + client, + subscriberId, + idempotencyKey, + options, + ), + ...options, + }); +} + +export function prefetchSubscribersPreferencesRetrieve( + queryClient: QueryClient, + client$: NovuCore, + subscriberId: string, + idempotencyKey?: string | undefined, +): Promise { + return queryClient.prefetchQuery({ + ...buildSubscribersPreferencesRetrieveQuery( + client$, + subscriberId, + idempotencyKey, + ), + }); +} + +export function setSubscribersPreferencesRetrieveData( + client: QueryClient, + queryKeyBase: [ + subscriberId: string, + parameters: { idempotencyKey?: string | undefined }, + ], + data: SubscribersPreferencesRetrieveQueryData, +): SubscribersPreferencesRetrieveQueryData | undefined { + const key = queryKeySubscribersPreferencesRetrieve(...queryKeyBase); + + return client.setQueryData( + key, + data, + ); +} + +export function invalidateSubscribersPreferencesRetrieve( + client: QueryClient, + queryKeyBase: TupleToPrefixes< + [subscriberId: string, parameters: { idempotencyKey?: string | undefined }] + >, + filters?: Omit, +): Promise { + return client.invalidateQueries({ + ...filters, + queryKey: ["@novu/api", "Preferences", "retrieve", ...queryKeyBase], + }); +} + +export function invalidateAllSubscribersPreferencesRetrieve( + client: QueryClient, + filters?: Omit, +): Promise { + return client.invalidateQueries({ + ...filters, + queryKey: ["@novu/api", "Preferences", "retrieve"], + }); +} + +export function buildSubscribersPreferencesRetrieveQuery( + client$: NovuCore, + subscriberId: string, + idempotencyKey?: string | undefined, + options?: RequestOptions, +): { + queryKey: QueryKey; + queryFn: ( + context: QueryFunctionContext, + ) => Promise; +} { + return { + queryKey: queryKeySubscribersPreferencesRetrieve(subscriberId, { + idempotencyKey, + }), + queryFn: async function subscribersPreferencesRetrieveQueryFn( + ctx, + ): Promise { + const sig = combineSignals(ctx.signal, options?.fetchOptions?.signal); + const mergedOptions = { + ...options, + fetchOptions: { ...options?.fetchOptions, signal: sig }, + }; + + return unwrapAsync(subscribersPreferencesRetrieve( + client$, + subscriberId, + idempotencyKey, + mergedOptions, + )); + }, + }; +} + +export function queryKeySubscribersPreferencesRetrieve( + subscriberId: string, + parameters: { idempotencyKey?: string | undefined }, +): QueryKey { + return ["@novu/api", "Preferences", "retrieve", subscriberId, parameters]; +} diff --git a/libs/internal-sdk/src/sdk/preferences.ts b/libs/internal-sdk/src/sdk/preferences.ts index d7225c70891..b038e583948 100644 --- a/libs/internal-sdk/src/sdk/preferences.ts +++ b/libs/internal-sdk/src/sdk/preferences.ts @@ -3,6 +3,7 @@ */ import { subscribersPreferencesList } from "../funcs/subscribersPreferencesList.js"; +import { subscribersPreferencesRetrieve } from "../funcs/subscribersPreferencesRetrieve.js"; import { subscribersPreferencesRetrieveByLevel } from "../funcs/subscribersPreferencesRetrieveByLevel.js"; import { subscribersPreferencesUpdate } from "../funcs/subscribersPreferencesUpdate.js"; import { subscribersPreferencesUpdateGlobal } from "../funcs/subscribersPreferencesUpdateGlobal.js"; @@ -86,4 +87,23 @@ export class Preferences extends ClientSDK { options, )); } + + /** + * Get subscriber preferences + * + * @remarks + * Get subscriber preferences + */ + async retrieve( + subscriberId: string, + idempotencyKey?: string | undefined, + options?: RequestOptions, + ): Promise { + return unwrapAsync(subscribersPreferencesRetrieve( + this, + subscriberId, + idempotencyKey, + options, + )); + } } diff --git a/packages/shared/src/entities/subscriber-preference/subscriber-preference.interface.ts b/packages/shared/src/entities/subscriber-preference/subscriber-preference.interface.ts index aa9ee96e5ac..e11dd955529 100644 --- a/packages/shared/src/entities/subscriber-preference/subscriber-preference.interface.ts +++ b/packages/shared/src/entities/subscriber-preference/subscriber-preference.interface.ts @@ -1,8 +1,13 @@ import { ChannelTypeEnum, PreferenceOverrideSourceEnum, PreferencesTypeEnum } from '../../types'; -import { IPreferenceChannelsDto } from '../../dto'; import { INotificationTrigger } from '../notification-trigger'; -export interface IPreferenceChannels extends IPreferenceChannelsDto {} +export interface IPreferenceChannels { + email?: boolean; + sms?: boolean; + in_app?: boolean; + chat?: boolean; + push?: boolean; +} export interface IPreferenceOverride { channel: ChannelTypeEnum; @@ -15,23 +20,7 @@ export interface ISubscriberPreferenceResponse { type: PreferencesTypeEnum; } -export interface ISubscriberWorkflowPreferenceResponse extends IPreferenceResponse { - workflow: ITemplateConfiguration; - level: PreferenceLevelEnum.TEMPLATE; -} - -export interface IWorkflow extends Omit { - id: string; -} -export interface ISubscriberPreferences { - level: PreferenceLevelEnum; - workflow?: IWorkflow; - enabled: boolean; - channels: IPreferenceChannels; - overrides?: IPreferenceOverride[]; -} - -export interface IPreferenceResponse { +interface IPreferenceResponse { enabled: boolean; channels: IPreferenceChannels; overrides: IPreferenceOverride[];