Middleware y Events

Amplía Transport, Endpoint, Service y los módulos colaborativos mediante Middleware y Events de propósito general.

Middleware y Events son puntos de extensión generales de Collaboration SDK. La identidad y la autorización se integran con Middleware. Úsalo para validar y restringir antes de una operación; usa Events para registrar cambios o iniciar tareas tras confirmar el estado. Ambos admiten registros, trazabilidad, métricas y actualizaciones de estado derivado.

Dos momentos de extensión

MiddlewareEvent
EjecuciónDurante una operaciónTras confirmar un cambio de estado
Participar o rechazar la operaciónSíNo
Ampliar el ContextSíLee el Context y resultado del Event
Fallo del receptorPuede fallar la operación actualAislado del resultado de dominio ya determinado
Usos habitualesIdentidad, autorización, validación, registro, medición de tiempoÍndices derivados, cachés, métricas, notificaciones internas

Usa Middleware para decidir si una operación puede continuar; Event para observar que un cambio ya ocurrió.

Modelo de ejecución de Middleware

Los Middleware de una Action forman una cadena asíncrona en orden de registro. await next() entra en el siguiente Middleware y la operación del SDK se ejecuta en el punto más interno:

TypeScript
service.use("submitChangeset", async (context, next) => {  const startedAt = performance.now();  context.customData.startedAt = startedAt;  try {    await next();  } finally {    metrics.observe("collaboration.submit.duration", performance.now() - startedAt);  }});

Middleware puede:

  • leer la solicitud específica de la Action;
  • compartir datos locales de la llamada con customData;
  • inspeccionar entradas o consultar sistemas antes de next();
  • registrar duración o resultados tras volver de next();
  • lanzar CollabError para rechazar una operación colaborativa prevista.

El Middleware HTTP de Transport puede terminar la respuesta sin llamar a next(). Los de Service y Endpoint deben rechazar con un error explícito en vez de omitir next() silenciosamente.

Middleware de Transport

transport.use() registra Middleware HTTP ordinario, que se ejecuta en orden de registro. Llama a await next() para continuar el procesamiento o finaliza la respuesta directamente. transport.useUpgrade() gestiona los protocolos de enlace WebSocket.

Por ejemplo, registra la duración HTTP, autentica y establece un userID de confianza y, después, registra el Collaboration Endpoint:

TypeScript
transport.use(async (context, next) => {  const start = performance.now();  context.response.once("finish", () => {    recordHttpDuration({      method: context.incomingMessage.method,      route: context.route?.path ?? "unmatched",      status: context.response.statusCode,      durationMs: performance.now() - start,    });  });  await next();});transport.use(async (context, next) => {  const user = await authenticate(context.incomingMessage);  if (!user) {    context.response.statusCode = 401;    context.response.end("Authentication required");    return;  }  context.userID = user.userId;  await next();});transport.register(collaborationEndpoint);

La aplicación proporciona recordHttpDuration y authenticate. Endpoint utiliza el userID establecido por los Middleware anteriores. El Middleware de observación se registra antes de la autenticación, por lo que también se registran los rechazos.

context.route?.path es la plantilla completa de la ruta coincidente, disponible cuando la ejecución llega al Endpoint. Usa el evento finish de la respuesta para medir el tiempo hasta su finalización; los rechazos anteriores a la resolución de la ruta y las rutas desconocidas se registran como unmatched.

Middleware de Endpoint

Participa en operaciones de Session en tiempo real y Presence:

ActionMomentoUsos habituales
connectTras consumir el ticket y crear Session, antes de HELLOPolítica de conexión, nombre y avatar del miembro
joinUnitAntes de entrar en una Room UnitAdmisión y visibilidad de la Unit
receivePresenceTras recibir Presence de una Session unida, antes de difundirValidación y filtrado de Presence
sendPresenceAntes de enviar Presence a cada miembroFiltrado por destinatario
TypeScript
endpoint.use("receivePresence", async (context, next) => {  if (JSON.stringify(context.payload).length > 8_000) {    throw new CollabError("INVALID_REQUEST", "Presence payload is too large");  }  await next();});

session.userID y session.customData de Endpoint proceden de la solicitud HTTP que emitió el Session Ticket. Endpoint crea memberID para la Session WebSocket actual; cambia al reconectar.

