@superblocksteam/gateway 2.0.155-next.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 (183) hide show
  1. package/LICENSE.txt +87 -0
  2. package/README.md +170 -0
  3. package/dist/agents/resolve-orchestrator-url.d.ts +22 -0
  4. package/dist/agents/resolve-orchestrator-url.js +38 -0
  5. package/dist/agents/resolve-orchestrator-url.js.map +1 -0
  6. package/dist/capabilities/import-prompt.d.ts +11 -0
  7. package/dist/capabilities/import-prompt.js +96 -0
  8. package/dist/capabilities/import-prompt.js.map +1 -0
  9. package/dist/capabilities/lifecycle.d.ts +73 -0
  10. package/dist/capabilities/lifecycle.js +2531 -0
  11. package/dist/capabilities/lifecycle.js.map +1 -0
  12. package/dist/capabilities/persisted-progress.d.ts +46 -0
  13. package/dist/capabilities/persisted-progress.js +246 -0
  14. package/dist/capabilities/persisted-progress.js.map +1 -0
  15. package/dist/capabilities/types.d.ts +446 -0
  16. package/dist/capabilities/types.js +47 -0
  17. package/dist/capabilities/types.js.map +1 -0
  18. package/dist/capture/browser-contract.d.ts +36 -0
  19. package/dist/capture/browser-contract.js +24 -0
  20. package/dist/capture/browser-contract.js.map +1 -0
  21. package/dist/capture/browser-instructions.d.ts +9 -0
  22. package/dist/capture/browser-instructions.js +17 -0
  23. package/dist/capture/browser-instructions.js.map +1 -0
  24. package/dist/capture/capture-library-probe.d.ts +55 -0
  25. package/dist/capture/capture-library-probe.js +177 -0
  26. package/dist/capture/capture-library-probe.js.map +1 -0
  27. package/dist/capture/capture-library.d.ts +52 -0
  28. package/dist/capture/capture-library.js +249 -0
  29. package/dist/capture/capture-library.js.map +1 -0
  30. package/dist/capture/classify-library-paint.d.ts +21 -0
  31. package/dist/capture/classify-library-paint.js +13 -0
  32. package/dist/capture/classify-library-paint.js.map +1 -0
  33. package/dist/capture/host-mcp-scan.d.ts +16 -0
  34. package/dist/capture/host-mcp-scan.js +64 -0
  35. package/dist/capture/host-mcp-scan.js.map +1 -0
  36. package/dist/capture/library-parent-script.d.ts +34 -0
  37. package/dist/capture/library-parent-script.js +82 -0
  38. package/dist/capture/library-parent-script.js.map +1 -0
  39. package/dist/capture/mode.d.ts +22 -0
  40. package/dist/capture/mode.js +45 -0
  41. package/dist/capture/mode.js.map +1 -0
  42. package/dist/config.d.ts +141 -0
  43. package/dist/config.js +109 -0
  44. package/dist/config.js.map +1 -0
  45. package/dist/debug.d.ts +2 -0
  46. package/dist/debug.js +9 -0
  47. package/dist/debug.js.map +1 -0
  48. package/dist/deps.d.ts +36 -0
  49. package/dist/deps.js +2 -0
  50. package/dist/deps.js.map +1 -0
  51. package/dist/events/cursor.d.ts +43 -0
  52. package/dist/events/cursor.js +78 -0
  53. package/dist/events/cursor.js.map +1 -0
  54. package/dist/events/memory-event-store.d.ts +34 -0
  55. package/dist/events/memory-event-store.js +110 -0
  56. package/dist/events/memory-event-store.js.map +1 -0
  57. package/dist/events/merge.d.ts +23 -0
  58. package/dist/events/merge.js +97 -0
  59. package/dist/events/merge.js.map +1 -0
  60. package/dist/events/normalized-collector.d.ts +62 -0
  61. package/dist/events/normalized-collector.js +156 -0
  62. package/dist/events/normalized-collector.js.map +1 -0
  63. package/dist/events/schema.d.ts +9 -0
  64. package/dist/events/schema.js +93 -0
  65. package/dist/events/schema.js.map +1 -0
  66. package/dist/events/snapshot.d.ts +32 -0
  67. package/dist/events/snapshot.js +57 -0
  68. package/dist/events/snapshot.js.map +1 -0
  69. package/dist/events/stream-key.d.ts +2 -0
  70. package/dist/events/stream-key.js +31 -0
  71. package/dist/events/stream-key.js.map +1 -0
  72. package/dist/events/types.d.ts +179 -0
  73. package/dist/events/types.js +66 -0
  74. package/dist/events/types.js.map +1 -0
  75. package/dist/health/readiness.d.ts +99 -0
  76. package/dist/health/readiness.js +202 -0
  77. package/dist/health/readiness.js.map +1 -0
  78. package/dist/index.d.ts +10 -0
  79. package/dist/index.js +10 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/integrations/filters.d.ts +8 -0
  82. package/dist/integrations/filters.js +40 -0
  83. package/dist/integrations/filters.js.map +1 -0
  84. package/dist/integrations/map.d.ts +26 -0
  85. package/dist/integrations/map.js +43 -0
  86. package/dist/integrations/map.js.map +1 -0
  87. package/dist/integrations/profile-key.d.ts +19 -0
  88. package/dist/integrations/profile-key.js +35 -0
  89. package/dist/integrations/profile-key.js.map +1 -0
  90. package/dist/main.d.ts +2 -0
  91. package/dist/main.js +5 -0
  92. package/dist/main.js.map +1 -0
  93. package/dist/orchestrator/client.d.ts +62 -0
  94. package/dist/orchestrator/client.js +160 -0
  95. package/dist/orchestrator/client.js.map +1 -0
  96. package/dist/playwright/ensure-chromium.d.ts +26 -0
  97. package/dist/playwright/ensure-chromium.js +60 -0
  98. package/dist/playwright/ensure-chromium.js.map +1 -0
  99. package/dist/preview/capture-screenshot.d.ts +52 -0
  100. package/dist/preview/capture-screenshot.js +158 -0
  101. package/dist/preview/capture-screenshot.js.map +1 -0
  102. package/dist/preview/viewer-url.d.ts +82 -0
  103. package/dist/preview/viewer-url.js +128 -0
  104. package/dist/preview/viewer-url.js.map +1 -0
  105. package/dist/process/fault-barrier.d.ts +55 -0
  106. package/dist/process/fault-barrier.js +113 -0
  107. package/dist/process/fault-barrier.js.map +1 -0
  108. package/dist/resume/memory-progress-store.d.ts +39 -0
  109. package/dist/resume/memory-progress-store.js +82 -0
  110. package/dist/resume/memory-progress-store.js.map +1 -0
  111. package/dist/resume/memory-recent-app-store.d.ts +14 -0
  112. package/dist/resume/memory-recent-app-store.js +27 -0
  113. package/dist/resume/memory-recent-app-store.js.map +1 -0
  114. package/dist/resume/memory-turn-store.d.ts +18 -0
  115. package/dist/resume/memory-turn-store.js +73 -0
  116. package/dist/resume/memory-turn-store.js.map +1 -0
  117. package/dist/resume/progress-key.d.ts +21 -0
  118. package/dist/resume/progress-key.js +58 -0
  119. package/dist/resume/progress-key.js.map +1 -0
  120. package/dist/resume/stores.d.ts +14 -0
  121. package/dist/resume/stores.js +18 -0
  122. package/dist/resume/stores.js.map +1 -0
  123. package/dist/resume/types.d.ts +124 -0
  124. package/dist/resume/types.js +13 -0
  125. package/dist/resume/types.js.map +1 -0
  126. package/dist/sabs/agent-facing-text.d.ts +33 -0
  127. package/dist/sabs/agent-facing-text.js +125 -0
  128. package/dist/sabs/agent-facing-text.js.map +1 -0
  129. package/dist/sabs/browser-context.d.ts +53 -0
  130. package/dist/sabs/browser-context.js +91 -0
  131. package/dist/sabs/browser-context.js.map +1 -0
  132. package/dist/sabs/editor-client-methods.d.ts +147 -0
  133. package/dist/sabs/editor-client-methods.js +715 -0
  134. package/dist/sabs/editor-client-methods.js.map +1 -0
  135. package/dist/sabs/recent-tool-runs.d.ts +14 -0
  136. package/dist/sabs/recent-tool-runs.js +61 -0
  137. package/dist/sabs/recent-tool-runs.js.map +1 -0
  138. package/dist/sabs/session-peer.d.ts +351 -0
  139. package/dist/sabs/session-peer.js +2 -0
  140. package/dist/sabs/session-peer.js.map +1 -0
  141. package/dist/sabs/turn-collector.d.ts +152 -0
  142. package/dist/sabs/turn-collector.js +573 -0
  143. package/dist/sabs/turn-collector.js.map +1 -0
  144. package/dist/sabs/websocket-session-peer.d.ts +514 -0
  145. package/dist/sabs/websocket-session-peer.js +2487 -0
  146. package/dist/sabs/websocket-session-peer.js.map +1 -0
  147. package/dist/security/constant-time.d.ts +9 -0
  148. package/dist/security/constant-time.js +13 -0
  149. package/dist/security/constant-time.js.map +1 -0
  150. package/dist/server/client.d.ts +371 -0
  151. package/dist/server/client.js +572 -0
  152. package/dist/server/client.js.map +1 -0
  153. package/dist/server/identity-reads.d.ts +76 -0
  154. package/dist/server/identity-reads.js +209 -0
  155. package/dist/server/identity-reads.js.map +1 -0
  156. package/dist/start.d.ts +14 -0
  157. package/dist/start.js +75 -0
  158. package/dist/start.js.map +1 -0
  159. package/dist/telemetry/metrics.d.ts +32 -0
  160. package/dist/telemetry/metrics.js +57 -0
  161. package/dist/telemetry/metrics.js.map +1 -0
  162. package/dist/transports/mcp/admin-tools.d.ts +47 -0
  163. package/dist/transports/mcp/admin-tools.js +164 -0
  164. package/dist/transports/mcp/admin-tools.js.map +1 -0
  165. package/dist/transports/mcp/app-status-html.d.ts +15 -0
  166. package/dist/transports/mcp/app-status-html.js +563 -0
  167. package/dist/transports/mcp/app-status-html.js.map +1 -0
  168. package/dist/transports/mcp/decision-elicitation.d.ts +74 -0
  169. package/dist/transports/mcp/decision-elicitation.js +233 -0
  170. package/dist/transports/mcp/decision-elicitation.js.map +1 -0
  171. package/dist/transports/mcp/dispatch-probe.d.ts +24 -0
  172. package/dist/transports/mcp/dispatch-probe.js +48 -0
  173. package/dist/transports/mcp/dispatch-probe.js.map +1 -0
  174. package/dist/transports/mcp/format-tool-content.d.ts +25 -0
  175. package/dist/transports/mcp/format-tool-content.js +48 -0
  176. package/dist/transports/mcp/format-tool-content.js.map +1 -0
  177. package/dist/transports/mcp/mount.d.ts +9 -0
  178. package/dist/transports/mcp/mount.js +469 -0
  179. package/dist/transports/mcp/mount.js.map +1 -0
  180. package/dist/transports/mcp/progress-notifier.d.ts +39 -0
  181. package/dist/transports/mcp/progress-notifier.js +52 -0
  182. package/dist/transports/mcp/progress-notifier.js.map +1 -0
  183. package/package.json +72 -0
@@ -0,0 +1,57 @@
1
+ import { advanceEventCursor, cursorPosition, } from "./cursor.js";
2
+ import { PRODUCERS_IN_ORDER, sortEvents } from "./merge.js";
3
+ import { EVENT_SNAPSHOT_TAIL } from "./types.js";
4
+ /**
5
+ * Assembles a snapshot from a store's three reads.
6
+ *
7
+ * Shared rather than written twice so the memory and Redis stores cannot drift
8
+ * into disagreeing about what resuming means — the same reason both build
9
+ * their keys from one builder. Each store supplies only the reads; the cursor
10
+ * arithmetic and the staleness rule live here.
11
+ */
12
+ export async function buildSnapshot(input, reads) {
13
+ const collected = [];
14
+ const tail = [];
15
+ const lost = [];
16
+ for (const producer of PRODUCERS_IN_ORDER) {
17
+ const resumedAfterSequence = cursorPosition(input.cursor, producer);
18
+ const afterEvents = await reads.readAfter({
19
+ afterSequence: resumedAfterSequence,
20
+ ...(input.limit === undefined ? {} : { limit: input.limit }),
21
+ producer,
22
+ });
23
+ collected.push(...afterEvents);
24
+ tail.push(...(await reads.readTail({ count: EVENT_SNAPSHOT_TAIL, producer })));
25
+ const firstRetainedSequence = await reads.firstRetainedSequence(producer);
26
+ // readAfter and firstRetainedSequence are two separate reads, not one
27
+ // atomic one, so retention can advance between them: firstRetainedSequence
28
+ // can then report a boundary past events readAfter had already captured
29
+ // moments earlier. A delivered sequence below that boundary proves the
30
+ // read beat the eviction, so what looks like a gap here never actually
31
+ // reached the caller as one.
32
+ const minDelivered = afterEvents.length > 0
33
+ ? Math.min(...afterEvents.map((event) => event.sequence))
34
+ : undefined;
35
+ const provenByDelivery = firstRetainedSequence !== undefined &&
36
+ minDelivered !== undefined &&
37
+ minDelivered < firstRetainedSequence;
38
+ // A gap only exists when the stream starts *past* the next sequence the
39
+ // cursor expects. An empty stream is not a gap: nothing was produced yet.
40
+ if (firstRetainedSequence !== undefined &&
41
+ firstRetainedSequence > resumedAfterSequence + 1 &&
42
+ !provenByDelivery) {
43
+ lost.push({ firstRetainedSequence, producer, resumedAfterSequence });
44
+ }
45
+ }
46
+ const events = sortEvents(collected);
47
+ const limited = input.limit === undefined ? events : events.slice(0, input.limit);
48
+ return {
49
+ // Advanced past what is actually being handed over, never past what was
50
+ // read and then cut by the limit — otherwise the remainder is skipped.
51
+ cursor: advanceEventCursor(input.cursor, limited),
52
+ events: limited,
53
+ lost,
54
+ tail: sortEvents(tail),
55
+ };
56
+ }
57
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/events/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,cAAc,GAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,mBAAmB,EAAuB,MAAM,YAAY,CAAC;AAqBtE;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA+C,EAC/C,KAAoB;IAEpB,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,MAAM,IAAI,GAAoB,EAAE,CAAC;IACjC,MAAM,IAAI,GAAqB,EAAE,CAAC;IAElC,KAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,CAAC;QAC1C,MAAM,oBAAoB,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpE,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC;YACxC,aAAa,EAAE,oBAAoB;YACnC,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5D,QAAQ;SACT,CAAC,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CACP,GAAG,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,CAAC,CAAC,CACpE,CAAC;QAEF,MAAM,qBAAqB,GAAG,MAAM,KAAK,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAC1E,sEAAsE;QACtE,2EAA2E;QAC3E,wEAAwE;QACxE,uEAAuE;QACvE,uEAAuE;QACvE,6BAA6B;QAC7B,MAAM,YAAY,GAChB,WAAW,CAAC,MAAM,GAAG,CAAC;YACpB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACzD,CAAC,CAAC,SAAS,CAAC;QAChB,MAAM,gBAAgB,GACpB,qBAAqB,KAAK,SAAS;YACnC,YAAY,KAAK,SAAS;YAC1B,YAAY,GAAG,qBAAqB,CAAC;QAEvC,wEAAwE;QACxE,0EAA0E;QAC1E,IACE,qBAAqB,KAAK,SAAS;YACnC,qBAAqB,GAAG,oBAAoB,GAAG,CAAC;YAChD,CAAC,gBAAgB,EACjB,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,qBAAqB,EAAE,QAAQ,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACrC,MAAM,OAAO,GACX,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACpE,OAAO;QACL,wEAAwE;QACxE,uEAAuE;QACvE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;QACjD,MAAM,EAAE,OAAO;QACf,IAAI;QACJ,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC;KACvB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { EventProducer, EventScope } from "./types.js";
2
+ export declare function streamSuffix(scope: EventScope, producer: EventProducer): string;
@@ -0,0 +1,31 @@
1
+ import { createHash } from "node:crypto";
2
+ /**
3
+ * Builds the stream address shared by every event store, so the two
4
+ * implementations cannot drift into addressing streams differently.
5
+ *
6
+ * Tenant identifiers (organization, application, live edit) are length-
7
+ * prefixed and SHA-256-digested before they reach Redis. Length-prefixing
8
+ * keeps `a:b`+`c` and `a`+`b:c` from colliding; digesting keeps the
9
+ * identifiers themselves out of key listings — ProgressStore already does
10
+ * the same for caller/org/app. The producer stays in the clear: it is a
11
+ * closed enum (`dev_server` | `sabs`), cannot identify a tenant, and naming
12
+ * the stream at a glance is worth more than the nothing it discloses.
13
+ *
14
+ * v0 has not shipped this key format, so there is no dual-read. Existing
15
+ * local Redis event keys from earlier builds are orphaned after deploy.
16
+ */
17
+ function digest(parts) {
18
+ const hash = createHash("sha256");
19
+ for (const part of parts) {
20
+ hash.update(`${part.length}:${part}`);
21
+ }
22
+ return hash.digest("hex");
23
+ }
24
+ export function streamSuffix(scope, producer) {
25
+ return `${digest([
26
+ scope.organizationId,
27
+ scope.applicationId,
28
+ scope.liveEditId,
29
+ ])}:${producer}`;
30
+ }
31
+ //# sourceMappingURL=stream-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-key.js","sourceRoot":"","sources":["../../src/events/stream-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC;;;;;;;;;;;;;;GAcG;AACH,SAAS,MAAM,CAAC,KAAwB;IACtC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,KAAiB,EACjB,QAAuB;IAEvB,OAAO,GAAG,MAAM,CAAC;QACf,KAAK,CAAC,cAAc;QACpB,KAAK,CAAC,aAAa;QACnB,KAAK,CAAC,UAAU;KACjB,CAAC,IAAI,QAAQ,EAAE,CAAC;AACnB,CAAC"}
@@ -0,0 +1,179 @@
1
+ import type { EventCursor } from "./cursor.js";
2
+ /**
3
+ * The versioned event contract SABS pushes over the direct authenticated
4
+ * callback. This mirrors `sabs/internal/gateway/event.go`; the two are kept in
5
+ * step by hand because the channel is deliberately not proto, and the bounds
6
+ * below are the only thing standing between a producer bug and unbounded
7
+ * Redis growth.
8
+ */
9
+ export declare const EVENT_CONTRACT_VERSION = 1;
10
+ export declare const MAX_IDENTIFIER_LENGTH = 128;
11
+ export declare const MAX_LABEL_LENGTH = 512;
12
+ export declare const MAX_TEXT_LENGTH = 8192;
13
+ /**
14
+ * Ceiling on an inbound sequence number. Every consumer of `sequence`
15
+ * (cursor comparisons, gap detection) does so with ordinary JS number
16
+ * arithmetic, which stops being exact past this point; a producer sequence
17
+ * that reached it would silently corrupt ordering rather than fail loudly.
18
+ */
19
+ export declare const MAX_SEQUENCE: number;
20
+ /** Kinds of fact a live-edit session reports. */
21
+ export declare const EVENT_KINDS: readonly ["auth_required", "chat_message", "generation_state", "progress", "session"];
22
+ export type LiveEditEventKind = (typeof EVENT_KINDS)[number];
23
+ /**
24
+ * Which stream a sequence number belongs to. The SABS control plane and the
25
+ * dev server both push about the same live edit and neither can see the
26
+ * other's counter, so ordering is defined per producer and Gateway keeps the
27
+ * two streams apart.
28
+ */
29
+ export declare const EVENT_PRODUCERS: readonly ["dev_server", "sabs"];
30
+ export type EventProducer = (typeof EVENT_PRODUCERS)[number];
31
+ export declare const GENERATION_STATES: readonly ["awaiting_user_input", "cancelled", "completed", "debugging", "generating", "idle", "summarizing"];
32
+ export declare const CHAT_ROLES: readonly ["assistant", "user"];
33
+ export declare const SESSION_STATUSES: readonly ["created", "terminated"];
34
+ export type LiveEditEventPayload = {
35
+ kind: "auth_required";
36
+ reason?: string;
37
+ } | {
38
+ kind: "chat_message";
39
+ messageId?: string;
40
+ messageType?: string;
41
+ role: (typeof CHAT_ROLES)[number];
42
+ text: string;
43
+ } | {
44
+ kind: "generation_state";
45
+ hasError?: boolean;
46
+ hasSuggestions?: boolean;
47
+ state: (typeof GENERATION_STATES)[number];
48
+ } | {
49
+ kind: "progress";
50
+ label: string;
51
+ } | {
52
+ kind: "session";
53
+ status: (typeof SESSION_STATUSES)[number];
54
+ };
55
+ /**
56
+ * One accepted event. `occurredAtMs` replaces the wire's ISO string so
57
+ * ordering never depends on re-parsing, and `payload` is narrowed by `kind`.
58
+ */
59
+ export type LiveEditEvent = {
60
+ applicationId: string;
61
+ eventId: string;
62
+ gatewayTurnId?: string;
63
+ kind: LiveEditEventKind;
64
+ liveEditId: string;
65
+ occurredAtMs: number;
66
+ organizationId: string;
67
+ payload: LiveEditEventPayload;
68
+ producer: EventProducer;
69
+ sequence: number;
70
+ version: typeof EVENT_CONTRACT_VERSION;
71
+ };
72
+ /**
73
+ * Why an event was refused. These values reach a metric label, so the set is
74
+ * closed and carries nothing derived from the event's content.
75
+ */
76
+ export type EventRejectionReason = "malformed_event" | "unsupported_version";
77
+ export type ParseResult = {
78
+ ok: true;
79
+ event: LiveEditEvent;
80
+ } | {
81
+ ok: false;
82
+ reason: EventRejectionReason;
83
+ };
84
+ /** Outcome of persisting one event. */
85
+ export type AppendOutcome = "accepted" | "duplicate";
86
+ /**
87
+ * The whole tenant path to one live-edit stream.
88
+ *
89
+ * A live-edit id alone would be enough to address a stream, and that is
90
+ * exactly the problem: it makes the store's isolation depend entirely on
91
+ * every caller having validated ownership first. Carrying the tenant in the
92
+ * key means a read cannot reach another tenant's history even if something
93
+ * upstream let the wrong id through.
94
+ */
95
+ export type EventScope = {
96
+ applicationId: string;
97
+ liveEditId: string;
98
+ organizationId: string;
99
+ };
100
+ /**
101
+ * A producer whose retention boundary overtook a caller's cursor.
102
+ *
103
+ * Reported rather than hidden: the caller asked to continue from a position
104
+ * that no longer exists, and answering with only the events that survived
105
+ * would present a stream with a hole in it as a complete one. Naming the
106
+ * producer and both boundaries lets a caller say exactly what it lost.
107
+ */
108
+ export type LostEventRange = {
109
+ /** Lowest sequence this producer's stream still holds. */
110
+ firstRetainedSequence: number;
111
+ producer: EventProducer;
112
+ /** Last sequence the caller's cursor had consumed. */
113
+ resumedAfterSequence: number;
114
+ };
115
+ /**
116
+ * How many events at the end of each producer's stream a snapshot carries.
117
+ *
118
+ * Current state has to be read from the stream's end rather than from the
119
+ * window after the cursor: a caller that already consumed the terminal event
120
+ * would otherwise be told nothing is known and would poll a build that ended.
121
+ * A tail bounds that read so it does not grow with the length of the session.
122
+ */
123
+ export declare const EVENT_SNAPSHOT_TAIL = 64;
124
+ /**
125
+ * What one caller sees when it resumes reading a live edit.
126
+ *
127
+ * `events` is what is new for this caller and `tail` is where the session
128
+ * currently stands; the two overlap freely and a reader is expected to take
129
+ * activity from the first and state from the second.
130
+ */
131
+ export type EventSnapshot = {
132
+ /** Advanced past every event in {@link EventSnapshot.events}. */
133
+ cursor: EventCursor;
134
+ /** Strictly after the incoming cursor, ordered deterministically. */
135
+ events: LiveEditEvent[];
136
+ /** Empty when the cursor was still inside every stream's retention. */
137
+ lost: LostEventRange[];
138
+ /** Newest {@link EVENT_SNAPSHOT_TAIL} events per producer, cursor aside. */
139
+ tail: LiveEditEvent[];
140
+ };
141
+ /**
142
+ * Durable, bounded record of what happened in a live-edit session.
143
+ *
144
+ * Retention is bounded twice over: a stream holds at most
145
+ * {@link MAX_EVENTS_PER_STREAM} events and expires after
146
+ * {@link EVENT_STREAM_TTL_MS} of silence. This is the source a resumed caller
147
+ * reads. Live turns hear Clark over the editor websocket.
148
+ */
149
+ export type EventStore = {
150
+ /** The event carries its own scope, so an append cannot be misfiled. */
151
+ append(event: LiveEditEvent): Promise<AppendOutcome>;
152
+ /** Events for a live edit, ordered deterministically across producers. */
153
+ list(input: EventScope & {
154
+ afterSequence?: number;
155
+ limit?: number;
156
+ producer?: EventProducer;
157
+ }): Promise<LiveEditEvent[]>;
158
+ /**
159
+ * Everything one caller needs to continue from where it left off, read
160
+ * without consuming anything: two callers resuming the same live edit each
161
+ * get their own view of it.
162
+ */
163
+ snapshot(input: EventScope & {
164
+ cursor?: EventCursor;
165
+ limit?: number;
166
+ }): Promise<EventSnapshot>;
167
+ };
168
+ /**
169
+ * Per-(live edit, producer) retention bound. A runaway producer overwrites its
170
+ * own oldest events rather than growing Redis without limit. The trade-off is
171
+ * explicit: an event evicted by count loses its de-duplication record, so a
172
+ * redelivery arriving after eviction is accepted again. Bounded memory is
173
+ * worth more than perfect de-duplication of an event nobody can still read.
174
+ */
175
+ export declare const MAX_EVENTS_PER_STREAM = 500;
176
+ /** How long a silent stream is kept before Redis reclaims it. */
177
+ export declare const EVENT_STREAM_TTL_MS = 3600000;
178
+ /** Cap on one inbound batch, matching the SABS publish bound. */
179
+ export declare const MAX_EVENTS_PER_REQUEST = 64;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The versioned event contract SABS pushes over the direct authenticated
3
+ * callback. This mirrors `sabs/internal/gateway/event.go`; the two are kept in
4
+ * step by hand because the channel is deliberately not proto, and the bounds
5
+ * below are the only thing standing between a producer bug and unbounded
6
+ * Redis growth.
7
+ */
8
+ export const EVENT_CONTRACT_VERSION = 1;
9
+ export const MAX_IDENTIFIER_LENGTH = 128;
10
+ export const MAX_LABEL_LENGTH = 512;
11
+ export const MAX_TEXT_LENGTH = 8192;
12
+ /**
13
+ * Ceiling on an inbound sequence number. Every consumer of `sequence`
14
+ * (cursor comparisons, gap detection) does so with ordinary JS number
15
+ * arithmetic, which stops being exact past this point; a producer sequence
16
+ * that reached it would silently corrupt ordering rather than fail loudly.
17
+ */
18
+ export const MAX_SEQUENCE = Number.MAX_SAFE_INTEGER;
19
+ /** Kinds of fact a live-edit session reports. */
20
+ export const EVENT_KINDS = [
21
+ "auth_required",
22
+ "chat_message",
23
+ "generation_state",
24
+ "progress",
25
+ "session",
26
+ ];
27
+ /**
28
+ * Which stream a sequence number belongs to. The SABS control plane and the
29
+ * dev server both push about the same live edit and neither can see the
30
+ * other's counter, so ordering is defined per producer and Gateway keeps the
31
+ * two streams apart.
32
+ */
33
+ export const EVENT_PRODUCERS = ["dev_server", "sabs"];
34
+ export const GENERATION_STATES = [
35
+ "awaiting_user_input",
36
+ "cancelled",
37
+ "completed",
38
+ "debugging",
39
+ "generating",
40
+ "idle",
41
+ "summarizing",
42
+ ];
43
+ export const CHAT_ROLES = ["assistant", "user"];
44
+ export const SESSION_STATUSES = ["created", "terminated"];
45
+ /**
46
+ * How many events at the end of each producer's stream a snapshot carries.
47
+ *
48
+ * Current state has to be read from the stream's end rather than from the
49
+ * window after the cursor: a caller that already consumed the terminal event
50
+ * would otherwise be told nothing is known and would poll a build that ended.
51
+ * A tail bounds that read so it does not grow with the length of the session.
52
+ */
53
+ export const EVENT_SNAPSHOT_TAIL = 64;
54
+ /**
55
+ * Per-(live edit, producer) retention bound. A runaway producer overwrites its
56
+ * own oldest events rather than growing Redis without limit. The trade-off is
57
+ * explicit: an event evicted by count loses its de-duplication record, so a
58
+ * redelivery arriving after eviction is accepted again. Bounded memory is
59
+ * worth more than perfect de-duplication of an event nobody can still read.
60
+ */
61
+ export const MAX_EVENTS_PER_STREAM = 500;
62
+ /** How long a silent stream is kept before Redis reclaims it. */
63
+ export const EVENT_STREAM_TTL_MS = 3_600_000;
64
+ /** Cap on one inbound batch, matching the SABS publish bound. */
65
+ export const MAX_EVENTS_PER_REQUEST = 64;
66
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/events/types.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAEpD,iDAAiD;AACjD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,eAAe;IACf,cAAc;IACd,kBAAkB;IAClB,UAAU;IACV,SAAS;CACD,CAAC;AAGX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,MAAM,CAAU,CAAC;AAG/D,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,qBAAqB;IACrB,WAAW;IACX,WAAW;IACX,WAAW;IACX,YAAY;IACZ,MAAM;IACN,aAAa;CACL,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,WAAW,EAAE,MAAM,CAAU,CAAC;AAEzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,YAAY,CAAU,CAAC;AAkFnE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAiDtC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC,iEAAiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C,iEAAiE;AACjE,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC"}
@@ -0,0 +1,99 @@
1
+ import type { GatewayFault } from "../process/fault-barrier.js";
2
+ /**
3
+ * What the gateway's own request path is doing.
4
+ *
5
+ * `unmounted` is not a degenerate case: `createApp` builds the HTTP surface
6
+ * before the MCP transport is mounted onto it, and a gateway in that window has
7
+ * no way to serve a tool call. Reporting it as healthy is the ENG-5809 bug in
8
+ * miniature.
9
+ */
10
+ export type DispatchState = "faulted" | "ok" | "unmounted" | "wedged";
11
+ export type UpstreamState = "reachable" | "unknown" | "unreachable";
12
+ export type ReadinessVerdict = {
13
+ dispatch: DispatchState;
14
+ /** Human-readable cause, present only when something is wrong. */
15
+ detail?: string;
16
+ /** Whether callers should be routed here. */
17
+ ready: boolean;
18
+ upstream: UpstreamState;
19
+ };
20
+ /**
21
+ * Proves the gateway can still take a request all the way through its own
22
+ * dispatch path. Resolving means it can; throwing or hanging means it cannot.
23
+ */
24
+ export type DispatchProbe = () => Promise<void>;
25
+ export type UpstreamProbe = () => Promise<UpstreamState>;
26
+ export type GatewayReadinessOptions = {
27
+ cacheMs?: number;
28
+ dispatchDeadlineMs?: number;
29
+ /** Where the cause behind a bounded `detail` goes. */
30
+ log?: (message: string, cause: unknown) => void;
31
+ now?: () => number;
32
+ /** The Superblocks origin this gateway fronts, named in the verdict. */
33
+ serverUrl: string;
34
+ upstreamProbe?: UpstreamProbe;
35
+ };
36
+ /**
37
+ * Probes an origin for reachability rather than for authorization.
38
+ *
39
+ * Any HTTP status is a pass, including 401: a server that refuses an
40
+ * unauthenticated probe has still proved it is answering, which is the only
41
+ * question a health check can ask without a caller's credential. Only a
42
+ * transport failure or a timeout means unreachable.
43
+ */
44
+ export declare function createUpstreamProbe(input: {
45
+ fetchImpl?: typeof fetch;
46
+ serverUrl: string;
47
+ timeoutMs?: number;
48
+ }): UpstreamProbe;
49
+ /**
50
+ * The gateway's honest answer to "are you working".
51
+ *
52
+ * Two questions, deliberately kept apart, because during the ENG-5809 outage
53
+ * nothing on the wire told the difference:
54
+ *
55
+ * - {@link liveness} asks whether *this process* can still serve. It fails on a
56
+ * broken or wedged dispatch path and on a fault it decided not to survive.
57
+ * An unreachable platform never fails it, because restarting this gateway
58
+ * cannot fix the platform, and a supervisor acting on liveness would restart
59
+ * a working process every few seconds until the platform came back.
60
+ * - {@link readiness} asks whether tool calls should be routed here, so an
61
+ * unreachable platform does fail it: nothing can be served through it.
62
+ *
63
+ * Both report `dispatch` and `upstream` as separate fields either way, so a
64
+ * caller reads which side to act on instead of inferring it from a bare "ok".
65
+ */
66
+ export declare class GatewayReadiness {
67
+ private cached;
68
+ private dispatchProbe;
69
+ private fatal;
70
+ private inFlight;
71
+ private readonly options;
72
+ constructor(options: GatewayReadinessOptions);
73
+ /**
74
+ * Hands over the real dispatch path, once there is one. Called by the MCP
75
+ * transport as it mounts; until then the gateway reports `unmounted`.
76
+ */
77
+ useDispatchProbe(probe: DispatchProbe): void;
78
+ /**
79
+ * Records what the process-level barrier caught.
80
+ *
81
+ * Only a fatal fault changes the verdict. A rejection the barrier absorbed
82
+ * cost one caller their call; failing liveness for it would hand a working
83
+ * process to a restart loop, which is the outage the barrier prevents.
84
+ */
85
+ recordFault(fault: GatewayFault): void;
86
+ liveness(): Promise<ReadinessVerdict>;
87
+ readiness(): Promise<ReadinessVerdict>;
88
+ private verdict;
89
+ /**
90
+ * One probe run per cache window, shared by however many pollers arrive
91
+ * while it is running. Eight concurrent agents polling health must not stack
92
+ * eight MCP servers onto a gateway that is already struggling.
93
+ */
94
+ private probe;
95
+ private runProbe;
96
+ private probeDispatch;
97
+ private log;
98
+ private probeUpstream;
99
+ }
@@ -0,0 +1,202 @@
1
+ import { recordReadinessVerdict } from "../telemetry/metrics.js";
2
+ /** How long the dispatch path gets to answer before it counts as wedged. */
3
+ const DEFAULT_DISPATCH_DEADLINE_MS = 5_000;
4
+ /** How long the upstream origin gets to answer before it counts as down. */
5
+ const DEFAULT_UPSTREAM_DEADLINE_MS = 3_000;
6
+ /** How long one probe run answers for. Health endpoints get polled hard. */
7
+ const DEFAULT_CACHE_MS = 2_000;
8
+ async function withDeadline(work, deadlineMs, onDeadline) {
9
+ let timer;
10
+ try {
11
+ return await Promise.race([
12
+ work,
13
+ new Promise((resolve) => {
14
+ timer = setTimeout(() => resolve(onDeadline()), deadlineMs);
15
+ timer.unref?.();
16
+ }),
17
+ ]);
18
+ }
19
+ finally {
20
+ if (timer) {
21
+ clearTimeout(timer);
22
+ }
23
+ }
24
+ }
25
+ /**
26
+ * Probes an origin for reachability rather than for authorization.
27
+ *
28
+ * Any HTTP status is a pass, including 401: a server that refuses an
29
+ * unauthenticated probe has still proved it is answering, which is the only
30
+ * question a health check can ask without a caller's credential. Only a
31
+ * transport failure or a timeout means unreachable.
32
+ */
33
+ export function createUpstreamProbe(input) {
34
+ const fetchImpl = input.fetchImpl ?? fetch;
35
+ return async () => {
36
+ try {
37
+ await fetchImpl(input.serverUrl, {
38
+ method: "GET",
39
+ signal: AbortSignal.timeout(input.timeoutMs ?? DEFAULT_UPSTREAM_DEADLINE_MS),
40
+ });
41
+ return "reachable";
42
+ }
43
+ catch {
44
+ return "unreachable";
45
+ }
46
+ };
47
+ }
48
+ /**
49
+ * The gateway's honest answer to "are you working".
50
+ *
51
+ * Two questions, deliberately kept apart, because during the ENG-5809 outage
52
+ * nothing on the wire told the difference:
53
+ *
54
+ * - {@link liveness} asks whether *this process* can still serve. It fails on a
55
+ * broken or wedged dispatch path and on a fault it decided not to survive.
56
+ * An unreachable platform never fails it, because restarting this gateway
57
+ * cannot fix the platform, and a supervisor acting on liveness would restart
58
+ * a working process every few seconds until the platform came back.
59
+ * - {@link readiness} asks whether tool calls should be routed here, so an
60
+ * unreachable platform does fail it: nothing can be served through it.
61
+ *
62
+ * Both report `dispatch` and `upstream` as separate fields either way, so a
63
+ * caller reads which side to act on instead of inferring it from a bare "ok".
64
+ */
65
+ export class GatewayReadiness {
66
+ cached;
67
+ dispatchProbe;
68
+ fatal;
69
+ inFlight;
70
+ options;
71
+ constructor(options) {
72
+ this.options = options;
73
+ }
74
+ /**
75
+ * Hands over the real dispatch path, once there is one. Called by the MCP
76
+ * transport as it mounts; until then the gateway reports `unmounted`.
77
+ */
78
+ useDispatchProbe(probe) {
79
+ this.dispatchProbe = probe;
80
+ }
81
+ /**
82
+ * Records what the process-level barrier caught.
83
+ *
84
+ * Only a fatal fault changes the verdict. A rejection the barrier absorbed
85
+ * cost one caller their call; failing liveness for it would hand a working
86
+ * process to a restart loop, which is the outage the barrier prevents.
87
+ */
88
+ recordFault(fault) {
89
+ if (fault.fatal) {
90
+ this.fatal = fault;
91
+ }
92
+ }
93
+ async liveness() {
94
+ return this.verdict("liveness");
95
+ }
96
+ async readiness() {
97
+ return this.verdict("readiness");
98
+ }
99
+ async verdict(probe) {
100
+ const probed = await this.probe();
101
+ const upstreamCounts = probe === "readiness";
102
+ const upstreamDown = upstreamCounts && probed.upstream === "unreachable";
103
+ const verdict = {
104
+ dispatch: probed.dispatch,
105
+ ready: probed.dispatch === "ok" && !upstreamDown,
106
+ upstream: probed.upstream,
107
+ ...detailOf(probed, upstreamDown, this.options.serverUrl),
108
+ };
109
+ recordReadinessVerdict({
110
+ dispatch: verdict.dispatch,
111
+ probe,
112
+ ready: verdict.ready,
113
+ upstream: verdict.upstream,
114
+ });
115
+ return verdict;
116
+ }
117
+ /**
118
+ * One probe run per cache window, shared by however many pollers arrive
119
+ * while it is running. Eight concurrent agents polling health must not stack
120
+ * eight MCP servers onto a gateway that is already struggling.
121
+ */
122
+ async probe() {
123
+ const now = (this.options.now ?? Date.now)();
124
+ const cacheMs = this.options.cacheMs ?? DEFAULT_CACHE_MS;
125
+ if (this.cached && now - this.cached.at < cacheMs) {
126
+ return this.cached;
127
+ }
128
+ this.inFlight ??= this.runProbe(now).finally(() => {
129
+ this.inFlight = undefined;
130
+ });
131
+ return this.inFlight;
132
+ }
133
+ async runProbe(at) {
134
+ const [dispatch, upstream] = await Promise.all([
135
+ this.probeDispatch(),
136
+ this.probeUpstream(),
137
+ ]);
138
+ const probed = { at, upstream, ...dispatch };
139
+ this.cached = probed;
140
+ return probed;
141
+ }
142
+ async probeDispatch() {
143
+ // A fault the process did not survive outranks anything a probe could say:
144
+ // the heap it left behind is what the probe would be running on.
145
+ if (this.fatal) {
146
+ // The kind and not the message. Both probes are unauthenticated, and an
147
+ // exception message can carry an internal route, a query, or an id that
148
+ // a caller cannot act on anyway. The message went to the log when the
149
+ // barrier caught it.
150
+ return {
151
+ dispatch: "faulted",
152
+ dispatchDetail: `The gateway recorded a fatal ${this.fatal.kind} and is waiting to be restarted.`,
153
+ };
154
+ }
155
+ const probe = this.dispatchProbe;
156
+ if (!probe) {
157
+ return {
158
+ dispatch: "unmounted",
159
+ dispatchDetail: "No MCP transport is mounted on this gateway yet.",
160
+ };
161
+ }
162
+ const deadlineMs = this.options.dispatchDeadlineMs ?? DEFAULT_DISPATCH_DEADLINE_MS;
163
+ try {
164
+ return await withDeadline(probe().then(() => ({ dispatch: "ok" })), deadlineMs, () => ({
165
+ dispatch: "wedged",
166
+ dispatchDetail: `The gateway's own dispatch path did not answer within ${deadlineMs}ms.`,
167
+ }));
168
+ }
169
+ catch (error) {
170
+ // Same reason as the fatal branch: the cause is for the operator reading
171
+ // logs, not for an unauthenticated caller reading a health endpoint.
172
+ this.log("gateway dispatch probe failed", error);
173
+ return {
174
+ dispatch: "wedged",
175
+ dispatchDetail: "The gateway's own dispatch path failed.",
176
+ };
177
+ }
178
+ }
179
+ log(message, cause) {
180
+ (this.options.log ?? ((text, err) => console.error(text, err)))(message, cause);
181
+ }
182
+ async probeUpstream() {
183
+ const probe = this.options.upstreamProbe;
184
+ if (!probe) {
185
+ return "unknown";
186
+ }
187
+ try {
188
+ return await probe();
189
+ }
190
+ catch {
191
+ return "unreachable";
192
+ }
193
+ }
194
+ }
195
+ function detailOf(probed, upstreamDown, serverUrl) {
196
+ const reasons = [
197
+ probed.dispatchDetail,
198
+ upstreamDown ? `${serverUrl} did not answer.` : undefined,
199
+ ].filter((reason) => reason !== undefined);
200
+ return reasons.length > 0 ? { detail: reasons.join(" ") } : {};
201
+ }
202
+ //# sourceMappingURL=readiness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readiness.js","sourceRoot":"","sources":["../../src/health/readiness.ts"],"names":[],"mappings":"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"}