Skip to content

Commit 3df71cd

Browse files
authored
feat: add electron build for desktop mac (#203)
1 parent 59206e7 commit 3df71cd

File tree

83 files changed

+6491
-3856
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+6491
-3856
lines changed

Diff for: .github/workflows/production.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ jobs:
3030

3131
- name: Build and push
3232
uses: docker/build-push-action@v5
33-
env:
34-
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
33+
# env:
34+
# SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
3535
with:
3636
context: .
3737
push: true
3838
tags: cfu288/mere-medical:latest,cfu288/mere-medical:${{ env.RELEASE_CALVER_VERSION }}
39-
secrets: |
40-
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
39+
# secrets: |
40+
# SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
4141

4242
- name: Create a GitHub release
4343
uses: ncipollo/release-action@v1

Diff for: apps/api/src/app/app.module.ts

+33-52
Original file line numberDiff line numberDiff line change
@@ -7,56 +7,36 @@ import { CernerModule } from './cerner/cerner.module';
77
import { EpicModule } from './epic/epic.module';
88
import { VeradigmModule } from './veradigm/veradigm.module';
99
import { TenantModule } from './tenant/tenant.module';
10+
import { VAModule } from './va/va.module';
1011
import { LoggerModule } from 'nestjs-pino';
1112

1213
const imports: ModuleMetadata['imports'] = [
1314
StaticModule,
1415
LoginProxyModule,
15-
CernerModule,
1616
EpicModule,
17+
CernerModule,
1718
VeradigmModule,
1819
TenantModule,
20+
VAModule,
1921
];
2022

21-
if (checkIfSentryConfigured()) {
22-
imports.unshift(
23-
LoggerModule.forRoot({
24-
pinoHttp: {
25-
level: 'warn',
26-
transport: {
27-
target: 'pino-sentry-transport',
28-
options: {
29-
sentry: {
30-
dsn: process.env.SENTRY_DSN,
31-
// additional options for sentry
32-
},
33-
withLogRecord: true, // default false - send the log record to sentry as a context.(if its more then 8Kb Sentry will throw an error)
34-
tags: ['id'], // sentry tags to add to the event, uses lodash.get to get the value from the log record
35-
context: ['hostname'], // sentry context to add to the event, uses lodash.get to get the value from the log record,
36-
minLevel: 30, // which level to send to sentry
37-
},
38-
},
39-
},
40-
})
41-
);
42-
} else {
43-
imports.unshift(
44-
LoggerModule.forRoot({
45-
pinoHttp: {
46-
level: 'info',
47-
transport: { target: 'pino-pretty' },
48-
},
49-
})
50-
);
51-
}
23+
imports.unshift(
24+
LoggerModule.forRoot({
25+
pinoHttp: {
26+
level: 'info',
27+
transport: { target: 'pino-pretty' },
28+
},
29+
}),
30+
);
5231

53-
if (checkIfOnPatientConfigured()) {
32+
const opConfigured = checkIfOnPatientConfigured();
33+
if (opConfigured.check) {
5434
imports.push(
5535
OnPatientModule.register({
56-
clientId: process.env.ONPATIENT_CLIENT_ID,
57-
clientSecret: process.env.ONPATIENT_CLIENT_SECRET,
36+
clientId: opConfigured.clientId,
37+
clientSecret: opConfigured.clientSecret,
5838
redirectUri: `${process.env.PUBLIC_URL}/api/v1/onpatient/callback`,
59-
})
39+
}),
6040
);
6141
}
6242

@@ -68,35 +48,36 @@ export class AppModule {}
6848

6949
// --- Helper functions ---
7050

