Fix privy secrets
This commit is contained in:
@@ -12,6 +12,28 @@ declare module 'fastify' {
|
||||
}
|
||||
}
|
||||
|
||||
// Module-level cache for Privy secrets - accessible without Fastify instance
|
||||
// This is populated ONCE at startup and never changed during runtime
|
||||
let cachedPrivySecrets: {
|
||||
appId: string
|
||||
appSecret: string
|
||||
authKey: string
|
||||
} | null = null
|
||||
|
||||
/**
|
||||
* Sets the cached Privy secrets (called once at startup)
|
||||
*/
|
||||
export function setCachedPrivySecrets(secrets: { appId: string; appSecret: string; authKey: string }) {
|
||||
cachedPrivySecrets = secrets
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cached Privy secrets (for use without Fastify instance)
|
||||
*/
|
||||
export function getCachedPrivySecrets(): { appId: string; appSecret: string; authKey: string } | null {
|
||||
return cachedPrivySecrets
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads Privy secrets ONCE at application startup from Infisical (production) or env vars/files (non-production).
|
||||
* Secrets are cached in memory via Fastify decorator and never reloaded during runtime.
|
||||
@@ -81,10 +103,32 @@ export default fp(async function (fastify) {
|
||||
const privyAppSecretSecret = allSecrets.secrets?.find(s => s.secretKey === 'PRIVY_APP_SECRET')
|
||||
const privyAuthKeySecret = allSecrets.secrets?.find(s => s.secretKey === 'PRIVY_AUTHORIZATION_KEY')
|
||||
|
||||
// Log which secrets were found
|
||||
fastify.log.info({
|
||||
foundAppId: !!privyAppIdSecret,
|
||||
foundAppSecret: !!privyAppSecretSecret,
|
||||
foundAuthKey: !!privyAuthKeySecret,
|
||||
allSecretKeys: allSecrets.secrets?.map(s => s.secretKey) || []
|
||||
}, 'Checking for Privy secrets in Infisical response')
|
||||
|
||||
appId = privyAppIdSecret?.secretValue || process.env.PRIVY_APP_ID || ''
|
||||
appSecret = privyAppSecretSecret?.secretValue || process.env.PRIVY_APP_SECRET || ''
|
||||
authKey = privyAuthKeySecret?.secretValue || process.env.PRIVY_AUTHORIZATION_KEY || ''
|
||||
|
||||
// Validate that we got the secrets
|
||||
if (!appId || !appSecret || !authKey) {
|
||||
fastify.log.error({
|
||||
hasAppId: !!appId,
|
||||
hasAppSecret: !!appSecret,
|
||||
hasAuthKey: !!authKey,
|
||||
fromInfisical: {
|
||||
appId: !!privyAppIdSecret,
|
||||
appSecret: !!privyAppSecretSecret,
|
||||
authKey: !!privyAuthKeySecret
|
||||
}
|
||||
}, '⚠️ Privy secrets incomplete after loading from Infisical')
|
||||
}
|
||||
|
||||
fastify.log.info({
|
||||
appId: !!appId,
|
||||
appSecret: !!appSecret,
|
||||
@@ -139,6 +183,13 @@ export default fp(async function (fastify) {
|
||||
nodeEnv: process.env.NODE_ENV
|
||||
}, '⚠️ WARNING: Privy secrets not fully resolved at plugin load - app will continue but Privy operations will fail')
|
||||
|
||||
// Store in module-level cache (even if empty, so getPrivyClient can detect the issue)
|
||||
setCachedPrivySecrets({
|
||||
appId: appId || '',
|
||||
appSecret: appSecret || '',
|
||||
authKey: authKey || ''
|
||||
})
|
||||
|
||||
// Still decorate with empty strings so the app doesn't crash
|
||||
// The actual error will be thrown in getPrivyClient when it's used
|
||||
fastify.decorate('privySecrets', {
|
||||
@@ -164,6 +215,13 @@ export default fp(async function (fastify) {
|
||||
return // Continue without throwing
|
||||
}
|
||||
|
||||
// Store secrets in module-level cache (accessible without Fastify instance)
|
||||
setCachedPrivySecrets({
|
||||
appId,
|
||||
appSecret,
|
||||
authKey
|
||||
})
|
||||
|
||||
// Decorate Fastify instance with secrets - these are cached in memory for the lifetime of the application
|
||||
// This decoration happens ONCE at startup, and secrets are reused from memory for all Privy client creations
|
||||
fastify.decorate('privySecrets', {
|
||||
@@ -176,7 +234,7 @@ export default fp(async function (fastify) {
|
||||
appId: appId.substring(0, 10) + '...',
|
||||
appSecret: appSecret.substring(0, 10) + '...',
|
||||
authKey: authKey.substring(0, 20) + '...',
|
||||
note: 'Secrets cached in memory - Infisical will not be called again during runtime'
|
||||
note: 'Secrets cached in memory (module-level and Fastify decorator) - Infisical will not be called again during runtime'
|
||||
}, '✅ Privy secrets loaded at startup and cached in memory')
|
||||
}, {
|
||||
name: 'privy-secrets',
|
||||
|
||||
@@ -14,6 +14,7 @@ import {CONTRACTS} from '../../generated/gmxsdk/configs/contracts.js'
|
||||
import {getClientForAddress, getTokenDataFromTicker} from './gmx.js'
|
||||
import {Address} from 'viem'
|
||||
import {Balance, Chain, Ticker} from '../../generated/ManagingApiTypes.js'
|
||||
import {getCachedPrivySecrets} from './privy-secrets.js'
|
||||
|
||||
// Load environment variables in non-production only
|
||||
if (process.env.NODE_ENV !== 'production') dotenv.config()
|
||||
@@ -59,16 +60,20 @@ declare module 'fastify' {
|
||||
*/
|
||||
export const getPrivyClient = (fastify?: FastifyInstance): PrivyClient => {
|
||||
// Read from cached secrets in memory (loaded once at startup):
|
||||
// 1. Fastify decorator (populated by privy-secrets plugin at startup - Infisical in prod, env in dev)
|
||||
// 2. Fastify config (from env plugin)
|
||||
// 3. Environment variables (fallback)
|
||||
// Note: In production, secrets come from Infisical and are cached in fastify.privySecrets at startup
|
||||
// Priority order:
|
||||
// 1. Module-level cache (populated by privy-secrets plugin at startup - accessible without Fastify instance)
|
||||
// 2. Fastify decorator (populated by privy-secrets plugin at startup - Infisical in prod, env in dev)
|
||||
// 3. Fastify config (from env plugin)
|
||||
// 4. Environment variables (fallback)
|
||||
// Note: In production, secrets come from Infisical and are cached in module-level variable and fastify.privySecrets at startup
|
||||
|
||||
// First, try module-level cache (works without Fastify instance)
|
||||
const cachedSecrets = getCachedPrivySecrets()
|
||||
const decorated = (fastify as any)?.privySecrets as { appId: string; appSecret: string; authKey: string } | undefined
|
||||
|
||||
const appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID
|
||||
const appSecret = decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET || process.env.PRIVY_APP_SECRET
|
||||
const authKey = decorated?.authKey || fastify?.config?.PRIVY_AUTHORIZATION_KEY || process.env.PRIVY_AUTHORIZATION_KEY
|
||||
const appId = cachedSecrets?.appId || decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID
|
||||
const appSecret = cachedSecrets?.appSecret || decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET || process.env.PRIVY_APP_SECRET
|
||||
const authKey = cachedSecrets?.authKey || decorated?.authKey || fastify?.config?.PRIVY_AUTHORIZATION_KEY || process.env.PRIVY_AUTHORIZATION_KEY
|
||||
|
||||
if (!appId || !appSecret || !authKey) {
|
||||
console.warn('Missing Privy environment variables:');
|
||||
@@ -76,6 +81,7 @@ export const getPrivyClient = (fastify?: FastifyInstance): PrivyClient => {
|
||||
console.warn('PRIVY_APP_SECRET:', appSecret ? 'present' : 'missing');
|
||||
console.warn('PRIVY_AUTHORIZATION_KEY:', authKey ? 'present' : 'missing');
|
||||
console.warn('NODE_ENV:', process.env.NODE_ENV);
|
||||
console.warn('Module-level cache available:', !!cachedSecrets);
|
||||
console.warn('Fastify privySecrets decorated:', !!decorated);
|
||||
console.warn('Fastify config available:', !!fastify?.config);
|
||||
|
||||
@@ -108,8 +114,10 @@ export async function getAuthorizationSignature(
|
||||
fastify?: FastifyInstance
|
||||
) {
|
||||
// Get app ID from cached secrets (loaded once at startup) or env fallback
|
||||
// Priority: module-level cache > Fastify decorator > Fastify config > env vars
|
||||
const cachedSecrets = getCachedPrivySecrets()
|
||||
const decorated = (fastify as any)?.privySecrets as { appId: string; authKey: string } | undefined
|
||||
const appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID || ''
|
||||
const appId = cachedSecrets?.appId || decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID || ''
|
||||
|
||||
const payload = {
|
||||
version: 1,
|
||||
@@ -127,10 +135,12 @@ export async function getAuthorizationSignature(
|
||||
const serializedPayloadBuffer = Buffer.from(serializedPayload);
|
||||
|
||||
// Resolve authorization key from cached secrets (loaded once at startup from Infisical in production)
|
||||
// Priority: module-level cache > Fastify decorator > Fastify config > file > env vars
|
||||
let resolvedKey: string | undefined
|
||||
|
||||
// Try Fastify decorator first (secrets cached in memory from Infisical at startup in production)
|
||||
if (decorated?.authKey) {
|
||||
if (cachedSecrets?.authKey) {
|
||||
resolvedKey = cachedSecrets.authKey
|
||||
} else if (decorated?.authKey) {
|
||||
resolvedKey = decorated.authKey
|
||||
} else if (fastify?.config?.PRIVY_AUTHORIZATION_KEY) {
|
||||
resolvedKey = fastify.config.PRIVY_AUTHORIZATION_KEY
|
||||
@@ -176,11 +186,12 @@ export const makePrivyRequest = async <T>(
|
||||
): Promise<T> => {
|
||||
try {
|
||||
// Resolve secrets from cached memory (loaded once at startup from Infisical in production)
|
||||
// Priority: module-level cache > Fastify decorator > Fastify config > env vars
|
||||
const cachedSecrets = getCachedPrivySecrets()
|
||||
const decorated = (fastify as any)?.privySecrets as { appId: string; appSecret: string } | undefined
|
||||
|
||||
// Try Fastify decorator first (secrets cached in memory from Infisical at startup in production)
|
||||
const appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID || ''
|
||||
const appSecret = decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET || process.env.PRIVY_APP_SECRET || ''
|
||||
const appId = cachedSecrets?.appId || decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID || ''
|
||||
const appSecret = cachedSecrets?.appSecret || decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET || process.env.PRIVY_APP_SECRET || ''
|
||||
|
||||
let headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
Reference in New Issue
Block a user