@realtimex/email-automator 2.28.1 → 2.28.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,20 +57,6 @@ export async function authMiddleware(
57
57
  const supabaseUrl = isEnvUrlValid ? envUrl : (headerConfig?.url || '');
58
58
  const supabaseAnonKey = isEnvKeyValid ? envKey : (headerConfig?.anonKey || '');
59
59
 
60
- // If encryption is not ready, try to initialize it using available Supabase config
61
- if (!isEncryptionReady() && supabaseUrl && supabaseAnonKey) {
62
- // Note: Ideally we use service role to read encryption_key from user_settings,
63
- // but even with anon key it might work if RLS allows or if we just use it
64
- // to check for existence of keys.
65
- const initClient = createClient(supabaseUrl, supabaseAnonKey, {
66
- auth: { autoRefreshToken: false, persistSession: false },
67
- });
68
- // Run in background to not block auth
69
- initializePersistenceEncryption(initClient).catch(err =>
70
- logger.warn('Failed to initialize encryption in auth middleware', { error: err.message })
71
- );
72
- }
73
-
74
60
  // Development bypass: skip auth if DISABLE_AUTH=true in non-production
75
61
  if (config.security.disableAuth && !config.isProduction) {
76
62
  logger.warn('Auth disabled for development - creating mock user');
@@ -97,6 +83,13 @@ export async function authMiddleware(
97
83
  req.supabase = supabase;
98
84
  // Initialize logger persistence for mock user
99
85
  Logger.setPersistence(supabase, req.user.id);
86
+
87
+ // If encryption is not ready, try to initialize it now
88
+ if (!isEncryptionReady()) {
89
+ initializePersistenceEncryption(supabase).catch(err =>
90
+ logger.warn('Failed to initialize encryption in dev mode', { error: err.message })
91
+ );
92
+ }
100
93
  } else {
101
94
  throw new AuthenticationError('Supabase not configured. Please set up Supabase in the app or provide SUPABASE_URL/ANON_KEY in .env');
102
95
  }
@@ -133,6 +126,13 @@ export async function authMiddleware(
133
126
  throw new AuthenticationError('Invalid or expired token');
134
127
  }
135
128
 
129
+ // If encryption is not ready, initialize it now with the authenticated client
130
+ if (!isEncryptionReady()) {
131
+ initializePersistenceEncryption(supabase).catch(err =>
132
+ logger.warn('Failed to initialize encryption with authenticated client', { error: err.message })
133
+ );
134
+ }
135
+
136
136
  // Initialize logger persistence for this request
137
137
  Logger.setPersistence(supabase, user.id);
138
138
 
@@ -21,15 +21,24 @@ export async function initializePersistenceEncryption(providedSupabase?: any) {
21
21
  // BYOK mode: Supabase not configured at startup (credentials come via HTTP headers)
22
22
  // If we don't have a key yet, generate a temporary one in memory
23
23
  if (!getEncryptionKeyHex()) {
24
- logger.info('Supabase not configured yet (BYOK mode)');
25
- logger.info('Generating temporary encryption key in memory - will be reconciled when Supabase becomes available');
24
+ logger.info('Supabase not configured yet (BYOK mode) - using temporary key');
26
25
  const newKey = crypto.randomBytes(32).toString('hex');
27
26
  setEncryptionKey(newKey);
28
- logger.info('✓ Temporary encryption key generated and loaded in memory');
29
27
  }
30
28
  return;
31
29
  }
32
30
 
31
+ // Check client type for logging
32
+ const isServiceRole = !!(supabase as any).supabaseServiceRoleKey || !(supabase as any).auth?.session;
33
+ const hasToken = !!(supabase as any).realtime?.accessToken; // Simple check for authenticated client
34
+
35
+ if (!isServiceRole && !hasToken) {
36
+ logger.debug('Skipping encryption reconciliation with unauthenticated anon client');
37
+ return;
38
+ }
39
+
40
+ logger.info(`Reconciling encryption key with database (${isServiceRole ? 'Service Role' : 'Authenticated User'})`);
41
+
33
42
  // 1. Check if ANY user has an encryption key stored
34
43
  // In sandbox mode, encryption key is always in database
35
44
  const { data: users, error } = await supabase
@@ -64,42 +73,47 @@ export async function initializePersistenceEncryption(providedSupabase?: any) {
64
73
  return;
65
74
  }
66
75
 
67
- // 2. No key in database - use in-memory key or generate and persist
68
- // This happens on first run or after fresh database setup
69
- let finalKey = getEncryptionKeyHex();
70
- if (!finalKey) {
71
- logger.info('No encryption key found in database or memory, generating new key...');
72
- finalKey = crypto.randomBytes(32).toString('hex');
73
- setEncryptionKey(finalKey);
74
- } else {
75
- logger.info('Persisting in-memory encryption key to new Supabase instance...');
76
- }
77
-
78
- // 3. Persist to all existing users in database
79
- const { data: allUsers } = await supabase
80
- .from('user_settings')
81
- .select('user_id')
82
- .limit(100);
83
-
84
- if (allUsers && allUsers.length > 0) {
85
- logger.info(`Saving encryption key to database for ${allUsers.length} user(s)...`);
86
-
87
- // Update all users with the new key
88
- const updates = allUsers.map((user: any) =>
89
- supabase
90
- .from('user_settings')
91
- .update({ encryption_key: finalKey })
92
- .eq('user_id', user.user_id)
93
- );
76
+ // 2. No key in database - only generate and persist if we are the "Master" (Service Role)
77
+ // or if we've explicitly decided this is a fresh setup.
78
+ if (isServiceRole) {
79
+ let finalKey = getEncryptionKeyHex();
80
+ if (!finalKey) {
81
+ logger.info('No encryption key found in database or memory, generating new key...');
82
+ finalKey = crypto.randomBytes(32).toString('hex');
83
+ setEncryptionKey(finalKey);
84
+ } else {
85
+ logger.info('Persisting in-memory encryption key to database...');
86
+ }
94
87
 
95
- await Promise.all(updates);
96
- logger.info('✓ Encryption key saved to database');
88
+ // 3. Persist to all existing users in database
89
+ const { data: allUsers } = await supabase
90
+ .from('user_settings')
91
+ .select('user_id')
92
+ .limit(100);
93
+
94
+ if (allUsers && allUsers.length > 0) {
95
+ logger.info(`Saving encryption key to database for ${allUsers.length} user(s)...`);
96
+
97
+ // Update all users with the new key
98
+ const updates = allUsers.map((user: any) =>
99
+ supabase
100
+ .from('user_settings')
101
+ .update({ encryption_key: finalKey })
102
+ .eq('user_id', user.user_id)
103
+ );
104
+
105
+ await Promise.all(updates);
106
+ logger.info('✓ Encryption key saved to database');
107
+ isEncryptionInitialized = true;
108
+ } else {
109
+ logger.info('No users found yet, encryption key loaded in memory');
110
+ logger.info('Key will be persisted when users are created');
111
+ // We don't set isEncryptionInitialized = true here because we still want
112
+ // to try reconciling once a user is actually created/logged in
113
+ }
97
114
  } else {
98
- logger.info('No users found yet, encryption key loaded in memory');
99
- logger.info('Key will be persisted when users are created');
115
+ logger.warn('No encryption key found in database, but cannot persist one with user-restricted client.');
100
116
  }
101
-
102
- isEncryptionInitialized = true;
103
117
  } catch (err) {
104
118
  logger.error('Error initializing encryption:', err);
105
119
  // Always ensure we have a key, even if there was an error
@@ -33,17 +33,6 @@ export async function authMiddleware(req, _res, next) {
33
33
  const isEnvKeyValid = !!envKey && envKey.length > 0;
34
34
  const supabaseUrl = isEnvUrlValid ? envUrl : (headerConfig?.url || '');
35
35
  const supabaseAnonKey = isEnvKeyValid ? envKey : (headerConfig?.anonKey || '');
36
- // If encryption is not ready, try to initialize it using available Supabase config
37
- if (!isEncryptionReady() && supabaseUrl && supabaseAnonKey) {
38
- // Note: Ideally we use service role to read encryption_key from user_settings,
39
- // but even with anon key it might work if RLS allows or if we just use it
40
- // to check for existence of keys.
41
- const initClient = createClient(supabaseUrl, supabaseAnonKey, {
42
- auth: { autoRefreshToken: false, persistSession: false },
43
- });
44
- // Run in background to not block auth
45
- initializePersistenceEncryption(initClient).catch(err => logger.warn('Failed to initialize encryption in auth middleware', { error: err.message }));
46
- }
47
36
  // Development bypass: skip auth if DISABLE_AUTH=true in non-production
48
37
  if (config.security.disableAuth && !config.isProduction) {
49
38
  logger.warn('Auth disabled for development - creating mock user');
@@ -67,6 +56,10 @@ export async function authMiddleware(req, _res, next) {
67
56
  req.supabase = supabase;
68
57
  // Initialize logger persistence for mock user
69
58
  Logger.setPersistence(supabase, req.user.id);
59
+ // If encryption is not ready, try to initialize it now
60
+ if (!isEncryptionReady()) {
61
+ initializePersistenceEncryption(supabase).catch(err => logger.warn('Failed to initialize encryption in dev mode', { error: err.message }));
62
+ }
70
63
  }
71
64
  else {
72
65
  throw new AuthenticationError('Supabase not configured. Please set up Supabase in the app or provide SUPABASE_URL/ANON_KEY in .env');
@@ -95,6 +88,10 @@ export async function authMiddleware(req, _res, next) {
95
88
  logger.debug('Auth failed', { error: error?.message });
96
89
  throw new AuthenticationError('Invalid or expired token');
97
90
  }
91
+ // If encryption is not ready, initialize it now with the authenticated client
92
+ if (!isEncryptionReady()) {
93
+ initializePersistenceEncryption(supabase).catch(err => logger.warn('Failed to initialize encryption with authenticated client', { error: err.message }));
94
+ }
98
95
  // Initialize logger persistence for this request
99
96
  Logger.setPersistence(supabase, user.id);
100
97
  // Attach user and supabase client to request
@@ -17,14 +17,20 @@ export async function initializePersistenceEncryption(providedSupabase) {
17
17
  // BYOK mode: Supabase not configured at startup (credentials come via HTTP headers)
18
18
  // If we don't have a key yet, generate a temporary one in memory
19
19
  if (!getEncryptionKeyHex()) {
20
- logger.info('Supabase not configured yet (BYOK mode)');
21
- logger.info('Generating temporary encryption key in memory - will be reconciled when Supabase becomes available');
20
+ logger.info('Supabase not configured yet (BYOK mode) - using temporary key');
22
21
  const newKey = crypto.randomBytes(32).toString('hex');
23
22
  setEncryptionKey(newKey);
24
- logger.info('✓ Temporary encryption key generated and loaded in memory');
25
23
  }
26
24
  return;
27
25
  }
26
+ // Check client type for logging
27
+ const isServiceRole = !!supabase.supabaseServiceRoleKey || !supabase.auth?.session;
28
+ const hasToken = !!supabase.realtime?.accessToken; // Simple check for authenticated client
29
+ if (!isServiceRole && !hasToken) {
30
+ logger.debug('Skipping encryption reconciliation with unauthenticated anon client');
31
+ return;
32
+ }
33
+ logger.info(`Reconciling encryption key with database (${isServiceRole ? 'Service Role' : 'Authenticated User'})`);
28
34
  // 1. Check if ANY user has an encryption key stored
29
35
  // In sandbox mode, encryption key is always in database
30
36
  const { data: users, error } = await supabase
@@ -54,37 +60,44 @@ export async function initializePersistenceEncryption(providedSupabase) {
54
60
  isEncryptionInitialized = true;
55
61
  return;
56
62
  }
57
- // 2. No key in database - use in-memory key or generate and persist
58
- // This happens on first run or after fresh database setup
59
- let finalKey = getEncryptionKeyHex();
60
- if (!finalKey) {
61
- logger.info('No encryption key found in database or memory, generating new key...');
62
- finalKey = crypto.randomBytes(32).toString('hex');
63
- setEncryptionKey(finalKey);
64
- }
65
- else {
66
- logger.info('Persisting in-memory encryption key to new Supabase instance...');
67
- }
68
- // 3. Persist to all existing users in database
69
- const { data: allUsers } = await supabase
70
- .from('user_settings')
71
- .select('user_id')
72
- .limit(100);
73
- if (allUsers && allUsers.length > 0) {
74
- logger.info(`Saving encryption key to database for ${allUsers.length} user(s)...`);
75
- // Update all users with the new key
76
- const updates = allUsers.map((user) => supabase
63
+ // 2. No key in database - only generate and persist if we are the "Master" (Service Role)
64
+ // or if we've explicitly decided this is a fresh setup.
65
+ if (isServiceRole) {
66
+ let finalKey = getEncryptionKeyHex();
67
+ if (!finalKey) {
68
+ logger.info('No encryption key found in database or memory, generating new key...');
69
+ finalKey = crypto.randomBytes(32).toString('hex');
70
+ setEncryptionKey(finalKey);
71
+ }
72
+ else {
73
+ logger.info('Persisting in-memory encryption key to database...');
74
+ }
75
+ // 3. Persist to all existing users in database
76
+ const { data: allUsers } = await supabase
77
77
  .from('user_settings')
78
- .update({ encryption_key: finalKey })
79
- .eq('user_id', user.user_id));
80
- await Promise.all(updates);
81
- logger.info('✓ Encryption key saved to database');
78
+ .select('user_id')
79
+ .limit(100);
80
+ if (allUsers && allUsers.length > 0) {
81
+ logger.info(`Saving encryption key to database for ${allUsers.length} user(s)...`);
82
+ // Update all users with the new key
83
+ const updates = allUsers.map((user) => supabase
84
+ .from('user_settings')
85
+ .update({ encryption_key: finalKey })
86
+ .eq('user_id', user.user_id));
87
+ await Promise.all(updates);
88
+ logger.info('✓ Encryption key saved to database');
89
+ isEncryptionInitialized = true;
90
+ }
91
+ else {
92
+ logger.info('No users found yet, encryption key loaded in memory');
93
+ logger.info('Key will be persisted when users are created');
94
+ // We don't set isEncryptionInitialized = true here because we still want
95
+ // to try reconciling once a user is actually created/logged in
96
+ }
82
97
  }
83
98
  else {
84
- logger.info('No users found yet, encryption key loaded in memory');
85
- logger.info('Key will be persisted when users are created');
99
+ logger.warn('No encryption key found in database, but cannot persist one with user-restricted client.');
86
100
  }
87
- isEncryptionInitialized = true;
88
101
  }
89
102
  catch (err) {
90
103
  logger.error('Error initializing encryption:', err);
@@ -1,4 +1,4 @@
1
- const e={"app.name":"Email Automator","app.connecting":"Conectando cuenta...","app.loadingWorkspace":"Cargando tu espacio de trabajo...","app.loggedOut":"Sesión cerrada exitosamente","app.statusLive":"EN VIVO","app.statusOffline":"DESCONECTADO","common.loading":"Cargando...","common.save":"Guardar cambios","common.cancel":"Cancelar","common.delete":"Eliminar","common.success":"Éxito","common.error":"Error","common.warning":"Advertencia","common.syncNow":"Sincronizar ahora","common.syncing":"Sincronizando...","common.stopSync":"Detener sincronización","common.systemSync":"Sincronización del sistema","common.viewLogs":"Ver registros","common.saveChanges":"Guardar cambios","common.errorOccurred":"Ocurrió un error","common.previous":"Anterior","common.next":"Siguiente","common.of":"de","common.yes":"Sí","common.no":"No","common.archive":"Archivar","common.flag":"Marcar","common.on":"Activado","common.off":"Desactivado","common.enabled":"Habilitado","common.disabled":"Deshabilitado","common.active":"Activo","common.inactive":"Inactivo","common.draft":"Borrador","common.star":"Estrella","nav.dashboard":"Panel de control","nav.drafts":"Borradores","nav.autopilot":"Piloto automático","nav.analytics":"Analítica","nav.configuration":"Configuración","nav.accountSettings":"Configuración de cuenta","nav.signOut":"Cerrar sesión","drafts.title":"Centro de revisión de borradores","drafts.pending":"borradores pendientes","drafts.noDrafts":"No hay borradores pendientes","drafts.noDraftsDesc":"Las respuestas borrador generadas por IA aparecerán aquí para su revisión","drafts.send":"Enviar ahora","drafts.preview":"Vista previa","drafts.dismiss":"Descartar","drafts.regenerate":"Regenerar","drafts.selectAll":"Seleccionar todo","drafts.sendSelected":"Enviar seleccionados","drafts.dismissSelected":"Descartar seleccionados","drafts.filterByAccount":"Todas las cuentas","drafts.filterByDate":"Filtrar por fecha","drafts.originalEmail":"Correo electrónico original","drafts.aiReply":"Respuesta generada por IA","drafts.createdBy":"Creado por regla:","drafts.sendSuccess":"¡Borrador enviado con éxito!","drafts.sendError":"Error al enviar el borrador","drafts.dismissSuccess":"Borrador descartado","drafts.loadError":"Error al cargar borradores","drafts.compose":"Redactar Borrador","drafts.feedback":"¿Qué está mal?","drafts.editPlaceholder":"Escribe tu respuesta en Markdown...","login.title":"Bienvenido de nuevo","login.subtitle":"Inicia sesión en tu agente de email con IA","login.email":"Dirección de correo electrónico","login.password":"Contraseña","login.signIn":"Iniciar sesión","login.noAccount":"¿No tienes una cuenta?","login.alreadyHaveAccount":"¿Ya tienes una cuenta?","login.signUp":"Registrarse","login.forgotPassword":"¿Olvidaste tu contraseña?","login.initialize":"Inicializar Automator","login.secureLogin":"Inicio de sesión seguro","login.firstNamePlaceholder":"Juan","login.lastNamePlaceholder":"Pérez","login.emailPlaceholder":"admin@automator.ai","login.initializeMaster":"Inicializar maestro","login.sendMagicLink":"Enviar enlace mágico","login.openDashboard":"Abrir panel de control","setup.title":"Configuración del sistema","setup.initiation":"Bienvenido","setup.coordinates":"Detalles de conexión","setup.foundation":"Configuración de base de datos","setup.ignition":"Lanzamiento","setup.start":"Iniciar configuración","setup.welcomeTitle":"Inicializando Automator","setup.welcomeSubtitle":"Configurando tu entorno especializado para inteligencia de bandeja de entrada de alta frecuencia.","setup.encryptedTitle":"Encriptado","setup.encryptedDesc":"Seguridad de datos autoalojados.","setup.turboTitle":"Turbo","setup.turboDesc":"Inferencia de IA en menos de un segundo.","setup.getStarted":"Comenzar","setup.connectionMode":"Modo de conexión","setup.selectVector":"Seleccionar modo de implementación","setup.quickIgnition":"Inicio rápido","setup.autoProvision":"Aprovisionamiento automático mediante token","setup.manualSync":"Sincronización manual","setup.existingCredentials":"Credenciales existentes","setup.abortAccess":"Abortar acceso","setup.injectCoordinates":"Ingresar credenciales existentes","setup.platformUrl":"URL de la plataforma","setup.urlHelp":"Ingrese la URL completa o solo el ID del proyecto","setup.anonMatrixKey":"Clave anónima de Supabase","setup.keyHelp":"Se encuentra en la configuración de tu proyecto Supabase","setup.back":"Atrás","setup.engage":"Conectar","setup.installation":"Instalación","setup.applyingSchema":"Configurando base de datos...","setup.emptyProject":"Proyecto vacío detectado. La inicialización es obligatoria para instalar los sistemas de IA principales.","setup.versionMismatch":"Incompatibilidad de versión detectada. Se recomienda normalización.","setup.tokenRequired":"Token de gestión requerido","setup.migrateHelp":"Se usa una vez para ejecutar migraciones en tu backend.","setup.bypassRisk":"Omitir (Arriesgado)","setup.installSystems":"Instalar sistemas","setup.normalizeSystem":"Normalizar sistema","setup.retryInstallation":"Reintentar instalación","setup.agent.systemInstruction":'Eres el asistente del Asistente de configuración. Guía al usuario para conectar Supabase, elegir un modo de configuración y completar las migraciones. Pide solo el siguiente dato requerido y ofrece pasos claros. Si el usuario dice "ayúdame a configurar", enumera inmediatamente los pasos de este asistente.',"agent.intro.setup":`👋 ¡Bienvenido a la configuración! Puedo ayudarte a:
1
+ const e={"app.name":"Email Automator","app.connecting":"Conectando cuenta...","app.loadingWorkspace":"Cargando tu espacio de trabajo...","app.loggedOut":"Sesión cerrada exitosamente","app.statusLive":"EN VIVO","app.statusOffline":"DESCONECTADO","common.loading":"Cargando...","common.save":"Guardar cambios","common.cancel":"Cancelar","common.delete":"Eliminar","common.success":"Éxito","common.error":"Error","common.warning":"Advertencia","common.syncNow":"Sincronizar ahora","common.syncing":"Sincronizando...","common.stopSync":"Detener sincronización","common.systemSync":"Sincronización del sistema","common.viewLogs":"Ver registros","common.saveChanges":"Guardar cambios","common.errorOccurred":"Ocurrió un error","common.previous":"Anterior","common.next":"Siguiente","common.of":"de","common.yes":"Sí","common.no":"No","common.archive":"Archivar","common.flag":"Marcar","common.on":"Activado","common.off":"Desactivado","common.enabled":"Habilitado","common.disabled":"Deshabilitado","common.active":"Activo","common.inactive":"Inactivo","common.draft":"Borrador","common.star":"Estrella","nav.dashboard":"Panel de control","nav.drafts":"Borradores","nav.autopilot":"Piloto automático","nav.analytics":"Analítica","nav.configuration":"Configuración","nav.accountSettings":"Configuración de cuenta","nav.signOut":"Cerrar sesión","drafts.title":"Centro de revisión de borradores","drafts.pending":"borradores pendientes","drafts.noDrafts":"No hay borradores pendientes","drafts.noDraftsDesc":"Las respuestas borrador generadas por IA aparecerán aquí para su revisión","drafts.send":"Enviar ahora","drafts.preview":"Vista previa","drafts.dismiss":"Descartar","drafts.regenerate":"Regenerar","drafts.selectAll":"Seleccionar todo","drafts.sendSelected":"Enviar seleccionados","drafts.dismissSelected":"Descartar seleccionados","drafts.filterByAccount":"Todas las cuentas","drafts.filterByDate":"Filtrar por fecha","drafts.originalEmail":"Correo electrónico original","drafts.aiReply":"Respuesta generada por IA","drafts.createdBy":"Creado por regla:","drafts.sendSuccess":"¡Borrador enviado con éxito!","drafts.sendError":"Error al enviar el borrador","drafts.dismissSuccess":"Borrador descartado","drafts.loadError":"Error al cargar borradores","drafts.compose":"Redactar Borrador","drafts.feedback":"¿Qué está mal?","drafts.editPlaceholder":"Escribe tu respuesta en Markdown...","login.title":"Bienvenido de nuevo","login.subtitle":"Inicia sesión en tu agente de email con IA","login.email":"Dirección de correo electrónico","login.password":"Contraseña","login.signIn":"Iniciar sesión","login.noAccount":"¿No tienes una cuenta?","login.alreadyHaveAccount":"¿Ya tienes una cuenta?","login.signUp":"Registrarse","login.forgotPassword":"¿Olvidaste tu contraseña?","login.initialize":"Inicializar Automator","login.secureLogin":"Inicio de sesión seguro","login.firstNamePlaceholder":"Juan","login.lastNamePlaceholder":"Pérez","login.emailPlaceholder":"admin@automator.ai","login.initializeMaster":"Inicializar maestro","login.sendMagicLink":"Enviar enlace mágico","login.openDashboard":"Abrir panel de control","login.resetConnection":"Restablecer conexión","login.resetConfirm":"¿Está seguro de que desea restablecer la conexión? Deberá volver a ingresar sus credenciales de Supabase.","setup.title":"Configuración del sistema","setup.initiation":"Bienvenido","setup.coordinates":"Detalles de conexión","setup.foundation":"Configuración de base de datos","setup.ignition":"Lanzamiento","setup.start":"Iniciar configuración","setup.welcomeTitle":"Inicializando Automator","setup.welcomeSubtitle":"Configurando tu entorno especializado para inteligencia de bandeja de entrada de alta frecuencia.","setup.encryptedTitle":"Encriptado","setup.encryptedDesc":"Seguridad de datos autoalojados.","setup.turboTitle":"Turbo","setup.turboDesc":"Inferencia de IA en menos de un segundo.","setup.getStarted":"Comenzar","setup.connectionMode":"Modo de conexión","setup.selectVector":"Seleccionar modo de implementación","setup.quickIgnition":"Inicio rápido","setup.autoProvision":"Aprovisionamiento automático mediante token","setup.manualSync":"Sincronización manual","setup.existingCredentials":"Credenciales existentes","setup.abortAccess":"Abortar acceso","setup.injectCoordinates":"Ingresar credenciales existentes","setup.platformUrl":"URL de la plataforma","setup.urlHelp":"Ingrese la URL completa o solo el ID del proyecto","setup.anonMatrixKey":"Clave anónima de Supabase","setup.keyHelp":"Se encuentra en la configuración de tu proyecto Supabase","setup.back":"Atrás","setup.engage":"Conectar","setup.installation":"Instalación","setup.applyingSchema":"Configurando base de datos...","setup.emptyProject":"Proyecto vacío detectado. La inicialización es obligatoria para instalar los sistemas de IA principales.","setup.versionMismatch":"Incompatibilidad de versión detectada. Se recomienda normalización.","setup.tokenRequired":"Token de gestión requerido","setup.migrateHelp":"Se usa una vez para ejecutar migraciones en tu backend.","setup.bypassRisk":"Omitir (Arriesgado)","setup.installSystems":"Instalar sistemas","setup.normalizeSystem":"Normalizar sistema","setup.retryInstallation":"Reintentar instalación","setup.agent.systemInstruction":'Eres el asistente del Asistente de configuración. Guía al usuario para conectar Supabase, elegir un modo de configuración y completar las migraciones. Pide solo el siguiente dato requerido y ofrece pasos claros. Si el usuario dice "ayúdame a configurar", enumera inmediatamente los pasos de este asistente.',"agent.intro.setup":`👋 ¡Bienvenido a la configuración! Puedo ayudarte a:
2
2
  • Elegir Inicio rápido o configuración manual
3
3
  • Conectar tu proyecto de Supabase
4
4
  • Ejecutar migraciones de base de datos
@@ -1,4 +1,4 @@
1
- const e={"app.name":"Email Automator","app.connecting":"Connexion du compte...","app.loadingWorkspace":"Chargement de votre espace de travail...","app.loggedOut":"Déconnexion réussie","app.statusLive":"EN DIRECT","app.statusOffline":"HORS LIGNE","common.loading":"Chargement...","common.save":"Enregistrer les modifications","common.cancel":"Annuler","common.delete":"Supprimer","common.success":"Succès","common.error":"Erreur","common.warning":"Avertissement","common.syncNow":"Synchroniser maintenant","common.syncing":"Synchronisation...","common.stopSync":"Arrêter la synchronisation","common.systemSync":"Synchronisation système","common.viewLogs":"Voir les journaux","common.saveChanges":"Enregistrer les modifications","common.errorOccurred":"Une erreur s'est produite","common.previous":"Précédent","common.next":"Suivant","common.of":"sur","common.yes":"Oui","common.no":"Non","common.archive":"Archiver","common.flag":"Marquer","common.on":"Activé","common.off":"Désactivé","common.enabled":"Activé","common.disabled":"Désactivé","common.active":"Actif","common.inactive":"Inactif","common.draft":"Brouillon","common.star":"Étoile","nav.dashboard":"Tableau de bord","nav.drafts":"Brouillons","nav.autopilot":"Pilote automatique","nav.analytics":"Analytique","nav.configuration":"Configuration","nav.accountSettings":"Paramètres du compte","nav.signOut":"Se déconnecter","drafts.title":"Centre de révision des brouillons","drafts.pending":"brouillons en attente","drafts.noDrafts":"Aucun brouillon en attente","drafts.noDraftsDesc":"Les réponses brouillons générées par l'IA apparaîtront ici pour votre révision","drafts.send":"Envoyer maintenant","drafts.preview":"Aperçu","drafts.dismiss":"Ignorer","drafts.regenerate":"Régénérer","drafts.selectAll":"Tout sélectionner","drafts.sendSelected":"Envoyer la sélection","drafts.dismissSelected":"Ignorer la sélection","drafts.filterByAccount":"Tous les comptes","drafts.filterByDate":"Filtrer par date","drafts.originalEmail":"Email original","drafts.aiReply":"Réponse générée par l'IA","drafts.createdBy":"Créé par la règle :","drafts.sendSuccess":"Brouillon envoyé avec succès !","drafts.sendError":"Échec de l'envoi du brouillon","drafts.dismissSuccess":"Brouillon ignoré","drafts.loadError":"Échec du chargement des brouillons","drafts.compose":"Rédiger un brouillon","drafts.feedback":"Quel est le problème ?","drafts.editPlaceholder":"Écrivez votre réponse en Markdown...","login.title":"Bienvenue","login.subtitle":"Connectez-vous à votre agent email IA","login.email":"Adresse e-mail","login.password":"Mot de passe","login.signIn":"Se connecter","login.noAccount":"Vous n'avez pas de compte ?","login.alreadyHaveAccount":"Vous avez déjà un compte ?","login.signUp":"S'inscrire","login.forgotPassword":"Mot de passe oublié ?","login.initialize":"Initialiser Automator","login.secureLogin":"Connexion sécurisée","login.firstNamePlaceholder":"Jean","login.lastNamePlaceholder":"Dupont","login.emailPlaceholder":"admin@automator.ai","login.initializeMaster":"Initialiser le maître","login.sendMagicLink":"Envoyer le lien magique","login.openDashboard":"Ouvrir le tableau de bord","setup.title":"Configuration du système","setup.initiation":"Bienvenue","setup.coordinates":"Détails de connexion","setup.foundation":"Configuration de la base de données","setup.ignition":"Lancement","setup.start":"Démarrer la configuration","setup.welcomeTitle":"Initialisation d'Automator","setup.welcomeSubtitle":"Configuration de votre environnement spécialisé pour l'intelligence de boîte de réception haute fréquence.","setup.encryptedTitle":"Chiffré","setup.encryptedDesc":"Sécurité des données auto-hébergées.","setup.turboTitle":"Turbo","setup.turboDesc":"Inférence IA en moins d'une seconde.","setup.getStarted":"Commencer","setup.connectionMode":"Mode de connexion","setup.selectVector":"Sélectionner le mode de déploiement","setup.quickIgnition":"Démarrage rapide","setup.autoProvision":"Provisionnement automatique via jeton","setup.manualSync":"Synchronisation manuelle","setup.existingCredentials":"Identifiants existants","setup.abortAccess":"Abandonner l'accès","setup.injectCoordinates":"Entrer les identifiants existants","setup.platformUrl":"URL de la plateforme","setup.urlHelp":"Entrez l'URL complète ou uniquement l'ID du projet","setup.anonMatrixKey":"Clé anonyme Supabase","setup.keyHelp":"Trouvée dans les paramètres de votre projet Supabase","setup.back":"Retour","setup.engage":"Connecter","setup.installation":"Installation","setup.applyingSchema":"Configuration de la base de données...","setup.emptyProject":"Projet vide détecté. L'initialisation est obligatoire pour installer les systèmes IA de base.","setup.versionMismatch":"Incompatibilité de version détectée. Normalisation recommandée.","setup.tokenRequired":"Jeton de gestion requis","setup.migrateHelp":"Utilisé une fois pour exécuter les migrations sur votre backend.","setup.bypassRisk":"Contourner (Risqué)","setup.installSystems":"Installer les systèmes","setup.normalizeSystem":"Normaliser le système","setup.retryInstallation":"Réessayer l'installation","setup.agent.systemInstruction":"Vous êtes l'assistant du guide de configuration. Aidez l'utilisateur à connecter Supabase, choisir un mode de configuration et terminer les migrations. Ne demandez que l'information suivante nécessaire et fournissez des étapes claires. Si l'utilisateur dit « aide-moi à configurer », listez immédiatement les étapes de ce guide.","agent.intro.setup":`👋 Bienvenue dans la configuration ! Je peux vous aider à :
1
+ const e={"app.name":"Email Automator","app.connecting":"Connexion du compte...","app.loadingWorkspace":"Chargement de votre espace de travail...","app.loggedOut":"Déconnexion réussie","app.statusLive":"EN DIRECT","app.statusOffline":"HORS LIGNE","common.loading":"Chargement...","common.save":"Enregistrer les modifications","common.cancel":"Annuler","common.delete":"Supprimer","common.success":"Succès","common.error":"Erreur","common.warning":"Avertissement","common.syncNow":"Synchroniser maintenant","common.syncing":"Synchronisation...","common.stopSync":"Arrêter la synchronisation","common.systemSync":"Synchronisation système","common.viewLogs":"Voir les journaux","common.saveChanges":"Enregistrer les modifications","common.errorOccurred":"Une erreur s'est produite","common.previous":"Précédent","common.next":"Suivant","common.of":"sur","common.yes":"Oui","common.no":"Non","common.archive":"Archiver","common.flag":"Marquer","common.on":"Activé","common.off":"Désactivé","common.enabled":"Activé","common.disabled":"Désactivé","common.active":"Actif","common.inactive":"Inactif","common.draft":"Brouillon","common.star":"Étoile","nav.dashboard":"Tableau de bord","nav.drafts":"Brouillons","nav.autopilot":"Pilote automatique","nav.analytics":"Analytique","nav.configuration":"Configuration","nav.accountSettings":"Paramètres du compte","nav.signOut":"Se déconnecter","drafts.title":"Centre de révision des brouillons","drafts.pending":"brouillons en attente","drafts.noDrafts":"Aucun brouillon en attente","drafts.noDraftsDesc":"Les réponses brouillons générées par l'IA apparaîtront ici pour votre révision","drafts.send":"Envoyer maintenant","drafts.preview":"Aperçu","drafts.dismiss":"Ignorer","drafts.regenerate":"Régénérer","drafts.selectAll":"Tout sélectionner","drafts.sendSelected":"Envoyer la sélection","drafts.dismissSelected":"Ignorer la sélection","drafts.filterByAccount":"Tous les comptes","drafts.filterByDate":"Filtrer par date","drafts.originalEmail":"Email original","drafts.aiReply":"Réponse générée par l'IA","drafts.createdBy":"Créé par la règle :","drafts.sendSuccess":"Brouillon envoyé avec succès !","drafts.sendError":"Échec de l'envoi du brouillon","drafts.dismissSuccess":"Brouillon ignoré","drafts.loadError":"Échec du chargement des brouillons","drafts.compose":"Rédiger un brouillon","drafts.feedback":"Quel est le problème ?","drafts.editPlaceholder":"Écrivez votre réponse en Markdown...","login.title":"Bienvenue","login.subtitle":"Connectez-vous à votre agent email IA","login.email":"Adresse e-mail","login.password":"Mot de passe","login.signIn":"Se connecter","login.noAccount":"Vous n'avez pas de compte ?","login.alreadyHaveAccount":"Vous avez déjà un compte ?","login.signUp":"S'inscrire","login.forgotPassword":"Mot de passe oublié ?","login.initialize":"Initialiser Automator","login.secureLogin":"Connexion sécurisée","login.firstNamePlaceholder":"Jean","login.lastNamePlaceholder":"Dupont","login.emailPlaceholder":"admin@automator.ai","login.initializeMaster":"Initialiser le maître","login.sendMagicLink":"Envoyer le lien magique","login.openDashboard":"Ouvrir le tableau de bord","login.resetConnection":"Réinitialiser la connexion","login.resetConfirm":"Êtes-vous sûr de vouloir réinitialiser la connexion ? Vous devrez saisir à nouveau vos identifiants Supabase.","setup.title":"Configuration du système","setup.initiation":"Bienvenue","setup.coordinates":"Détails de connexion","setup.foundation":"Configuration de la base de données","setup.ignition":"Lancement","setup.start":"Démarrer la configuration","setup.welcomeTitle":"Initialisation d'Automator","setup.welcomeSubtitle":"Configuration de votre environnement spécialisé pour l'intelligence de boîte de réception haute fréquence.","setup.encryptedTitle":"Chiffré","setup.encryptedDesc":"Sécurité des données auto-hébergées.","setup.turboTitle":"Turbo","setup.turboDesc":"Inférence IA en moins d'une seconde.","setup.getStarted":"Commencer","setup.connectionMode":"Mode de connexion","setup.selectVector":"Sélectionner le mode de déploiement","setup.quickIgnition":"Démarrage rapide","setup.autoProvision":"Provisionnement automatique via jeton","setup.manualSync":"Synchronisation manuelle","setup.existingCredentials":"Identifiants existants","setup.abortAccess":"Abandonner l'accès","setup.injectCoordinates":"Entrer les identifiants existants","setup.platformUrl":"URL de la plateforme","setup.urlHelp":"Entrez l'URL complète ou uniquement l'ID du projet","setup.anonMatrixKey":"Clé anonyme Supabase","setup.keyHelp":"Trouvée dans les paramètres de votre projet Supabase","setup.back":"Retour","setup.engage":"Connecter","setup.installation":"Installation","setup.applyingSchema":"Configuration de la base de données...","setup.emptyProject":"Projet vide détecté. L'initialisation est obligatoire pour installer les systèmes IA de base.","setup.versionMismatch":"Incompatibilité de version détectée. Normalisation recommandée.","setup.tokenRequired":"Jeton de gestion requis","setup.migrateHelp":"Utilisé une fois pour exécuter les migrations sur votre backend.","setup.bypassRisk":"Contourner (Risqué)","setup.installSystems":"Installer les systèmes","setup.normalizeSystem":"Normaliser le système","setup.retryInstallation":"Réessayer l'installation","setup.agent.systemInstruction":"Vous êtes l'assistant du guide de configuration. Aidez l'utilisateur à connecter Supabase, choisir un mode de configuration et terminer les migrations. Ne demandez que l'information suivante nécessaire et fournissez des étapes claires. Si l'utilisateur dit « aide-moi à configurer », listez immédiatement les étapes de ce guide.","agent.intro.setup":`👋 Bienvenue dans la configuration ! Je peux vous aider à :
2
2
  • Choisir un démarrage rapide ou une configuration manuelle
3
3
  • Connecter votre projet Supabase
4
4
  • Exécuter les migrations de base de données