mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-09 07:25:19 +02:00
remove ld deps and feature flags
This commit is contained in:
parent
b5000404ef
commit
435c6c6fad
20 changed files with 5 additions and 165 deletions
|
@ -1,6 +1,5 @@
|
||||||
import { useAuth0 } from '@auth0/auth0-react'
|
import { useAuth0 } from '@auth0/auth0-react'
|
||||||
import { useIntercom } from '@maybe-finance/client/shared'
|
import { useIntercom } from '@maybe-finance/client/shared'
|
||||||
import { useLDClient } from 'launchdarkly-react-client-sdk'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import * as Sentry from '@sentry/react'
|
import * as Sentry from '@sentry/react'
|
||||||
|
@ -8,7 +7,6 @@ import * as Sentry from '@sentry/react'
|
||||||
export default function APM() {
|
export default function APM() {
|
||||||
const { user } = useAuth0()
|
const { user } = useAuth0()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const ld = useLDClient()
|
|
||||||
const intercom = useIntercom()
|
const intercom = useIntercom()
|
||||||
|
|
||||||
// Boot intercom
|
// Boot intercom
|
||||||
|
@ -36,18 +34,5 @@ export default function APM() {
|
||||||
}
|
}
|
||||||
}, [user])
|
}, [user])
|
||||||
|
|
||||||
// Identify LaunchDarkly user
|
|
||||||
useEffect(() => {
|
|
||||||
if (ld && user) {
|
|
||||||
ld.waitUntilReady().then(() => {
|
|
||||||
ld.identify({
|
|
||||||
key: user.sub,
|
|
||||||
email: user.email,
|
|
||||||
name: user.name,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [ld, user])
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,14 @@ import {
|
||||||
UserAccountContextProvider,
|
UserAccountContextProvider,
|
||||||
AuthProvider,
|
AuthProvider,
|
||||||
} from '@maybe-finance/client/shared'
|
} from '@maybe-finance/client/shared'
|
||||||
import type { ClientType } from '@maybe-finance/client/shared'
|
|
||||||
import { AccountsManager } from '@maybe-finance/client/features'
|
import { AccountsManager } from '@maybe-finance/client/features'
|
||||||
import { AccountContextProvider } from '@maybe-finance/client/shared'
|
import { AccountContextProvider } from '@maybe-finance/client/shared'
|
||||||
import * as Sentry from '@sentry/react'
|
import * as Sentry from '@sentry/react'
|
||||||
import { BrowserTracing } from '@sentry/tracing'
|
import { BrowserTracing } from '@sentry/tracing'
|
||||||
import { useFlags, withLDProvider } from 'launchdarkly-react-client-sdk'
|
|
||||||
import env from '../env'
|
import env from '../env'
|
||||||
import '../styles.css'
|
import '../styles.css'
|
||||||
import { withAuthenticationRequired } from '@auth0/auth0-react'
|
import { withAuthenticationRequired } from '@auth0/auth0-react'
|
||||||
import ModalManager from '../components/ModalManager'
|
import ModalManager from '../components/ModalManager'
|
||||||
import Maintenance from '../components/Maintenance'
|
|
||||||
import Meta from '../components/Meta'
|
import Meta from '../components/Meta'
|
||||||
import APM from '../components/APM'
|
import APM from '../components/APM'
|
||||||
|
|
||||||
|
@ -51,7 +48,7 @@ const WithAuth = withAuthenticationRequired(function ({ children }: PropsWithChi
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
function App({
|
export default function App({
|
||||||
Component: Page,
|
Component: Page,
|
||||||
pageProps,
|
pageProps,
|
||||||
}: AppProps & {
|
}: AppProps & {
|
||||||
|
@ -60,15 +57,8 @@ function App({
|
||||||
isPublic?: boolean
|
isPublic?: boolean
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
const flags = useFlags() as ClientType.ClientSideFeatureFlag
|
|
||||||
|
|
||||||
const getLayout = Page.getLayout ?? ((page) => page)
|
const getLayout = Page.getLayout ?? ((page) => page)
|
||||||
|
|
||||||
// Maintenance Guard
|
|
||||||
if (flags.maintenance) {
|
|
||||||
return <Maintenance />
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LogProvider logger={console}>
|
<LogProvider logger={console}>
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
|
@ -98,9 +88,3 @@ function App({
|
||||||
</LogProvider>
|
</LogProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withLDProvider<{ Component; pageProps }>({
|
|
||||||
clientSideID: env.NEXT_PUBLIC_LD_CLIENT_SIDE_ID,
|
|
||||||
// Prevent a new LD user being registered on each page load by always initializing with the same key
|
|
||||||
user: { key: 'anonymous-client', anonymous: true },
|
|
||||||
})(App)
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ import { resetUser } from './utils/user'
|
||||||
import { createTestInvestmentAccount } from './utils/account'
|
import { createTestInvestmentAccount } from './utils/account'
|
||||||
import { default as _plaid } from '../lib/plaid'
|
import { default as _plaid } from '../lib/plaid'
|
||||||
|
|
||||||
jest.mock('launchdarkly-node-server-sdk')
|
|
||||||
jest.mock('../middleware/validate-plaid-jwt.ts')
|
jest.mock('../middleware/validate-plaid-jwt.ts')
|
||||||
jest.mock('bull')
|
jest.mock('bull')
|
||||||
jest.mock('plaid')
|
jest.mock('plaid')
|
||||||
|
|
|
@ -12,7 +12,6 @@ import { default as _plaid } from '../lib/plaid'
|
||||||
import nock from 'nock'
|
import nock from 'nock'
|
||||||
import { resetUser } from './utils/user'
|
import { resetUser } from './utils/user'
|
||||||
|
|
||||||
jest.mock('launchdarkly-node-server-sdk')
|
|
||||||
jest.mock('../middleware/validate-plaid-jwt.ts')
|
jest.mock('../middleware/validate-plaid-jwt.ts')
|
||||||
jest.mock('plaid')
|
jest.mock('plaid')
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@ import stripe from '../lib/stripe'
|
||||||
import { PgService } from '@maybe-finance/server/shared'
|
import { PgService } from '@maybe-finance/server/shared'
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
|
|
||||||
jest.mock('launchdarkly-node-server-sdk')
|
|
||||||
|
|
||||||
const prisma = new PrismaClient()
|
const prisma = new PrismaClient()
|
||||||
const logger = createLogger({ transports: new transports.Console() })
|
const logger = createLogger({ transports: new transports.Console() })
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { IFeatureFlagService, IMarketDataService } from '@maybe-finance/server/shared'
|
import type { IMarketDataService } from '@maybe-finance/server/shared'
|
||||||
import type {
|
import type {
|
||||||
IAccountQueryService,
|
IAccountQueryService,
|
||||||
IInstitutionService,
|
IInstitutionService,
|
||||||
|
@ -13,7 +13,6 @@ import {
|
||||||
EndpointFactory,
|
EndpointFactory,
|
||||||
QueueService,
|
QueueService,
|
||||||
PgService,
|
PgService,
|
||||||
LaunchDarklyFeatureFlagService,
|
|
||||||
PolygonMarketDataService,
|
PolygonMarketDataService,
|
||||||
CacheService,
|
CacheService,
|
||||||
ServerUtil,
|
ServerUtil,
|
||||||
|
@ -55,7 +54,6 @@ import {
|
||||||
} from '@maybe-finance/server/features'
|
} from '@maybe-finance/server/features'
|
||||||
import { SharedType } from '@maybe-finance/shared'
|
import { SharedType } from '@maybe-finance/shared'
|
||||||
import prisma from './prisma'
|
import prisma from './prisma'
|
||||||
import ldClient from './ldClient'
|
|
||||||
import plaid, { getPlaidWebhookUrl } from './plaid'
|
import plaid, { getPlaidWebhookUrl } from './plaid'
|
||||||
import finicity, { getFinicityTxPushUrl, getFinicityWebhookUrl } from './finicity'
|
import finicity, { getFinicityTxPushUrl, getFinicityWebhookUrl } from './finicity'
|
||||||
import stripe from './stripe'
|
import stripe from './stripe'
|
||||||
|
@ -74,8 +72,6 @@ const redis = new Redis(env.NX_REDIS_URL, {
|
||||||
retryStrategy: ServerUtil.redisRetryStrategy({ maxAttempts: 5 }),
|
retryStrategy: ServerUtil.redisRetryStrategy({ maxAttempts: 5 }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const featureFlagService: IFeatureFlagService = new LaunchDarklyFeatureFlagService(ldClient)
|
|
||||||
|
|
||||||
export const queueService = new QueueService(
|
export const queueService = new QueueService(
|
||||||
logger.child({ service: 'QueueService' }),
|
logger.child({ service: 'QueueService' }),
|
||||||
process.env.NODE_ENV === 'test'
|
process.env.NODE_ENV === 'test'
|
||||||
|
@ -352,7 +348,6 @@ export async function createContext(req: Request) {
|
||||||
valuationService,
|
valuationService,
|
||||||
institutionService,
|
institutionService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
featureFlagService,
|
|
||||||
queueService,
|
queueService,
|
||||||
plaidService,
|
plaidService,
|
||||||
plaidWebhooks,
|
plaidWebhooks,
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { init } from 'launchdarkly-node-server-sdk'
|
|
||||||
import env from '../../env'
|
|
||||||
|
|
||||||
const ldClient = init(env.NX_LD_SDK_KEY, { offline: process.env.NODE_ENV === 'test' })
|
|
||||||
|
|
||||||
export default ldClient
|
|
|
@ -1,23 +1,7 @@
|
||||||
import { createLogger } from '@maybe-finance/server/shared'
|
import { createLogger } from '@maybe-finance/server/shared'
|
||||||
import ldClient from './ldClient'
|
|
||||||
|
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
})
|
})
|
||||||
|
|
||||||
function setLevel() {
|
|
||||||
ldClient
|
|
||||||
.variation('server-log-level', { key: 'anonymous-server', anonymous: true }, 'info')
|
|
||||||
.then((level) => {
|
|
||||||
logger.level = level
|
|
||||||
logger[level](`Server logger using level: ${level}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't configure for Jest
|
|
||||||
if (process.env.NODE_ENV !== 'test') {
|
|
||||||
ldClient.waitForInitialization().then(setLevel)
|
|
||||||
ldClient.on('update:server-log-level', setLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default logger
|
export default logger
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import type { Express } from 'express'
|
import type { Express } from 'express'
|
||||||
import ldClient from '../lib/ldClient'
|
|
||||||
|
|
||||||
type MaintenanceOptions = {
|
type MaintenanceOptions = {
|
||||||
statusCode?: number
|
statusCode?: number
|
||||||
|
@ -9,28 +8,9 @@ type MaintenanceOptions = {
|
||||||
|
|
||||||
export default function maintenance(
|
export default function maintenance(
|
||||||
app: Express,
|
app: Express,
|
||||||
{ statusCode = 503, path = '/maintenance', featureKey = 'maintenance' }: MaintenanceOptions = {}
|
{ statusCode = 503, path = '/maintenance' }: MaintenanceOptions = {}
|
||||||
) {
|
) {
|
||||||
let enabled = false
|
const enabled = false
|
||||||
|
|
||||||
function loadFeatureFlag() {
|
|
||||||
ldClient
|
|
||||||
.waitForInitialization()
|
|
||||||
.then((ld) => {
|
|
||||||
ld.variation(featureKey, { key: 'anonymous-server', anonymous: true }, false).then(
|
|
||||||
(flag) => (enabled = flag)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error(`error loading feature flag`, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
loadFeatureFlag()
|
|
||||||
|
|
||||||
ldClient.on(`update:${featureKey}`, () => {
|
|
||||||
loadFeatureFlag()
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get(path, async (req, res) => {
|
app.get(path, async (req, res) => {
|
||||||
res.status(200).json({ enabled })
|
res.status(200).json({ enabled })
|
||||||
|
|
|
@ -2,7 +2,6 @@ import type { AddressInfo } from 'net'
|
||||||
import env from './env'
|
import env from './env'
|
||||||
import app from './app/app'
|
import app from './app/app'
|
||||||
import logger from './app/lib/logger'
|
import logger from './app/lib/logger'
|
||||||
import ldClient from './app/lib/ldClient'
|
|
||||||
import * as Sentry from '@sentry/node'
|
import * as Sentry from '@sentry/node'
|
||||||
|
|
||||||
process.on('uncaughtException', function (error) {
|
process.on('uncaughtException', function (error) {
|
||||||
|
@ -22,5 +21,4 @@ const server = app.listen(env.NX_PORT, () => {
|
||||||
// Handle SIGTERM coming from ECS Fargate
|
// Handle SIGTERM coming from ECS Fargate
|
||||||
process.on('SIGTERM', () => server.close())
|
process.on('SIGTERM', () => server.close())
|
||||||
|
|
||||||
server.on('close', () => ldClient.close())
|
|
||||||
server.on('error', (err) => logger.error('Server failed to start from main.ts', err))
|
server.on('error', (err) => logger.error('Server failed to start from main.ts', err))
|
||||||
|
|
|
@ -18,7 +18,6 @@ import '../../main'
|
||||||
import { queueService, securityPricingService } from '../lib/di'
|
import { queueService, securityPricingService } from '../lib/di'
|
||||||
|
|
||||||
jest.mock('plaid')
|
jest.mock('plaid')
|
||||||
jest.mock('launchdarkly-node-server-sdk')
|
|
||||||
|
|
||||||
// For TypeScript support
|
// For TypeScript support
|
||||||
const plaid = jest.mocked(_plaid)
|
const plaid = jest.mocked(_plaid)
|
||||||
|
|
|
@ -40,13 +40,12 @@ import {
|
||||||
EmailProcessor,
|
EmailProcessor,
|
||||||
TransactionService,
|
TransactionService,
|
||||||
} from '@maybe-finance/server/features'
|
} from '@maybe-finance/server/features'
|
||||||
import type { IFeatureFlagService, IMarketDataService } from '@maybe-finance/server/shared'
|
import type { IMarketDataService } from '@maybe-finance/server/shared'
|
||||||
import {
|
import {
|
||||||
BullQueueFactory,
|
BullQueueFactory,
|
||||||
CacheService,
|
CacheService,
|
||||||
CryptoService,
|
CryptoService,
|
||||||
InMemoryQueueFactory,
|
InMemoryQueueFactory,
|
||||||
LaunchDarklyFeatureFlagService,
|
|
||||||
PgService,
|
PgService,
|
||||||
PolygonMarketDataService,
|
PolygonMarketDataService,
|
||||||
QueueService,
|
QueueService,
|
||||||
|
@ -58,7 +57,6 @@ import logger from './logger'
|
||||||
import prisma from './prisma'
|
import prisma from './prisma'
|
||||||
import plaid from './plaid'
|
import plaid from './plaid'
|
||||||
import finicity from './finicity'
|
import finicity from './finicity'
|
||||||
import ldClient from './ldClient'
|
|
||||||
import postmark from './postmark'
|
import postmark from './postmark'
|
||||||
import { managementClient } from './auth0'
|
import { managementClient } from './auth0'
|
||||||
import stripe from './stripe'
|
import stripe from './stripe'
|
||||||
|
@ -71,7 +69,6 @@ const redis = new Redis(env.NX_REDIS_URL, {
|
||||||
retryStrategy: ServerUtil.redisRetryStrategy({ maxAttempts: 5 }),
|
retryStrategy: ServerUtil.redisRetryStrategy({ maxAttempts: 5 }),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const featureFlagService: IFeatureFlagService = new LaunchDarklyFeatureFlagService(ldClient)
|
|
||||||
export const cryptoService = new CryptoService(env.NX_DATABASE_SECRET)
|
export const cryptoService = new CryptoService(env.NX_DATABASE_SECRET)
|
||||||
export const pgService = new PgService(logger.child({ service: 'PgService' }), env.NX_DATABASE_URL)
|
export const pgService = new PgService(logger.child({ service: 'PgService' }), env.NX_DATABASE_URL)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { init } from 'launchdarkly-node-server-sdk'
|
|
||||||
import env from '../../env'
|
|
||||||
|
|
||||||
const ldClient = init(env.NX_LD_SDK_KEY, { offline: process.env.NODE_ENV === 'test' })
|
|
||||||
|
|
||||||
export default ldClient
|
|
|
@ -1,23 +1,7 @@
|
||||||
import { createLogger } from '@maybe-finance/server/shared'
|
import { createLogger } from '@maybe-finance/server/shared'
|
||||||
import ldClient from './ldClient'
|
|
||||||
|
|
||||||
const logger = createLogger({
|
const logger = createLogger({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
})
|
})
|
||||||
|
|
||||||
function setLevel() {
|
|
||||||
ldClient
|
|
||||||
.variation('workers-log-level', { key: 'anonymous-server', anonymous: true }, 'info')
|
|
||||||
.then((level) => {
|
|
||||||
logger.level = level
|
|
||||||
logger[level](`Workers logger using level: ${level}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't configure for Jest
|
|
||||||
if (process.env.NODE_ENV !== 'test') {
|
|
||||||
ldClient.waitForInitialization().then(setLevel)
|
|
||||||
ldClient.on('update:workers-log-level', setLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default logger
|
export default logger
|
||||||
|
|
|
@ -170,15 +170,6 @@ export class ServerStack extends Stack {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
NX_LD_SDK_KEY: ECSSecret.fromSsmParameter(
|
|
||||||
StringParameter.fromSecureStringParameterAttributes(
|
|
||||||
this,
|
|
||||||
'LaunchDarklySDKKeyParam',
|
|
||||||
{
|
|
||||||
parameterName: '/providers/NX_LD_SDK_KEY',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
),
|
|
||||||
NX_POLYGON_API_KEY: ECSSecret.fromSsmParameter(
|
NX_POLYGON_API_KEY: ECSSecret.fromSsmParameter(
|
||||||
StringParameter.fromSecureStringParameterAttributes(
|
StringParameter.fromSecureStringParameterAttributes(
|
||||||
this,
|
this,
|
||||||
|
|
|
@ -124,15 +124,6 @@ export class WorkersStack extends Stack {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
NX_LD_SDK_KEY: ECSSecret.fromSsmParameter(
|
|
||||||
StringParameter.fromSecureStringParameterAttributes(
|
|
||||||
this,
|
|
||||||
'LaunchDarklySDKKeyParam',
|
|
||||||
{
|
|
||||||
parameterName: '/providers/NX_LD_SDK_KEY',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
),
|
|
||||||
NX_POLYGON_API_KEY: ECSSecret.fromSsmParameter(
|
NX_POLYGON_API_KEY: ECSSecret.fromSsmParameter(
|
||||||
StringParameter.fromSecureStringParameterAttributes(
|
StringParameter.fromSecureStringParameterAttributes(
|
||||||
this,
|
this,
|
||||||
|
|
|
@ -1,5 +1 @@
|
||||||
export type MetricStatus = 'coming-soon' | 'under-construction' | 'active'
|
export type MetricStatus = 'coming-soon' | 'under-construction' | 'active'
|
||||||
|
|
||||||
export type ClientSideFeatureFlag = Partial<{
|
|
||||||
maintenance: boolean
|
|
||||||
}>
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
import type { LDClient, LDUser } from 'launchdarkly-node-server-sdk'
|
|
||||||
|
|
||||||
export interface IFeatureFlagService {
|
|
||||||
getFlag<TValue = any>(flagKey: string, defaultValue: TValue, user?: LDUser): Promise<TValue>
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LaunchDarklyFeatureFlagService implements IFeatureFlagService {
|
|
||||||
constructor(private readonly ldClient: LDClient) {}
|
|
||||||
|
|
||||||
async getFlag<TValue = any>(
|
|
||||||
flagKey: string,
|
|
||||||
defaultValue: TValue,
|
|
||||||
user?: LDUser
|
|
||||||
): Promise<TValue> {
|
|
||||||
if (!this.ldClient) return defaultValue
|
|
||||||
|
|
||||||
await this.ldClient.waitForInitialization()
|
|
||||||
|
|
||||||
return await this.ldClient.variation(
|
|
||||||
flagKey,
|
|
||||||
user ?? { key: 'anonymous-server', anonymous: true },
|
|
||||||
defaultValue
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
export * from './crypto.service'
|
export * from './crypto.service'
|
||||||
export * from './feature-flag.service'
|
|
||||||
export * from './queue.service'
|
export * from './queue.service'
|
||||||
export * from './queue'
|
export * from './queue'
|
||||||
export * from './cache.service'
|
export * from './cache.service'
|
||||||
|
|
|
@ -121,8 +121,6 @@
|
||||||
"jwk-to-pem": "^2.0.5",
|
"jwk-to-pem": "^2.0.5",
|
||||||
"jwks-rsa": "^3.0.0",
|
"jwks-rsa": "^3.0.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"launchdarkly-node-server-sdk": "^6.4.3",
|
|
||||||
"launchdarkly-react-client-sdk": "^2.25.1",
|
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"luxon": "^3.1.0",
|
"luxon": "^3.1.0",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue