Skip to content

Commit

Permalink
Merge pull request #5346 from novuhq/small_dx_touch_leveraging_env_va…
Browse files Browse the repository at this point in the history
…r_in_node_sdk

Small dx touch leveraging env var in node sdk
  • Loading branch information
SokratisVidros authored Apr 3, 2024
2 parents 518a086 + 938461c commit 5a0a4bc
Show file tree
Hide file tree
Showing 13 changed files with 2,368 additions and 221 deletions.
6 changes: 4 additions & 2 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,8 @@
"usecase",
"zulip",
"uuidv",
"Vonage"
"Vonage",
"runtimes"
],
"flagWords": [],
"patterns": [
Expand Down Expand Up @@ -702,6 +703,7 @@
"angular.json",
"ng-package.json",
"libs/shared/src/types/timezones/timezones.types.ts",
"*.riv"
"*.riv",
"cafebabe"
]
}
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ module.exports = {
{
patterns: [
'@novu/shared/*',
'!@novu/shared/utils',
'@novu/dal/*',
'!import2/good',
'*../libs/dal/*',
Expand Down
12 changes: 12 additions & 0 deletions libs/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@
"files": [
"dist/"
],
"exports": {
".": {
"require": "./dist/cjs/index.js",
"import": "./dist/esm/index.js",
"types": "./dist/esm/index.d.js"
},
"./utils": {
"require": "./dist/cjs/utils/index.js",
"import": "./dist/esm/utils/index.js",
"types": "./dist/esm/utils/index.d.js"
}
},
"dependencies": {
"axios": "^1.6.2",
"class-transformer": "0.5.1",
Expand Down
31 changes: 16 additions & 15 deletions libs/shared/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
export * from './entities/user';
export * from './entities/organization';
export * from './entities/notification-template';
export * from './config';
export * from './consts';
export * from './dto';
export * from './entities/change';
export * from './entities/environment';
export * from './entities/execution-details';
export * from './entities/messages';
export * from './entities/feed/feed.interface';
export * from './entities/notification';
export * from './entities/message-template';
export * from './entities/integration';
export * from './entities/job';
export * from './entities/layout';
export * from './entities/log';
export * from './entities/change';
export * from './entities/message-template';
export * from './entities/messages';
export * from './entities/notification-group';
export * from './entities/notification-template';
export * from './entities/notification';
export * from './entities/organization';
export * from './entities/step';
export * from './entities/job';
export * from './entities/subscriber-preference';
export * from './entities/subscriber';
export * from './entities/layout';
export * from './entities/notification-group';
export * from './entities/integration';
export * from './entities/tenant';
export * from './entities/user';
export * from './entities/workflow-override';
export * from './services';
export * from './types';
export * from './dto';
export * from './consts';
export * from './ui';
export * from './services';
export * from './config';
export * from './utils';
51 changes: 51 additions & 0 deletions libs/shared/src/utils/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
type CloudflareEnv = { env: Record<string, string> };

// https://remix.run/blog/remix-vite-stable#cloudflare-pages-support
const hasCloudflareProxyContext = (context: any): context is { cloudflare: CloudflareEnv } => {
return !!context?.cloudflare?.env;
};

const hasCloudflareContext = (context: any): context is CloudflareEnv => {
return !!context?.env;
};

/**
*
* Utility function to get env variables across Node and Edge runtimes.
*
* @param name Pass the name of the environment variable. The param is case-sensitive.
* @returns string Returns the value of the environment variable if exists.
*/
export const getEnvVariable = (name: string, context?: any): string => {
// Node envs
if (typeof process !== 'undefined' && process.env && typeof process.env[name] === 'string') {
return process.env[name] as string;
}

/*
* Remix + Cloudflare pages
* if (typeof (context?.cloudflare as CloudflareEnv)?.env !== 'undefined') {
*/
if (hasCloudflareProxyContext(context)) {
return context.cloudflare.env[name] || '';
}

// Cloudflare
if (hasCloudflareContext(context)) {
return context.env[name] || '';
}

// Check whether the value exists in the context object directly
if (context && typeof context[name] === 'string') {
return context[name] as string;
}

// Cloudflare workers
try {
return globalThis[name as keyof typeof globalThis];
} catch (_) {
// This will raise an error in Cloudflare Pages
}

return '';
};
1 change: 1 addition & 0 deletions libs/shared/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './env';
7 changes: 7 additions & 0 deletions packages/node/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
uuid: require.resolve('uuid'),
},
};
11 changes: 2 additions & 9 deletions packages/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@
"@types/uuid": "^8.3.4",
"axios": "^1.6.2",
"codecov": "^3.5.0",
"jest": "^27.0.6",
"jest": "^29.7.0",
"nock": "^13.1.3",
"npm-run-all": "^4.1.5",
"open-cli": "^6.0.1",
"rimraf": "^3.0.2",
"run-p": "0.0.0",
"ts-jest": "^27.0.5",
"ts-jest": "^29.1.2",
"typedoc": "^0.24.0",
"typescript": "4.9.5"
},
Expand All @@ -76,13 +76,6 @@
"LICENSE",
"README.md"
],
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",
"moduleNameMapper": {
"^axios$": "axios/dist/node/axios.cjs"
}
},
"prettier": {
"singleQuote": true
}
Expand Down
1 change: 1 addition & 0 deletions packages/node/src/lib/novu.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface IRetryConfig {
}

