@unbrained/pm-web 2026.8.10 → 2026.8.14

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 (173) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/app.d.ts +16 -0
  3. package/dist/app.js +16 -0
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth.d.ts +5 -0
  6. package/dist/auth.js.map +1 -1
  7. package/dist/board.d.ts +53 -0
  8. package/dist/board.js +48 -0
  9. package/dist/board.js.map +1 -1
  10. package/dist/crypto.d.ts +23 -0
  11. package/dist/crypto.js +32 -0
  12. package/dist/crypto.js.map +1 -1
  13. package/dist/db.d.ts +19 -0
  14. package/dist/db.js +19 -0
  15. package/dist/db.js.map +1 -1
  16. package/dist/ical.d.ts +72 -0
  17. package/dist/ical.js +73 -0
  18. package/dist/ical.js.map +1 -1
  19. package/dist/index.d.ts +11 -0
  20. package/dist/index.js +52 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/middleware/auth.d.ts +8 -0
  23. package/dist/middleware/auth.js.map +1 -1
  24. package/dist/oidc.d.ts +87 -0
  25. package/dist/oidc.js +113 -0
  26. package/dist/oidc.js.map +1 -1
  27. package/dist/routes/admin.js +15 -0
  28. package/dist/routes/admin.js.map +1 -1
  29. package/dist/routes/github.js +13 -0
  30. package/dist/routes/github.js.map +1 -1
  31. package/dist/routes/oidc.d.ts +10 -0
  32. package/dist/routes/oidc.js +51 -0
  33. package/dist/routes/oidc.js.map +1 -1
  34. package/dist/routes/pm.js +132 -1
  35. package/dist/routes/pm.js.map +1 -1
  36. package/dist/routes/sharing.js +8 -0
  37. package/dist/routes/sharing.js.map +1 -1
  38. package/dist/services/mutation-event-watcher.js +13 -0
  39. package/dist/services/mutation-event-watcher.js.map +1 -1
  40. package/dist/services/pm-runner.d.ts +82 -0
  41. package/dist/services/pm-runner.js +121 -0
  42. package/dist/services/pm-runner.js.map +1 -1
  43. package/dist/services/project-watcher.d.ts +22 -0
  44. package/dist/services/project-watcher.js +51 -0
  45. package/dist/services/project-watcher.js.map +1 -1
  46. package/dist/services/realtime-bus.d.ts +46 -0
  47. package/dist/services/realtime-bus.js +59 -0
  48. package/dist/services/realtime-bus.js.map +1 -1
  49. package/dist/services/sse.d.ts +134 -0
  50. package/dist/services/sse.js +145 -0
  51. package/dist/services/sse.js.map +1 -1
  52. package/manifest.json +1 -1
  53. package/package.json +5 -3
  54. package/public/src/app.js +44 -1
  55. package/public/src/app.js.map +1 -1
  56. package/public/src/app.ts +44 -1
  57. package/public/src/components/modals.js +11 -0
  58. package/public/src/components/modals.js.map +1 -1
  59. package/public/src/components/modals.ts +11 -0
  60. package/public/src/components/toast.js +2 -0
  61. package/public/src/components/toast.js.map +1 -1
  62. package/public/src/components/toast.ts +2 -0
  63. package/public/src/constants.js +21 -4
  64. package/public/src/constants.js.map +1 -1
  65. package/public/src/constants.ts +21 -4
  66. package/public/src/filters.js +10 -7
  67. package/public/src/filters.js.map +1 -1
  68. package/public/src/filters.ts +10 -7
  69. package/public/src/i18n.js +11 -1
  70. package/public/src/i18n.js.map +1 -1
  71. package/public/src/i18n.ts +13 -1
  72. package/public/src/state.js +3 -0
  73. package/public/src/state.js.map +1 -1
  74. package/public/src/state.ts +3 -0
  75. package/public/src/sw.ts +71 -7
  76. package/public/src/theme.js +13 -1
  77. package/public/src/theme.js.map +1 -1
  78. package/public/src/theme.ts +15 -1
  79. package/public/src/types.ts +2 -0
  80. package/public/src/utils.js +26 -1
  81. package/public/src/utils.js.map +1 -1
  82. package/public/src/utils.ts +26 -1
  83. package/public/src/views/activity.js +1 -0
  84. package/public/src/views/activity.js.map +1 -1
  85. package/public/src/views/activity.ts +1 -0
  86. package/public/src/views/admin.js +134 -0
  87. package/public/src/views/admin.js.map +1 -1
  88. package/public/src/views/admin.ts +134 -0
  89. package/public/src/views/auth.js +31 -0
  90. package/public/src/views/auth.js.map +1 -1
  91. package/public/src/views/auth.ts +31 -0
  92. package/public/src/views/calendar.js +3 -0
  93. package/public/src/views/calendar.js.map +1 -1
  94. package/public/src/views/calendar.ts +3 -0
  95. package/public/src/views/comments-audit.js +1 -0
  96. package/public/src/views/comments-audit.js.map +1 -1
  97. package/public/src/views/comments-audit.ts +1 -0
  98. package/public/src/views/config.js +67 -0
  99. package/public/src/views/config.js.map +1 -1
  100. package/public/src/views/config.ts +67 -0
  101. package/public/src/views/context.js +2 -0
  102. package/public/src/views/context.js.map +1 -1
  103. package/public/src/views/context.ts +2 -0
  104. package/public/src/views/create.js +3 -0
  105. package/public/src/views/create.js.map +1 -1
  106. package/public/src/views/create.ts +3 -0
  107. package/public/src/views/dedupe.js +1 -0
  108. package/public/src/views/dedupe.js.map +1 -1
  109. package/public/src/views/dedupe.ts +1 -0
  110. package/public/src/views/export.js +6 -0
  111. package/public/src/views/export.js.map +1 -1
  112. package/public/src/views/export.ts +6 -0
  113. package/public/src/views/github.js +58 -0
  114. package/public/src/views/github.js.map +1 -1
  115. package/public/src/views/github.ts +58 -0
  116. package/public/src/views/graph-canvas.js +18 -0
  117. package/public/src/views/graph-canvas.js.map +1 -1
  118. package/public/src/views/graph-canvas.ts +20 -0
  119. package/public/src/views/graph.js +41 -0
  120. package/public/src/views/graph.js.map +1 -1
  121. package/public/src/views/graph.ts +42 -1
  122. package/public/src/views/groups.js +45 -0
  123. package/public/src/views/groups.js.map +1 -1
  124. package/public/src/views/groups.ts +45 -0
  125. package/public/src/views/guide.js +3 -0
  126. package/public/src/views/guide.js.map +1 -1
  127. package/public/src/views/guide.ts +3 -0
  128. package/public/src/views/health.js +3 -0
  129. package/public/src/views/health.js.map +1 -1
  130. package/public/src/views/health.ts +3 -0
  131. package/public/src/views/items.js +196 -6
  132. package/public/src/views/items.js.map +1 -1
  133. package/public/src/views/items.ts +196 -6
  134. package/public/src/views/normalize.js +2 -0
  135. package/public/src/views/normalize.js.map +1 -1
  136. package/public/src/views/normalize.ts +2 -0
  137. package/public/src/views/packages.js +41 -0
  138. package/public/src/views/packages.js.map +1 -1
  139. package/public/src/views/packages.ts +41 -0
  140. package/public/src/views/plan-execution.js +6 -0
  141. package/public/src/views/plan-execution.js.map +1 -1
  142. package/public/src/views/plan-execution.ts +8 -0
  143. package/public/src/views/plan.js +145 -0
  144. package/public/src/views/plan.js.map +1 -1
  145. package/public/src/views/plan.ts +146 -1
  146. package/public/src/views/projects.js +60 -0
  147. package/public/src/views/projects.js.map +1 -1
  148. package/public/src/views/projects.ts +60 -0
  149. package/public/src/views/router.js +43 -0
  150. package/public/src/views/router.js.map +1 -1
  151. package/public/src/views/router.ts +43 -0
  152. package/public/src/views/search.js +5 -0
  153. package/public/src/views/search.js.map +1 -1
  154. package/public/src/views/search.ts +5 -0
  155. package/public/src/views/settings.js +36 -0
  156. package/public/src/views/settings.js.map +1 -1
  157. package/public/src/views/settings.ts +36 -0
  158. package/public/src/views/shared.js +1 -0
  159. package/public/src/views/shared.js.map +1 -1
  160. package/public/src/views/shared.ts +1 -0
  161. package/public/src/views/sharing.js +32 -0
  162. package/public/src/views/sharing.js.map +1 -1
  163. package/public/src/views/sharing.ts +32 -0
  164. package/public/src/views/stats.js +1 -0
  165. package/public/src/views/stats.js.map +1 -1
  166. package/public/src/views/stats.ts +1 -0
  167. package/public/src/views/templates.js +4 -0
  168. package/public/src/views/templates.js.map +1 -1
  169. package/public/src/views/templates.ts +4 -0
  170. package/public/src/views/validate.js +1 -0
  171. package/public/src/views/validate.js.map +1 -1
  172. package/public/src/views/validate.ts +1 -0
  173. package/public/sw.js +60 -5
