Saltar al contenido principal

Resumen

Cada aplicación debe tener exactamente una llamada a defineApplication. Declara:
  • Identidad — identificador universal, nombre para mostrar, descripción.
  • Permisos — bajo qué rol se ejecutan sus funciones de lógica y componentes de frontend.
  • Capacidades multimedia (opcional): acceso al micrófono o a la cámara solicitado por los componentes frontales, aprobado por separado de los permisos de rol.
  • Variables (opcionales) — pares clave–valor expuestos a tu código como variables de entorno.
  • Hooks de preinstalación / posinstalación / desinstalación (opcionales) — consulta Funciones de lógica.
  • Facturación (opcional) — billing.recurring para las tarifas de suscripción que la plataforma cobra automáticamente, billing.operations para aquello por lo que tu aplicación cobra créditos y billing.description para el mercado; consulta Cobro de créditos.
src/application-config.ts
Notas:
  • Los campos universalIdentifier son UUID que generas una vez y te pertenecen. Manténlos estables entre sincronizaciones. El universalIdentifier propio de la aplicación debe ser un UUID válido: el servidor rechaza un manifiesto cuyo identificador no es un UUID válido. Es único en toda la instancia y está vinculado al espacio de trabajo propietario de su registro, por lo que solo ese espacio de trabajo puede sincronizar la aplicación; consulta Propiedad del registro.
  • applicationVariables acepta una label opcional: un nombre fácil de usar que se muestra en la página de configuración de la aplicación en lugar de la clave de variable sin procesar.
  • applicationVariables se convierten en variables de entorno para tus funciones y componentes de frontend. En las funciones lógicas (del lado del servidor), están disponibles como process.env.VARIABLE_NAME. En los componentes de frontend, usa getApplicationVariable('VARIABLE_NAME') de twenty-sdk/front-component. Las variables marcadas con isSecret: true solo se inyectan en las funciones lógicas. Los componentes de frontend solo reciben variables no secretas. Una variable con scope: 'USER' contiene el valor del miembro para el que se ejecuta el código: consulta Variables de espacio de trabajo y de usuario.
  • Tu aplicación también puede leer y actualizar los valores de sus propias variables en tiempo de ejecución, que es la forma en que un componente de configuración personalizado guarda lo que escribió el usuario: consulta Lectura y actualización de variables en tiempo de ejecución. Una aplicación solo puede acceder a sus propias variables, en su propio espacio de trabajo.
  • El rol predeterminado se detecta automáticamente a partir del archivo de rol marcado con defineApplicationRole(); no necesitas hacer referencia a él desde defineApplication().
  • Las funciones de preinstalación, posinstalación y desinstalación, y las comprobaciones de estado, se detectan automáticamente durante la compilación del manifiesto; no necesitas referenciarlas en defineApplication().
  • Pasar defaultRoleUniversalIdentifier explícitamente sigue siendo compatible por motivos de retrocompatibilidad, pero está en desuso en favor de defineApplicationRole().
  • serverVariables son configuraciones y secretos con ámbito de instancia (por ejemplo, claves de API). A diferencia de applicationVariables, no declaran ningún valor en el manifiesto: el operador del espacio de trabajo los completa desde la configuración de la aplicación, y se inyectan en las funciones lógicas solo una vez que se han establecido.
  • Una aplicación puede informar de su propio estado de configuración con defineHealthCheck(), para aquello que solo la aplicación puede saber: una clave que está presente pero revocada, una cuenta de terceros con el plan incorrecto. isRequired cubre lo que Twenty puede ver por sí mismo; la comprobación de estado cubre el resto. Establece runOnUserPreferences: true para comprobar la configuración propia de cada miembro en su página de preferencias de Apps en lugar de en la configuración de la app del espacio de trabajo. Omitir la opción o establecerla en false mantiene la comprobación existente del espacio de trabajo.
  • Ambos tipos de variable aceptan isRequired: true. Una variable obligatoria que el espacio de trabajo aún no ha rellenado deja la aplicación sin configurar: su página de configuración muestra un banner que indica las variables que faltan, con un botón que salta a la pestaña donde se configuran. Marca como obligatorio solo lo que la aplicación realmente no puede ejecutar sin ello; una variable opcional con un valor predeterminado razonable debe seguir siendo opcional.
  • Ambos tipos de variable aceptan isDeprecated: true. Úsala para retirar una variable en lugar de eliminarla: mantener la clave declarada conserva el valor almacenado (eliminarla destruye el valor que el operador introdujo), y la variable sigue siendo inyectada, por lo que tu código puede recurrir a ella — process.env.NEW_API_KEY ?? process.env.API_KEY. Una variable obsoleta desaparece de la configuración de la app una vez que no tiene ningún valor y nunca cuenta para la verificación de configuración de la app, por lo que isDeprecated tiene prioridad sobre isRequired.
  • Twenty establece estos nombres para cada ejecución de función lógica, por lo que están reservados: TWENTY_API_URL, TWENTY_APP_ACCESS_TOKEN, TWENTY_APP_APPLICATION_ACCESS_TOKEN, TWENTY_API_KEY, TWENTY_FUNCTIONS_URL, TWENTY_SERVER_ROUTES_URL y APPLICATION_ID. También se reserva cualquier otro nombre que comience con TWENTY_, para las variables que Twenty agregue más adelante. Un manifiesto que declara un nombre reservado como variable de aplicación o servidor se rechaza cuando la aplicación se sincroniza o publica.
  • Para añadir tus propias entradas al menú de configuración de la aplicación (en lugar de la página Variables generada), declara un componente de frontend y apunta un defineSettingsMenuItem() a él, en su propio archivo. Declara tantos como necesites y ordénalos con position; scope coloca un elemento en la configuración del espacio de trabajo o en la configuración propia de cada miembro. El elemento General administrado por el sistema (actualización automática, URL de la app, conexiones) siempre aparece primero, y la URL de la app solo se muestra cuando la app tiene funciones activadas mediante HTTP.