Middleware de Service

Participa en el ciclo de vida de los datos colaborativos autoritativos:

ActionLímiteUsos habituales
readUnitDataAntes de leer instantáneas, bloques o cambiosLectura, comprobación de inquilino, auditoría
createUnitAntes de crear una Unit atómicamenteTipos, política de creación, reglas de negocio
deleteUnitsAntes de escribir el lote de eliminaciónPolítica de eliminación y comprobaciones por Unit
recoverUnitsAntes de escribir el lote de recuperaciónPolítica de recuperación y auditoría
submitChangesetAntes de idempotencia y OT del envío lógicoEdición, límite de tamaño total, trazas
applyChangesetAntes de aplicar los cambios transformados al estado candidatoValidación por mutación
commitChangesetAntes del CAS de revisión y commit del AdapterReglas finales de revisión y métricas
TypeScript
service.use("createUnit", async (context, next) => {  await creationPolicy.assertAllowed({    userID: context.userID,    unitID: context.request.snapshot.unitID,    type: context.request.snapshot.type,  });  context.customData.creationPolicyChecked = true;  await next();});

submitChangeset se ejecuta una vez por envío lógico. La contención de revisiones puede repetir applyChangeset y commitChangeset con otro attempt. Esos Middleware deben ser seguros ante reintentos y no enviar directamente mensajes externos irreversibles ni efectuar cobros de una sola vez.

Alcance de customData

customData es un objeto escribible por la aplicación y local a la llamada, apropiado para:

  • ID de inquilino, trazas o registradores de solicitudes;
  • consultas ACL reutilizadas en la llamada;
  • puntos de inicio de medición o etiquetas de auditoría;
  • objetos de negocio compartidos por una cadena Middleware.

HTTP ordinario, llamadas Service y Sessions WebSocket tienen ciclos de vida distintos. customData no se persiste, envía al navegador ni registra automáticamente. Los datos duraderos siguen en el almacenamiento de la aplicación.

Modelo de ejecución de Events

Los Services registran receptores locales al proceso con on(), que devuelve una suscripción liberable:

TypeScript
const subscription = service.on("changesetCommitted", async (event) => {  metrics.increment("collaboration.changeset.committed", {    unitType: String(event.changeset.type),  });  localCache.delete(event.changeset.unitID);});subscription.dispose();

Los receptores del mismo Event se ejecutan secuencialmente en orden de registro y se espera su finalización. Sus errores se registran y aíslan del resultado de dominio ya determinado. Por ejemplo, un fallo de changesetCommitted no revierte cambios ya guardados por Adapter.

Events es adecuado para tareas internas, recuperables o no críticas. No comparte un límite transaccional con el commit de la base ni garantiza la entrega a sistemas externos.

Events del Service principal

EventHecho confirmadoUso habitual
unitCreatedUnit y datos iniciales creadosCaché de catálogo local o índice derivado
changesetCommittedCambios confirmados y revisión avanzadaDifusión, métricas, índices derivados
unitsDeletedAdapter confirmó el lote de eliminaciónLimpiar estado relacionado del proceso
unitsRecoveredAdapter confirmó el lote de recuperaciónRestaurar estado derivado del proceso

Endpoint escucha changesetCommitted en el mismo Service y difunde los cambios confirmados a los clientes unidos a la Unit en el proceso actual, o en todos los nodos cuando hay un adaptador pub/sub configurado. También expone memberLeftUnit para salida explícita, desconexión y liberación del Endpoint.

Las extensiones tienen puntos independientes

History, Thread Comment y Worktree no heredan Middleware ni Events del Collaboration Service principal:

  • History proporciona Middleware de lectura para getHistoryList, listHistoryCreators y getHistoryChangesets;
  • Comment proporciona añadir, responder, editar, eliminar, resolver y listar, más commentCommitted;
  • Worktree proporciona ciclo de vida y lectura/envío/commit de borradores, más Events de creación, estado, fusión y commit de borrador.

Instala las reglas por separado en cada módulo activo. El Middleware de registro, inquilino o autorización del Service principal no los cubre automáticamente.

Continúa con Identidad y autorización para asociar usuarios y ACL existentes con estos límites generales.

¿Cómo es esta guía?

© 2026 DreamNum Co., Ltd.