@@ -1 +1 @@
1
- {"version":3,"file":"project-watcher.js","sourceRoot":"","sources":["../../src/services/project-watcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"project-watcher.js","sourceRoot":"","sources":["../../src/services/project-watcher.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,54 @@ interface RealtimeEnvelope {
5
5
  data: unknown;
6
6
  sourceId?: string;
7
7
  }
8
+ /**
9
+ * Parse and validate a realtime NOTIFY payload into an envelope.
10
+ *
11
+ * Returns `null` when the payload is missing or exceeds 7,500 bytes, or when
12
+ * JSON parsing, the project-id (UUID) check, or the event-type check fails. The
13
+ * envelope's data is passed through {@link safeSharedData}; a `sourceId` is kept
14
+ * only when present, so receivers can ignore their own broadcasts.
15
+ *
16
+ * @param raw - The raw NOTIFY payload string, or `undefined`.
17
+ * @returns The validated envelope, or `null`.
18
+ */
8
19
  export declare function parseEnvelope(raw: string | undefined): RealtimeEnvelope | null;
20
+ /**
21
+ * Serialize a project event into a realtime NOTIFY payload.
22
+ *
23
+ * Returns `null` without throwing when the project id is not a UUID or the event
24
+ * type is malformed, or when the JSON payload (after {@link safeSharedData}) would
25
+ * exceed 7,500 bytes — so an over-large event is dropped rather than corrupting
26
+ * the channel.
27
+ *
28
+ * @param projectId - The project the event belongs to.
29
+ * @param event - The SSE event to encode.
30
+ * @param sourceId - This instance's id, embedded so other instances can skip it.
31
+ * @returns The JSON payload string, or `null` when invalid or too large.
32
+ */
9
33
  export declare function buildEnvelope(projectId: string, event: SSEEvent, sourceId: string): string | null;
34
+ /**
35
+ * Deliver one NOTIFY payload to local clients, ignoring this instance's own.
36
+ *
37
+ * Parses the payload (no-op when invalid); if it carries a `sourceId` matching
38
+ * this instance the event is dropped to avoid echoing it back, otherwise the
39
+ * event is handed to `deliver` for local SSE fan-out.
40
+ *
41
+ * @param raw - The raw NOTIFY payload.
42
+ * @param instanceId - This instance's id, to suppress self-echo.
43
+ * @param deliver - Sink that fans the event out to local clients.
44
+ */
10
45
  export declare function handleIncomingEnvelope(raw: string | undefined, instanceId: string, deliver: (projectId: string, event: SSEEvent) => void): void;
46
+ /**
47
+ * Start the Postgres LISTEN/NOTIFY realtime bus and return a stop function.
48
+ *
49
+ * A no-op (returning a resolver that does nothing) when `PM_REALTIME_ENABLED`
50
+ * is `"false"`. Otherwise reserves a pool client on the `pm_workspace_events`
51
+ * channel, fans incoming envelopes out to local SSE clients (skipping this
52
+ * instance's own), publishes local events via `pg_notify`, and reconnects with
53
+ * exponential backoff on disconnect. The returned function undoes all of it.
54
+ *
55
+ * @returns A function that stops the bus and releases the listener.
56
+ */
11
57
  export declare function startRealtimeBus(): Promise<() => Promise<void>>;
12
58
  export {};
@@ -5,6 +5,19 @@ const CHANNEL = "pm_workspace_events";
5
5
  const INSTANCE_ID = randomUUID();
6
6
  const PROJECT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
7
7
  const EVENT_TYPE = /^[a-z][a-z0-9-]{0,63}$/;
8
+ /**
9
+ * Project a raw event payload down to a small, safe object for cross-instance
10
+ * transport.
11
+ *
12
+ * Only a fixed whitelist of keys (`itemId`, `userId`, `change`, `target`,
13
+ * `rel`, `reason`, `count`, `source`, `operation`) is copied, and only when the
14
+ * value is a string of at most 256 characters or a finite number. Non-objects
15
+ * and arrays yield an empty object, so the NOTIFY payload stays small and free
16
+ * of arbitrary user data.
17
+ *
18
+ * @param data - The raw event data.
19
+ * @returns The filtered, transport-safe data object.
20
+ */
8
21
  function safeSharedData(data) {
9
22
  if (!data || typeof data !== "object" || Array.isArray(data))
10
23
  return {};
@@ -19,6 +32,17 @@ function safeSharedData(data) {
19
32
  }
20
33
  return safe;
21
34
  }
35
+ /**
36
+ * Parse and validate a realtime NOTIFY payload into an envelope.
37
+ *
38
+ * Returns `null` when the payload is missing or exceeds 7,500 bytes, or when
39
+ * JSON parsing, the project-id (UUID) check, or the event-type check fails. The
40
+ * envelope's data is passed through {@link safeSharedData}; a `sourceId` is kept
41
+ * only when present, so receivers can ignore their own broadcasts.
42
+ *
43
+ * @param raw - The raw NOTIFY payload string, or `undefined`.
44
+ * @returns The validated envelope, or `null`.
45
+ */
22
46
  export function parseEnvelope(raw) {
23
47
  if (!raw || Buffer.byteLength(raw, "utf8") > 7_500)
24
48
  return null;
@@ -32,18 +56,53 @@ export function parseEnvelope(raw) {
32
56
  return null;
33
57
  }
34
58
  }
59
+ /**
60
+ * Serialize a project event into a realtime NOTIFY payload.
61
+ *
62
+ * Returns `null` without throwing when the project id is not a UUID or the event
63
+ * type is malformed, or when the JSON payload (after {@link safeSharedData}) would
64
+ * exceed 7,500 bytes — so an over-large event is dropped rather than corrupting
65
+ * the channel.
66
+ *
67
+ * @param projectId - The project the event belongs to.
68
+ * @param event - The SSE event to encode.
69
+ * @param sourceId - This instance's id, embedded so other instances can skip it.
70
+ * @returns The JSON payload string, or `null` when invalid or too large.
71
+ */
35
72
  export function buildEnvelope(projectId, event, sourceId) {
36
73
  if (!PROJECT_ID.test(projectId) || !EVENT_TYPE.test(event.type))
37
74
  return null;
38
75
  const payload = JSON.stringify({ projectId, type: event.type, data: safeSharedData(event.data), sourceId });
39
76
  return Buffer.byteLength(payload, "utf8") <= 7_500 ? payload : null;
40
77
  }
78
+ /**
79
+ * Deliver one NOTIFY payload to local clients, ignoring this instance's own.
80
+ *
81
+ * Parses the payload (no-op when invalid); if it carries a `sourceId` matching
82
+ * this instance the event is dropped to avoid echoing it back, otherwise the
83
+ * event is handed to `deliver` for local SSE fan-out.
84
+ *
85
+ * @param raw - The raw NOTIFY payload.
86
+ * @param instanceId - This instance's id, to suppress self-echo.
87
+ * @param deliver - Sink that fans the event out to local clients.
88
+ */
41
89
  export function handleIncomingEnvelope(raw, instanceId, deliver) {
42
90
  const event = parseEnvelope(raw);
43
91
  if (!event || event.sourceId === instanceId)
44
92
  return;
45
93
  deliver(event.projectId, { type: event.type, data: event.data });
46
94
  }
95
+ /**
96
+ * Start the Postgres LISTEN/NOTIFY realtime bus and return a stop function.
97
+ *
98
+ * A no-op (returning a resolver that does nothing) when `PM_REALTIME_ENABLED`
99
+ * is `"false"`. Otherwise reserves a pool client on the `pm_workspace_events`
100
+ * channel, fans incoming envelopes out to local SSE clients (skipping this
101
+ * instance's own), publishes local events via `pg_notify`, and reconnects with
102
+ * exponential backoff on disconnect. The returned function undoes all of it.
103
+ *
104
+ * @returns A function that stops the bus and releases the listener.
105
+ */
47
106
  export async function startRealtimeBus() {
48
107
  if (process.env.PM_REALTIME_ENABLED === "false")
49
108
  return async () => undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"realtime-bus.js","sourceRoot":"","sources":["../../src/services/realtime-bus.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"realtime-bus.js","sourceRoot":"","sources":["../../src/services/realtime-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EACL,8BAA8B,EAC9B,mBAAmB,GAEpB,MAAM,UAAU,CAAC;AAElB,MAAM,OAAO,GAAG,qBAAqB,CAAC;AACtC,MAAM,WAAW,GAAG,UAAU,EAAE,CAAC;AACjC,MAAM,UAAU,GAAG,4EAA4E,CAAC;AAChG,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAS5C;;;;;;;;;;;;GAYG;AACH,SAAS,cAAc,CAAC,IAAa;IACnC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACxE,MAAM,MAAM,GAAG,IAA+B,CAAC;IAC/C,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC;QAC5G,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;aACnE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAClF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK;QAAE,OAAO,IAAI,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA8B,CAAC;QAC3D,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACtH,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACrJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB,EAAE,KAAe,EAAE,QAAgB;IAChF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5G,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAuB,EACvB,UAAkB,EAClB,OAAqD;IAErD,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,UAAU;QAAE,OAAO;IACpD,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,OAAO;QAAE,OAAO,KAAK,IAAI,EAAE,CAAC,SAAS,CAAC;IAE9E,IAAI,QAAQ,GAAsB,IAAI,CAAC;IACvC,IAAI,cAAc,GAA0B,IAAI,CAAC;IACjD,IAAI,gBAAgB,GAAG,GAAG,CAAC;IAC3B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,UAAU,GAAyB,IAAI,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAGpB,CAAC;IAEL,MAAM,cAAc,GAAG,CAAC,KAAc,EAA0B,EAAE;QAChE,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,OAAO,KAAK,EAAE,CAAC;QAC7D,MAAM,IAAI,GAAI,KAAoC,CAAC,IAAI,CAAC;QACxD,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,CAAC,IAAI,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnF,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,MAAkB,EAAE,OAAgB,EAAQ,EAAE;QACnE,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,CAAC,UAAU;YAAE,OAAO;QACxB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;QACpD,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACxB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAAQ,EAAE;QACjD,IAAI,OAAO,IAAI,cAAc;YAAE,OAAO;QACtC,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;QAClF,MAAM,KAAK,GAAG,gBAAgB,CAAC;QAC/B,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1D,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YAC/B,cAAc,GAAG,IAAI,CAAC;YACtB,KAAK,OAAO,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC1C,CAAC,EAAE,KAAK,CAAC,CAAC;QACV,cAAc,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,IAAmB,EAAE;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,CAAC,OAA6B,EAAQ,EAAE;YAC3D,sBAAsB,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,mBAAmB,CAAC,CAAC;QAC5E,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,KAAY,EAAQ,EAAE;YACnC,IAAI,QAAQ,KAAK,MAAM;gBAAE,OAAO;YAChC,QAAQ,GAAG,IAAI,CAAC;YAChB,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC5B,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC,CAAC;QACF,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QAC9C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC1B,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;QACxC,QAAQ,GAAG,MAAM,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,QAAQ,KAAK,MAAM;gBAAE,QAAQ,GAAG,IAAI,CAAC;YACzC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC5B,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,QAAQ,KAAK,MAAM;gBAAE,QAAQ,GAAG,IAAI,CAAC;YACzC,MAAM,MAAM,CAAC,KAAK,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACjE,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QACD,gBAAgB,GAAG,GAAG,CAAC;IACzB,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,GAAkB,EAAE;QAClC,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC;QAClC,UAAU,GAAG,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACjE,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;IAEF,MAAM,OAAO,EAAE,CAAC;IAEhB,8BAA8B,CAAC,KAAK,EAAE,SAAiB,EAAE,KAAe,EAAE,EAAE;QAC1E,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;QAC7D,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,CAAC,KAAK,CAAC,0BAA0B,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,+CAA+C,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACzF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,IAAI,EAAE;QAChB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,cAAc;YAAE,YAAY,CAAC,cAAc,CAAC,CAAC;QACjD,cAAc,GAAG,IAAI,CAAC;QACtB,8BAA8B,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,QAAQ,CAAC;QACxB,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,MAAM,CAAC,KAAK,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YACjE,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import type { Response } from "express";
2
+ /**
3
+ * One connected SSE viewer, indexed both by client id and by project so that
4
+ * per-event work scales with the clients on the affected project rather than
5
+ * the total number of connected clients.
6
+ */
2
7
  export interface SSEClient {
3
8
  id: string;
4
9
  projectId: string;
@@ -14,22 +19,151 @@ export interface PresenceUser {
14
19
  currentView: string;
15
20
  connectedAt: string;
16
21
  }
22
+ /**
23
+ * Record that a mutation in this project was just announced to clients, so the
24
+ * filesystem change-detector can suppress re-announcing the same change.
25
+ *
26
+ * @param projectId - The project whose workspace changed.
27
+ */
17
28
  export declare function noteSignaledMutation(projectId: string): void;
29
+ /**
30
+ * Record that a mutation of one specific item was just announced to clients.
31
+ *
32
+ * The mutation-event watcher consults {@link consumeSignaledItemMutation} to
33
+ * skip the matching committed-mutation event, giving per-item dedupe so a
34
+ * concurrent change to a different item by another agent is still delivered.
35
+ *
36
+ * @param projectId - The project containing the item.
37
+ * @param itemId - The item that was announced.
38
+ */
18
39
  export declare function noteSignaledItemMutation(projectId: string, itemId: string): void;
40
+ /**
41
+ * Consume one per-item signal, returning whether one was present.
42
+ *
43
+ * Returns `true` and deletes the entry when this instance already announced the
44
+ * given project+item (so the mutation-event watcher skips its own write);
45
+ * otherwise returns `false`. Consumption is one-shot: at most one event per
46
+ * recorded signal is ever suppressed.
47
+ *
48
+ * @param projectId - The project containing the item.
49
+ * @param itemId - The item to check.
50
+ * @returns True when a signal was present and has been consumed.
51
+ */
19
52
  export declare function consumeSignaledItemMutation(projectId: string, itemId: string): boolean;
53
+ /**
54
+ * Report whether a project was signaled within the given time window.
55
+ *
56
+ * @param projectId - The project to check.
57
+ * @param windowMs - How recently a signal must have been recorded.
58
+ * @param now - Current time in ms; defaults to `Date.now()` (injectable for tests).
59
+ * @returns True when a signal exists and is within the window.
60
+ */
20
61
  export declare function wasSignaledWithin(projectId: string, windowMs: number, now?: number): boolean;
62
+ /**
63
+ * Consume a project-level signal after the change-detector has attributed one
64
+ * filesystem delta to it, so suppression correlates 1:1 with a signaled write
65
+ * rather than swallowing every later delta in the window.
66
+ *
67
+ * @param projectId - The project whose signal to clear.
68
+ */
21
69
  export declare function consumeSignaledMutation(projectId: string): void;
70
+ /**
71
+ * Return the ids of projects that currently have at least one connected client,
72
+ * in the order they were first connected.
73
+ */
22
74
  export declare function getActiveProjectIds(): string[];
75
+ /**
76
+ * Install (or clear, with `null`) the cross-instance event publisher.
77
+ *
78
+ * When set, {@link broadcastProjectEvent} forwards each event to it so other
79
+ * pm-web instances receive it over the realtime bus; passing `null` detaches
80
+ * the bus.
81
+ *
82
+ * @param publisher - The async publisher, or `null` to clear.
83
+ */
23
84
  export declare function configureProjectEventPublisher(publisher: ((projectId: string, event: SSEEvent) => Promise<void>) | null): void;
85
+ /**
86
+ * Register a new SSE client and return its unsubscribe function.
87
+ *
88
+ * Indexes the client by id and project, writes an initial `connected` event,
89
+ * and schedules a presence broadcast. The returned function removes the client
90
+ * and schedules a fresh presence broadcast for the project on disconnect.
91
+ *
92
+ * @param client - The client to register.
93
+ * @returns A function that unregisters the client.
94
+ */
24
95
  export declare function addSSEClient(client: SSEClient): () => void;
96
+ /**
97
+ * Broadcast an event to a project's viewers locally and across instances.
98
+ *
99
+ * When the event data carries a plausible string `itemId`, records a per-item
100
+ * signal so the mutation-event watcher can skip the matching committed fact,
101
+ * then delivers the event to local clients and forwards it to the cross-instance
102
+ * publisher when one is configured.
103
+ *
104
+ * @param projectId - The project to broadcast to.
105
+ * @param event - The SSE event.
106
+ */
25
107
  export declare function broadcastProjectEvent(projectId: string, event: SSEEvent): void;
108
+ /**
109
+ * Deliver an event to the local SSE clients of one project.
110
+ *
111
+ * Records a project-level signal, then writes the SSE-formatted payload to every
112
+ * client in the project's set; a write to a disconnected client is swallowed
113
+ * (cleanup happens on the next heartbeat). The project-level signal is recorded
114
+ * even when the project has no clients, so a no-client call is not a complete
115
+ * no-op.
116
+ *
117
+ * @param projectId - The project to deliver to.
118
+ * @param event - The SSE event.
119
+ */
26
120
  export declare function deliverProjectEvent(projectId: string, event: SSEEvent): void;
121
+ /**
122
+ * Broadcast the current presence list to a project's viewers.
123
+ *
124
+ * A no-op when the project has no clients; otherwise writes an SSE `presence`
125
+ * event carrying the deduplicated user list to each connected client.
126
+ *
127
+ * @param projectId - The project whose presence to broadcast.
128
+ */
27
129
  export declare function broadcastPresence(projectId: string): void;
130
+ /**
131
+ * Update a client's current view when caller and client agree.
132
+ *
133
+ * Sets the view only when a client with the given id belongs to the given user
134
+ * and project, then schedules a presence broadcast. Returns whether the update
135
+ * applied, so a mismatched/stale client id is reported rather than silently
136
+ * mutating another user's view.
137
+ */
28
138
  export declare function updateClientView(clientId: string, userId: string, projectId: string, currentView: string): boolean;
139
+ /**
140
+ * Return the presence list for a project.
141
+ *
142
+ * @param projectId - The project to read.
143
+ * @returns The deduplicated presence users (empty when none connected).
144
+ */
29
145
  export declare function getProjectPresence(projectId: string): PresenceUser[];
146
+ /**
147
+ * Write the SSE response headers for a streaming connection.
148
+ *
149
+ * Sets `text/event-stream`, no-cache, keep-alive, and `X-Accel-Buffering: no`
150
+ * (so nginx/proxies do not buffer the stream), with status 200.
151
+ */
30
152
  export declare function setupSSEHeaders(res: Response): void;
153
+ /** Return the total number of currently connected SSE clients. */
31
154
  export declare function getSSEClientCount(): number;
155
+ /**
156
+ * Close long-lived clients and prune stale signal entries.
157
+ *
158
+ * Ends and removes any client connected for more than 12 hours, schedules a
159
+ * presence broadcast for each affected project, and drops project/item signal
160
+ * timestamps older than {@link SIGNAL_ENTRY_TTL_MS} (60 s).
161
+ */
32
162
  export declare function cleanupStaleClients(): void;
163
+ /**
164
+ * One Server-Sent Events message: a client-facing event `type` and an opaque
165
+ * `data` payload serialized to JSON on the wire.
166
+ */
33
167
  export interface SSEEvent {
34
168
  type: string;
35
169
  data: unknown;
@@ -17,6 +17,12 @@ const SIGNAL_ENTRY_TTL_MS = 60_000;
17
17
  // Record that an item mutation for this project was just delivered to clients
18
18
  // (via API broadcast or a received cross-process NOTIFY). The filesystem
19
19
  // change-detector uses this to suppress re-announcing changes already signaled.
20
+ /**
21
+ * Record that a mutation in this project was just announced to clients, so the
22
+ * filesystem change-detector can suppress re-announcing the same change.
23
+ *
24
+ * @param projectId - The project whose workspace changed.
25
+ */
20
26
  export function noteSignaledMutation(projectId) {
21
27
  lastSignaledAt.set(projectId, Date.now());
22
28
  }
@@ -31,6 +37,16 @@ export function noteSignaledMutation(projectId) {
31
37
  // commits, so if the watcher's poll lands between commit and broadcast one
32
38
  // duplicate workspace-changed can still reach clients. That is harmless because
33
39
  // the client handler is an idempotent refetch — noted rather than pretended away.
40
+ /**
41
+ * Record that a mutation of one specific item was just announced to clients.
42
+ *
43
+ * The mutation-event watcher consults {@link consumeSignaledItemMutation} to
44
+ * skip the matching committed-mutation event, giving per-item dedupe so a
45
+ * concurrent change to a different item by another agent is still delivered.
46
+ *
47
+ * @param projectId - The project containing the item.
48
+ * @param itemId - The item that was announced.
49
+ */
34
50
  export function noteSignaledItemMutation(projectId, itemId) {
35
51
  signaledItemAt.set(`${projectId}\u0000${itemId}`, Date.now());
36
52
  }
@@ -61,6 +77,18 @@ export function noteSignaledItemMutation(projectId, itemId) {
61
77
  // mis-pair can do is attribute the surviving event's `operation`/`author`
62
78
  // metadata to the wrong mutation — that metadata drives only a cosmetic toast,
63
79
  // never state.
80
+ /**
81
+ * Consume one per-item signal, returning whether one was present.
82
+ *
83
+ * Returns `true` and deletes the entry when this instance already announced the
84
+ * given project+item (so the mutation-event watcher skips its own write);
85
+ * otherwise returns `false`. Consumption is one-shot: at most one event per
86
+ * recorded signal is ever suppressed.
87
+ *
88
+ * @param projectId - The project containing the item.
89
+ * @param itemId - The item to check.
90
+ * @returns True when a signal was present and has been consumed.
91
+ */
64
92
  export function consumeSignaledItemMutation(projectId, itemId) {
65
93
  const key = `${projectId}\u0000${itemId}`;
66
94
  if (signaledItemAt.has(key)) {
@@ -69,6 +97,14 @@ export function consumeSignaledItemMutation(projectId, itemId) {
69
97
  }
70
98
  return false;
71
99
  }
100
+ /**
101
+ * Report whether a project was signaled within the given time window.
102
+ *
103
+ * @param projectId - The project to check.
104
+ * @param windowMs - How recently a signal must have been recorded.
105
+ * @param now - Current time in ms; defaults to `Date.now()` (injectable for tests).
106
+ * @returns True when a signal exists and is within the window.
107
+ */
72
108
  export function wasSignaledWithin(projectId, windowMs, now = Date.now()) {
73
109
  const at = lastSignaledAt.get(projectId);
74
110
  return at !== undefined && now - at <= windowMs;
@@ -78,15 +114,42 @@ export function wasSignaledWithin(projectId, windowMs, now = Date.now()) {
78
114
  // write instead of swallowing every delta for the whole window — so a later,
79
115
  // *unrelated* direct write on the shared volume is still surfaced rather than
80
116
  // being silently absorbed by a recent API/NOTIFY event's window.
117
+ /**
118
+ * Consume a project-level signal after the change-detector has attributed one
119
+ * filesystem delta to it, so suppression correlates 1:1 with a signaled write
120
+ * rather than swallowing every later delta in the window.
121
+ *
122
+ * @param projectId - The project whose signal to clear.
123
+ */
81
124
  export function consumeSignaledMutation(projectId) {
82
125
  lastSignaledAt.delete(projectId);
83
126
  }
127
+ /**
128
+ * Return the ids of projects that currently have at least one connected client,
129
+ * in the order they were first connected.
130
+ */
84
131
  export function getActiveProjectIds() {
85
132
  return [...byProject.keys()];
86
133
  }
134
+ /**
135
+ * Install (or clear, with `null`) the cross-instance event publisher.
136
+ *
137
+ * When set, {@link broadcastProjectEvent} forwards each event to it so other
138
+ * pm-web instances receive it over the realtime bus; passing `null` detaches
139
+ * the bus.
140
+ *
141
+ * @param publisher - The async publisher, or `null` to clear.
142
+ */
87
143
  export function configureProjectEventPublisher(publisher) {
88
144
  projectEventPublisher = publisher;
89
145
  }
146
+ /**
147
+ * Remove a client from both indexes.
148
+ *
149
+ * Deletes it from the by-id map and from its project's client set, dropping the
150
+ * project set entirely when it becomes empty so {@link getActiveProjectIds}
151
+ * stops reporting a project with no viewers.
152
+ */
90
153
  function removeClient(client) {
91
154
  if (byId.get(client.id) === client)
92
155
  byId.delete(client.id);
@@ -97,6 +160,12 @@ function removeClient(client) {
97
160
  byProject.delete(client.projectId);
98
161
  }
99
162
  }
163
+ /**
164
+ * Build the presence list for one project's clients, one entry per user.
165
+ *
166
+ * Deduplicates by `userId`, keeping the most-recently-connected client per user,
167
+ * and maps each to a {@link PresenceUser}. An empty or absent set yields `[]`.
168
+ */
100
169
  function presenceUsers(set) {
101
170
  if (!set || set.size === 0)
102
171
  return [];
@@ -114,6 +183,13 @@ function presenceUsers(set) {
114
183
  connectedAt: c.connectedAt.toISOString(),
115
184
  }));
116
185
  }
186
+ /**
187
+ * Debounce a presence broadcast for a project by 75 ms.
188
+ *
189
+ * Replaces any pending presence timer for the project, so a burst of
190
+ * joins/leaves/view changes triggers a single {@link broadcastPresence} rather
191
+ * than one per event.
192
+ */
117
193
  function schedulePresence(projectId) {
118
194
  const active = presenceTimers.get(projectId);
119
195
  if (active)
@@ -123,6 +199,16 @@ function schedulePresence(projectId) {
123
199
  broadcastPresence(projectId);
124
200
  }, 75));
125
201
  }
202
+ /**
203
+ * Register a new SSE client and return its unsubscribe function.
204
+ *
205
+ * Indexes the client by id and project, writes an initial `connected` event,
206
+ * and schedules a presence broadcast. The returned function removes the client
207
+ * and schedules a fresh presence broadcast for the project on disconnect.
208
+ *
209
+ * @param client - The client to register.
210
+ * @returns A function that unregisters the client.
211
+ */
126
212
  export function addSSEClient(client) {
127
213
  byId.set(client.id, client);
128
214
  let set = byProject.get(client.projectId);
@@ -142,6 +228,17 @@ export function addSSEClient(client) {
142
228
  schedulePresence(client.projectId);
143
229
  };
144
230
  }
231
+ /**
232
+ * Broadcast an event to a project's viewers locally and across instances.
233
+ *
234
+ * When the event data carries a plausible string `itemId`, records a per-item
235
+ * signal so the mutation-event watcher can skip the matching committed fact,
236
+ * then delivers the event to local clients and forwards it to the cross-instance
237
+ * publisher when one is configured.
238
+ *
239
+ * @param projectId - The project to broadcast to.
240
+ * @param event - The SSE event.
241
+ */
145
242
  export function broadcastProjectEvent(projectId, event) {
146
243
  // When a route broadcasts an item-scoped event, note it per-item so the
147
244
  // mutation-event watcher can skip the corresponding committed-mutation fact.
@@ -161,6 +258,18 @@ export function broadcastProjectEvent(projectId, event) {
161
258
  void projectEventPublisher(projectId, event).catch(() => undefined);
162
259
  }
163
260
  }
261
+ /**
262
+ * Deliver an event to the local SSE clients of one project.
263
+ *
264
+ * Records a project-level signal, then writes the SSE-formatted payload to every
265
+ * client in the project's set; a write to a disconnected client is swallowed
266
+ * (cleanup happens on the next heartbeat). The project-level signal is recorded
267
+ * even when the project has no clients, so a no-client call is not a complete
268
+ * no-op.
269
+ *
270
+ * @param projectId - The project to deliver to.
271
+ * @param event - The SSE event.
272
+ */
164
273
  export function deliverProjectEvent(projectId, event) {
165
274
  noteSignaledMutation(projectId);
166
275
  const set = byProject.get(projectId);
@@ -176,6 +285,14 @@ export function deliverProjectEvent(projectId, event) {
176
285
  }
177
286
  }
178
287
  }
288
+ /**
289
+ * Broadcast the current presence list to a project's viewers.
290
+ *
291
+ * A no-op when the project has no clients; otherwise writes an SSE `presence`
292
+ * event carrying the deduplicated user list to each connected client.
293
+ *
294
+ * @param projectId - The project whose presence to broadcast.
295
+ */
179
296
  export function broadcastPresence(projectId) {
180
297
  const set = byProject.get(projectId);
181
298
  if (!set || set.size === 0)
@@ -191,6 +308,14 @@ export function broadcastPresence(projectId) {
191
308
  }
192
309
  }
193
310
  }
311
+ /**
312
+ * Update a client's current view when caller and client agree.
313
+ *
314
+ * Sets the view only when a client with the given id belongs to the given user
315
+ * and project, then schedules a presence broadcast. Returns whether the update
316
+ * applied, so a mismatched/stale client id is reported rather than silently
317
+ * mutating another user's view.
318
+ */
194
319
  export function updateClientView(clientId, userId, projectId, currentView) {
195
320
  const client = byId.get(clientId);
196
321
  if (client && client.userId === userId && client.projectId === projectId) {
@@ -200,9 +325,21 @@ export function updateClientView(clientId, userId, projectId, currentView) {
200
325
  }
201
326
  return false;
202
327
  }
328
+ /**
329
+ * Return the presence list for a project.
330
+ *
331
+ * @param projectId - The project to read.
332
+ * @returns The deduplicated presence users (empty when none connected).
333
+ */
203
334
  export function getProjectPresence(projectId) {
204
335
  return presenceUsers(byProject.get(projectId));
205
336
  }
337
+ /**
338
+ * Write the SSE response headers for a streaming connection.
339
+ *
340
+ * Sets `text/event-stream`, no-cache, keep-alive, and `X-Accel-Buffering: no`
341
+ * (so nginx/proxies do not buffer the stream), with status 200.
342
+ */
206
343
  export function setupSSEHeaders(res) {
207
344
  res.writeHead(200, {
208
345
  "Content-Type": "text/event-stream",
@@ -211,9 +348,17 @@ export function setupSSEHeaders(res) {
211
348
  "X-Accel-Buffering": "no", // Disable nginx buffering
212
349
  });
213
350
  }
351
+ /** Return the total number of currently connected SSE clients. */
214
352
  export function getSSEClientCount() {
215
353
  return byId.size;
216
354
  }
355
+ /**
356
+ * Close long-lived clients and prune stale signal entries.
357
+ *
358
+ * Ends and removes any client connected for more than 12 hours, schedules a
359
+ * presence broadcast for each affected project, and drops project/item signal
360
+ * timestamps older than {@link SIGNAL_ENTRY_TTL_MS} (60 s).
361
+ */
217
362
  export function cleanupStaleClients() {
218
363
  const now = Date.now();
219
364
  const staleProjectIds = new Set();