Capacidades multimedia solicitadas

Establece requestedCapabilities cuando un componente frontal use navigator.mediaDevices.getUserMedia(). La matriz opcional acepta 'microphone', 'camera' o ambos. Omítela o usa una matriz vacía cuando la aplicación no necesite captura multimedia.
Las capacidades declaradas aparecen durante la instalación. La aprobación requiere un miembro del espacio de trabajo que pueda administrar aplicaciones y se aplica a todo el espacio de trabajo. Estas concesiones son independientes de los permisos de rol de la aplicación y no sustituyen los permisos del navegador ni del sistema operativo. Una aplicación instalada sin la concesión requerida pausa la captura y muestra un cuadro de diálogo de aprobación en el primer uso, incluidas las aplicaciones antiguas sin declaraciones de capacidades. Rechazarla mantiene la captura bloqueada antes de que se soliciten los permisos del navegador. Las actualizaciones de paquetes no conceden automáticamente acceso adicional. Las aplicaciones de desarrollo sincronizadas localmente reciben las capacidades declaradas en su manifiesto. Consulta Captura multimedia para conocer el comportamiento de la captura y los indicadores de grabación.

Acceso a medios de sitios web incrustados

Establezca requestedIframeMediaPermissions cuando un componente frontal o un widget de diseño de página IFRAME incruste un sitio web que necesite el micrófono o la cámara, como una herramienta de teléfono o vídeo. Enumere hasta 20 sitios web, cada uno como un origen HTTPS exacto, con el acceso al micrófono y a la cámara configurado por separado. Los orígenes deben ser únicos, no contener rutas ni comodines y solicitar acceso al menos al micrófono o a la cámara.
Los sitios web declarados aparecen durante la instalación. La aprobación requiere un miembro del espacio de trabajo que pueda administrar aplicaciones y se aplica a todo el espacio de trabajo, para los propios componentes frontales y widgets iframe de la aplicación. Las aprobaciones de seguridad del espacio de trabajo se aplican solo a los widgets creados en el espacio de trabajo. Las aplicaciones de desarrollo sincronizadas localmente reciben los sitios web declarados en su manifiesto. Estas autorizaciones no sustituyen los permisos del navegador ni del sistema operativo. Las cabeceras del navegador tienen un límite de tamaño, por lo que, si los sitios web de un espacio de trabajo lo superan, los sitios web aprobados por el espacio de trabajo tienen prioridad y los sitios web restantes no reciben acceso a medios. Las actualizaciones de las aplicaciones publicadas conservan las autorizaciones existentes y no conceden automáticamente acceso adicional a medios. Para aprobar nuevas solicitudes, un miembro que pueda administrar aplicaciones abre la pestaña General de la aplicación instalada y selecciona Revisar acceso a medios en Acceso a medios de sitios web incrustados. Esta aprobación utiliza una confirmación nativa del navegador que muestra la aplicación, los orígenes de los sitios web y el acceso solicitado al micrófono o a la cámara. Después de aprobar, vuelva a cargar las pestañas abiertas de Twenty para aplicar los permisos actualizados. Consulte Sitios web incrustados con acceso a medios para conocer los requisitos de iframe.

