Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const providers: Record<ChannelTypeEnum, ProvidersIdEnum[]> = {
PushProviderIdEnum.OneSignal,
PushProviderIdEnum.Pushpad,
PushProviderIdEnum.PusherBeams,
PushProviderIdEnum.AppIO,
PushProviderIdEnum.Pushwoosh,
],
[ChannelTypeEnum.SMS]: [
SmsProviderIdEnum.Twilio,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './one-signal.handler';
export * from './push-webhook.handler';
export * from './pusher-beams.handler';
export * from './pushpad.handler';
export * from './appio.handler';
export * from './appio.handler';
export * from './pushwoosh.handler';
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { PushwooshPushProvider } from '@novu/providers';
import { ChannelTypeEnum, ICredentials, PushProviderIdEnum } from '@novu/shared';
import { BasePushHandler } from './base.handler';

export class PushwooshHandler extends BasePushHandler {
constructor() {
super(PushProviderIdEnum.Pushwoosh, ChannelTypeEnum.PUSH);
}

buildProvider(credentials: ICredentials) {
if (!credentials.apiKey || !credentials.applicationId) {
throw Error('Config is not valid for Pushwoosh');
}

this.provider = new PushwooshPushProvider({
applicationId: credentials.applicationId,
apiKey: credentials.apiKey,
});
}
}
2 changes: 2 additions & 0 deletions libs/application-generic/src/factories/push/push.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
PushpadHandler,
PushWebhookHandler,
AppIOHandler,
PushwooshHandler,
} from './handlers';
import { IPushFactory, IPushHandler } from './interfaces';

Expand All @@ -21,6 +22,7 @@ export class PushFactory implements IPushFactory {
new PushWebhookHandler(),
new PusherBeamsHandler(),
new AppIOHandler(),
new PushwooshHandler(),
];

