chore(api-service, worker, ws): upgrade to nest js v11#10653
chore(api-service, worker, ws): upgrade to nest js v11#10653
Conversation
❌ Deploy Preview for dashboard-v2-novu-staging failed. Why did it fail? →
|
|
Hey there and thank you for opening this pull request! 👋 We require pull request titles to follow specific formatting rules and it looks like your proposed title needs to be adjusted. Your PR title is: Requirements:
Expected format: Details: PR title must end with 'fixes TICKET-ID' (e.g., 'fixes NOV-123') or include ticket ID in branch name |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughMonorepo-wide updates: bumped NestJS 10→11 across packages, standardized Swagger optional decorators and object type metadata, adjusted Express query parsing to extended, refactored API key Passport strategy, switched runtime dynamic requires to static/typed imports in tests/EE helpers, and updated test runner/configs and SDK generated models/types. Changes
Sequence Diagram(s)(omitted) Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
|
Update Swagger ApiProperty decorators to emit enums as strings in the OpenAPI schema. Replace enum class types with type: String and add enumName where needed; also adjust the example for actionType to a string. Files updated: subscriber-notification-action.dto.ts (actionType) and feeds-response.dto.ts (ActorFeedItemDto.type, NotificationFeedItemDto.channel). This ensures correct schema generation and consistent string examples in the API docs.
@novu/agent-toolkit
@novu/framework
novu
@novu/providers
@novu/shared
commit: |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/shared/package.json (1)
35-45:⚠️ Potential issue | 🟠 MajorExport map shape must use nested
typeswithin condition-specific entries, not siblingtypes.The current flat structure causes both CJS and ESM consumers to resolve the same
.d.tsfile, creating type mismatches. Nesttypesinsiderequireandimportconditions, and provide condition-specific declarations (.d.ctsfor CJS,.d.tsfor ESM) aspackages/frameworkdoes. This follows TypeScript 4.7+ export field guidance and ensures correct type resolution for both module kinds.Per coding guidelines,
packages/shared/**requires extra care—changes affect the entire monorepo and must maintain backward compatibility. Verify semver implications before applying this fix.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/shared/package.json` around lines 35 - 45, The exports map in package.json currently places "types" as a sibling to "require" and "import", causing both CJS and ESM consumers to resolve the same .d.ts; update the "exports" object (including the "./" and "./utils" entries) to nest "types" inside each condition-specific entry so "require" points to a CJS declaration (e.g. .d.cts) and "import" points to an ESM declaration (e.g. .d.ts), mirroring packages/framework's shape; ensure you add/emit the corresponding .d.cts and .d.ts outputs and run type checks, and confirm this change is semver-safe for the monorepo before merging.libs/application-generic/src/dtos/step-filter-dto.ts (1)
131-141:⚠️ Potential issue | 🟠 MajorFix optionality decorators:
isNegatedandtypeare optional but use@ApiPropertyinstead of@ApiPropertyOptional.Lines 117–118 and 120–124 declare optional properties with
?but use@ApiProperty. Change to@ApiPropertyOptionalto align with the DTO optionality guidelines:
- Line 118:
isNegated?: boolean→ use@ApiPropertyOptional()- Lines 120–124:
type?: BuilderFieldType→ use@ApiPropertyOptional({...})while preserving theenumandenumNamepropertiesThe
childrenproperty at line 131–141 is correctly decorated as required with@ApiProperty.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/application-generic/src/dtos/step-filter-dto.ts` around lines 131 - 141, The optional properties isNegated and type in the DTO are decorated with `@ApiProperty` but should use `@ApiPropertyOptional`; update the decorator on isNegated to `@ApiPropertyOptional`() and change the decorator on type to `@ApiPropertyOptional`({ enum: BuilderFieldType, enumName: 'BuilderFieldType' }) while preserving the optional ? in their declarations; leave the children property (children: FilterPartsDto[]) and its `@ApiProperty` decorator unchanged.enterprise/packages/shared-services/package.json (1)
1-47:⚠️ Potential issue | 🟡 MinorPlease confirm the mirrored enterprise PR is opened and linked.
This PR updates
enterprise/...; please add the correspondingnovuhq/packages-enterprisePR link (branched fromnext) in the description for traceability/release sync.Based on learnings: When changes touch
enterprise/directory, also open a matching PR innovuhq/packages-enterpriserepository on a branch fromnext.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@enterprise/packages/shared-services/package.json` around lines 1 - 47, This change touches enterprise/ (package `@novu/ee-shared-services`); open a mirrored PR in the novuhq/packages-enterprise repo branched from next and add that PR URL to this PR description for traceability; ensure the enterprise PR branch is created from next, mention the corresponding package (`@novu/ee-shared-services`) in the enterprise PR title/body, and paste the enterprise PR link into this PR description.
🧹 Nitpick comments (3)
libs/application-generic/src/decorators/user-session.decorator.ts (1)
5-5: Prefer a typedgetType()check overas string.Nest documents GraphQL context detection via a typed
getType<...>()call; casting the result tostringjust suppresses the Nest 11 typing without preserving the contract. A union generic keeps the comparison typed and self-documenting. (docs.nestjs.com)♻️ Suggested change
- if ((ctx.getType() as string) === 'graphql') { + if (ctx.getType<'http' | 'ws' | 'rpc' | 'graphql'>() === 'graphql') {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/application-generic/src/decorators/user-session.decorator.ts` at line 5, Replace the unchecked cast "(ctx.getType() as string) === 'graphql'" in the user-session decorator with a typed getType call so the comparison is type-safe: call ctx.getType<'graphql' | 'http' | 'rpc'>() (or the minimal union your app uses) and compare the returned value to 'graphql' in the decorator function that receives the ExecutionContext (ctx) so the check is properly typed and self-documenting.apps/worker/src/app/shared/response.interceptor.ts (1)
13-14: LGTM - type cast aligns with NestJS 11 changes.The explicit cast
(context.getType() as string)is necessary in NestJS 11 wheregetType()returns a more specific type. This pattern is consistently applied across both API and worker response interceptors.Consider adding explicit type annotation for improved clarity:
♻️ Optional: Add explicit type annotation
- intercept(context, next: CallHandler): Observable<Response<T>> { + intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {With import:
-import { CallHandler, Injectable, NestInterceptor } from '@nestjs/common'; +import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/worker/src/app/shared/response.interceptor.ts` around lines 13 - 14, The intercept method lacks an explicit type for the first parameter; update the signature to intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> and add the ExecutionContext import from '@nestjs/common' so the existing cast (context.getType() as string) is clearly typed and consistent with other interceptors (reference symbols: intercept, ExecutionContext, CallHandler, Response<T>).apps/ws/package.json (1)
25-33: Migrateapp.flushLogs()as part of the NestJS 11 bump.In
apps/ws/src/bootstrap.ts(line 25),app.flushLogs()is deprecated in NestJS 11. Update the bootstrap logging setup to use the native NestJS 11 flow.Also applies to: 63-65
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/ws/package.json` around lines 25 - 33, Replace deprecated app.flushLogs() calls in bootstrap.ts with NestJS 11 native logging configuration: remove any app.flushLogs() invocations and instead configure logging when creating the app (pass the logger option to NestFactory.create or call Logger.overrideLogger(...) before bootstrap completes) and ensure logs are flushed by awaiting app.init() / app.listen(...) normally; update both occurrences that reference app.flushLogs() so logging is driven by NestFactory.create and Logger.overrideLogger rather than the removed app.flushLogs() method.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api/src/app/shared/dtos/subscriptions/create-subscriptions.dto.ts`:
- Around line 42-48: The DTO property enabled is only marked `@IsOptional`() so
non-boolean values like "false" or 1 pass validation; add the class-validator
boolean check by applying `@IsBoolean`() to the enabled property (keep
`@IsOptional`() and `@ApiPropertyOptional`) and update imports in
create-subscriptions.dto.ts to include IsBoolean so the DTO enforces a true
boolean type at validation time.
In `@apps/api/src/config/cors.config.ts`:
- Around line 2-8: The exported CORS delegate is incorrectly typed and uses the
global Fetch Request; import Request from 'express' and change the export
signature to use Nest's CorsOptionsDelegate<Request> so the function signature
matches (replace the current Parameters<INestApplication['enableCors']>[0] with
CorsOptionsDelegate<Request]); update the top imports to include Request from
'express' and ensure the exported symbol corsOptionsDelegate keeps the same
implementation but with the new type so tests no longer need `@ts-expect-error` or
the null-as-Error cast.
In `@apps/ws/src/bootstrap.ts`:
- Around line 18-19: The token extraction is vulnerable to array values when
Express query parser is 'extended'; update the extractToken function in
ws.gateway.ts to explicitly check typeof token === 'string' (and non-empty)
before returning it, and ensure places that call jwtService.verify (e.g., in
handleConnection / validateConnection) only receive a string token — treat
arrays or non-string values as invalid (return null or undefined) so the
existing falsy/null checks (token === 'null') handle them instead of letting
arrays reach jwtService.verify.
---
Outside diff comments:
In `@enterprise/packages/shared-services/package.json`:
- Around line 1-47: This change touches enterprise/ (package
`@novu/ee-shared-services`); open a mirrored PR in the novuhq/packages-enterprise
repo branched from next and add that PR URL to this PR description for
traceability; ensure the enterprise PR branch is created from next, mention the
corresponding package (`@novu/ee-shared-services`) in the enterprise PR
title/body, and paste the enterprise PR link into this PR description.
In `@libs/application-generic/src/dtos/step-filter-dto.ts`:
- Around line 131-141: The optional properties isNegated and type in the DTO are
decorated with `@ApiProperty` but should use `@ApiPropertyOptional`; update the
decorator on isNegated to `@ApiPropertyOptional`() and change the decorator on
type to `@ApiPropertyOptional`({ enum: BuilderFieldType, enumName:
'BuilderFieldType' }) while preserving the optional ? in their declarations;
leave the children property (children: FilterPartsDto[]) and its `@ApiProperty`
decorator unchanged.
In `@packages/shared/package.json`:
- Around line 35-45: The exports map in package.json currently places "types" as
a sibling to "require" and "import", causing both CJS and ESM consumers to
resolve the same .d.ts; update the "exports" object (including the "./" and
"./utils" entries) to nest "types" inside each condition-specific entry so
"require" points to a CJS declaration (e.g. .d.cts) and "import" points to an
ESM declaration (e.g. .d.ts), mirroring packages/framework's shape; ensure you
add/emit the corresponding .d.cts and .d.ts outputs and run type checks, and
confirm this change is semver-safe for the monorepo before merging.
---
Nitpick comments:
In `@apps/worker/src/app/shared/response.interceptor.ts`:
- Around line 13-14: The intercept method lacks an explicit type for the first
parameter; update the signature to intercept(context: ExecutionContext, next:
CallHandler): Observable<Response<T>> and add the ExecutionContext import from
'@nestjs/common' so the existing cast (context.getType() as string) is clearly
typed and consistent with other interceptors (reference symbols: intercept,
ExecutionContext, CallHandler, Response<T>).
In `@apps/ws/package.json`:
- Around line 25-33: Replace deprecated app.flushLogs() calls in bootstrap.ts
with NestJS 11 native logging configuration: remove any app.flushLogs()
invocations and instead configure logging when creating the app (pass the logger
option to NestFactory.create or call Logger.overrideLogger(...) before bootstrap
completes) and ensure logs are flushed by awaiting app.init() / app.listen(...)
normally; update both occurrences that reference app.flushLogs() so logging is
driven by NestFactory.create and Logger.overrideLogger rather than the removed
app.flushLogs() method.
In `@libs/application-generic/src/decorators/user-session.decorator.ts`:
- Line 5: Replace the unchecked cast "(ctx.getType() as string) === 'graphql'"
in the user-session decorator with a typed getType call so the comparison is
type-safe: call ctx.getType<'graphql' | 'http' | 'rpc'>() (or the minimal union
your app uses) and compare the returned value to 'graphql' in the decorator
function that receives the ExecutionContext (ctx) so the check is properly typed
and self-documenting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 1f036fc3-5a0a-4006-b5ca-6eb84042f43c
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (45)
.sourceapps/api/package.jsonapps/api/scripts/generate-metadata.tsapps/api/src/app/auth/framework/community.user.auth.guard.tsapps/api/src/app/auth/services/passport/apikey.strategy.tsapps/api/src/app/contexts/dtos/create-context-request.dto.tsapps/api/src/app/contexts/dtos/update-context-request.dto.tsapps/api/src/app/events/dtos/trigger-event-request.dto.tsapps/api/src/app/events/dtos/trigger-event-to-all-request.dto.tsapps/api/src/app/layouts-v2/dtos/generate-layout-preview-response.dto.tsapps/api/src/app/notifications/dtos/activities-response.dto.tsapps/api/src/app/shared/dtos/subscriptions/create-subscriptions-response.dto.tsapps/api/src/app/shared/dtos/subscriptions/create-subscriptions.dto.tsapps/api/src/app/shared/framework/response.interceptor.tsapps/api/src/app/shared/framework/user.decorator.tsapps/api/src/app/subscribers-v2/dtos/get-subscriber-notifications-response.dto.tsapps/api/src/app/widgets/dtos/feeds-response.dto.tsapps/api/src/bootstrap.tsapps/api/src/config/cors.config.tsapps/api/src/error-dto.tsapps/webhook/src/shared/framework/user.decorator.tsapps/worker/package.jsonapps/worker/src/app/shared/response.interceptor.tsapps/worker/src/bootstrap.tsapps/ws/package.jsonapps/ws/src/bootstrap.tsenterprise/packages/ai/package.jsonenterprise/packages/api/package.jsonenterprise/packages/auth/package.jsonenterprise/packages/billing/package.jsonenterprise/packages/shared-services/package.jsonenterprise/packages/translation/package.jsonlibs/application-generic/package.jsonlibs/application-generic/src/decorators/context-payload.decorator.tslibs/application-generic/src/decorators/user-session.decorator.tslibs/application-generic/src/dtos/step-filter-dto.tslibs/application-generic/src/dtos/workflow/generate-preview-response.dto.tslibs/application-generic/src/webhooks/dtos/webhook-payload.dto.tslibs/application-generic/tsconfig.jsonlibs/application-generic/tsconfig.module.jsonlibs/dal/package.jsonlibs/notifications/package.jsonpackage.jsonpackages/framework/package.jsonpackages/shared/package.json
|
@cursoragent fix the failing tests api e2e |
|
Here is what was wrong and what I changed. Root causes
Files touched
Committed as Note: A full shard run is long in this environment; after these fixes, bootstrap proceeds past Swagger and listens once. If anything still fails in CI, grab the first failing test name from the shard log. |
…eps) - Remove invalid Node --no-experimental-strip-types from api mocha scripts and .mocharc - Stop loading e2e/setup.ts twice (mocharc + shard script) to avoid EADDRINUSE on PORT - Fix Nest Swagger v11 circular schema on ButtonTypeEnum path params via ParseEnumPipe + string reflection - Declare @novu/ee-auth and @novu/application-generic on @novu/testing for dynamic requires Co-authored-by: Dima Grossman <dima@grossman.io>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api/package.json`:
- Around line 49-57: Remove the unused nest-raven dependency from
apps/api/package.json (delete the "nest-raven@10.1.0" entry) because it requires
`@nestjs/common` v10 and will break peer deps after upgrading to NestJS 11; also
check for any imports/usages of nest-raven in the codebase (search for
"nest-raven") and delete them if present. For Sentry, locate any references to
"@sentry/nestjs" (package.json and any imports like SentryModule or
SentryService) and either disable the Sentry integration or plan/make a
migration to a version that supports NestJS 11 before merging. Ensure
package.json and lockfile are updated (run install) after removing the
dependency.
- Line 34: The npm script "test:e2e:novu-v0" is passing --file e2e/setup.ts
explicitly which duplicates the "file": ["e2e/setup.ts"] already defined in
.mocharc.json and causes the setup to run twice; edit the "test:e2e:novu-v0"
script to remove the `--file e2e/setup.ts` flag so Mocha uses the configuration
from .mocharc.json and the e2e/setup.ts file is loaded only once.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3bab3e29-67cf-4fec-b46c-f18ab651e451
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
apps/api/.mocharc.jsonapps/api/package.jsonapps/api/scripts/run-novu-v2-e2e-shard.cjsapps/api/src/app/subscribers-v2/subscribers.controller.tsapps/api/src/app/subscribers/subscribersV1.controller.tslibs/testing/package.json
💤 Files with no reviewable changes (2)
- apps/api/.mocharc.json
- apps/api/scripts/run-novu-v2-e2e-shard.cjs
✅ Files skipped from review due to trivial changes (1)
- libs/testing/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/api/src/app/subscribers/subscribersV1.controller.ts
- apps/api/src/app/subscribers-v2/subscribers.controller.ts
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
libs/internal-sdk/src/models/operations/subscribersv1controllermarkactionasseen.ts (1)
1-3:⚠️ Potential issue | 🟠 MajorGenerated SDK artifact appears directly edited.
This file is marked as generated (
DO NOT EDIT). Please apply this change in the source API/spec and regeneratelibs/internal-sdkoutputs to prevent drift/overwrite in the next codegen run.As per coding guidelines, "libs/internal-sdk/**: Never edit auto-generated files in libs/internal-sdk".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/internal-sdk/src/models/operations/subscribersv1controllermarkactionasseen.ts` around lines 1 - 3, This change was made to a generated file (subscribersv1controllermarkactionasseen.ts) which must not be edited directly; instead update the upstream API/spec (the OpenAPI/Swagger source where the operation "SubscribersV1Controller.markActionAsSeen" or the corresponding path/operationId is defined) with the desired change, then run the project's codegen/build process to regenerate the libs/internal-sdk artifacts so the updated subscribersv1controllermarkactionasseen.ts is produced automatically; do not commit manual edits to the generated file.libs/internal-sdk/src/react-query/subscribersNotificationsUnseenCount.core.ts (1)
1-3:⚠️ Potential issue | 🟠 MajorRegenerate this file from source instead of manually editing.
This file is marked as auto-generated by Speakeasy (
DO NOT EDIT), but it contains direct modifications. Per coding guidelines,libs/internal-sdk/**files must never be manually edited—regenerate from the OpenAPI spec or source specification instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/internal-sdk/src/react-query/subscribersNotificationsUnseenCount.core.ts` around lines 1 - 3, The file docs indicate it is auto-generated (libs/internal-sdk/src/react-query/subscribersNotificationsUnseenCount.core.ts) and must not be edited manually; instead regenerate this file from the source OpenAPI/spec by running the Speakeasy code generator (or the project's generation script) that produces the libs/internal-sdk artifacts, verify the regenerated subscribersNotificationsUnseenCount.core.ts contains your intended changes, and commit the generated output; do not make direct edits to the generated file—update the source spec and re-run the generator.
🧹 Nitpick comments (2)
libs/testing/src/ee/ee.repository.factory.ts (1)
13-21: Refactor to keyed return types or overloads to strengthen type safety.The
as Tcasts allow mismatched generic/className pairs to type-check (e.g.,getEERepository<UserRepository>('OrganizationRepository')). While verification shows no current mismatches in the codebase, using keyed return types or function overloads would prevent this type of error at compile time rather than relying on runtime correctness.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@libs/testing/src/ee/ee.repository.factory.ts` around lines 13 - 21, The current getEERepository<T> uses unchecked casts (as T) which allow mismatched generic/className pairs; change the API to a keyed return type or explicit overloads so the return type is tied to the className literal — e.g., replace getEERepository<T>(className: ...) with either (1) function overloads: getEERepository('OrganizationRepository'): OrganizationRepository; getEERepository('MemberRepository'): MemberRepository; getEERepository('UserRepository'): UserRepository; or (2) a mapped type signature like getEERepository<K extends 'OrganizationRepository'|'MemberRepository'|'UserRepository'>(className: K): K extends 'OrganizationRepository' ? OrganizationRepository : K extends 'MemberRepository' ? MemberRepository : UserRepository; then remove the as T casts and return the concrete calls to getEEOrganizationRepository(), getEEMemberRepository(), and getEEUserRepository() directly.apps/api/src/app/billing/e2e/create-checkout-session.e2e-ee.ts (1)
27-29: Remove unreachable "module exists" guard after static importLine 27 check is redundant: when using static imports like
import { CreateCheckoutSession }, module loading fails before tests run if the export doesn't exist. The guard will never evaluate to true.Suggested cleanup
- if (!CreateCheckoutSession) { - throw new Error("CreateCheckoutSession doesn't exist"); - }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/api/src/app/billing/e2e/create-checkout-session.e2e-ee.ts` around lines 27 - 29, The redundant runtime guard checking CreateCheckoutSession after a static import should be removed: delete the if-block that throws an error for CreateCheckoutSession since static imports guarantee the export exists at load time (the module would fail to load before tests run); locate the check referencing CreateCheckoutSession in the test file and remove that conditional and its throw to clean up unreachable code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/api/src/app/billing/e2e/create-subscription.e2e-ee.ts`:
- Line 7: The test deep-imports internal symbols StripeSubscriptionStatusEnum
and StripeUsageTypeEnum from '@novu/ee-billing/src/stripe/types' which is
fragile; instead add re-exports for those enums in the public entrypoint of the
`@novu/ee-billing` package (e.g., export { StripeSubscriptionStatusEnum,
StripeUsageTypeEnum } from './src/stripe/types' in the package's main index) and
update the test import in create-subscription.e2e-ee.ts to import them from
'@novu/ee-billing' so the test uses the package public API.
In
`@libs/internal-sdk/src/models/operations/subscriberscontrollergetsubscribernotifications.ts`:
- Around line 29-32: The generated validator for the tags field is wrong (it
currently uses an empty z.object which rejects valid input); update the
Speakeasy/OpenAPI source schema for the tags property (the one that produces
components.ObjectT / the tags field in the subscribers controller model) to be a
union that accepts either string[] (OR) or an object shaped as { and: Array<{
or: string[] }> } (AND of OR-groups); then regenerate the SDK so the generated
type and schema (the tags type and its validator used in the subscribers
controller) validate string[] and { and: [{ or: string[] }, ...] } correctly
instead of z.object({}).
In
`@libs/internal-sdk/src/models/operations/subscribersv1controllergetnotificationsfeed.ts`:
- Line 16: The ObjectT schema is too strict (z.object({}) outbound) causing
filter objects for feedIdentifier, feedId, and tags to be stripped; update the
upstream OpenAPI components.ObjectT schema to allow passthrough properties
(e.g., add additionalProperties: true or define the expected properties) so
outboundSchema isn't an empty object, then regenerate the Speakeasy client so
SubscribersV1ControllerGetNotificationsFeedRequest.feedIdentifier,
SubscribersV1ControllerGetUnseenCountRequest.feedId, and
SubscribersControllerGetSubscriberNotificationsRequest.tags preserve their
contents.
In
`@libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts`:
- Around line 14-17: The generated model's feedId property is incorrectly typed
as components.ObjectT (empty object); update the source OpenAPI/Speakeasy
specification for the subscribersv1controllergetunseencount schema so feedId is
defined as either a single string or an array of strings (e.g., use oneOf:
[{type: "string"}, {type: "array", items: {type: "string"}}] or equivalent
Speakeasy schema), not components.ObjectT; regenerate the SDK so the generated
property feedId and its schema reflect string/array-of-strings instead of {}.
In `@libs/internal-sdk/src/react-query/channelConnectionsRetrieve.core.ts`:
- Line 81: This file
(libs/internal-sdk/src/react-query/channelConnectionsRetrieve.core.ts) is
auto-generated and must not be manually edited; revert any manual changes and
instead update the Speakeasy generator inputs/templates that produce the
"ChannelConnections" export (and any related schema/config) and then re-run the
code generation pipeline so the updated output is regenerated with the DO NOT
EDIT marker intact.
---
Outside diff comments:
In
`@libs/internal-sdk/src/models/operations/subscribersv1controllermarkactionasseen.ts`:
- Around line 1-3: This change was made to a generated file
(subscribersv1controllermarkactionasseen.ts) which must not be edited directly;
instead update the upstream API/spec (the OpenAPI/Swagger source where the
operation "SubscribersV1Controller.markActionAsSeen" or the corresponding
path/operationId is defined) with the desired change, then run the project's
codegen/build process to regenerate the libs/internal-sdk artifacts so the
updated subscribersv1controllermarkactionasseen.ts is produced automatically; do
not commit manual edits to the generated file.
In
`@libs/internal-sdk/src/react-query/subscribersNotificationsUnseenCount.core.ts`:
- Around line 1-3: The file docs indicate it is auto-generated
(libs/internal-sdk/src/react-query/subscribersNotificationsUnseenCount.core.ts)
and must not be edited manually; instead regenerate this file from the source
OpenAPI/spec by running the Speakeasy code generator (or the project's
generation script) that produces the libs/internal-sdk artifacts, verify the
regenerated subscribersNotificationsUnseenCount.core.ts contains your intended
changes, and commit the generated output; do not make direct edits to the
generated file—update the source spec and re-run the generator.
---
Nitpick comments:
In `@apps/api/src/app/billing/e2e/create-checkout-session.e2e-ee.ts`:
- Around line 27-29: The redundant runtime guard checking CreateCheckoutSession
after a static import should be removed: delete the if-block that throws an
error for CreateCheckoutSession since static imports guarantee the export exists
at load time (the module would fail to load before tests run); locate the check
referencing CreateCheckoutSession in the test file and remove that conditional
and its throw to clean up unreachable code.
In `@libs/testing/src/ee/ee.repository.factory.ts`:
- Around line 13-21: The current getEERepository<T> uses unchecked casts (as T)
which allow mismatched generic/className pairs; change the API to a keyed return
type or explicit overloads so the return type is tied to the className literal —
e.g., replace getEERepository<T>(className: ...) with either (1) function
overloads: getEERepository('OrganizationRepository'): OrganizationRepository;
getEERepository('MemberRepository'): MemberRepository;
getEERepository('UserRepository'): UserRepository; or (2) a mapped type
signature like getEERepository<K extends
'OrganizationRepository'|'MemberRepository'|'UserRepository'>(className: K): K
extends 'OrganizationRepository' ? OrganizationRepository : K extends
'MemberRepository' ? MemberRepository : UserRepository; then remove the as T
casts and return the concrete calls to getEEOrganizationRepository(),
getEEMemberRepository(), and getEEUserRepository() directly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 43a5d499-699d-426b-bd71-ef8c3d675775
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (106)
.sourceapps/api/.mocharc.e2e.jsonapps/api/.mocharc.jsonapps/api/package.jsonapps/api/scripts/run-novu-v2-e2e-shard.cjsapps/api/src/app/billing/e2e/checkout-session-completed.e2e-ee.tsapps/api/src/app/billing/e2e/create-checkout-session.e2e-ee.tsapps/api/src/app/billing/e2e/create-subscription.e2e-ee.tsapps/api/src/app/billing/e2e/create-usage-records.e2e-ee.tsapps/api/src/app/billing/e2e/customer-subscription-created.e2e-ee.tsapps/api/src/app/billing/e2e/customer-subscription-deleted.e2e-ee.tsapps/api/src/app/billing/e2e/get-platform-notification-usage.e2e-ee.tsapps/api/src/app/billing/e2e/get-portal-link.e2e-ee.tsapps/api/src/app/billing/e2e/get-prices.e2e-ee.tsapps/api/src/app/billing/e2e/get-subscription.e2e-ee.tsapps/api/src/app/billing/e2e/verify-customer.e2e-ee.tsapps/api/src/app/environments-v1/dtos/create-environment-request.dto.tsapps/api/src/app/message-template/message-template.module.tsapps/api/src/app/subscribers/usecases/chat-oauth-callback/is-not-empty.spec.tsapps/api/src/app/widgets/pipes/limit-pipe/limit-pipe.spec.tsapps/api/src/app/workflows-v2/dtos/create-workflow.dto.tsapps/api/src/config/cors.config.spec.tsapps/api/src/config/cors.config.tsapps/api/src/config/load-test-env.tsapps/worker/src/app/shared/response.interceptor.tslibs/application-generic/jest.config.jslibs/application-generic/package.jsonlibs/application-generic/src/decorators/user-session.decorator.tslibs/application-generic/src/dtos/layout/create-layout.dto.tslibs/application-generic/src/dtos/ui-schema-property.dto.tslibs/internal-sdk/src/funcs/subscribersNotificationsFeed.tslibs/internal-sdk/src/funcs/subscribersNotificationsList.tslibs/internal-sdk/src/funcs/subscribersNotificationsUnseenCount.tslibs/internal-sdk/src/lib/config.tslibs/internal-sdk/src/models/components/activitynotificationexecutiondetailresponsedto.tslibs/internal-sdk/src/models/components/activitynotificationresponsedto.tslibs/internal-sdk/src/models/components/activitynotificationtemplateresponsedto.tslibs/internal-sdk/src/models/components/buttontypeenum.tslibs/internal-sdk/src/models/components/channeltypeenum.tslibs/internal-sdk/src/models/components/chatstepresponsedto.tslibs/internal-sdk/src/models/components/createlayoutdto.tslibs/internal-sdk/src/models/components/createworkflowdto.tslibs/internal-sdk/src/models/components/customstepresponsedto.tslibs/internal-sdk/src/models/components/delaycontroldto.tslibs/internal-sdk/src/models/components/delaystepresponsedto.tslibs/internal-sdk/src/models/components/digeststepresponsedto.tslibs/internal-sdk/src/models/components/emailstepresponsedto.tslibs/internal-sdk/src/models/components/failedworkflowdto.tslibs/internal-sdk/src/models/components/getpreferencesresponsedto.tslibs/internal-sdk/src/models/components/httprequeststepresponsedto.tslibs/internal-sdk/src/models/components/inappstepresponsedto.tslibs/internal-sdk/src/models/components/inboxnotificationdto.tslibs/internal-sdk/src/models/components/index.tslibs/internal-sdk/src/models/components/messagebutton.tslibs/internal-sdk/src/models/components/notificationfeeditemdto.tslibs/internal-sdk/src/models/components/notificationworkflowdto.tslibs/internal-sdk/src/models/components/object.tslibs/internal-sdk/src/models/components/providersidenum.tslibs/internal-sdk/src/models/components/pushstepresponsedto.tslibs/internal-sdk/src/models/components/resourcedependencydto.tslibs/internal-sdk/src/models/components/resourcediffdto.tslibs/internal-sdk/src/models/components/resourcediffresultdto.tslibs/internal-sdk/src/models/components/resourceoriginenum.tslibs/internal-sdk/src/models/components/resourcetopublishdto.tslibs/internal-sdk/src/models/components/severitylevelenum.tslibs/internal-sdk/src/models/components/skippedworkflowdto.tslibs/internal-sdk/src/models/components/smsstepresponsedto.tslibs/internal-sdk/src/models/components/stepresponsedto.tslibs/internal-sdk/src/models/components/subscriberpreferenceoverridedto.tslibs/internal-sdk/src/models/components/subscriptionpreferencedto.tslibs/internal-sdk/src/models/components/syncedworkflowdto.tslibs/internal-sdk/src/models/components/syncresultdto.tslibs/internal-sdk/src/models/components/throttlestepresponsedto.tslibs/internal-sdk/src/models/components/triggereventrequestdto.tslibs/internal-sdk/src/models/components/triggereventtoallrequestdto.tslibs/internal-sdk/src/models/components/uicomponentenum.tslibs/internal-sdk/src/models/components/uischemaproperty.tslibs/internal-sdk/src/models/components/updateworkflowdto.tslibs/internal-sdk/src/models/components/workflowlistresponsedto.tslibs/internal-sdk/src/models/components/workflowresponsedto.tslibs/internal-sdk/src/models/operations/messagescontrollergetmessages.tslibs/internal-sdk/src/models/operations/subscriberscontrollergetsubscribernotifications.tslibs/internal-sdk/src/models/operations/subscribersv1controllergetnotificationsfeed.tslibs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.tslibs/internal-sdk/src/models/operations/subscribersv1controllermarkactionasseen.tslibs/internal-sdk/src/react-query/channelConnectionsCreate.tslibs/internal-sdk/src/react-query/channelConnectionsDelete.tslibs/internal-sdk/src/react-query/channelConnectionsList.core.tslibs/internal-sdk/src/react-query/channelConnectionsList.tslibs/internal-sdk/src/react-query/channelConnectionsRetrieve.core.tslibs/internal-sdk/src/react-query/channelConnectionsRetrieve.tslibs/internal-sdk/src/react-query/channelConnectionsUpdate.tslibs/internal-sdk/src/react-query/channelEndpointsCreate.tslibs/internal-sdk/src/react-query/channelEndpointsDelete.tslibs/internal-sdk/src/react-query/channelEndpointsList.core.tslibs/internal-sdk/src/react-query/channelEndpointsList.tslibs/internal-sdk/src/react-query/channelEndpointsRetrieve.core.tslibs/internal-sdk/src/react-query/channelEndpointsRetrieve.tslibs/internal-sdk/src/react-query/channelEndpointsUpdate.tslibs/internal-sdk/src/react-query/subscribersNotificationsFeed.core.tslibs/internal-sdk/src/react-query/subscribersNotificationsFeed.tslibs/internal-sdk/src/react-query/subscribersNotificationsList.core.tslibs/internal-sdk/src/react-query/subscribersNotificationsList.tslibs/internal-sdk/src/react-query/subscribersNotificationsUnseenCount.core.tslibs/internal-sdk/src/react-query/subscribersNotificationsUnseenCount.tslibs/testing/src/ee/ee.repository.factory.ts
💤 Files with no reviewable changes (3)
- libs/internal-sdk/src/models/operations/messagescontrollergetmessages.ts
- libs/internal-sdk/src/models/components/channeltypeenum.ts
- libs/internal-sdk/src/models/components/uicomponentenum.ts
✅ Files skipped from review due to trivial changes (49)
- apps/api/.mocharc.e2e.json
- libs/internal-sdk/src/models/components/httprequeststepresponsedto.ts
- apps/api/src/app/environments-v1/dtos/create-environment-request.dto.ts
- apps/api/src/app/billing/e2e/customer-subscription-created.e2e-ee.ts
- libs/internal-sdk/src/models/components/failedworkflowdto.ts
- libs/internal-sdk/src/models/components/messagebutton.ts
- libs/internal-sdk/src/models/components/chatstepresponsedto.ts
- libs/internal-sdk/src/models/components/stepresponsedto.ts
- libs/internal-sdk/src/models/components/skippedworkflowdto.ts
- apps/api/src/app/widgets/pipes/limit-pipe/limit-pipe.spec.ts
- libs/internal-sdk/src/models/components/updateworkflowdto.ts
- libs/internal-sdk/src/models/components/pushstepresponsedto.ts
- apps/api/src/app/billing/e2e/verify-customer.e2e-ee.ts
- apps/api/src/app/billing/e2e/checkout-session-completed.e2e-ee.ts
- libs/internal-sdk/src/models/components/delaystepresponsedto.ts
- libs/internal-sdk/src/models/components/resourcediffresultdto.ts
- libs/internal-sdk/src/models/components/severitylevelenum.ts
- libs/internal-sdk/src/models/components/digeststepresponsedto.ts
- libs/internal-sdk/src/models/components/syncedworkflowdto.ts
- libs/internal-sdk/src/models/components/buttontypeenum.ts
- libs/internal-sdk/src/models/components/inappstepresponsedto.ts
- libs/internal-sdk/src/models/components/providersidenum.ts
- libs/internal-sdk/src/models/components/getpreferencesresponsedto.ts
- libs/internal-sdk/src/models/components/resourcedependencydto.ts
- libs/internal-sdk/src/models/components/customstepresponsedto.ts
- libs/internal-sdk/src/models/components/notificationfeeditemdto.ts
- libs/internal-sdk/src/models/components/emailstepresponsedto.ts
- libs/internal-sdk/src/models/components/subscriberpreferenceoverridedto.ts
- libs/internal-sdk/src/models/components/triggereventrequestdto.ts
- libs/internal-sdk/src/models/components/syncresultdto.ts
- libs/internal-sdk/src/models/components/resourcediffdto.ts
- libs/internal-sdk/src/models/components/workflowresponsedto.ts
- libs/application-generic/jest.config.js
- libs/internal-sdk/src/models/components/triggereventtoallrequestdto.ts
- libs/internal-sdk/src/models/components/smsstepresponsedto.ts
- libs/internal-sdk/src/models/components/subscriptionpreferencedto.ts
- libs/internal-sdk/src/models/components/inboxnotificationdto.ts
- apps/api/src/config/load-test-env.ts
- libs/application-generic/src/decorators/user-session.decorator.ts
- libs/internal-sdk/src/models/components/object.ts
- libs/internal-sdk/src/models/components/activitynotificationexecutiondetailresponsedto.ts
- libs/internal-sdk/src/models/components/resourceoriginenum.ts
- libs/internal-sdk/src/models/components/activitynotificationtemplateresponsedto.ts
- libs/internal-sdk/src/models/components/workflowlistresponsedto.ts
- libs/internal-sdk/src/lib/config.ts
- libs/internal-sdk/src/models/components/notificationworkflowdto.ts
- libs/internal-sdk/src/models/components/activitynotificationresponsedto.ts
- libs/internal-sdk/src/models/components/resourcetopublishdto.ts
- libs/internal-sdk/src/models/components/throttlestepresponsedto.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- .source
- apps/api/scripts/run-novu-v2-e2e-shard.cjs
- apps/api/.mocharc.json
- apps/worker/src/app/shared/response.interceptor.ts
- libs/application-generic/package.json
- apps/api/package.json
- apps/api/src/config/cors.config.ts
| GetPrices, | ||
| UpdateServiceLevel, | ||
| } from '@novu/ee-billing'; | ||
| import { StripeSubscriptionStatusEnum, StripeUsageTypeEnum } from '@novu/ee-billing/src/stripe/types'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
EE_PKG="$(fd -a package.json | rg '/ee-billing/package.json$' | head -n1)"
echo "ee-billing package file: $EE_PKG"
jq '{name, exports, main, module, types}' "$EE_PKG"
EE_DIR="$(dirname "$EE_PKG")"
echo "Checking enum declarations/exports in ee-billing..."
rg -n "enum Stripe(SubscriptionStatusEnum|UsageTypeEnum)|export .*Stripe(SubscriptionStatusEnum|UsageTypeEnum)" "$EE_DIR/src" -g '*.ts'
echo "Checking deep-import usage in billing e2e tests..."
rg -n "@novu/ee-billing/src/stripe/types" apps/api/src/app/billing/e2e -g '*.ts'Repository: novuhq/novu
Length of output: 37
🏁 Script executed:
# Step 1: Find ee-billing package location
find . -type f -name "package.json" | grep -E "ee-billing" | head -5Repository: novuhq/novu
Length of output: 37
🏁 Script executed:
# Step 2: Search more broadly for billing packages and workspace configuration
find . -type f -name "pnpm-workspace.yaml" -o -name "package.json" | head -3
ls -la | head -20Repository: novuhq/novu
Length of output: 1358
🏁 Script executed:
# Step 3: Check the test file and search for enum definitions
cat -n apps/api/src/app/billing/e2e/create-subscription.e2e-ee.ts | head -30
# Also search for StripeSubscriptionStatusEnum definition
rg "StripeSubscriptionStatusEnum|StripeUsageTypeEnum" -g '*.ts' | head -20Repository: novuhq/novu
Length of output: 2591
🏁 Script executed:
# Step 4: Find ee-billing package location and check its exports
find . -type d -name "*ee-billing*" | grep -v node_modules | grep -v ".git"
# Also check tsconfig for path mappings
cat tsconfig.base.json 2>/dev/null | jq '.compilerOptions.paths | select(. != null) | keys[] | select(contains("ee-billing"))' 2>/dev/null || echo "Checking alternate tsconfig..."Repository: novuhq/novu
Length of output: 37
🏁 Script executed:
# Step 4b: Broader search for the actual location
ls -la libs/ 2>/dev/null | head -20 || echo "No libs directory"
ls -la packages/ 2>/dev/null | head -20 || echo "No packages directory"
# Search directly for stripe/types file
find . -path "*/stripe/types.ts" -not -path "*/node_modules/*" -not -path "*/.git/*"Repository: novuhq/novu
Length of output: 1556
🏁 Script executed:
# Step 5: Check packages/novu structure for ee-billing
ls -la packages/novu/ | head -20
# Search for stripe/types.ts
find . -path "*/stripe/types.ts" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null
find . -name "types.ts" -path "*/stripe/*" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/nullRepository: novuhq/novu
Length of output: 795
🏁 Script executed:
# Step 6: Explore packages/novu/src structure
ls -la packages/novu/src/
# Find stripe/types.ts more directly
find packages/novu -name "types.ts" 2>/dev/null | head -10
# Also search for StripeSubscriptionStatusEnum definition
rg "StripeSubscriptionStatusEnum|StripeUsageTypeEnum" packages/novu/ -g '*.ts' 2>/dev/null | head -15Repository: novuhq/novu
Length of output: 809
🏁 Script executed:
# Step 7: Search for `@novu/ee-billing` references and StripeSubscriptionStatusEnum definition
rg "@novu/ee-billing" --type json | head -10
# Search for where StripeSubscriptionStatusEnum is defined
rg "enum StripeSubscriptionStatusEnum|export.*StripeSubscriptionStatusEnum" -g '*.ts' 2>/dev/null | head -10
# Check for any ee-billing directories
find . -type d -name "*ee*billing*" -not -path "*/node_modules/*" -not -path "*/.git/*"Repository: novuhq/novu
Length of output: 321
🏁 Script executed:
# Step 8: Explore enterprise/packages/billing structure
ls -la enterprise/packages/billing/
ls -la enterprise/packages/billing/src/ 2>/dev/null || echo "No src directory"
# Check for stripe/types.ts
find enterprise/packages/billing -name "types.ts" -path "*/stripe/*" 2>/dev/null
# Check package.json exports
cat enterprise/packages/billing/package.json | jq '{name, exports, main, types, files}' 2>/dev/nullRepository: novuhq/novu
Length of output: 758
🏁 Script executed:
# Step 9: Find the actual source and check index.ts
find . -type d -path "*/.source/billing/src" -not -path "*/node_modules/*"
# Also check relative path from enterprise/packages/billing
ls -la enterprise/packages/billing/../../../.source/billing/src/ 2>/dev/null || echo "Path not found"
# Try to find .source directory
find . -type d -name ".source" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null | head -5Repository: novuhq/novu
Length of output: 79
🏁 Script executed:
# Step 10: Check .source/billing/src structure
ls -la .source/billing/src/ 2>/dev/null || echo "Directory structure not found"
# List all files in .source/billing
find .source/billing -type f -name "*.ts" | head -20
# Check if index.ts exists and what it exports
cat .source/billing/src/index.ts 2>/dev/null | head -50Repository: novuhq/novu
Length of output: 152
🏁 Script executed:
# Step 11: Check .source directory
ls -la .source/ | head -30
# Search for stripe directory anywhere
find . -type d -name "stripe" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null
# Search for any stripe/types.ts anywhere
find . -type f -path "*/stripe/types.ts" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null
# Also search for StripeSubscriptionStatusEnum definition
rg "enum StripeSubscriptionStatusEnum" -g '*.ts' 2>/dev/nullRepository: novuhq/novu
Length of output: 167
🏁 Script executed:
# Step 12: Check enterprise/packages/billing directly for any files
find enterprise/packages/billing -type f -name "*.ts" | head -20
# Search for stripe in entire repo more carefully
find . -type d -name "stripe" -not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null
# Search for StripeSubscriptionStatusEnum or StripeUsageTypeEnum definition more broadly
rg "StripeSubscriptionStatusEnum|StripeUsageTypeEnum" -g '*.ts' --type-list 2>/dev/null | grep -v "import\|from" | head -20
# Check actual dist output if it exists
find enterprise/packages/billing/dist -type f 2>/dev/null | head -10Repository: novuhq/novu
Length of output: 37
🏁 Script executed:
# Step 13: Check for submodules and gitignore
cat .gitmodules 2>/dev/null | grep -i billing || echo "No billing submodule"
cat .gitignore | grep -i billing || echo "No billing in gitignore"
# Check enterprise/.gitignore
cat enterprise/.gitignore 2>/dev/null | grep -i billing || echo "No billing in enterprise/.gitignore"
# Check what package.json says about main field - follow the reference
cat enterprise/packages/billing/package.json | jq '.main'
# Check the full package.json
cat enterprise/packages/billing/package.jsonRepository: novuhq/novu
Length of output: 1907
🏁 Script executed:
# Step 14: Check the build script and source structure
cat enterprise/packages/billing/check-ee.mjs
# Also check if src is actually accessible (since symlink is broken, show what's in dist)
ls -la enterprise/packages/billing/dist/ 2>/dev/null | head -20
# Try to find the real source by checking if there's a different path
find . -path "*/billing/src/stripe/types.ts" -not -path "*/node_modules/*" 2>/dev/null
# Also check tsconfig to understand source mapping
cat enterprise/packages/billing/tsconfig.jsonRepository: novuhq/novu
Length of output: 1938
🏁 Script executed:
# Step 15: Search for index files and stripe enum exports in ee-billing context
rg "export.*Stripe(Subscription|Usage)" enterprise/packages/billing/ -g '*.ts' 2>/dev/null || echo "No exports found"
# Check if there's any src directory (maybe not symlinked but actual)
find enterprise/packages/billing -type d -name src 2>/dev/null
# Search entire repo for where StripeSubscriptionStatusEnum is defined and exported
rg "export.*(enum|const) Stripe(Subscription|Usage)" -g '*.ts' | head -20Repository: novuhq/novu
Length of output: 71
Avoid deep-importing @novu/ee-billing/src/... in this test
The import on line 7 pulls enums from an internal source path (@novu/ee-billing/src/stripe/types), which bypasses the package's public API. This approach is fragile because:
- The
srcdirectory is a symlink that may not exist in all build contexts - Only the
dist/output is published;srcis not distributed to consumers - The package has no explicit export maps, making the public API unclear
Suggested fix
-import { StripeSubscriptionStatusEnum, StripeUsageTypeEnum } from '@novu/ee-billing/src/stripe/types';
+import { StripeSubscriptionStatusEnum, StripeUsageTypeEnum } from '@novu/ee-billing';If these enums are not currently exported from the public entrypoint, re-export them from @novu/ee-billing's main index file.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/api/src/app/billing/e2e/create-subscription.e2e-ee.ts` at line 7, The
test deep-imports internal symbols StripeSubscriptionStatusEnum and
StripeUsageTypeEnum from '@novu/ee-billing/src/stripe/types' which is fragile;
instead add re-exports for those enums in the public entrypoint of the
`@novu/ee-billing` package (e.g., export { StripeSubscriptionStatusEnum,
StripeUsageTypeEnum } from './src/stripe/types' in the package's main index) and
update the test import in create-subscription.e2e-ee.ts to import them from
'@novu/ee-billing' so the test uses the package public API.
| /** | ||
| * Filter by workflow tags. Plain string[] is OR. Use { and: [{ or: string[] }, ...] } for AND of OR-groups (same as inbox). | ||
| */ | ||
| tags?: components.ObjectT | undefined; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify documented shape vs validator shape
rg -n "Filter by workflow tags|string\\[\\]|tags\\?: components\\.ObjectT|tags: components\\.ObjectT\\$outboundSchema\\.optional" \
libs/internal-sdk/src/models/operations/subscriberscontrollergetsubscribernotifications.ts
sed -n '1,30p' libs/internal-sdk/src/models/components/object.tsRepository: novuhq/novu
Length of output: 721
Fix the source schema for tags — generated validator contradicts documented API shape.
This is an auto-generated file (Speakeasy). The schema at line 114 uses z.object({}) which rejects all inputs, but the JSDoc at line 30 documents valid inputs as string[] or { and: [{ or: string[] }, ...] }. Fix the source schema definition so Speakeasy regenerates this file with the correct validator.
The generated type and schema should accept:
string[]for OR logic{ and: Array<{ or: string[] }> }for AND of OR-groups
Also applies to lines 90, 114.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@libs/internal-sdk/src/models/operations/subscriberscontrollergetsubscribernotifications.ts`
around lines 29 - 32, The generated validator for the tags field is wrong (it
currently uses an empty z.object which rejects valid input); update the
Speakeasy/OpenAPI source schema for the tags property (the one that produces
components.ObjectT / the tags field in the subscribers controller model) to be a
union that accepts either string[] (OR) or an object shaped as { and: Array<{
or: string[] }> } (AND of OR-groups); then regenerate the SDK so the generated
type and schema (the tags type and its validator used in the subscribers
controller) validate string[] and { and: [{ or: string[] }, ...] } correctly
instead of z.object({}).
| subscriberId: string; | ||
| page?: number | undefined; | ||
| limit?: number | undefined; | ||
| feedIdentifier?: components.ObjectT | undefined; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Confirm ObjectT schema shape
rg -n --type ts 'export const ObjectT\\$outboundSchema|z\\.object\\(\\{\\}\\)' libs/internal-sdk/src/models/components/object.ts
# 2) Find operations using ObjectT$outboundSchema for outbound query fields
rg -n --type ts 'ObjectT\\$outboundSchema\\.optional\\(\\)' libs/internal-sdk/src/models/operations
# 3) Find request funcs that serialize those fields into query params
rg -n --type ts '"(tags|feedId|feedIdentifier)"\\s*:\\s*payload\\.(tags|feedId|feedIdentifier)' libs/internal-sdk/src/funcsRepository: novuhq/novu
Length of output: 251
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Confirm ObjectT schema shape - search for ObjectT definition
echo "=== Looking for ObjectT definition ==="
find libs/internal-sdk/src/models/components -name "*object.ts" -o -name "*objectT.ts" 2>/dev/null | head -10
# 2) Search for ObjectT$outboundSchema usage more carefully
echo "=== Searching for ObjectT\$outboundSchema usage ==="
rg -n 'ObjectT.*outboundSchema' libs/internal-sdk/src/models/operations --type ts | head -20
# 3) Look at the specific file mentioned in the review
echo "=== Examining subscribersv1controllergetnotificationsfeed.ts ==="
wc -l libs/internal-sdk/src/models/operations/subscribersv1controllergetnotificationsfeed.ts
# 4) Check if the file exists and get a specific range
if [ -f "libs/internal-sdk/src/models/operations/subscribersv1controllergetnotificationsfeed.ts" ]; then
echo "=== Lines 10-70 of the file ==="
sed -n '10,70p' libs/internal-sdk/src/models/operations/subscribersv1controllergetnotificationsfeed.ts
fiRepository: novuhq/novu
Length of output: 2752
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the ObjectT definition file
echo "=== Finding ObjectT model file ==="
find libs/internal-sdk/src/models/components -type f -name "*.ts" | xargs rg -l "ObjectT.*outboundSchema" | head -5
# Check what z.object({}) looks like
echo "=== Searching for empty z.object patterns ==="
rg -n 'z\.object\(\)' libs/internal-sdk/src/models/components --type ts | head -10Repository: novuhq/novu
Length of output: 185
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the ObjectT definition file
echo "=== ObjectT definition ==="
cat libs/internal-sdk/src/models/components/object.ts
echo ""
echo "=== Checking subscribersNotificationsFeed.ts funcs ==="
if [ -f "libs/internal-sdk/src/funcs/subscribersNotificationsFeed.ts" ]; then
wc -l libs/internal-sdk/src/funcs/subscribersNotificationsFeed.ts
echo "=== Lines 100-120 ==="
sed -n '100,120p' libs/internal-sdk/src/funcs/subscribersNotificationsFeed.ts
fiRepository: novuhq/novu
Length of output: 1193
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check the tags field in subscriberscontrollergetsubscribernotifications.ts
echo "=== tags field in subscriberscontrollergetsubscribernotifications.ts ==="
sed -n '100,120p' libs/internal-sdk/src/models/operations/subscriberscontrollergetsubscribernotifications.ts
echo ""
echo "=== feedId field in subscribersv1controllergetunseencount.ts ==="
sed -n '40,60p' libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts
echo ""
# Check how these are used in funcs
echo "=== searching for tags and feedId in funcs files ==="
rg -n 'tags.*payload\.|feedId.*payload\.' libs/internal-sdk/src/funcs --type ts | head -10Repository: novuhq/novu
Length of output: 2043
🏁 Script executed:
#!/bin/bash
set -euo zipfail
# Let's verify the data loss issue by examining the ObjectT definition more carefully
# and see if there are any comments about this being a placeholder
echo "=== Checking if ObjectT is auto-generated and what it should be ==="
head -2 libs/internal-sdk/src/models/components/object.ts
# Check if this is marked as auto-generated
rg -B5 -A10 'export type ObjectT' libs/internal-sdk/src/models/components/object.tsRepository: novuhq/novu
Length of output: 107
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check if these files are marked as auto-generated
echo "=== Checking auto-generated markers ==="
head -5 libs/internal-sdk/src/models/components/object.ts
head -5 libs/internal-sdk/src/models/operations/subscribersv1controllergetnotificationsfeed.ts
echo ""
echo "=== Looking for OpenAPI definition or source config ==="
find . -maxdepth 3 -type f \( -name "*.yaml" -o -name "*.yml" -o -name "*.json" \) | grep -i 'openapi\|swagger\|api' | head -10Repository: novuhq/novu
Length of output: 642
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check if ObjectT is used elsewhere and what the pattern suggests
echo "=== How many files use ObjectT ==="
rg -l 'components\.ObjectT' libs/internal-sdk/src --type ts | wc -l
echo ""
echo "=== Sample of ObjectT usage in different contexts ==="
rg -B2 'ObjectT\$outboundSchema' libs/internal-sdk/src/models/operations --type ts | head -30Repository: novuhq/novu
Length of output: 1293
feedIdentifier, feedId, and tags are at risk of being serialized as {} (filter data loss).
Because components.ObjectT$outboundSchema is z.object({}), filter objects passed to these fields are stripped during validation, causing downstream data loss in query parameters. Affected operations:
SubscribersV1ControllerGetNotificationsFeedRequest.feedIdentifier(line 16)SubscribersV1ControllerGetUnseenCountRequest.feedId(line 40)SubscribersControllerGetSubscriberNotificationsRequest.tags(line 114)
These are auto-generated files (Speakeasy). Fix the ObjectT definition in the upstream API specification to properly define the expected object schema with passthrough properties (e.g., additionalProperties: true in OpenAPI), then regenerate.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@libs/internal-sdk/src/models/operations/subscribersv1controllergetnotificationsfeed.ts`
at line 16, The ObjectT schema is too strict (z.object({}) outbound) causing
filter objects for feedIdentifier, feedId, and tags to be stripped; update the
upstream OpenAPI components.ObjectT schema to allow passthrough properties
(e.g., add additionalProperties: true or define the expected properties) so
outboundSchema isn't an empty object, then regenerate the Speakeasy client so
SubscribersV1ControllerGetNotificationsFeedRequest.feedIdentifier,
SubscribersV1ControllerGetUnseenCountRequest.feedId, and
SubscribersControllerGetSubscriberNotificationsRequest.tags preserve their
contents.
| /** | ||
| * Identifier for the feed. Can be a single string or an array of strings. | ||
| */ | ||
| feedId?: components.ObjectT | undefined; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify feedId docs vs validator/type in this model
rg -n "feedId|single string|array of strings|ObjectT\\$outboundSchema" \
libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts
sed -n '1,30p' libs/internal-sdk/src/models/components/object.tsRepository: novuhq/novu
Length of output: 702
🏁 Script executed:
#!/bin/bash
# View the actual file content around the flagged lines
echo "=== Lines 1-20 (header and context) ==="
sed -n '1,20p' libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts
echo ""
echo "=== Lines 14-17 (feedId definition) ==="
sed -n '14,17p' libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts
echo ""
echo "=== Lines 38-42 (around line 40) ==="
sed -n '38,42p' libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts
echo ""
echo "=== Lines 52-56 (around line 54, schema) ==="
sed -n '52,56p' libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts
echo ""
echo "=== Full line count ==="
wc -l libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.tsRepository: novuhq/novu
Length of output: 1504
This file is auto-generated by Speakeasy; the issue must be fixed in the source specification, not here.
Line 15 documents feedId as accepting "a single string or an array of strings," but the type (line 17) and schema (line 54) use components.ObjectT ({}), which only validates empty objects. This causes runtime validation failures for valid inputs.
However, libs/internal-sdk/** contains auto-generated code and must not be edited directly. The fix must be applied to the source OpenAPI/Speakeasy specification that generates this file, not to the generated output.
Also applies to: lines 40, 54
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@libs/internal-sdk/src/models/operations/subscribersv1controllergetunseencount.ts`
around lines 14 - 17, The generated model's feedId property is incorrectly typed
as components.ObjectT (empty object); update the source OpenAPI/Speakeasy
specification for the subscribersv1controllergetunseencount schema so feedId is
defined as either a single string or an array of strings (e.g., use oneOf:
[{type: "string"}, {type: "array", items: {type: "string"}}] or equivalent
Speakeasy schema), not components.ObjectT; regenerate the SDK so the generated
property feedId and its schema reflect string/array-of-strings instead of {}.
| return [ | ||
| "@novu/api", | ||
| "Channel Connections", | ||
| "ChannelConnections", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n libs/internal-sdk/src/react-query/channelConnectionsRetrieve.core.ts | head -20Repository: novuhq/novu
Length of output: 912
🏁 Script executed:
sed -n '70,90p' libs/internal-sdk/src/react-query/channelConnectionsRetrieve.core.ts | cat -nRepository: novuhq/novu
Length of output: 450
Update the auto-generated file through code generation, not manual edits.
This file is auto-generated by Speakeasy (DO NOT EDIT marker on line 2). Any changes to this file must be made by updating the generator inputs/templates and re-running code generation, rather than editing the file directly. This applies to all files under libs/internal-sdk/.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@libs/internal-sdk/src/react-query/channelConnectionsRetrieve.core.ts` at line
81, This file
(libs/internal-sdk/src/react-query/channelConnectionsRetrieve.core.ts) is
auto-generated and must not be manually edited; revert any manual changes and
instead update the Speakeasy generator inputs/templates that produce the
"ChannelConnections" export (and any related schema/config) and then re-run the
code generation pipeline so the updated output is regenerated with the DO NOT
EDIT marker intact.
|
@cursoragent fix merge conflicts with origin/next |
|
Here is what was done. Merge
|
Resolve submodule by merging enterprise next (ff75602) into Nest 11 auth fix; keep worker on Nest 11 deps and add yargs from next; align internal-sdk SDK_METADATA with next OpenAPI 3.15.0; regenerate pnpm-lock.yaml. Co-authored-by: Dima Grossman <dima@grossman.io>
…xt (ff75602) validate-submodule-sync requires .source HEAD to match origin/next exactly. Co-authored-by: Dima Grossman <dima@grossman.io>
…9f68194) Single commit on top of packages-enterprise next (ff75602). CI validate-submodule-sync stays green only after merging branch cursor/nest11-keyless-from-next-31bf into next. Co-authored-by: Dima Grossman <dima@grossman.io>
Register translation change providers and remove the synchronous forwardRef helper to simplify DI and break circular imports. change.module.ts now provides TRANSLATION_CHANGE_SERVICE and TRANSLATION_GROUP_CHANGE_SERVICE backed by PromoteTranslationChange and PromoteTranslationGroupChange. Deleted apply-change.forward-ref.ts and updated promote-change-to-environment to inject the translation services via tokens (ITranslationChangeService / ITranslationGroupChangeService). PromoteTranslationChange and PromoteTranslationGroupChange now implement the respective service interfaces and import ApplyChange directly instead of using the forwardRef helper.


What changed? Why was the change needed?
What changed
Upgraded NestJS from 10.x to 11.x across the monorepo to stay current with framework changes and remove type/compatibility friction. Changes include dependency bumps, TypeScript typing and Swagger decorator adjustments, bootstrap changes to preserve Express v4-style query parsing, and minor runtime refactors to align with NestJS v11 APIs and improve type safety.
Affected areas
Key technical decisions
Testing
No large new test suites added; test config and small spec fixes were applied (Mocha config, load-test-env, cors config tests) to address failing API unit and e2e tests after the upgrade—verification is expected via existing unit and e2e test runs.
Screenshots
Expand for optional sections
Related enterprise PR
Special notes for your reviewer