Tipos de variables

Tanto applicationVariables como serverVariables aceptan un type opcional (y, para SELECT / MULTI_SELECT, una lista de options). Tipos admitidos: TEXT (predeterminado), BOOLEAN, NUMBER, NUMERIC, DATE, DATE_TIME, SELECT, MULTI_SELECT, ARRAY, RAW_JSON, RICH_TEXT.
src/application-config.ts
El type solo afecta a la presentación y validación: selecciona la entrada correspondiente en la interfaz de configuración del espacio de trabajo (un interruptor, campo numérico, lista desplegable, selector de fecha, editor JSON, …) y permite que la compilación valide tu configuración (por ejemplo, SELECT / MULTI_SELECT deben declarar options no vacías). No cambia cómo el valor llega a tu código. Los valores siempre se inyectan como cadenas; esto es inherente a las variables de entorno (process.env.* solo admite cadenas). Cuando se ejecuta tu función lógica, el ejecutor serializa cada valor según su type declarado al construir process.env, por lo que el formato de cadena es coherente independientemente de cómo se haya establecido el valor (valor predeterminado del manifiesto, interfaz de configuración o una versión anterior): Analiza la cadena para volver al tipo que esperas:
Lo mismo se aplica a los componentes de interfaz que leen valores mediante getApplicationVariable('VARIABLE_NAME'): el valor devuelto es una cadena; analízalo según sea necesario.

Variables de espacio de trabajo y de usuario

Cada variable de aplicación tiene un scope:
  • WORKSPACE (predeterminado): un valor para todo el espacio de trabajo, establecido por un miembro que puede administrar aplicaciones.
  • USER: cada miembro conserva su propio valor.
src/application-config.ts
El value de una variable de usuario es su valor predeterminado: un miembro que no haya establecido el suyo lo lee, y una nueva versión de tu aplicación puede cambiarlo. Una variable secreta no puede tener un valor predeterminado. Sin uno, un miembro que no haya establecido el suyo lee una cadena vacía, por lo que tu aplicación decide qué significa un valor no establecido. Un administrador del espacio de trabajo no puede establecer un valor para una variable de usuario: sus valores pertenecen a cada miembro. El ámbito de una variable se establece al crearla y no puede cambiar. Para cambiarla, declara la variable con un nuevo universalIdentifier: la sincronización elimina la variable anterior, con los valores de sus miembros, y crea la nueva. Las variables de usuario pueden ser isSecret, isRequired o ambas. Por ejemplo, una clave de API personal puede declarar scope: 'USER', isSecret: true, isRequired: true. Los valores se cifran en reposo. Para las variables de usuario, isRequired describe un requisito por miembro. Un miembro que no tenga ningún valor para ella, ni uno propio ni uno predeterminado, verá tu aplicación marcada como Falta configuración en las preferencias de Apps, con un banner que indica las variables. No afecta a la advertencia de configuración del espacio de trabajo, y no se aplica nada en tiempo de ejecución: su código sigue decidiendo qué significa un valor no establecido. Una variable de usuario se inyecta con el valor del miembro para el que se ejecuta tu código, o con su valor predeterminado hasta que establezca el suyo:
  • En una función lógica, process.env contiene los valores del miembro que activó la ejecución, el mismo miembro como el que actúa TWENTY_APP_ACCESS_TOKEN. Una ejecución sin nadie detrás, como un trabajo cron o un hook de instalación, no obtiene ninguna variable de usuario.
  • En un componente de front-end, getApplicationVariable devuelve los valores del miembro que lo está viendo. Las variables de usuario secretas se omiten, al igual que las variables secretas del espacio de trabajo.