71-
function checkIfOnPatientConfigured(): boolean {
51+
function checkIfOnPatientConfigured():
52+
| {
53+
check: true;
54+
clientId: string;
55+
clientSecret: string;
56+
}
57+
| { check: false } {
7258
const check =
7359
!!process.env.ONPATIENT_CLIENT_ID && !!process.env.ONPATIENT_CLIENT_SECRET;
7460
if (!process.env.ONPATIENT_CLIENT_ID) {
7561
Logger.warn(
76-
'ONPATIENT_CLIENT_ID was not provided: OnPatient services will be disabled.'
62+
'ONPATIENT_CLIENT_ID was not provided: OnPatient services will be disabled.',
7763
);
7864
}
7965
if (!process.env.ONPATIENT_CLIENT_SECRET) {
8066
Logger.warn(
81-
'ONPATIENT_CLIENT_SECRET was not provided: OnPatient services will be disabled.'
67+
'ONPATIENT_CLIENT_SECRET was not provided: OnPatient services will be disabled.',
8268
);
8369
}
8470
if (check) {
8571
Logger.log(
86-
'ONPATIENT_CLIENT_ID and ONPATIENT_CLIENT_SECRET were provided: OnPatient service will be enabled.'
72+
'ONPATIENT_CLIENT_ID and ONPATIENT_CLIENT_SECRET were provided: OnPatient service will be enabled.',
8773
);
88-
}
8974

90-
return check;
91-
}
92-
93-
function checkIfSentryConfigured(): boolean {
94-
if (!process.env.SENTRY_DSN) {
95-
Logger.warn(
96-
'SENTRY_DSN was not provided: Sentry logging will be disabled.'
97-
);
98-
} else {
99-
Logger.log('SENTRY_DSN was provided: Sentry logging will be enabled.');
75+
return {
76+
check,
77+
clientId: process.env.ONPATIENT_CLIENT_ID!,
78+
clientSecret: process.env.ONPATIENT_CLIENT_SECRET!,
79+
};
10080
}
101-
return !!process.env.SENTRY_DSN;
81+
82+
return { check };
10283
}

Diff for: apps/api/src/app/cerner/cerner.controller.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export class CernerController {
77
constructor(private readonly cernerService: CernerService) {}
88

99
@Get('tenants')
10-
async getData(@Res() response: Response, @Query('query') query) {
10+
async getData(@Res() response: Response, @Query('query') query: string) {
1111
try {
1212
const data = await this.cernerService.queryTenants(query);
1313
response.json(data);

Diff for: apps/api/src/app/epic/epic.controller.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class EpicController {
1717
async getDSTU2Tenants(
1818
@NestRequest() request: Request,
1919
@Res() response: Response,
20-
@Query('query') query
20+
@Query('query') query: string,
2121
) {
2222
try {
2323
const data = await this.epicService.queryTenants(query);
@@ -29,7 +29,7 @@ export class EpicController {
2929
}
3030

3131
@Get('tenants')
32-
async getTenants(@Res() response: Response, @Query('query') query) {
32+
async getTenants(@Res() response: Response, @Query('query') query: string) {
3333
try {
3434
const data = await this.epicService.queryTenants(query);
3535
response.json(data);

Diff for: apps/api/src/app/onpatient/onpatient.controller.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ export class OnPatientController {
77
constructor(private readonly onPatientService: OnPatientService) {}
88

99
@Get('callback')
10-
async getData(@Res() response: Response, @Query('code') code) {
10+
async getData(@Res() response: Response, @Query('code') code: string) {
1111
try {
1212
const data = await this.onPatientService.getAuthCode(code);
1313
response.redirect(
14-
`${process.env.PUBLIC_URL}/onpatient/callback?accessToken=${data.access_token}&refreshToken=${data.refresh_token}&expiresIn=${data.expires_in}`
14+
`${process.env.PUBLIC_URL}/onpatient/callback?accessToken=${data.access_token}&refreshToken=${data.refresh_token}&expiresIn=${data.expires_in}`,
1515
);
1616
} catch (e) {
1717
Logger.error(e);

Diff for: apps/api/src/app/onpatient/onpatient.service.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class OnPatientService {
1515

1616
constructor(
1717
@Inject('CONFIG') private options: OnPatientServiceConfig,
18-
private readonly httpService: HttpService
18+
private readonly httpService: HttpService,
1919
) {
2020
this.envConfig = options;
2121
}
@@ -24,7 +24,7 @@ export class OnPatientService {
2424
if (!code) {
2525
throw new HttpException(
2626
'Forbidden: no auth code provided in callback url',
27-
HttpStatus.FORBIDDEN
27+
HttpStatus.FORBIDDEN,
2828
);
2929
}
3030

@@ -39,20 +39,27 @@ export class OnPatientService {
3939
const response = await this.httpService.post<OnPatientAuthResponse>(
4040
'https://onpatient.com/o/token/?' + new URLSearchParams(params),
4141
null,
42-
{ method: 'POST' }
42+
{ method: 'POST' },
4343
);
4444

4545
const awaitedRes = await response.toPromise();
46-
const status = await awaitedRes.status;
46+
const status = await awaitedRes?.status;
4747

4848
if (status !== 200) {
4949
throw new HttpException(
5050
'Forbidden: unable to get auth token with code',
51-
HttpStatus.FORBIDDEN
51+
HttpStatus.FORBIDDEN,
5252
);
5353
}
5454

55-
const data = await awaitedRes.data;
55+
const data = await awaitedRes?.data;
56+
57+
if (!data) {
58+
throw new HttpException(
59+
'Forbidden: unable to get auth token with code',
60+
HttpStatus.FORBIDDEN,
61+
);
62+
}
5663

5764
return data;
5865
}

Diff for: apps/api/src/app/proxy/controllers/proxy.controller.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ export class ProxyController {
1919
async proxy(
2020
@Res() response: Response,
2121
@NestRequest() request: Request,
22-
@Param() params
22+
@Param() params: any,
2323
) {
2424
try {
2525
Logger.debug(
26-
`Proxy request was made with params: ${JSON.stringify(params)}`
26+
`Proxy request was made with params: ${JSON.stringify(params)}`,
2727
);
2828
this.proxyService.proxyRequest(request, response, params);
2929
} catch (err) {

Diff for: apps/api/src/app/proxy/proxy.module.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// @ts-nocheck
12
// import { EpicDSTU2TenantEndpoints } from '@mere/epic';
23
import { DynamicModule, Logger, Module, Provider } from '@nestjs/common';
34
import { createProxyServer } from 'http-proxy';
@@ -35,7 +36,8 @@ const proxyFactory = {
3536
cookies = cookies
3637
.split(';')
3738
.filter(
38-
(cookie) => allowedCookies.indexOf(cookie.split('=')[0].trim()) !== -1
39+
(cookie) =>
40+
allowedCookies.indexOf(cookie.split('=')[0].trim()) !== -1,
3941
)
4042
.join(';');
4143

@@ -65,7 +67,7 @@ const proxyFactory = {
6567
proxy.on('proxyRes', function (proxyRes, req, res) {
6668
const url = concatPath(
6769
`${proxyRes['req'].protocol}//${proxyRes['req'].host}`,
68-
req.url
70+
req.url,
6971
);
7072
logger.debug(`Received ${req.method} ${url}`);
7173
});
@@ -100,7 +102,7 @@ export class ProxyModule {
100102
}
101103

102104
private static createAsyncProviders(
103-
options: ProxyModuleAsyncOptions
105+
options: ProxyModuleAsyncOptions,
104106
): Provider[] {
105107
if (options.useExisting || options.useFactory) {
106108
return [this.createAsyncOptionsProvider(options)];
@@ -115,7 +117,7 @@ export class ProxyModule {
115117
}
116118

117119
private static createAsyncOptionsProvider(
118-
options: ProxyModuleAsyncOptions
120+
options: ProxyModuleAsyncOptions,
119121
): Provider {
120122
if (options.useFactory) {
121123
return {

Diff for: apps/api/src/app/proxy/services/proxy.service.ts

+13-9
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ export class ProxyService {
1010
private readonly logger = new Logger(ProxyService.name);
1111

1212
constructor(
13-
@Inject(HTTP_PROXY) private proxy: server | any,
14-
@Inject(PROXY_MODULE_OPTIONS) private options: ProxyModuleOptions
13+
@Inject(HTTP_PROXY) private proxy: server,
14+
@Inject(PROXY_MODULE_OPTIONS) private options: ProxyModuleOptions,
1515
) {}
1616

17-
async proxyRequest(req: Request, res: Response, @Param() params?) {
17+
async proxyRequest(
18+
req: Request,
19+
res: Response,
20+
@Param() params?: Record<string, string>,
21+
) {
1822
const target = req.query.target as string;
1923
const target_type = req.query.target_type as string;
2024
let serviceId = (req.query.serviceId as string).trim();
@@ -45,7 +49,7 @@ export class ProxyService {
4549
const services = new Map(
4650
this.options.services
4751
? this.options.services.map((service) => [service.id, service])
48-
: []
52+
: [],
4953
);
5054
// Temp workaround for sandbox
5155
const isSandbox =
@@ -56,7 +60,7 @@ export class ProxyService {
5660
}
5761

5862
if (services.has(serviceId) || isSandbox) {
59-
const service = services.get(serviceId);
63+
const service = services.get(serviceId)!;
6064
this.logger.debug(`Proxying ${req.method} ${req.url} to ${serviceId}`);
6165
const baseUrl = service.url;
6266
const authUrl = service.authorize;
@@ -71,7 +75,7 @@ export class ProxyService {
7175
urlToProxy =
7276
(baseUrl.replace('/api/FHIR/DSTU2/', '') || '').replace(
7377
'api/FHIR/DSTU2',
74-
''
78+
'',
7579
) + '/oauth2/register';
7680
}
7781

@@ -80,7 +84,7 @@ export class ProxyService {
8084
res,
8185
target ? concatPath(urlToProxy, prefix, target) : urlToProxy,
8286
service.forwardToken === false ? null : token,
83-
{ ...service.config, headers }
87+
{ ...service.config, headers },
8488
);
8589
} else {
8690
const error = `Could not find serviceId '${serviceId}'`;
@@ -108,7 +112,7 @@ export class ProxyService {
108112
res: Response,
109113
target: string,
110114
token: string,
111-
options: server.ServerOptions = {}
115+
options: server.ServerOptions = {},
112116
) {
113117
const url = new URL(target);
114118
req.url = `${url.pathname}${url.search}`;
@@ -128,7 +132,7 @@ export class ProxyService {
128132
...(options && options.headers),
129133
}; // To deep extend headers
130134

131-
this.proxy.web(req, res, requestOptions, (err) => {
135+
this.proxy.web(req, res, requestOptions, (err: any) => {
132136
if (err.code === 'ECONNRESET') return;
133137

134138
this.logger.error({

Diff for: apps/api/src/app/proxy/utils/url.utils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { URL } from 'url';
22

3-
export function getBaseURL(path) {
3+
export function getBaseURL(path: string) {
44
const url = new URL(path);
55
return url.origin;
66
}
@@ -9,7 +9,7 @@ export function concatPath(...args: string[]) {
99
return urlJoin(...args);
1010
}
1111

12-
export function isAbsolute(path) {
12+
export function isAbsolute(path: string) {
1313
return !path.indexOf('/');
1414
}
1515

Diff for: apps/api/src/app/tenant/tenant.controller.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ export class TenantController {
99
@Get('/')
1010
async getData(
1111
@Res() response: Response,
12-
@Query('query') query,
13-
@Query('vendor') vendors
12+
@Query('query') query: string,
13+
@Query('vendor') vendors: string[],
1414
) {
15-
console.log('vendors', vendors);
1615
try {
1716
const data = await this.tenantService.queryTenants(query, vendors);
1817
response.json(data);

0 commit comments

Comments
 (0)