getHandler(
Expand Down
21 changes: 11 additions & 10 deletions packages/framework/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ export interface IAttachmentOptions {
export interface ITriggerPayload {
attachments?: IAttachmentOptions[];
[key: string]:
| string
| string[]
| boolean
| number
| undefined
| IAttachmentOptions
| IAttachmentOptions[]
| Record<string, unknown>;
| string
| string[]
| boolean
| number
| undefined
| IAttachmentOptions
| IAttachmentOptions[]
| Record<string, unknown>;
}

export interface ISubscriberPayload {
Expand Down Expand Up @@ -186,6 +186,7 @@ export enum PushProviderIdEnum {
PushWebhook = 'push-webhook',
PusherBeams = 'pusher-beams',
AppIO = 'appio',
Pushwoosh = 'pushwoosh',
}

export enum InAppProviderIdEnum {
Expand Down Expand Up @@ -251,8 +252,8 @@ export type WorkflowPreferences = {
// TODO: This utility also exists in src/types/util.types.ts. They should be consolidated.
export type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;

/** A partial set of workflow preferences. */
Expand Down
1 change: 1 addition & 0 deletions packages/providers/src/lib/push/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './one-signal/one-signal.provider';
export * from './push-webhook/push-webhook.provider';
export * from './pusher-beams/pusher-beams.provider';
export * from './pushpad/pushpad.provider';
export * from './pushwoosh/pushwoosh.provider';
export * from './appio/appio.provider';
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ChannelTypeEnum, PushProviderIdEnum } from '@novu/shared';
import { PushwooshPushProvider } from './pushwoosh.provider';

describe('PushwooshPushProvider', () => {
const config = {
applicationId: 'TEST-APP-CODE',
apiKey: 'test-api-key',
};

test('should create provider instance', () => {
const provider = new PushwooshPushProvider(config);
expect(provider.id).toBe(PushProviderIdEnum.Pushwoosh);
expect(provider.channelType).toBe(ChannelTypeEnum.PUSH);
});

test('should throw not implemented error', async () => {
const provider = new PushwooshPushProvider(config);

const options = {
title: 'Test Notification',
content: 'This is a test message',
target: ['device-token-1', 'device-token-2'],
payload: {
customData: 'test',
},
};

await expect(provider.sendMessage(options)).rejects.toThrow(
'PushwooshPushProvider.sendMessage is not implemented yet'
);
});
});

31 changes: 31 additions & 0 deletions packages/providers/src/lib/push/pushwoosh/pushwoosh.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
ChannelTypeEnum,
IPushOptions,
IPushProvider,
ISendMessageSuccessResponse,
} from '@novu/stateless';
import { PushProviderIdEnum } from '@novu/shared';
import { BaseProvider, CasingEnum } from '../../../base.provider';

export class PushwooshPushProvider extends BaseProvider implements IPushProvider {
id = PushProviderIdEnum.Pushwoosh;
channelType = ChannelTypeEnum.PUSH as ChannelTypeEnum.PUSH;
protected casing: CasingEnum = CasingEnum.CAMEL_CASE;

constructor(
private config: {
applicationId: string;
apiKey: string;
}
) {
super();
}

async sendMessage(
options: IPushOptions
): Promise<ISendMessageSuccessResponse> {
void options;

throw new Error('PushwooshPushProvider.sendMessage is not implemented yet');
}
}
9 changes: 9 additions & 0 deletions packages/shared/src/consts/providers/channels/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
oneSignalConfig,
pusherBeamsConfig,
pushpadConfig,
pushwooshConfig,
pushWebhookConfig,
} from '../credentials';
Comment on lines +18 to 20
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 1) Confirm the logo asset exists somewhere in-repo
echo "=== Searching for pushwoosh.svg asset ==="
rg -n --hidden -S "pushwoosh\.svg" .

# 2) Find where provider credentials are transformed
echo ""
echo "=== Searching for applicationCode references ==="
rg -n --type=ts -C2 "applicationCode" .

echo ""
echo "=== Searching for CredentialsKeyEnum.ApplicationId ==="
rg -n --type=ts -C2 "CredentialsKeyEnum\.ApplicationId" packages

Repository: novuhq/novu

Length of output: 4963


🏁 Script executed:

#!/bin/bash
# 1) Search for actual asset files - look in public/assets or similar directories
echo "=== Searching for actual .svg asset files ==="
find . -type f -name "*.svg" | grep -i pushwoosh

echo ""
echo "=== Search all directories for .svg files to see where assets are stored ==="
find . -type d -name "assets" -o -type d -name "public" | head -20

echo ""
echo "=== Look at the pushwooshConfig definition ==="
rg -n --type=ts "export const pushwooshConfig" packages/shared/src/consts/providers/credentials/ -A 20

echo ""
echo "=== Find credential transformation/mapping logic ==="
rg -n --type=ts "credentials.*config\|mapCredentials\|transformCredentials" packages/providers/src/lib/push/pushwoosh/ -A 5

Repository: novuhq/novu

Length of output: 2741


🏁 Script executed:

#!/bin/bash
# Search for credential transformation, base provider, or factory patterns
echo "=== Search for credential mapping utilities ==="
rg -n --type=ts "CredentialsKeyEnum" packages/providers/src/lib/ -B 2 -A 2 | head -50

echo ""
echo "=== Look for BaseProvider or transformation patterns ==="
rg -n --type=ts "class.*Provider|constructor.*credentials" packages/providers/src/lib/push/pushwoosh/ -A 10

echo ""
echo "=== Check if there's a credentials-to-config mapping somewhere ==="
rg -n --type=ts "camelCase|toCamelCase|mapCredentials\|ApplicationId.*applicationCode" packages/providers/src/ -B 2 -A 2 | head -60

echo ""
echo "=== Check the full pushwoosh provider implementation ==="
cat -n packages/providers/src/lib/push/pushwoosh/pushwoosh.provider.ts

Repository: novuhq/novu

Length of output: 6252


🏁 Script executed:

#!/bin/bash
# Search for where PushwooshPushProvider is instantiated
echo "=== Find provider instantiation patterns ==="
rg -n --type=ts "new PushwooshPushProvider\|PushwooshPushProvider\(" packages/providers/src/ -B 5 -A 5

echo ""
echo "=== Look for factory/provider instantiation patterns ==="
rg -n --type=ts "providerFactory\|createProvider\|instantiate" packages/providers/src/lib/ -B 2 -A 5 | head -80

echo ""
echo "=== Check if BaseProvider has credential handling logic ==="
sed -n '1,150p' packages/providers/src/base.provider.ts | cat -n

Repository: novuhq/novu

Length of output: 5600


🏁 Script executed:

#!/bin/bash
# Search for credential initialization or mapping patterns
echo "=== Search for credentials hydration/mapping ==="
rg -n --type=ts "credentials.*\[CredentialsKeyEnum\|credentials\[.*ApplicationId\|config\[.*applicationCode" packages/providers/src/ -B 3 -A 3

echo ""
echo "=== Search for push provider factory or resolver ==="
rg -n --type=ts "pushwoosh\|Pushwoosh" packages/ --type=ts | grep -E "(factory|resolver|instantiate|create|hydrate)" | head -30

echo ""
echo "=== Look for index/exports in push providers to find integration point ==="
cat -n packages/providers/src/lib/push/index.ts 2>/dev/null || echo "File not found"

echo ""
echo "=== Search for any credential mapping patterns ==="
rg -n --type=ts "CredentialsKeyEnum\.(ApiKey|ApplicationId)" packages/providers/src/ -B 3 -A 3 | head -100

Repository: novuhq/novu

Length of output: 750


🏁 Script executed:

#!/bin/bash
# Search in shared package for credential handling
echo "=== Search in shared for push provider credential handling ==="
rg -n --type=ts "PushwooshPushProvider\|pushwoosh" packages/shared/src/ -B 2 -A 5

echo ""
echo "=== Search for credential resolver or factory pattern ==="
rg -n --type=ts "credentials\[.*key\]|getCredentialField|resolveCredential" packages/ --type=ts -B 2 -A 5 | head -80

echo ""
echo "=== Look at push.ts file more carefully to understand imports ==="
head -50 packages/shared/src/consts/providers/channels/push.ts

echo ""
echo "=== Check how other providers use credentials in registry ==="
rg -n --type=ts "credentials:" packages/shared/src/consts/providers/channels/ -B 1 -A 1 | head -40

Repository: novuhq/novu

Length of output: 5135


🏁 Script executed:

#!/bin/bash
# Search for CredentialsKeyEnum definition to understand enum-to-field mapping
echo "=== Find CredentialsKeyEnum definition ==="
rg -n "enum CredentialsKeyEnum|export enum CredentialsKeyEnum" packages/ -A 30 | head -80

echo ""
echo "=== Search for any credential transformation or mapping ==="
rg -n --type=ts "ApplicationId.*applicationCode\|applicationCode.*ApplicationId" packages/ -B 2 -A 2

echo ""
echo "=== Look for any Pushwoosh-specific credential handling ==="
rg -n --type=ts "pushwoosh.*cred\|credential.*pushwoosh" packages/providers/src/lib/push/pushwoosh/ -i -B 3 -A 3

Repository: novuhq/novu

Length of output: 2363


🏁 Script executed:

#!/bin/bash
# Double-check the logo asset exists and is correctly referenced
echo "=== Verify pushwoosh logo assets exist ==="
ls -la ./apps/dashboard/public/images/providers/light/square/pushwoosh.svg
ls -la ./apps/web/public/static/images/providers/light/square/pushwoosh.svg
ls -la ./apps/web/public/static/images/providers/dark/square/pushwoosh.svg

echo ""
echo "=== Confirm the provider expects applicationCode ==="
grep -n "applicationCode" packages/providers/src/lib/push/pushwoosh/pushwoosh.provider.ts

Repository: novuhq/novu

Length of output: 612


Fix Pushwoosh provider credential key mismatch.

The credentials: pushwooshConfig uses CredentialsKeyEnum.ApplicationId, which maps to the field name 'applicationId'. However, the Pushwoosh provider constructor expects 'applicationCode' (line 17 of pushwoosh.provider.ts). This mismatch will cause the provider to receive undefined for the application code at runtime.

Verify that the credentials-to-provider mapper correctly transforms CredentialsKeyEnum.ApplicationId to the applicationCode field, or update the credential configuration to use the correct enum key.

🤖 Prompt for AI Agents
In @packages/shared/src/consts/providers/channels/push.ts around lines 18 - 20,
pushwooshConfig is wired with CredentialsKeyEnum.ApplicationId (which yields
'applicationId') but the Pushwoosh provider constructor (pushwoosh.provider.ts
expecting applicationCode) will receive undefined; update the mapping so the
credentials-to-provider mapper maps CredentialsKeyEnum.ApplicationId to the
provider field name applicationCode (or change the credential key to the correct
enum that resolves to 'applicationCode') ensuring pushwooshConfig ->
applicationCode is supplied to the Pushwoosh provider constructor.

import { IProviderConfig } from '../provider.interface';
Expand All @@ -37,6 +38,14 @@ export const pushProviders: IProviderConfig[] = [
docReference: `https://docs.novu.co/platform/integrations/push/pushpad${UTM_CAMPAIGN_QUERY_PARAM}`,
logoFileName: { light: 'pushpad.svg', dark: 'pushpad.svg' },
},
{
id: PushProviderIdEnum.Pushwoosh,
displayName: 'Pushwoosh',
channel: ChannelTypeEnum.PUSH,
credentials: pushwooshConfig,
docReference: `https://docs.novu.co/platform/integrations/push/pushwoosh${UTM_CAMPAIGN_QUERY_PARAM}`,
logoFileName: { light: 'pushwoosh.svg', dark: 'pushwoosh.svg' },
},
{
id: PushProviderIdEnum.FCM,
displayName: 'Firebase Cloud Messaging',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,22 @@ export const pushpadConfig: IConfigCredential[] = [
...pushConfigBase,
];

export const pushwooshConfig: IConfigCredential[] = [
{
key: CredentialsKeyEnum.ApiKey,
displayName: 'API Access Token',
type: 'text',
required: true,
},
{
key: CredentialsKeyEnum.ApplicationId,
displayName: 'Application Code',
type: 'text',
required: true,
},
...pushConfigBase,
];
Comment on lines +744 to +758
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the provider-credentials.ts file to understand pushConfigBase and the full context
fd provider-credentials.ts

Repository: novuhq/novu

Length of output: 127


🏁 Script executed:

# Search for Pushwoosh provider implementation
rg -i "pushwoosh" --type ts --type tsx -l

Repository: novuhq/novu

Length of output: 82


🏁 Script executed:

# Search for how credentials are mapped/used
rg "applicationCode" --type ts --type tsx -B 2 -A 2

Repository: novuhq/novu

Length of output: 82


🏁 Script executed:

# Search for Pushwoosh without type filters
rg -i "pushwoosh" -B 2 -A 2

Repository: novuhq/novu

Length of output: 6245


🏁 Script executed:

# Look at the provider-credentials.ts file to see pushConfigBase
cat packages/shared/src/consts/providers/credentials/provider-credentials.ts | head -100

Repository: novuhq/novu

Length of output: 2146


🏁 Script executed:

# Search for where credentials are mapped or used
rg "applicationCode" -B 3 -A 3

Repository: novuhq/novu

Length of output: 2014


🏁 Script executed:

# Find Pushwoosh provider implementation
fd -i pushwoosh

Repository: novuhq/novu

Length of output: 429


🏁 Script executed:

# Find where credentials are mapped to provider config
rg "CredentialsKeyEnum" -B 2 -A 2

Repository: novuhq/novu

Length of output: 50367


🏁 Script executed:

# Look at CredentialsKeyEnum definition
fd -i credentials -type d

Repository: novuhq/novu

Length of output: 225


🏁 Script executed:

# Search for provider initialization with credentials
rg "new.*Provider.*config" -B 3 -A 3

Repository: novuhq/novu

Length of output: 21998


🏁 Script executed:

# Search for any mapping or transform from credentials to provider config
rg "applicationCode\|ApplicationId" -B 3 -A 3

Repository: novuhq/novu

Length of output: 37


🏁 Script executed:

# Search for Pushwoosh handler in factories
find libs/application-generic/src/factories -name "*pushwoosh*"

Repository: novuhq/novu

Length of output: 37


🏁 Script executed:

# List all push handlers
ls -la libs/application-generic/src/factories/push/handlers/

Repository: novuhq/novu

Length of output: 834


🏁 Script executed:

# Search for buildProvider or push handlers that might map credentials
rg "buildProvider" libs/application-generic/src/factories/push/ -A 8 | head -100

Repository: novuhq/novu

Length of output: 8504


🏁 Script executed:

# Check if Pushwoosh is registered in the push.factory.ts
cat libs/application-generic/src/factories/push/push.factory.ts

Repository: novuhq/novu

Length of output: 1013


🏁 Script executed:

# Check the index.ts file to see what handlers are exported
cat libs/application-generic/src/factories/push/handlers/index.ts

Repository: novuhq/novu

Length of output: 335


🏁 Script executed:

# Check the Pushwoosh provider test to confirm it expects applicationCode
cat packages/providers/src/lib/push/pushwoosh/pushwoosh.provider.spec.ts

Repository: novuhq/novu

Length of output: 1078


🏁 Script executed:

# Verify the provider class to see the exact config property names
cat packages/providers/src/lib/push/pushwoosh/pushwoosh.provider.ts

Repository: novuhq/novu

Length of output: 1112


Missing Pushwoosh integration handler and breaking credential key mismatch.

The Pushwoosh provider integration is incomplete: no handler exists in the factory system, and there's a property name mismatch between credentials and provider expectations. The pushwooshConfig defines the "Application Code" credential as CredentialsKeyEnum.ApplicationId, but the PushwooshPushProvider constructor expects config.applicationCode. Without a handler to map credentials to the provider config, this integration cannot function.

Create libs/application-generic/src/factories/push/handlers/pushwoosh.handler.ts with explicit mapping from credentials.applicationId to applicationCode, register it in the factory, and update provider-credentials.ts to use a credential key that matches the provider's expected property name (or add the mapping layer).

🤖 Prompt for AI Agents
In @packages/shared/src/consts/providers/credentials/provider-credentials.ts
around lines 744 - 758, pushwooshConfig uses CredentialsKeyEnum.ApplicationId
but PushwooshPushProvider expects config.applicationCode and there is no handler
wiring credentials into the provider; add a new handler file named
pushwoosh.handler.ts in libs/application-generic/src/factories/push/handlers
that maps credentials.applicationId (or CredentialsKeyEnum.ApplicationId) to
applicationCode and passes apiKey to the provider, register this handler in the
push provider factory so the factory returns a PushwooshPushProvider instance
wired with { applicationCode, apiKey } (or adjust provider-credentials.ts to
rename the key to match applicationCode if you prefer key-name alignment instead
of mapping).


export const apnsConfig: IConfigCredential[] = [
{
key: CredentialsKeyEnum.SecretKey,
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/types/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export enum PushProviderIdEnum {
PushWebhook = 'push-webhook',
PusherBeams = 'pusher-beams',
AppIO = 'appio',
Pushwoosh = 'pushwoosh',
}

export enum InAppProviderIdEnum {
Expand Down
Loading