Skip to content

Commit

Permalink
feat(js, react, shared): user agents (#6626)
Browse files Browse the repository at this point in the history
  • Loading branch information
BiswaViraj authored Oct 4, 2024
1 parent 172d172 commit 1142df0
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/js/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
module.exports = {
preset: 'ts-jest',
setupFiles: ['./jest.setup.ts'],
};
2 changes: 2 additions & 0 deletions packages/js/jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
global.PACKAGE_VERSION = 'test-version';
global.PACKAGE_NAME = 'test-package';
1 change: 1 addition & 0 deletions packages/js/src/api/inbox-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class InboxService {
this.#httpClient = new HttpClient(options);
this.#httpClient.updateHeaders({
'Novu-API-Version': NOVU_API_VERSION,
'Novu-User-Agent': options.userAgent || '@novu/js',
});
}

Expand Down
4 changes: 4 additions & 0 deletions packages/js/src/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
/* eslint-disable vars-on-top */
/* eslint-disable no-var */
import { Novu } from './novu';

declare global {
var PACKAGE_NAME: string;
var PACKAGE_VERSION: string;
interface Window {
Novu: typeof Novu;
}
Expand Down
11 changes: 10 additions & 1 deletion packages/js/src/novu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import { PRODUCTION_BACKEND_URL } from './utils/config';
import type { NovuOptions } from './types';
import { InboxService } from './api';

// @ts-ignore
const version = PACKAGE_VERSION;
// @ts-ignore
const name = PACKAGE_NAME;
const userAgent = `${name}@${version}`;

export class Novu implements Pick<NovuEventEmitter, 'on' | 'off'> {
#emitter: NovuEventEmitter;
#session: Session;
Expand All @@ -20,7 +26,10 @@ export class Novu implements Pick<NovuEventEmitter, 'on' | 'off'> {
public off: <Key extends EventNames>(eventName: Key, listener: EventHandler<Events[Key]>) => void;

constructor(options: NovuOptions) {
this.#inboxService = new InboxService({ backendUrl: options.backendUrl ?? PRODUCTION_BACKEND_URL });
this.#inboxService = new InboxService({
backendUrl: options.backendUrl ?? PRODUCTION_BACKEND_URL,
userAgent: options.__userAgent ?? userAgent,
});
this.#emitter = new NovuEventEmitter();
this.#session = new Session(
{
Expand Down
4 changes: 4 additions & 0 deletions packages/js/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,8 @@ export type NovuOptions = {
backendUrl?: string;
socketUrl?: string;
useCache?: boolean;
/**
* @internal Should be used internally
*/
__userAgent?: string;
};
7 changes: 4 additions & 3 deletions packages/react/src/components/Inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DefaultProps, DefaultInboxProps, WithChildrenProps } from '../utils/typ
import { Mounter } from './Mounter';
import { useNovuUI } from '../context/NovuUIContext';
import { useRenderer } from '../context/RendererContext';
import { NovuProvider, useNovu, useUnsafeNovu } from '../hooks/NovuProvider';
import { InternalNovuProvider, NovuProvider, useNovu, useUnsafeNovu } from '../hooks/NovuProvider';
import { NovuUI } from './NovuUI';
import { withRenderer } from './Renderer';

Expand Down Expand Up @@ -49,15 +49,16 @@ export const Inbox = React.memo((props: InboxProps) => {
}

return (
<NovuProvider
<InternalNovuProvider
applicationIdentifier={applicationIdentifier}
subscriberId={subscriberId}
subscriberHash={subscriberHash}
backendUrl={backendUrl}
socketUrl={socketUrl}
userAgentType="components"
>
<InboxChild {...props} />
</NovuProvider>
</InternalNovuProvider>
);
});

Expand Down
49 changes: 47 additions & 2 deletions packages/react/src/hooks/NovuProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Novu, NovuOptions } from '@novu/js';
import { ReactNode, createContext, useContext, useMemo } from 'react';

// @ts-ignore
const version = PACKAGE_VERSION;
// @ts-ignore
const name = PACKAGE_NAME;
const baseUserAgent = `${name}@${version}`;

type NovuProviderProps = NovuOptions & {
children: ReactNode;
};
Expand All @@ -16,9 +22,48 @@ export const NovuProvider = ({
socketUrl,
useCache,
}: NovuProviderProps) => {
return (
<InternalNovuProvider
applicationIdentifier={applicationIdentifier}
subscriberId={subscriberId}
subscriberHash={subscriberHash}
backendUrl={backendUrl}
socketUrl={socketUrl}
useCache={useCache}
userAgentType="hooks"
>
{children}
</InternalNovuProvider>
);
};

/**
* @internal Should be used internally not to be exposed outside of the library
* This is needed to differentiate between the hooks and components user agents
* Better to use this internally to avoid confusion.
*/
export const InternalNovuProvider = ({
children,
applicationIdentifier,
subscriberId,
subscriberHash,
backendUrl,
socketUrl,
useCache,
userAgentType,
}: NovuProviderProps & { userAgentType: 'components' | 'hooks' }) => {
const novu = useMemo(
() => new Novu({ applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache }),
[applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache]
() =>
new Novu({
applicationIdentifier,
subscriberId,
subscriberHash,
backendUrl,
socketUrl,
useCache,
__userAgent: `${baseUserAgent} ${userAgentType}`,
}),
[applicationIdentifier, subscriberId, subscriberHash, backendUrl, socketUrl, useCache, userAgentType]
);

return <NovuContext.Provider value={novu}>{children}</NovuContext.Provider>;
Expand Down
26 changes: 13 additions & 13 deletions packages/react/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
import { defineConfig } from 'tsup';
import { defineConfig, Options } from 'tsup';
import { name, version } from './package.json';

const baseConfig: Options = {
sourcemap: true,
clean: true,
dts: true,
define: { PACKAGE_NAME: `"${name}"`, PACKAGE_VERSION: `"${version}"` },
};

export default defineConfig([
{
...baseConfig,
entry: ['src/index.ts'], // Entry point for client-side code
format: ['esm', 'cjs'],
target: 'esnext',
platform: 'browser',
outDir: 'dist/client', // Output directory for client-side build
sourcemap: true,
clean: true,
dts: true,
},
{
...baseConfig,
entry: ['src/server.ts'], // Entry point for server-side code
format: ['esm', 'cjs'],
target: 'node14', // Target environment for server-side build
platform: 'node',
outDir: 'dist/server', // Output directory for server-side build
splitting: false,
sourcemap: true,
clean: true,
dts: true,
},
{
...baseConfig,
entry: ['src/hooks/index.ts'],
format: ['esm', 'cjs'],
target: 'esnext',
platform: 'neutral',
outDir: 'dist/hooks',
splitting: false,
sourcemap: true,
clean: true,
dts: true,
},
{
...baseConfig,
entry: ['src/themes/index.ts'],
format: ['esm', 'cjs'],
target: 'esnext',
platform: 'neutral',
outDir: 'dist/themes',
splitting: false,
sourcemap: true,
clean: true,
dts: true,
},
]);
1 change: 1 addition & 0 deletions packages/shared/src/types/http/headers.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export enum HttpRequestHeaderKeysEnum {
SENTRY_TRACE = 'Sentry-Trace',
NOVU_ENVIRONMENT_ID = 'Novu-Environment-Id',
NOVU_API_VERSION = 'Novu-API-Version',
NOVU_USER_AGENT = 'Novu-User-Agent',
}
testHttpHeaderEnumValidity(HttpRequestHeaderKeysEnum);

Expand Down

0 comments on commit 1142df0

Please sign in to comment.