export interface INovuConfiguration {
apiKey?: string;
backendUrl?: string;
retryConfig?: IRetryConfig;
}
Expand Down
21 changes: 21 additions & 0 deletions packages/node/src/lib/novu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ const mockConfig = {

jest.mock('axios');

describe('test initialization of novu node package', () => {
let novu: Novu;

const originalEnv = process.env;

beforeEach(() => {
process.env = {
...originalEnv,
NOVU_API_KEY: 'cafebabe',
};
});

afterEach(() => {
process.env = originalEnv;
});

test('should use the NOVU_API_KEY when defined', async () => {
expect(new Novu().apiKey).toBe('cafebabe');
});
});

describe('test use of novu node package', () => {
const mockedAxios = axios as jest.Mocked<typeof axios>;
let novu: Novu;
Expand Down
22 changes: 20 additions & 2 deletions packages/node/src/lib/novu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios, { AxiosInstance } from 'axios';
import { getEnvVariable } from '@novu/shared/utils';
import { Subscribers } from './subscribers/subscribers';
import { EventEmitter } from 'events';
import { Changes } from './changes/changes';
Expand All @@ -21,7 +22,7 @@ import { WorkflowOverrides } from './workflow-override/workflow-override';
import { makeRetryable } from './retry';

export class Novu extends EventEmitter {
private readonly apiKey?: string;
public readonly apiKey?: string;
private readonly http: AxiosInstance;
readonly subscribers: Subscribers;
readonly environments: Environments;
Expand All @@ -40,8 +41,25 @@ export class Novu extends EventEmitter {
readonly organizations: Organizations;
readonly workflowOverrides: WorkflowOverrides;

constructor(apiKey: string, config?: INovuConfiguration) {
constructor(config?: INovuConfiguration);
constructor(apiKey: string, config?: INovuConfiguration);
constructor(...args: any) {
super();

let apiKey: string | undefined;
let config: INovuConfiguration | undefined;

if (arguments.length === 2) {
apiKey = args[0];
config = args[1];
} else if (arguments.length === 1) {
const { apiKey: key, ...rest } = args[0];
apiKey = key;
config = rest;
} else {
apiKey = getEnvVariable('NOVU_API_KEY');
}

this.apiKey = apiKey;
const axiosInstance = axios.create({
baseURL: this.buildBackendUrl(config),
Expand Down
3 changes: 2 additions & 1 deletion packages/node/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"strictNullChecks": true,
"allowSyntheticDefaultImports": true,
"outDir": "build/main",
"module": "commonjs",
"module": "CommonJS",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"rootDir": "src",
"strict": true,
Expand Down
Loading

0 comments on commit 5a0a4bc

Please sign in to comment.