opinionated-machine 6.14.0 → 6.15.0

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.
Files changed (30) hide show
  1. package/README.md +196 -0
  2. package/dist/lib/sse/AbstractSSEController.js +4 -3
  3. package/dist/lib/sse/AbstractSSEController.js.map +1 -1
  4. package/dist/lib/sse/index.d.ts +2 -1
  5. package/dist/lib/sse/index.js +2 -0
  6. package/dist/lib/sse/index.js.map +1 -1
  7. package/dist/lib/sse/rooms/SSERoomBroadcaster.d.ts +20 -4
  8. package/dist/lib/sse/rooms/SSERoomBroadcaster.js +44 -12
  9. package/dist/lib/sse/rooms/SSERoomBroadcaster.js.map +1 -1
  10. package/dist/lib/sse/rooms/SSERoomManager.d.ts +5 -2
  11. package/dist/lib/sse/rooms/SSERoomManager.js +8 -5
  12. package/dist/lib/sse/rooms/SSERoomManager.js.map +1 -1
  13. package/dist/lib/sse/rooms/adapters/InMemoryAdapter.d.ts +1 -1
  14. package/dist/lib/sse/rooms/adapters/InMemoryAdapter.js +1 -1
  15. package/dist/lib/sse/rooms/adapters/InMemoryAdapter.js.map +1 -1
  16. package/dist/lib/sse/rooms/index.d.ts +1 -1
  17. package/dist/lib/sse/rooms/types.d.ts +34 -2
  18. package/dist/lib/sse/subscriptions/SSESubscriptionManager.d.ts +47 -0
  19. package/dist/lib/sse/subscriptions/SSESubscriptionManager.js +298 -0
  20. package/dist/lib/sse/subscriptions/SSESubscriptionManager.js.map +1 -0
  21. package/dist/lib/sse/subscriptions/defineEventMetadata.d.ts +50 -0
  22. package/dist/lib/sse/subscriptions/defineEventMetadata.js +44 -0
  23. package/dist/lib/sse/subscriptions/defineEventMetadata.js.map +1 -0
  24. package/dist/lib/sse/subscriptions/index.d.ts +3 -0
  25. package/dist/lib/sse/subscriptions/index.js +3 -0
  26. package/dist/lib/sse/subscriptions/index.js.map +1 -0
  27. package/dist/lib/sse/subscriptions/types.d.ts +141 -0
  28. package/dist/lib/sse/subscriptions/types.js +2 -0
  29. package/dist/lib/sse/subscriptions/types.js.map +1 -0
  30. package/package.json +1 -1
