Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(root): Release 2024-11-07 08:05 #6880

Merged
merged 14 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,7 @@
"projectIds"
],
"ignorePaths": [
"apps/api/src/app/workflows-v2/maily-test-data.ts",
"apps/api/src/.env.test",
"apps/ws/src/.env.test",
"apps/ws/src/.example.env",
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/reusable-widget-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ jobs:
parallel: false
config-file: cypress.config.ts

- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-screenshots
path: apps/widget/cypress/screenshots
# Test run video was always captured, so this action uses "always()" condition
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: always()
with:
name: cypress-videos
Expand Down
1 change: 1 addition & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .source
32 changes: 32 additions & 0 deletions LICENSE-ENTERPRISE
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Portions of this software are licensed as follows:

* All content that resides under https://github.com/novuhq/novu/tree/next/enterprise/packages and
https://github.com/novuhq/novu/tree/next/apps/web/src/ee directory of this repository (Commercial License) is licensed under the license defined in "https://github.com/novuhq/novu/blob/next/apps/web/src/ee/LICENSE".
* All third party components incorporated into the Novu Software are licensed under the original license provided by the owner of the applicable component.
* Content outside of the above mentioned directories or restrictions above is available under the "MIT" license as defined below.

Novu Proprietary Software License

IMPORTANT – READ CAREFULLY: This License Agreement ("Agreement") is a legal agreement between you (either an individual or a single entity) and Novu Corporation ("Novu") for the software product identified below, which includes computer software and associated media, printed materials, and "online" or electronic documentation (collectively, the "Software").

By installing, copying, or otherwise using these files, you agree to be bound by the terms of this Agreement.
If you do not agree to the terms of this Agreement, do not install or use the Software.

Grant of License: Subject to the terms of this Agreement, Novu hereby grants you a non-exclusive, non-transferable license to use the Software solely for your internal operations.
You may not rent, lease, lend, sell, redistribute, sublicense or provide commercial hosting services with the Software.

- Use Restrictions: Use of the Software is conditional upon your compliance with the terms set forth below:
- Approval Required: You may not use the Software without obtaining prior written approval from Novu. To request approval, you must contact Novu at [contact information].
- No Modification: You may not modify, adapt, or translate the Software. You may not reverse engineer, decompile, disassemble, or otherwise attempt to discover the source code of the Software, except to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation.

Intellectual Property Rights: The Software is the property of Novu and is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. The Software is licensed, not sold.

Termination: This Agreement is effective until terminated. Your rights under this Agreement will terminate automatically without notice from Novu if you fail to comply with any of the terms and conditions of this Agreement. Upon termination, you must cease all use of the Software and destroy all copies, full or partial, of the Software.

No Warranties: Novu expressly disclaims any warranty for the Software. The Software is provided 'As Is' without any express or implied warranty of any kind, including but not limited to any warranties of merchantability, noninfringement, or fitness for a particular purpose. Novu does not warrant or assume responsibility for the accuracy or completeness of any information, text, graphics, links, or other items contained within the Software.

Limitation of Liability: In no event shall Novu be liable for any damages whatsoever (including, without limitation, damages for loss of profits, business interruption, loss of information, or any other pecuniary loss) arising out of the use of or inability to use this Software, even if Novu has been advised of the possibility of such damages.

By installing, copying, or otherwise using the Software, you acknowledge that you have read this Agreement, understand it, and agree to be bound by its terms and conditions.

You also agree that this Agreement is the complete and exclusive statement of agreement between the parties and supersedes all proposals or prior agreements, oral or written, and any other communications between the parties relating to the subject matter of this Agreement.
5 changes: 1 addition & 4 deletions LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2019 Noti-fire apps ltd.
Copyright (c) 2019 Noti-fire Apps Ltd.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -19,6 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

This license applies to the entire repo except for subfolders that have their own license file.
In such cases, the license file in the subfolder takes precedence.
1 change: 1 addition & 0 deletions apps/api/src/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,4 @@ HUBSPOT_PRIVATE_APP_ACCESS_TOKEN=

CLERK_ISSUER_URL=
CLERK_WEBHOOK_SECRET=
PLAIN_SUPPORT_KEY='PLAIN_SUPPORT_KEY'
1 change: 1 addition & 0 deletions apps/api/src/.env.production
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,4 @@ HUBSPOT_PRIVATE_APP_ACCESS_TOKEN=

CLERK_ISSUER_URL=
CLERK_WEBHOOK_SECRET=
PLAIN_SUPPORT_KEY='PLAIN_SUPPORT_KEY'
1 change: 1 addition & 0 deletions apps/api/src/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,4 @@ CLERK_PEM_PUBLIC_KEY=

TUNNEL_BASE_ADDRESS=example.com
API_ROOT_URL=http://localhost:1337
PLAIN_SUPPORT_KEY='PLAIN_SUPPORT_KEY'
1 change: 1 addition & 0 deletions apps/api/src/.example.env
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,4 @@ CLERK_ISSUER_URL=
CLERK_LONG_LIVED_TOKEN=

TUNNEL_BASE_ADDRESS=
PLAIN_SUPPORT_KEY='PLAIN_SUPPORT_KEY'
3 changes: 3 additions & 0 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ const enterpriseImports = (): Array<Type | DynamicModule | Promise<DynamicModule
if (require('@novu/ee-billing')?.BillingModule) {
modules.push(require('@novu/ee-billing')?.BillingModule.forRoot());
}
if (require('./app/support/support.module')?.SupportModule) {
modules.push(require('./app/support/support.module')?.SupportModule);
}
}

