diff --git a/src/backend/clients/event/types.ts b/src/backend/clients/event/types.ts index f9c65f7ace..27387de960 100644 --- a/src/backend/clients/event/types.ts +++ b/src/backend/clients/event/types.ts @@ -204,6 +204,13 @@ export type EventMap = { // ---- Subdomains ---- 'subdomain.delete': { subdomain: string }; 'subdomain.update': { subdomain: string }; + 'site.htmlServed': { + subdomain: string; + entry: unknown; + host: string; + requestPath: string; + mime: string; + }; // ---- Thumbnails ---- 'thumbnail.read': { diff --git a/src/backend/core/http/middleware/puterSite.ts b/src/backend/core/http/middleware/puterSite.ts index 457090f8b1..6e60ae4274 100644 --- a/src/backend/core/http/middleware/puterSite.ts +++ b/src/backend/core/http/middleware/puterSite.ts @@ -21,9 +21,9 @@ import type { RequestHandler } from 'express'; import { contentType as contentTypeFromMime } from 'mime-types'; import { posix as pathPosix } from 'node:path'; import type { puterClients } from '../../../clients'; +import { FS_COSTS } from '../../../controllers/fs/costs'; import type { puterServices } from '../../../services'; import type { puterStores } from '../../../stores'; -import { FS_COSTS } from '../../../controllers/fs/costs'; import type { IConfig, LayerInstances } from '../../../types'; import { buildAppCenterFallback, @@ -495,6 +495,25 @@ export const createPuterSiteMiddleware = ( const mime = contentTypeFromMime(entry.name) || 'application/octet-stream'; res.setHeader('Content-Type', mime); + + // Fire-and-forget signal for downstream extensions + if (mime === 'text/html' || mime === 'application/xhtml+xml') { + try { + layers.clients.event.emit( + 'site.htmlServed', + { + subdomain, + entry, + host, + requestPath: req.path, + mime, + }, + {}, + ); + } catch (e) { + console.warn('[puter-site] site.htmlServed emit failed', e); + } + } if (download.contentLength !== null) { res.setHeader('Content-Length', String(download.contentLength)); }