package/README.md CHANGED
@@ -58,6 +58,17 @@ Very opinionated DI framework for fastify, built on top of awilix
58
58
  - [Room Query Methods](#room-query-methods)
59
59
  - [Auto-Leave on Disconnect](#auto-leave-on-disconnect)
60
60
  - [Multi-Node Deployments with Redis](#multi-node-deployments-with-redis)
61
+ - [SSE Subscriptions](#sse-subscriptions)
62
+ - [Defining Event Metadata](#defining-event-metadata)
63
+ - [Defining Resolvers](#defining-resolvers)
64
+ - [Configuring the Manager](#configuring-the-manager)
65
+ - [Integrating with a Controller](#integrating-with-a-controller)
66
+ - [Publishing Events](#publishing-events)
67
+ - [Refreshing Preferences Mid-Connection](#refreshing-preferences-mid-connection)
68
+ - [Pipeline Semantics](#pipeline-semantics)
69
+ - [Multi-Node Support](#multi-node-support)
70
+ - [Data Loading with layered-loader](#data-loading-with-layered-loader)
71
+ - [Testing](#testing)
61
72
  - [SSE Test Utilities](#sse-test-utilities)
62
73
  - [Quick Reference](#quick-reference)
63
74
  - [Inject vs HTTP Comparison](#inject-vs-http-comparison)
@@ -1803,6 +1814,191 @@ The Redis adapter uses Pub/Sub for cross-node message propagation. When you call
1803
1814
 
1804
1815
  See the [@opinionated-machine/sse-rooms-redis](./packages/sse-rooms-redis/README.md) package for detailed documentation on Redis adapter configuration and usage.
1805
1816
 
1817
+ ### SSE Subscriptions
1818
+
1819
+ SSE Subscriptions add user-centered event filtering on top of SSE Rooms. Users connect once to a universal stream, and a **resolver pipeline** determines which events reach them based on membership, preferences, and arbitrary business rules.
1820
+
1821
+ #### Defining Event Metadata
1822
+
1823
+ Define a discriminated union describing all event scopes, then create type-safe guards with `defineEventMetadata()`:
1824
+
1825
+ ```typescript
1826
+ import { defineEventMetadata } from 'opinionated-machine'
1827
+
1828
+ type EventMetadata =
1829
+ | { scope: 'project'; projectId: string }
1830
+ | { scope: 'team'; teamId: string }
1831
+ | { scope: 'global' }
1832
+
1833
+ const meta = defineEventMetadata<EventMetadata>()('scope', ['project', 'team', 'global'])
1834
+
1835
+ // In resolvers, guards narrow the type:
1836
+ if (meta.project(event.metadata)) {
1837
+ event.metadata.projectId // TypeScript knows this is string
1838
+ }
1839
+ ```
1840
+
1841
+ #### Defining Resolvers
1842
+
1843
+ Resolvers are stateless filters evaluated in pipeline order. Each resolver can `allow`, `deny`, or `defer`:
1844
+
1845
+ ```typescript
1846
+ import type { SubscriptionResolver, SubscriptionContext, FilterVerdict } from 'opinionated-machine'
1847
+
1848
+ class ProjectMembershipResolver {
1849
+ readonly name = 'project-membership'
1850
+
1851
+ async onConnect(ctx: SubscriptionContext<UserCtx>) {
1852
+ const memberships = await this.membershipLoader.get(ctx.userContext.userId)
1853
+ const projectIds = new Set(memberships.map(m => m.projectId))
1854
+ return {
1855
+ userContext: { ...ctx.userContext, projectIds },
1856
+ rooms: Array.from(projectIds).map(id => `project:${id}`),
1857
+ }
1858
+ }
1859
+
1860
+ evaluate(ctx: SubscriptionContext<UserCtx>, event: IncomingEvent<EventMetadata>): FilterVerdict {
1861
+ if (meta.project(event.metadata)) {
1862
+ return ctx.userContext.projectIds.has(event.metadata.projectId)
1863
+ ? { action: 'allow' }
1864
+ : { action: 'deny', reason: 'not a project member' }
1865
+ }
1866
+ return { action: 'defer' }
1867
+ }
1868
+
1869
+ async refresh(ctx: SubscriptionContext<UserCtx>) {
1870
+ // Re-fetch memberships on demand
1871
+ const memberships = await this.membershipLoader.get(ctx.userContext.userId)
1872
+ const projectIds = new Set(memberships.map(m => m.projectId))
1873
+ return {
1874
+ userContext: { ...ctx.userContext, projectIds },
1875
+ rooms: Array.from(projectIds).map(id => `project:${id}`),
1876
+ }
1877
+ }
1878
+ }
1879
+ ```
1880
+
1881
+ #### Configuring the Manager
1882
+
1883
+ ```typescript
1884
+ import { SSESubscriptionManager } from 'opinionated-machine'
1885
+
1886
+ const subscriptionManager = new SSESubscriptionManager<UserCtx, EventMetadata>(
1887
+ {
1888
+ resolveUserContext: async (request) => ({
1889
+ userId: request.user.id,
1890
+ projectIds: new Set(),
1891
+ mutedEventTypes: new Set(),
1892
+ }),
1893
+ resolvers: [
1894
+ new ProjectMembershipResolver(membershipLoader),
1895
+ new MutePreferencesResolver(prefsLoader),
1896
+ ],
1897
+ defaultPolicy: 'deny',
1898
+ resolveUserId: (ctx) => ctx.userId,
1899
+ },
1900
+ { sseRoomManager, sseRoomBroadcaster },
1901
+ )
1902
+ ```
1903
+
1904
+ #### Integrating with a Controller
1905
+
1906
+ Wire `handleConnect` and `handleDisconnect` into the SSE session lifecycle:
1907
+
1908
+ ```typescript
1909
+ class NotificationController extends AbstractSSEController<Contracts> {
1910
+ private handleStream = buildHandler(contract, {
1911
+ sse: (request, sse) => {
1912
+ const session = sse.start('keepAlive')
1913
+ this.subscriptionManager.handleConnect(session).catch(() => {
1914
+ // Handle connection setup failure (e.g., resolver threw)
1915
+ })
1916
+ },
1917
+ }, {
1918
+ onClose: (session) => {
1919
+ this.subscriptionManager.handleDisconnect(session)
1920
+ },
1921
+ })
1922
+ }
1923
+ ```
1924
+
1925
+ #### Publishing Events
1926
+
1927
+ ```typescript
1928
+ const result = await subscriptionManager.publish({
1929
+ eventName: 'announcement',
1930
+ data: { message: 'New feature released!' },
1931
+ targetRooms: ['project:123'],
1932
+ metadata: { scope: 'project', projectId: '123' },
1933
+ })
1934
+ // result: { delivered: 5, filtered: 2 }
1935
+ ```
1936
+
1937
+ `targetRooms` controls routing:
1938
+ - **Specific rooms** (`['project:123']`) — broadcast to those rooms, filter via resolver pipeline
1939
+ - **`undefined`** (omitted) — broadcast to all rooms of all managed connections
1940
+ - **Empty array** (`[]`) — no-op, returns `{ delivered: 0, filtered: 0 }`
1941
+
1942
+ #### Refreshing Preferences Mid-Connection
1943
+
1944
+ When a user updates preferences (e.g., mutes an event type), refresh their active connections:
1945
+
1946
+ ```typescript
1947
+ // In your REST endpoint handler:
1948
+ await prefsLoader.invalidateCacheFor(userId)
1949
+ await subscriptionManager.refreshUser(userId)
1950
+ ```
1951
+
1952
+ The manager diffs rooms and joins/leaves as needed — no reconnection required.
1953
+
1954
+ #### Pipeline Semantics
1955
+
1956
+ - Resolvers are evaluated in array order
1957
+ - First `deny` short-circuits — event is not delivered
1958
+ - `allow` does not short-circuit — subsequent resolvers can still deny
1959
+ - If all resolvers return `defer`, `defaultPolicy` applies (default: `deny`)
1960
+ - Resolver `evaluate()` errors are treated as `deny`
1961
+ - Resolver `refresh()` errors are caught per-resolver — the failed resolver keeps its previous state while remaining resolvers continue refreshing
1962
+ - Later resolvers in the array receive the accumulated `userContext` from earlier resolvers — use spread (`{ ...ctx.userContext, ...newFields }`) to preserve prior resolver data
1963
+ - `defaultPolicy` defaults to `'deny'` when not specified
1964
+
1965
+ #### Multi-Node Support
1966
+
1967
+ - Metadata flows through the adapter chain (Redis pub/sub) alongside the SSE message
1968
+ - Resolver pipeline runs locally on each node for its own connections
1969
+ - Wire format is a single v1 schema with optional `meta` — older nodes simply have no metadata
1970
+ - Use `layered-loader` for distributed cache invalidation across nodes
1971
+
1972
+ #### Data Loading with layered-loader
1973
+
1974
+ `layered-loader` is recommended (not required) for resolver data loading. It provides in-memory → Redis → DB caching with TTL, refresh-ahead, and distributed invalidation:
1975
+
1976
+ ```typescript
1977
+ import { Loader } from 'layered-loader'
1978
+
1979
+ const membershipLoader = new Loader<ProjectMembership[]>({
1980
+ inMemoryCache: { cacheType: 'lru-map', ttlInMsecs: 120_000, maxItems: 500 },
1981
+ asyncCache: new RedisCache(redis, { json: true, ttlInMsecs: 900_000 }),
1982
+ dataSources: [membershipDataSource],
1983
+ })
1984
+ ```
1985
+
1986
+ #### Testing
1987
+
1988
+ Create mock resolvers for unit tests:
1989
+
1990
+ ```typescript
1991
+ const mockResolver = {
1992
+ name: 'mock',
1993
+ evaluate: vi.fn().mockReturnValue({ action: 'allow' }),
1994
+ }
1995
+
1996
+ const manager = new SSESubscriptionManager(
1997
+ { resolveUserContext: async () => mockContext, resolvers: [mockResolver] },
1998
+ { sseRoomManager, sseRoomBroadcaster },
1999
+ )
2000
+ ```
2001
+
1806
2002
  ### SSE Test Utilities
1807
2003
 
1808
2004
  The library provides utilities for testing SSE endpoints.
@@ -393,9 +393,9 @@ export class AbstractSSEController {
393
393
  * })
394
394
  * ```
395
395
  */
396
- broadcastToRoom(room, eventName, data, options) {
396
+ async broadcastToRoom(room, eventName, data, options) {
397
397
  if (!this._roomBroadcaster) {
398
- return Promise.resolve(0);
398
+ return 0;
399
399
  }
400
400
  const message = {
401
401
  event: eventName,
@@ -403,7 +403,8 @@ export class AbstractSSEController {
403
403
  id: options?.id ?? randomUUID(),
404
404
  retry: options?.retry,
405
405
  };
406
- return this._roomBroadcaster.broadcastMessage(room, message, options);
406
+ const { delivered } = await this._roomBroadcaster.broadcastMessage(room, message, options);
407
+ return delivered;
407
408
  }
408
409
  /**
409
410
  * Join a connection to one or more rooms.
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractSSEController.js","sourceRoot":"","sources":["../../../lib/sse/AbstractSSEController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAOxC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAOnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAmBlD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAkBlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,OAAgB,qBAAqB;IAGzC,gDAAgD;IACtC,WAAW,GAA4B,IAAI,GAAG,EAAE,CAAA;IAE1D,yCAAyC;IACxB,cAAc,CAAgB;IAE/C,0DAA0D;IACzC,YAAY,CAAiB;IAE9C,kEAAkE;IACjD,gBAAgB,CAAqB;IAEtD;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,aAAqB,EAAE,SAA+B;QAChE,IAAI,SAAS,EAAE,mBAAmB,EAAE,CAAC;YACnC,IAAI,CAAC,cAAc,GAAG,IAAI,aAAa,EAAE,CAAA;QAC3C,CAAC;QAED,IAAI,SAAS,EAAE,eAAe,EAAE,CAAC;YAC/B,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC,eAAe,CAAA;YACjD,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC,eAAe,CAAC,WAAW,CAAA;YACzD,SAAS,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAA;QAChF,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,IAAW,aAAa;QACtB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,wFAAwF;gBACtF,gDAAgD,CACnD,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,cAAc,CAAA;IAC5B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,IAAW,eAAe;QACxB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,2FAA2F,CAC5F,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,gBAAgB,CAAA;IAC9B,CAAC;IA0BD;;;;;;;;;;;;;;;OAeG;IACK,KAAK,CAAC,SAAS,CAAI,YAAoB,EAAE,OAAsB;QACrE,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QACrD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,KAAK,CAAA;QACd,CAAC;QAED,kDAAkD;QAClD,IAAI,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,YAAY,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YACrD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;gBAC7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpB,MAAM,IAAI,aAAa,CAAC;wBACtB,OAAO,EAAE,0CAA0C,OAAO,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;wBAC5F,SAAS,EAAE,4BAA4B;qBACxC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,UAAU,CAAC,KAAiB,CAAA;YAC1C,iFAAiF;YACjF,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,KAAK,EAAE,OAAO,CAAC,KAAK;aACrB,CAAC,CAAA;YACF,OAAO,IAAI,CAAA;QACb,CAAC;QAAC,MAAM,CAAC;YACP,uFAAuF;YACvF,6EAA6E;YAC7E,gEAAgE;YAChE,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAA;YACvC,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,aAAa,CAAI,YAAoB,EAAE,OAAsB;QAClE,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;IAED;;;;OAIG;IACH,IAAW,oBAAoB;QAC7B,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACI,iBAAiB,CACtB,YAAoB,EACpB,OAKC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;IAED;;;;;OAKG;IACO,KAAK,CAAC,SAAS,CAAI,OAAsB;QACjD,IAAI,IAAI,GAAG,CAAC,CAAA;QACZ,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAA;QACzD,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;YAC/B,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;gBACtC,IAAI,EAAE,CAAA;YACR,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;OAMG;IACO,KAAK,CAAC,WAAW,CACzB,OAAsB,EACtB,SAA8C;QAE9C,IAAI,IAAI,GAAG,CAAC,CAAA;QACZ,KAAK,MAAM,CAAC,EAAE,EAAE,UAAU,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAChD,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;gBACjE,IAAI,EAAE,CAAA;YACR,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;OAEG;IACO,cAAc;QACtB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED;;OAEG;IACO,kBAAkB;QAC1B,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA;IAC9B,CAAC;IAED;;;;;;;;;;;OAWG;IACI,eAAe,CAAC,YAAoB;QACzC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QACrD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,KAAK,CAAA;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,UAAU,CAAC,KAAiB,CAAA;YAC1C,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;QAED,gEAAgE;QAChE,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAA;QACvC,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;OAGG;IACI,mBAAmB;QACxB,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAA;QACzD,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACI,kBAAkB,CAAC,UAAsB;QAC9C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;QAE/C,IAAI,CAAC,uBAAuB,EAAE,CAAC,UAAU,CAAC,CAAA;QAC1C,qEAAqE;QACrE,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IAChD,CAAC;IAED;;;;;;OAMG;IACI,oBAAoB,CAAC,YAAoB;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QACrD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,kEAAkE;YAClE,OAAM;QACR,CAAC;QACD,IAAI,CAAC,kBAAkB,EAAE,CAAC,UAAU,CAAC,CAAA;QACrC,8BAA8B;QAC9B,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;QAEnD,qCAAqC;QACrC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;QACzC,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAA;QAEtD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACvC,CAAC;IAED,+EAA+E;IAC/E,kBAAkB;IAClB,+EAA+E;IAE/E;;;;;OAKG;IACH,IAAc,WAAW;QACvB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,qFAAqF,CACtF,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;IAED;;OAEG;IACH,IAAc,YAAY;QACxB,OAAO,IAAI,CAAC,YAAY,KAAK,SAAS,CAAA;IACxC,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACO,eAAe,CACvB,IAAuB,EACvB,SAAoB,EACpB,IAES,EACT,OAAgE;QAEhE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAC3B,CAAC;QACD,MAAM,OAAO,GAAe;YAC1B,KAAK,EAAE,SAAS;YAChB,IAAI;YACJ,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,UAAU,EAAE;YAC/B,KAAK,EAAE,OAAO,EAAE,KAAK;SACtB,CAAA;QACD,OAAO,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACvE,CAAC;IAED;;;;;;OAMG;IACO,QAAQ,CAAC,YAAoB,EAAE,IAAuB;QAC9D,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;IAC7C,CAAC;IAED;;;;;;OAMG;IACO,SAAS,CAAC,YAAoB,EAAE,IAAuB;QAC/D,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;IAC9C,CAAC;IAED;;;;;OAKG;IACO,oBAAoB,CAAC,IAAY;QACzC,OAAO,IAAI,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IAChE,CAAC;IAED;;;;;OAKG;IACO,wBAAwB,CAAC,IAAY;QAC7C,OAAO,IAAI,CAAC,gBAAgB,EAAE,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnE,CAAC;CACF"}
1
+ {"version":3,"file":"AbstractSSEController.js","sourceRoot":"","sources":["../../../lib/sse/AbstractSSEController.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ export type { AllContractEventNames, AllContractEvents, AnySSEContractDefinition
2
2
  export { type BuildFastifySSERoutesReturnType, buildFastifyRoute, buildHandler, type FastifySSEHandlerConfig, type FastifySSEPreHandler, type FastifySSERouteOptions, type InferSSERequest, type RegisterSSERoutesOptions, type SSEContext, type SSEOnlyHandlers, type SSERouteHandler, type SSESession, } from '../routes/index.js';
3
3
  export { AbstractSSEController, type SSEControllerConfig, type SSEEventSender, type SSELogger, type SSEMessage, } from './AbstractSSEController.js';
4
4
  export { defineEvent, type SSEEventDefinition } from './defineEvent.js';
5
- export { defineRoom, InMemoryAdapter, type RoomBroadcastOptions, type RoomNameResolver, type SSERoomAdapter, SSERoomBroadcaster, SSERoomManager, type SSERoomManagerConfig, type SSERoomMessageHandler, type SSERoomOperations, } from './rooms/index.js';
5
+ export { defineRoom, InMemoryAdapter, type PreDeliveryFilter, type RoomBroadcastOptions, type RoomNameResolver, type SSERoomAdapter, SSERoomBroadcaster, SSERoomManager, type SSERoomManagerConfig, type SSERoomMessageHandler, type SSERoomOperations, } from './rooms/index.js';
6
6
  export { type SSESessionEvent, SSESessionSpy } from './SSESessionSpy.js';
7
7
  export { type ParsedSSEEvent, type ParseSSEBufferResult, parseSSEBuffer, parseSSEEvents, } from './sseParser.js';
8
+ export { defineEventMetadata, type ExtractMetadata, type FilterVerdict, type IncomingEvent, type MetadataGuard, type MetadataGuards, type PublishResult, type ResolverResult, SSESubscriptionManager, type SSESubscriptionManagerConfig, type SubscriptionContext, type SubscriptionPolicy, type SubscriptionResolver, } from './subscriptions/index.js';
@@ -6,4 +6,6 @@ export { defineEvent } from './defineEvent.js';
6
6
  export { defineRoom, InMemoryAdapter, SSERoomBroadcaster, SSERoomManager, } from './rooms/index.js';
7
7
  export { SSESessionSpy } from './SSESessionSpy.js';
8
8
  export { parseSSEBuffer, parseSSEEvents, } from './sseParser.js';
9
+ // SSE Subscriptions
10
+ export { defineEventMetadata, SSESubscriptionManager, } from './subscriptions/index.js';
9
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/sse/index.ts"],"names":[],"mappings":"AAUA,2CAA2C;AAC3C,OAAO,EAEL,iBAAiB,EACjB,YAAY,GAUb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,qBAAqB,GAKtB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,WAAW,EAA2B,MAAM,kBAAkB,CAAA;AACvE,mCAAmC;AACnC,OAAO,EACL,UAAU,EACV,eAAe,EAIf,kBAAkB,EAClB,cAAc,GAIf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAwB,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAGL,cAAc,EACd,cAAc,GACf,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/sse/index.ts"],"names":[],"mappings":"AAUA,2CAA2C;AAC3C,OAAO,EAEL,iBAAiB,EACjB,YAAY,GAUb,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,qBAAqB,GAKtB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,WAAW,EAA2B,MAAM,kBAAkB,CAAA;AACvE,mCAAmC;AACnC,OAAO,EACL,UAAU,EACV,eAAe,EAKf,kBAAkB,EAClB,cAAc,GAIf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAwB,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAGL,cAAc,EACd,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,oBAAoB;AACpB,OAAO,EACL,mBAAmB,EAQnB,sBAAsB,GAKvB,MAAM,0BAA0B,CAAA"}
@@ -2,7 +2,7 @@ import type { z } from 'zod';
2
2
  import type { SSEEventDefinition } from '../defineEvent.js';
3
3
  import type { SSEMessage } from '../sseTypes.js';
4
4
  import type { SSERoomManager } from './SSERoomManager.js';
5
- import type { RoomBroadcastOptions } from './types.js';
5
+ import type { BroadcastResult, PreDeliveryFilter, RoomBroadcastOptions } from './types.js';
6
6
  /**
7
7
  * Shared, non-generic room broadcaster that can be registered once in DI
8
8
  * and used by multiple controllers and domain services.
@@ -31,9 +31,18 @@ export declare class SSERoomBroadcaster {
31
31
  private readonly _roomManager;
32
32
  private readonly senders;
33
33
  private readonly dedupCache;
34
+ private preDeliveryFilter?;
34
35
  constructor(deps: {
35
36
  sseRoomManager: SSERoomManager;
36
37
  });
38
+ /**
39
+ * Set a pre-delivery filter that runs before sending to each connection.
40
+ * Used by SSESubscriptionManager for resolver pipeline evaluation.
41
+ * Only one filter can be active at a time — calling this method twice throws,
42
+ * to prevent silently replacing an already-installed filter (which is almost
43
+ * always a wiring bug, e.g. registering two SSESubscriptionManagers).
44
+ */
45
+ setPreDeliveryFilter(filter: PreDeliveryFilter): void;
37
46
  /**
38
47
  * Public getter for the underlying room manager.
39
48
  * Used by the route builder for `session.rooms`.
@@ -54,11 +63,13 @@ export declare class SSERoomBroadcaster {
54
63
  * @param event - Event definition created by `defineEvent()`
55
64
  * @param data - Event data (must match the schema from the event definition)
56
65
  * @param options - Broadcast options (local, id, retry)
57
- * @returns Number of local connections the message was sent to
66
+ * @returns Number of local connections the message was successfully delivered to.
67
+ * For separate `delivered`/`filtered` counts, call {@link broadcastMessage}.
58
68
  */
59
69
  broadcastToRoom<T extends z.ZodType>(room: string | string[], event: SSEEventDefinition<string, T>, data: z.input<T>, options?: RoomBroadcastOptions & {
60
70
  id?: string;
61
71
  retry?: number;
72
+ metadata?: Record<string, unknown>;
62
73
  }): Promise<number>;
63
74
  /**
64
75
  * Lower-level broadcast API — sends a raw SSEMessage to all connections in one or more rooms.
@@ -68,9 +79,14 @@ export declare class SSERoomBroadcaster {
68
79
  * @param room - Room name or array of room names
69
80
  * @param message - The SSE message to broadcast
70
81
  * @param options - Broadcast options (local)
71
- * @returns Number of local connections the message was sent to
82
+ * @returns `delivered` is the number of local connections the message was sent to;
83
+ * `filtered` is the number of local connections skipped by the pre-delivery
84
+ * filter. Returning both per-call (rather than tracking on the broadcaster)
85
+ * avoids races between concurrent broadcasts.
72
86
  */
73
- broadcastMessage(room: string | string[], message: SSEMessage, options?: RoomBroadcastOptions): Promise<number>;
87
+ broadcastMessage(room: string | string[], message: SSEMessage, options?: RoomBroadcastOptions & {
88
+ metadata?: Record<string, unknown>;
89
+ }): Promise<BroadcastResult>;
74
90
  /**
75
91
  * Get all connection IDs in a room.
76
92
  *
@@ -29,13 +29,27 @@ export class SSERoomBroadcaster {
29
29
  _roomManager;
30
30
  senders = [];
31
31
  dedupCache = new Map();
32
+ preDeliveryFilter;
32
33
  constructor(deps) {
33
34
  this._roomManager = deps.sseRoomManager;
34
35
  // Wire up adapter message handler to forward remote broadcasts to local connections
35
- this._roomManager.onRemoteMessage((room, message, _sourceNodeId) => {
36
- return this.handleRemoteBroadcast(room, message);
36
+ this._roomManager.onRemoteMessage((room, message, _sourceNodeId, metadata) => {
37
+ return this.handleRemoteBroadcast(room, message, metadata);
37
38
  });
38
39
  }
40
+ /**
41
+ * Set a pre-delivery filter that runs before sending to each connection.
42
+ * Used by SSESubscriptionManager for resolver pipeline evaluation.
43
+ * Only one filter can be active at a time — calling this method twice throws,
44
+ * to prevent silently replacing an already-installed filter (which is almost
45
+ * always a wiring bug, e.g. registering two SSESubscriptionManagers).
46
+ */
47
+ setPreDeliveryFilter(filter) {
48
+ if (this.preDeliveryFilter) {
49
+ throw new Error('SSERoomBroadcaster pre-delivery filter is already set; only one filter can be active at a time');
50
+ }
51
+ this.preDeliveryFilter = filter;
52
+ }
39
53
  /**
40
54
  * Public getter for the underlying room manager.
41
55
  * Used by the route builder for `session.rooms`.
@@ -60,16 +74,18 @@ export class SSERoomBroadcaster {
60
74
  * @param event - Event definition created by `defineEvent()`
61
75
  * @param data - Event data (must match the schema from the event definition)
62
76
  * @param options - Broadcast options (local, id, retry)
63
- * @returns Number of local connections the message was sent to
77
+ * @returns Number of local connections the message was successfully delivered to.
78
+ * For separate `delivered`/`filtered` counts, call {@link broadcastMessage}.
64
79
  */
65
- broadcastToRoom(room, event, data, options) {
80
+ async broadcastToRoom(room, event, data, options) {
66
81
  const message = {
67
82
  event: event.event,
68
83
  data,
69
84
  id: options?.id ?? randomUUID(),
70
85
  retry: options?.retry,
71
86
  };
72
- return this.broadcastMessage(room, message, options);
87
+ const { delivered } = await this.broadcastMessage(room, message, options);
88
+ return delivered;
73
89
  }
74
90
  /**
75
91
  * Lower-level broadcast API — sends a raw SSEMessage to all connections in one or more rooms.
@@ -79,25 +95,36 @@ export class SSERoomBroadcaster {
79
95
  * @param room - Room name or array of room names
80
96
  * @param message - The SSE message to broadcast
81
97
  * @param options - Broadcast options (local)
82
- * @returns Number of local connections the message was sent to
98
+ * @returns `delivered` is the number of local connections the message was sent to;
99
+ * `filtered` is the number of local connections skipped by the pre-delivery
100
+ * filter. Returning both per-call (rather than tracking on the broadcaster)
101
+ * avoids races between concurrent broadcasts.
83
102
  */
84
103
  async broadcastMessage(room, message, options) {
85
104
  const rooms = Array.isArray(room) ? room : [room];
86
105
  const connectionIds = this.collectRoomConnections(rooms);
87
- // Send to all local connections
88
- let sent = 0;
106
+ let delivered = 0;
107
+ let filtered = 0;
89
108
  for (const connId of connectionIds) {
109
+ // Check pre-delivery filter if set
110
+ if (this.preDeliveryFilter) {
111
+ const allowed = await this.preDeliveryFilter(connId, message, options?.metadata);
112
+ if (!allowed) {
113
+ filtered++;
114
+ continue;
115
+ }
116
+ }
90
117
  if (await this.sendToConnection(connId, message)) {
91
- sent++;
118
+ delivered++;
92
119
  }
93
120
  }
94
121
  // Publish to adapter for cross-node propagation (unless local-only)
95
122
  if (!options?.local) {
96
123
  for (const r of rooms) {
97
- await this._roomManager.publish(r, message, options);
124
+ await this._roomManager.publish(r, message, options, options?.metadata);
98
125
  }
99
126
  }
100
- return sent;
127
+ return { delivered, filtered };
101
128
  }
102
129
  /**
103
130
  * Get all connection IDs in a room.
@@ -139,12 +166,17 @@ export class SSERoomBroadcaster {
139
166
  * Handle broadcasts from other nodes (via adapter).
140
167
  * Deduplicates messages per-connection based on message ID.
141
168
  */
142
- async handleRemoteBroadcast(room, message) {
169
+ async handleRemoteBroadcast(room, message, metadata) {
143
170
  const connectionIds = this._roomManager.getConnectionsInRoom(room);
144
171
  for (const connId of connectionIds) {
145
172
  if (this.isDuplicateMessage(connId, message.id)) {
146
173
  continue;
147
174
  }
175
+ if (this.preDeliveryFilter) {
176
+ const allowed = await this.preDeliveryFilter(connId, message, metadata);
177
+ if (!allowed)
178
+ continue;
179
+ }
148
180
  await this.sendToConnection(connId, message);
149
181
  }
150
182
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SSERoomBroadcaster.js","sourceRoot":"","sources":["../../../../lib/sse/rooms/SSERoomBroadcaster.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SSERoomBroadcaster.js","sourceRoot":"","sources":["../../../../lib/sse/rooms/SSERoomBroadcaster.ts"],"names":[],"mappings":"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"}
@@ -128,7 +128,10 @@ export declare class SSERoomManager {
128
128
  *
129
129
  * @param room - The room to publish to
130
130
  * @param message - The SSE message to broadcast
131
- * @param options - Broadcast options
131
+ * @param options - Broadcast options (e.g. `local: true` to skip adapter)
132
+ * @param metadata - Optional opaque metadata propagated to other nodes
133
+ * alongside the message. Used by `SSESubscriptionManager` for cross-node
134
+ * resolver evaluation; not delivered to clients.
132
135
  */
133
- publish(room: string, message: SSEMessage, options?: RoomBroadcastOptions): Promise<void>;
136
+ publish(room: string, message: SSEMessage, options?: RoomBroadcastOptions, metadata?: Record<string, unknown>): Promise<void>;
134
137
  }
@@ -51,12 +51,12 @@ export class SSERoomManager {
51
51
  this.adapter = config.adapter ?? new InMemoryAdapter();
52
52
  this.nodeId = config.nodeId ?? randomUUID();
53
53
  // Set up adapter message handler
54
- this.adapter.onMessage((room, message, sourceNodeId) => {
54
+ this.adapter.onMessage((room, message, sourceNodeId, metadata) => {
55
55
  // Skip messages from this node (we already handled them locally)
56
56
  if (sourceNodeId === this.nodeId) {
57
57
  return;
58
58
  }
59
- this.messageHandler?.(room, message, sourceNodeId);
59
+ return this.messageHandler?.(room, message, sourceNodeId, metadata);
60
60
  });
61
61
  }
62
62
  /**
@@ -222,13 +222,16 @@ export class SSERoomManager {
222
222
  *
223
223
  * @param room - The room to publish to
224
224
  * @param message - The SSE message to broadcast
225
- * @param options - Broadcast options
225
+ * @param options - Broadcast options (e.g. `local: true` to skip adapter)
226
+ * @param metadata - Optional opaque metadata propagated to other nodes
227
+ * alongside the message. Used by `SSESubscriptionManager` for cross-node
228
+ * resolver evaluation; not delivered to clients.
226
229
  */
227
- async publish(room, message, options) {
230
+ async publish(room, message, options, metadata) {
228
231
  if (options?.local) {
229
232
  return; // Skip adapter for local-only broadcasts
230
233
  }
231
- await this.adapter.publish(room, message);
234
+ await this.adapter.publish(room, message, metadata);
232
235
  }
233
236
  }
234
237
  //# sourceMappingURL=SSERoomManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SSERoomManager.js","sourceRoot":"","sources":["../../../../lib/sse/rooms/SSERoomManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SSERoomManager.js","sourceRoot":"","sources":["../../../../lib/sse/rooms/SSERoomManager.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,6 @@ export declare class InMemoryAdapter implements SSERoomAdapter {
13
13
  disconnect(): Promise<void>;
14
14
  subscribe(_room: string): Promise<void>;
15
15
  unsubscribe(_room: string): Promise<void>;
16
- publish(_room: string, _message: SSEMessage): Promise<void>;
16
+ publish(_room: string, _message: SSEMessage, _metadata?: Record<string, unknown>): Promise<void>;
17
17
  onMessage(_handler: SSERoomMessageHandler): void;
18
18
  }
@@ -23,7 +23,7 @@ export class InMemoryAdapter {
23
23
  // No-op for in-memory adapter
24
24
  return Promise.resolve();
25
25
  }
26
- publish(_room, _message) {
26
+ publish(_room, _message, _metadata) {
27
27
  // No-op for in-memory adapter - messages are only sent locally
28
28
  // The controller handles local delivery directly
29
29
  return Promise.resolve();
@@ -1 +1 @@
1
- {"version":3,"file":"InMemoryAdapter.js","sourceRoot":"","sources":["../../../../../lib/sse/rooms/adapters/InMemoryAdapter.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,OAAO,eAAe;IAC1B,OAAO;QACL,8BAA8B;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,UAAU;QACR,8BAA8B;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,SAAS,CAAC,KAAa;QACrB,kEAAkE;QAClE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,8BAA8B;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,QAAoB;QACzC,+DAA+D;QAC/D,iDAAiD;QACjD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,SAAS,CAAC,QAA+B;QACvC,wDAAwD;IAC1D,CAAC;CACF"}
1
+ {"version":3,"file":"InMemoryAdapter.js","sourceRoot":"","sources":["../../../../../lib/sse/rooms/adapters/InMemoryAdapter.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,OAAO,eAAe;IAC1B,OAAO;QACL,8BAA8B;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,UAAU;QACR,8BAA8B;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,SAAS,CAAC,KAAa;QACrB,kEAAkE;QAClE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,8BAA8B;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,QAAoB,EAAE,SAAmC;QAC9E,+DAA+D;QAC/D,iDAAiD;QACjD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,SAAS,CAAC,QAA+B;QACvC,wDAAwD;IAC1D,CAAC;CACF"}
@@ -2,4 +2,4 @@ export { InMemoryAdapter } from './adapters/InMemoryAdapter.js';
2
2
  export { defineRoom } from './defineRoom.js';
3
3
  export { SSERoomBroadcaster } from './SSERoomBroadcaster.js';
4
4
  export { SSERoomManager } from './SSERoomManager.js';
5
- export type { RoomBroadcastOptions, RoomNameResolver, SSERoomAdapter, SSERoomManagerConfig, SSERoomMessageHandler, SSERoomOperations, } from './types.js';
5
+ export type { PreDeliveryFilter, RoomBroadcastOptions, RoomNameResolver, SSERoomAdapter, SSERoomManagerConfig, SSERoomMessageHandler, SSERoomOperations, } from './types.js';
@@ -63,8 +63,11 @@ export type SSERoomAdapter = {
63
63
  *
64
64
  * @param room - The room to publish to
65
65
  * @param message - The SSE message to broadcast
66
+ * @param metadata - Optional opaque metadata for cross-node subscription
67
+ * filtering (e.g. event scope, project id). Adapters serialize this
68
+ * alongside the message; it is not delivered to SSE clients.
66
69
  */
67
- publish(room: string, message: SSEMessage): Promise<void>;
70
+ publish(room: string, message: SSEMessage, metadata?: Record<string, unknown>): Promise<void>;
68
71
  /**
69
72
  * Register a handler for messages received from other nodes.
70
73
  * The handler should forward the message to local connections in the room.
@@ -75,8 +78,37 @@ export type SSERoomAdapter = {
75
78
  };
76
79
  /**
77
80
  * Handler for messages received from the adapter (other nodes).
81
+ *
82
+ * @param room - The room the message was published to
83
+ * @param message - The SSE message
84
+ * @param sourceNodeId - Id of the node that originated the publish; used to
85
+ * suppress echoing the publisher's own messages back to it
86
+ * @param metadata - Optional opaque metadata attached at publish time;
87
+ * `undefined` for v1 (pre-metadata) messages from older nodes
88
+ */
89
+ export type SSERoomMessageHandler = (room: string, message: SSEMessage, sourceNodeId: string, metadata?: Record<string, unknown>) => void | Promise<void>;
90
+ /**
91
+ * Pre-delivery filter called before sending to each connection.
92
+ * Returns true to deliver, false to skip.
93
+ *
94
+ * Used by SSESubscriptionManager to inject resolver pipeline evaluation
95
+ * into the broadcaster's delivery path.
96
+ *
97
+ * When no filter is set, all connections receive all messages (existing behavior).
78
98
  */
79
- export type SSERoomMessageHandler = (room: string, message: SSEMessage, sourceNodeId: string) => void | Promise<void>;
99
+ export type PreDeliveryFilter = (connectionId: string, message: SSEMessage, metadata?: Record<string, unknown>) => Promise<boolean> | boolean;
100
+ /**
101
+ * Result of a single broadcast call.
102
+ *
103
+ * Returned per-call (rather than tracked on the broadcaster) so that concurrent
104
+ * broadcasts cannot interleave their counters.
105
+ */
106
+ export type BroadcastResult = {
107
+ /** Local connections the message was successfully sent to. */
108
+ delivered: number;
109
+ /** Local connections skipped by the pre-delivery filter. */
110
+ filtered: number;
111
+ };
80
112
  /**
81
113
  * Configuration for the SSE Room Manager.
82
114
  */