return modules;
Expand Down
4 changes: 1 addition & 3 deletions apps/api/src/app/bridge/bridge.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,11 @@ export class BridgeController {
@Get('/status')
@UseGuards(UserAuthGuard)
async health(@UserSession() user: UserSessionData) {
const result = await this.getBridgeStatus.execute(
return this.getBridgeStatus.execute(
GetBridgeStatusCommand.create({
environmentId: user.environmentId,
})
);

return result;
}

@Post('/preview/:workflowId/:stepId')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,14 @@ export class GetBridgeStatus {
constructor(private executeBridgeRequest: ExecuteBridgeRequest) {}

async execute(command: GetBridgeStatusCommand): Promise<HealthCheck> {
try {
const response = (await this.executeBridgeRequest.execute(
ExecuteBridgeRequestCommand.create({
environmentId: command.environmentId,
action: GetActionEnum.HEALTH_CHECK,
workflowOrigin: WorkflowOriginEnum.EXTERNAL,
statelessBridgeUrl: command.statelessBridgeUrl,
retriesLimit: 1,
})
)) as ExecuteBridgeRequestDto<GetActionEnum.HEALTH_CHECK>;

return response;
} catch (err: any) {
Logger.error(
`Failed to verify Bridge endpoint for environment ${command.environmentId} with error: ${(err as Error).message || err}`,
(err as Error).stack,
LOG_CONTEXT
);
throw err;
}
return (await this.executeBridgeRequest.execute(
ExecuteBridgeRequestCommand.create({
environmentId: command.environmentId,
action: GetActionEnum.HEALTH_CHECK,
workflowOrigin: WorkflowOriginEnum.EXTERNAL,
statelessBridgeUrl: command.statelessBridgeUrl,
retriesLimit: 1,
})
)) as ExecuteBridgeRequestDto<GetActionEnum.HEALTH_CHECK>;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EnvironmentWithUserCommand } from '@novu/application-generic';
import { Subscriber } from '@novu/framework/internal';
import { WorkflowOriginEnum } from '@novu/shared';
import { JobStatusEnum, WorkflowOriginEnum } from '@novu/shared';

export class PreviewStepCommand extends EnvironmentWithUserCommand {
workflowId: string;
Expand All @@ -9,4 +9,13 @@ export class PreviewStepCommand extends EnvironmentWithUserCommand {
payload: Record<string, unknown>;
subscriber?: Subscriber;
workflowOrigin: WorkflowOriginEnum;
state?: FrameworkPreviousStepsOutputState[];
}
export type FrameworkPreviousStepsOutputState = {
stepId: string;
outputs: Record<string, unknown>;
state: {
status: JobStatusEnum;
error?: string;
};
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common';
import { Event, ExecuteOutput, HttpQueryKeysEnum, JobStatusEnum, PostActionEnum } from '@novu/framework/internal';
import { Event, ExecuteOutput, HttpQueryKeysEnum, PostActionEnum } from '@novu/framework/internal';
import { ExecuteBridgeRequest, ExecuteBridgeRequestCommand } from '@novu/application-generic';

import { PreviewStepCommand } from './preview-step.command';
Expand Down Expand Up @@ -35,7 +35,7 @@ export class PreviewStep {
return {
controls: command.controls || {},
payload: command.payload || {},
state: [],
state: command.state || [],
subscriber: command.subscriber || {},
stepId: command.stepId,
workflowId: command.workflowId,
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/app/environments-v1/novu-bridge-client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Inject, Injectable, Scope } from '@nestjs/common';
import type { Request, Response } from 'express';
import { PostActionEnum, type Workflow } from '@novu/framework/internal';
import { Client, NovuRequestHandler, NovuHandler } from '@novu/framework/nest';
import { Client, NovuHandler, NovuRequestHandler } from '@novu/framework/nest';
import { GetDecryptedSecretKey, GetDecryptedSecretKeyCommand } from '@novu/application-generic';
import { ConstructFrameworkWorkflow, ConstructFrameworkWorkflowCommand } from './usecases/construct-framework-workflow';

Expand Down Expand Up @@ -45,6 +45,7 @@ export class NovuBridgeClient {
environmentId: req.params.environmentId,
workflowId: req.query.workflowId as string,
controlValues: req.body.controls,
action: req.query.action as PostActionEnum,
})
);

Expand Down
8 changes: 5 additions & 3 deletions apps/api/src/app/environments-v1/novu-bridge.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { ConstructFrameworkWorkflow } from './usecases/construct-framework-workf
import { NovuBridgeController } from './novu-bridge.controller';
import {
ChatOutputRendererUsecase,
EmailOutputRendererUsecase,
ExpandEmailEditorSchemaUsecase,
HydrateEmailSchemaUseCase,
InAppOutputRendererUsecase,
PushOutputRendererUsecase,
RenderEmailOutputUsecase,
SmsOutputRendererUsecase,
} from './usecases/output-renderers';

Expand All @@ -28,12 +29,13 @@ import {
ConstructFrameworkWorkflow,
GetDecryptedSecretKey,
InAppOutputRendererUsecase,
EmailOutputRendererUsecase,
RenderEmailOutputUsecase,
SmsOutputRendererUsecase,
ChatOutputRendererUsecase,
PushOutputRendererUsecase,
EmailOutputRendererUsecase,
RenderEmailOutputUsecase,
ExpandEmailEditorSchemaUsecase,
HydrateEmailSchemaUseCase,
],
})
export class NovuBridgeModule {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { EnvironmentLevelCommand } from '@novu/application-generic';
import { IsDefined, IsObject, IsString } from 'class-validator';
import { IsDefined, IsEnum, IsObject, IsString } from 'class-validator';
import { PostActionEnum } from '@novu/framework/internal';

export class ConstructFrameworkWorkflowCommand extends EnvironmentLevelCommand {
@IsString()
Expand All @@ -9,4 +10,7 @@ export class ConstructFrameworkWorkflowCommand extends EnvironmentLevelCommand {
@IsObject()
@IsDefined()
controlValues: Record<string, unknown>;

@IsEnum(PostActionEnum)
action: PostActionEnum;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
import { workflow } from '@novu/framework/express';
import {
ActionStep,
Expand All @@ -15,9 +15,10 @@ import { StepTypeEnum } from '@novu/shared';
import { ConstructFrameworkWorkflowCommand } from './construct-framework-workflow.command';
import {
ChatOutputRendererUsecase,
EmailOutputRendererUsecase,
FullPayloadForRender,
InAppOutputRendererUsecase,
PushOutputRendererUsecase,
RenderEmailOutputUsecase,
SmsOutputRendererUsecase,
} from '../output-renderers';

Expand All @@ -26,7 +27,7 @@ export class ConstructFrameworkWorkflow {
constructor(
private workflowsRepository: NotificationTemplateRepository,
private inAppOutputRendererUseCase: InAppOutputRendererUsecase,
private emailOutputRendererUseCase: EmailOutputRendererUsecase,
private emailOutputRendererUseCase: RenderEmailOutputUsecase,
private smsOutputRendererUseCase: SmsOutputRendererUsecase,
private chatOutputRendererUseCase: ChatOutputRendererUsecase,
private pushOutputRendererUseCase: PushOutputRendererUsecase
Expand All @@ -40,15 +41,21 @@ export class ConstructFrameworkWorkflow {
}
}

return this.constructFrameworkWorkflow(dbWorkflow);
return this.constructFrameworkWorkflow(dbWorkflow, command.action);
}

private constructFrameworkWorkflow(newWorkflow: NotificationTemplateEntity): Workflow {
private constructFrameworkWorkflow(newWorkflow, action) {
return workflow(
newWorkflow.triggers[0].identifier,
async ({ step }) => {
async ({ step, payload, subscriber }) => {
const fullPayloadForRender: FullPayloadForRender = { payload, subscriber, steps: {} };
for await (const staticStep of newWorkflow.steps) {
await this.constructStep(step, staticStep);
try {
const stepOutputs = await this.constructStep(step, staticStep, fullPayloadForRender);
fullPayloadForRender.steps[staticStep.stepId || staticStep._templateId] = stepOutputs;
} catch (e) {
Logger.log(`Cannot Construct Step ${staticStep.stepId || staticStep._templateId}`, e);
}
}
},
{
Expand All @@ -66,7 +73,11 @@ export class ConstructFrameworkWorkflow {
);
}

private constructStep(step: Step, staticStep: NotificationStepEntity): StepOutput<Record<string, unknown>> {
private constructStep(
step: Step,
staticStep: NotificationStepEntity,
fullPayloadForRender: FullPayloadForRender
): StepOutput<Record<string, unknown>> {
const stepTemplate = staticStep.template;

if (!stepTemplate) {
Expand All @@ -91,7 +102,7 @@ export class ConstructFrameworkWorkflow {
stepId,
// The step callback function. Takes controls and returns the step outputs
async (controlValues) => {
return this.inAppOutputRendererUseCase.execute({ controlValues });
return this.inAppOutputRendererUseCase.execute({ controlValues, fullPayloadForRender });
},
// Step options
this.constructChannelStepOptions(staticStep)
Expand All @@ -100,31 +111,31 @@ export class ConstructFrameworkWorkflow {
return step.email(
stepId,
async (controlValues) => {
return this.emailOutputRendererUseCase.execute({ controlValues });
return this.emailOutputRendererUseCase.execute({ controlValues, fullPayloadForRender });
},
this.constructChannelStepOptions(staticStep)
);
case StepTypeEnum.SMS:
return step.inApp(
stepId,
async (controlValues) => {
return this.smsOutputRendererUseCase.execute({ controlValues });
return this.smsOutputRendererUseCase.execute({ controlValues, fullPayloadForRender });
},
this.constructChannelStepOptions(staticStep)
);
case StepTypeEnum.CHAT:
return step.inApp(
stepId,
async (controlValues) => {
return this.chatOutputRendererUseCase.execute({ controlValues });
return this.chatOutputRendererUseCase.execute({ controlValues, fullPayloadForRender });
},
this.constructChannelStepOptions(staticStep)
);
case StepTypeEnum.PUSH:
return step.inApp(
stepId,
async (controlValues) => {
return this.pushOutputRendererUseCase.execute({ controlValues });
return this.pushOutputRendererUseCase.execute({ controlValues, fullPayloadForRender });
},
this.constructChannelStepOptions(staticStep)
);
Expand Down
Loading
Loading