El miembro que activó una ejecución no siempre es el miembro del que trata: un evento de base de datos se ejecuta como quien haya editado el registro. Cuando una ejecución trata sobre otra persona o sobre todos los miembros, lee los valores con myUserApplicationVariables mediante MetadataApiClient. Enumera todos los miembros con los valores de las variables de usuario de tu aplicación y funciona en cada ejecución de función lógica, incluidos los trabajos cron y los webhooks. Cada entrada incluye userWorkspaceId, workspaceMemberId y variables del miembro: la declaración de cada variable de usuario (label, description, type, options, isSecret, isRequired, isDeprecated) y el valor del miembro, o el valor predeterminado hasta que establezca el suyo. Consúltalo como la aplicación para obtener valores reales: con un token que tiene una persona detrás, solo devuelve la entrada de esa persona, con los secretos enmascarados.
Los valores son cadenas, en el mismo formato que process.env (consulta Tipos de variables). updateMyUserApplicationVariable guarda el valor propio de un miembro. Toma el applicationUniversalIdentifier de tu aplicación y escribe el valor de la persona detrás del token: la propia sesión del miembro o el token de tu aplicación cuando hay un miembro detrás de él, como en un componente frontal o una función lógica ejecutada para un miembro. El token de tu aplicación solo puede nombrar tu propia aplicación, y se rechaza un token sin nadie detrás de él, como en una tarea cron o un hook de instalación. Un valor vacío elimina el valor propio del miembro, por lo que vuelve a leer el valor predeterminado o una cadena vacía para una variable que no tiene uno. No necesita el permiso Aplicaciones del espacio de trabajo, pero sí necesita Aplicaciones de usuario: en el rol del miembro y, cuando el token de tu aplicación realiza la llamada, también en el rol predeterminado de tu aplicación, si declara uno. Si tu aplicación guarda variables de usuario, añade SystemPermissionFlag.USER_APPS a permissionFlagUniversalIdentifiers en su rol.

Rol de función predeterminado

El rol declarado con defineApplicationRole() controla a qué pueden acceder las funciones de lógica y los componentes de interfaz de la aplicación:
  • Los tokens en tiempo de ejecución inyectados en tus funciones de lógica se derivan de este rol. Una llamada que actúa como una persona se limita aún más a lo que esa persona puede hacer, por lo que nunca puede superar ninguno de los dos. Consulta Qué acceso usa una llamada.
  • El cliente de API tipado está restringido a los permisos otorgados a ese rol.
  • Sigue el principio de mínimo privilegio: declara solo los permisos que necesitan tus funciones.
Cuando generas una nueva aplicación, la CLI crea un archivo de rol inicial en src/roles/default-role.ts. Consulta Roles y permisos para obtener la referencia completa.

Metadatos del Marketplace

Si planeas publicar tu aplicación, estos campos opcionales controlan cómo aparece en el marketplace:
logoUrl y screenshots son alias obsoletos de logo y galleryImages. Las URL absolutas externas (http:// o https://) no son compatibles para estos campos: se descartan con una advertencia en tiempo de compilación. En su lugar, incluye las imágenes en la carpeta public/ de tu aplicación.