feat: new secrets

This commit is contained in:
2026-07-20 15:23:16 +02:00
parent 5a6833c1a2
commit 3fff09ba81
18 changed files with 121 additions and 109 deletions
+2
View File
@@ -7,6 +7,7 @@ const sharp = require('sharp')
const crypto = require('crypto')
// Imports internes
const { GEMINI_API_KEY } = require('../config/secrets')
const { generateImageV2 } = require('../helpers/gemini')
const { generatePicturePrompt } = require('../helpers/prompts')
const { ALERT_TYPE, refList } = require('../index')
@@ -284,6 +285,7 @@ exports.onTaskCreateGenerateCover = onDocumentCreated(
timeoutSeconds: 540, // 9 minutes max (Imagen peut être lent)
memory: '1GiB',
document: 'tasks/{taskId}',
secrets: [GEMINI_API_KEY],
},
async (event) => {
const data = event.data?.data() || {}
+4 -4
View File
@@ -2,7 +2,7 @@ const { onCall, HttpsError } = require('firebase-functions/v2/https')
const { z } = require('genkit')
const { generateAI, analyseLyrics } = require('../helpers/gemini')
const { SUNO_API_BASE, SUNO_TIMESTAMPED_LYRICS_PATH } = require('../config/suno')
const { SUNO_API_KEY } = require('../config/keys')
const { GEMINI_API_KEY, SUNO_API_KEY } = require('../config/secrets')
const axios = require('axios')
const { FieldValue } = require('firebase-admin/firestore')
const { refList } = require('../index')
@@ -137,7 +137,7 @@ const buildModerationBrief = ({
// --- GENERATION DE PAROLES (MAIN) ---
exports.generateLyrics = onCall({}, async ({ auth = {}, data = {} }) => {
exports.generateLyrics = onCall({ secrets: [GEMINI_API_KEY] }, async ({ auth = {}, data = {} }) => {
try {
const {
objective = '',
@@ -344,7 +344,7 @@ const softenModerationDecision = (rawResult = {}) => {
}
}
exports.analyseLyricsToxicity = onCall({}, async ({ data = {} }) => {
exports.analyseLyricsToxicity = onCall({ secrets: [GEMINI_API_KEY] }, async ({ data = {} }) => {
try {
const requestSchema = z.object({
title: z.string().optional(),
@@ -420,7 +420,7 @@ async function getSunoTimestamps(projectId) {
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${SUNO_API_KEY}`,
Authorization: `Bearer ${SUNO_API_KEY.value()}`,
},
timeout: 30000,
}
+5 -5
View File
@@ -8,7 +8,7 @@ const { randomUUID } = require('crypto')
const { ALERT_TYPE, refList } = require('../index')
const { sendNotification } = require('./notifications')
const { createOrderDocument, ORDER_TYPES } = require('./helpers/orders')
const { SUNO_API_KEY } = require('../config/keys')
const { SUNO_API_KEY } = require('../config/secrets')
const {
SUNO_MODEL,
SUNO_CALLBACK_URL,
@@ -468,7 +468,7 @@ const mergeMusicUrls = async (projectRef, newUrls) => {
// 5. FONCTIONS PRINCIPALES (CLOUD FUNCTIONS)
// ==========================================
exports.generateMusic = onCall(async ({ data = {} }) => {
exports.generateMusic = onCall({ secrets: [SUNO_API_KEY] }, async ({ data = {} }) => {
try {
// Extraction des données du Frontend
const {
@@ -542,7 +542,7 @@ exports.generateMusic = onCall(async ({ data = {} }) => {
const response = await axios.post(`${SUNO_API_BASE}${SUNO_API_PATH}`, payload, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${SUNO_API_KEY}`,
Authorization: `Bearer ${SUNO_API_KEY.value()}`,
},
})
@@ -571,12 +571,12 @@ exports.generateMusic = onCall(async ({ data = {} }) => {
})
// GET STATUS (inchangé mais inclus pour complétude)
exports.getSunoStatus = onCall(async ({ data = {} }) => {
exports.getSunoStatus = onCall({ secrets: [SUNO_API_KEY] }, async ({ data = {} }) => {
const { taskId } = data
if (!taskId) throw new Error('TaskId manquant')
try {
const response = await axios.get(`${SUNO_API_BASE}${SUNO_STATUS_PATH}?taskId=${taskId}`, {
headers: { Authorization: `Bearer ${SUNO_API_KEY}` },
headers: { Authorization: `Bearer ${SUNO_API_KEY.value()}` },
timeout: 30000,
})
return {
+28 -21
View File
@@ -4,9 +4,16 @@ const { refList, ALERT_TYPE } = require('../index')
const { Expo } = require('expo-server-sdk')
const { Resend } = require('resend')
const { basicTemplate } = require('../helpers/email')
const { RESEND_API_KEY } = require('../config/keys')
const { RESEND_API_KEY } = require('../config/secrets')
const resendInstance = RESEND_API_KEY ? new Resend(RESEND_API_KEY) : null
let resendInstance = null
const getResendInstance = () => {
if (!resendInstance) {
resendInstance = new Resend(RESEND_API_KEY.value())
}
return resendInstance
}
// Initialisation de Expo SDK
let expo = new Expo()
@@ -58,7 +65,11 @@ function buildNotificationEmailPayload({ title = '', message = '', template = {}
}
exports.sendNotificationWhenDocIsCreated = onDocumentCreated(
{ region: 'europe-west1', document: 'notifications/{notificationId}' },
{
region: 'europe-west1',
document: 'notifications/{notificationId}',
secrets: [RESEND_API_KEY],
},
async (event) => {
try {
const {
@@ -112,24 +123,20 @@ exports.sendNotificationWhenDocIsCreated = onDocumentCreated(
}
if ((emailNotifications || mailOnly) && !!receiverEmail) {
if (!resendInstance) {
console.warn('Resend client not configured; unable to send notification email.')
} else {
try {
const { subject, html } = buildNotificationEmailPayload({
title,
message,
template: notifData?.email,
})
await resendInstance.emails.send({
from: EMAIL_FROM,
to: [receiverEmail],
subject,
html,
})
} catch (e) {
console.log('Error sending email:', e)
}
try {
const { subject, html } = buildNotificationEmailPayload({
title,
message,
template: notifData?.email,
})
await getResendInstance().emails.send({
from: EMAIL_FROM,
to: [receiverEmail],
subject,
html,
})
} catch (e) {
console.log('Error sending email:', e)
}
} else {
console.log(
+7 -1
View File
@@ -3,11 +3,17 @@ const { FieldValue } = require('firebase-admin/firestore')
const { onDocumentWritten } = require('firebase-functions/firestore')
const _ = require('lodash')
const { refList, db } = require('../index')
const { SUNO_API_KEY } = require('../config/secrets')
const { getSunoTimestamps } = require('./lyrics')
const { deleteFolder } = require('../helpers/firebase')
const { buildMonthKey } = require('../helpers/stats')
exports.onProjectWritten = onDocumentWritten('projects/{projectId}', async (projectSnap) => {
const PROJECT_FUNCTION_OPTIONS = {
document: 'projects/{projectId}',
secrets: [SUNO_API_KEY],
}
exports.onProjectWritten = onDocumentWritten(PROJECT_FUNCTION_OPTIONS, async (projectSnap) => {
try {
const { projectId } = projectSnap.params
const beforeData = projectSnap?.data?.before?.data() || null
+7 -5
View File
@@ -9,6 +9,7 @@ try {
}
const { REGION, refsList } = require('../index')
const { STRIPE_SECRET_KEY } = require('../config/secrets')
const STRIPE_MODE = 'test'
const {
getStripeClient,
@@ -22,6 +23,7 @@ const {
} = require('../helpers/stripe')
const paymentsCollection = admin.firestore().collection('payments')
const STRIPE_FUNCTION_OPTIONS = { region: REGION, secrets: [STRIPE_SECRET_KEY] }
const getServerTimestamp = () => {
if (FieldValue?.serverTimestamp) {
@@ -47,7 +49,7 @@ const normalizePaymentIntent = (paymentIntent) => ({
metadata: paymentIntent.metadata,
})
const createCheckoutSession = onCall({ region: REGION }, async (request) => {
const createCheckoutSession = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -123,7 +125,7 @@ const createCheckoutSession = onCall({ region: REGION }, async (request) => {
}
})
const getPremiumStatus = onCall({ region: REGION }, async (request) => {
const getPremiumStatus = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -203,7 +205,7 @@ const getPremiumStatus = onCall({ region: REGION }, async (request) => {
}
})
const createStripeCustomerPortalSession = onCall({ region: REGION }, async (request) => {
const createStripeCustomerPortalSession = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -365,7 +367,7 @@ const ensureStripeConnectAccount = async ({ uid, stripe, userRef, userData }) =>
}
}
const createStripeConnectLoginLink = onCall({ region: REGION }, async (request) => {
const createStripeConnectLoginLink = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -425,7 +427,7 @@ const createStripeConnectLoginLink = onCall({ region: REGION }, async (request)
}
})
const verifyStripePayment = onCall({ region: REGION }, async (request) => {
const verifyStripePayment = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
+4 -2
View File
@@ -1,6 +1,7 @@
const { HttpsError, onCall } = require('firebase-functions/https')
const { getStripeClient, mapStripeErrorToHttps } = require('../../helpers/stripe')
const { STRIPE_SECRET_KEY } = require('../../config/secrets')
const { REGION } = require('./config')
const {
SUBSCRIPTION_PRICE_IDS,
@@ -8,6 +9,7 @@ const {
COIN_PACK_PRODUCTS,
} = require('./constants')
const { parseCoinsPerMonth, formatCoinPack } = require('./shared')
const STRIPE_FUNCTION_OPTIONS = { region: REGION, secrets: [STRIPE_SECRET_KEY] }
const formatPlan = (price, priceId) => {
if (!price || typeof price !== 'object') {
@@ -40,7 +42,7 @@ const formatPlan = (price, priceId) => {
}
}
const listSubscriptionPlans = onCall({ region: REGION }, async () => {
const listSubscriptionPlans = onCall(STRIPE_FUNCTION_OPTIONS, async () => {
try {
const stripe = getStripeClient()
@@ -76,7 +78,7 @@ const listSubscriptionPlans = onCall({ region: REGION }, async () => {
}
})
const listCoinPacks = onCall({ region: REGION }, async () => {
const listCoinPacks = onCall(STRIPE_FUNCTION_OPTIONS, async () => {
try {
const stripe = getStripeClient()
+6 -4
View File
@@ -8,6 +8,7 @@ const {
formatCheckoutSessionResponse,
mapStripeErrorToHttps,
} = require('../../helpers/stripe')
const { STRIPE_SECRET_KEY } = require('../../config/secrets')
const { REGION } = require('./config')
const {
ALL_SUBSCRIPTION_PRICE_IDS,
@@ -17,6 +18,7 @@ const {
const { refsList, formatCoinPack, getSubscriptionMetaFromPrice } = require('./shared')
const CHECKOUT_UI_MODES = new Set(['hosted', 'embedded'])
const STRIPE_FUNCTION_OPTIONS = { region: REGION, secrets: [STRIPE_SECRET_KEY] }
const sanitizePriceId = (value) => {
if (typeof value !== 'string') {
@@ -65,7 +67,7 @@ const withCheckoutNavigationParams = (baseParams, { uiMode, successUrl, cancelUr
}
}
const createSubscriptionCheckoutSession = onCall({ region: REGION }, async (request) => {
const createSubscriptionCheckoutSession = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -152,7 +154,7 @@ const createSubscriptionCheckoutSession = onCall({ region: REGION }, async (requ
}
})
const createSongDownloadCheckoutSession = onCall({ region: REGION }, async (request) => {
const createSongDownloadCheckoutSession = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -231,7 +233,7 @@ const createSongDownloadCheckoutSession = onCall({ region: REGION }, async (requ
}
})
const createPlaybackDownloadCheckoutSession = onCall({ region: REGION }, async (request) => {
const createPlaybackDownloadCheckoutSession = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -310,7 +312,7 @@ const createPlaybackDownloadCheckoutSession = onCall({ region: REGION }, async (
}
})
const createCoinPackCheckoutSession = onCall({ region: REGION }, async (request) => {
const createCoinPackCheckoutSession = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
+4 -2
View File
@@ -1,11 +1,13 @@
const { HttpsError, onCall } = require('firebase-functions/https')
const { getStripeClient, mapStripeErrorToHttps } = require('../../helpers/stripe')
const { STRIPE_SECRET_KEY } = require('../../config/secrets')
const { REGION } = require('./config')
const { CANCELABLE_SUBSCRIPTION_STATUSES, ACTIVE_SUBSCRIPTION_STATUSES } = require('./constants')
const { refsList, formatSubscriptionForClient, resolveUserContext } = require('./shared')
const STRIPE_FUNCTION_OPTIONS = { region: REGION, secrets: [STRIPE_SECRET_KEY] }
const cancelActiveSubscription = onCall({ region: REGION }, async (request) => {
const cancelActiveSubscription = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
@@ -101,7 +103,7 @@ const cancelActiveSubscription = onCall({ region: REGION }, async (request) => {
}
})
const getActiveSubscription = onCall({ region: REGION }, async (request) => {
const getActiveSubscription = onCall(STRIPE_FUNCTION_OPTIONS, async (request) => {
try {
const uid = request?.auth?.uid
if (!uid) {
+2 -8
View File
@@ -2,7 +2,7 @@ const admin = require('firebase-admin')
const { FieldValue } = require('firebase-admin/firestore')
const { refList } = require('../../index')
const { STRIPE_WEBHOOK_SECRET } = require('../../config/keys')
const { STRIPE_WEBHOOK_SECRET } = require('../../config/secrets')
const {
SUBSCRIPTION_LEVEL_ALLOWANCES,
SUBSCRIPTION_PRICE_METADATA,
@@ -120,13 +120,7 @@ const resolveStripeWebhookSecret = () => {
return cachedStripeWebhookSecret
}
const envSecret =
typeof process?.env?.STRIPE_WEBHOOK_SECRET === 'string'
? process.env.STRIPE_WEBHOOK_SECRET.trim()
: ''
const inlineSecret = typeof STRIPE_WEBHOOK_SECRET === 'string' ? STRIPE_WEBHOOK_SECRET.trim() : ''
const secret = envSecret || inlineSecret
const secret = STRIPE_WEBHOOK_SECRET.value().trim()
if (!secret) {
throw new Error('STRIPE_WEBHOOK_SECRET not configured')
}
+6 -1
View File
@@ -3,6 +3,7 @@ const { HttpsError } = require('firebase-functions/https')
const { ORDER_TYPES, createOrderDocument } = require('../helpers/orders')
const { getStripeClient } = require('../../helpers/stripe')
const { STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET } = require('../../config/secrets')
const { REGION } = require('./config')
const {
paymentsCollection,
@@ -20,6 +21,10 @@ const {
upsertPaymentDocument,
} = require('./shared')
const { PREMIUM_SUBSCRIPTION_STATUSES } = require('./constants')
const STRIPE_WEBHOOK_OPTIONS = {
region: REGION,
secrets: [STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET],
}
const isPaidCheckoutSession = (session) => {
if (!session || typeof session !== 'object') {
@@ -749,7 +754,7 @@ const handleStripeWebhookEvent = async ({ event, stripe }) => {
}
}
const handleStripeWebhook = onRequest({ region: REGION }, async (req, res) => {
const handleStripeWebhook = onRequest(STRIPE_WEBHOOK_OPTIONS, async (req, res) => {
if (req.method !== 'POST') {
res.status(405).send('Method Not Allowed')
return
+18 -10
View File
@@ -6,14 +6,26 @@ const { ORDER_TYPES, createOrderDocument } = require('./helpers/orders')
const { deleteFolder } = require('../helpers/firebase')
const { Resend } = require('resend')
const { welcomeTemplate } = require('../helpers/email')
const { RESEND_API_KEY } = require('../config/keys')
const { RESEND_API_KEY } = require('../config/secrets')
const { onRequest } = require('firebase-functions/https')
const resendClient = new Resend(RESEND_API_KEY)
let resendClient = null
const getResendClient = () => {
if (!resendClient) {
resendClient = new Resend(RESEND_API_KEY.value())
}
return resendClient
}
const WELCOME_EMAIL_FROM = 'MusicLand <musicland@musicland.ai>'
const WELCOME_EMAIL_SUBJECT = 'Bienvenue sur MusicLand'
const USER_CREATED_OPTIONS = {
document: 'users/{userID}',
secrets: [RESEND_API_KEY],
}
exports.testWelcomMail = onRequest(async (req, res) => {
exports.testWelcomMail = onRequest({ secrets: [RESEND_API_KEY] }, async (req, res) => {
if (req.method !== 'GET') {
res.set('Allow', 'GET')
return res.status(405).json({ success: false, error: 'Method not allowed' })
@@ -22,7 +34,7 @@ exports.testWelcomMail = onRequest(async (req, res) => {
const targetEmail = req.query.email || 'tdtomthomas@gmail.com'
const firstName = req.query.firstName || 'Toto'
const lastName = req.query.lastName || 'Test'
const { data, error } = await resendClient.emails.send({
const { data, error } = await getResendClient().emails.send({
from: WELCOME_EMAIL_FROM,
to: [targetEmail],
subject: WELCOME_EMAIL_SUBJECT,
@@ -40,7 +52,7 @@ exports.testWelcomMail = onRequest(async (req, res) => {
}
})
exports.onUserCreated = onDocumentCreated('users/{userID}', async (event) => {
exports.onUserCreated = onDocumentCreated(USER_CREATED_OPTIONS, async (event) => {
try {
const { email = '', firstName = '', lastName = '' } = event?.data?.data() || {}
@@ -62,13 +74,9 @@ exports.onUserCreated = onDocumentCreated('users/{userID}', async (event) => {
)
}
if (email) {
if (!resendClient) {
console.warn('Resend API key not configured; skipping welcome email.')
return
}
try {
console.log(`Sending welcome email to ${email}`)
const { data, error } = await resendClient.emails.send({
const { data, error } = await getResendClient().emails.send({
from: WELCOME_EMAIL_FROM,
to: [email],
subject: WELCOME_EMAIL_SUBJECT,