stitchkit 0.60.0 → 0.61.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 (63) hide show
  1. package/dist/agent-runtime/coordinator.d.ts +10 -0
  2. package/dist/agent-runtime/coordinator.d.ts.map +1 -1
  3. package/dist/agent-runtime/run-execution.d.ts.map +1 -1
  4. package/dist/agent-runtime/runtime.d.ts.map +1 -1
  5. package/dist/agent-runtime/schemas.d.ts.map +1 -1
  6. package/dist/agent-runtime/store-driver.d.ts.map +1 -1
  7. package/dist/agent-runtime.js +97 -12
  8. package/dist/application/grammy.d.ts +12 -6
  9. package/dist/application/grammy.d.ts.map +1 -1
  10. package/dist/application/kernel.d.ts +35 -2
  11. package/dist/application/kernel.d.ts.map +1 -1
  12. package/dist/application/server-resource.d.ts.map +1 -1
  13. package/dist/application-grammy.js +5 -3
  14. package/dist/application.d.ts +1 -1
  15. package/dist/application.d.ts.map +1 -1
  16. package/dist/application.js +12 -6
  17. package/dist/browser/socket-io.d.ts +47 -0
  18. package/dist/browser/socket-io.d.ts.map +1 -1
  19. package/dist/browser/stream.d.ts +23 -0
  20. package/dist/browser/stream.d.ts.map +1 -1
  21. package/dist/cli.js +5 -4
  22. package/dist/contract/errors.d.ts +1 -0
  23. package/dist/contract/errors.d.ts.map +1 -1
  24. package/dist/contract/index.js +1 -1
  25. package/dist/{index-8pc5s3pz.js → index-1pgeyyee.js} +3 -3
  26. package/dist/{index-9h1vba8n.js → index-413xk7ga.js} +2 -1
  27. package/dist/{index-8es1hrv4.js → index-6taryy00.js} +1 -1
  28. package/dist/{index-1zencgcb.js → index-eabpd4tb.js} +61 -10
  29. package/dist/{index-3w74r08v.js → index-mfw1pec7.js} +7 -5
  30. package/dist/{index-f7521k0x.js → index-s1tywej8.js} +95 -24
  31. package/dist/{index-6fbp58g8.js → index-tvwcrx2d.js} +4 -2
  32. package/dist/{index-v6e8hnkx.js → index-wd8g8z6e.js} +1 -84
  33. package/dist/{index-2akar0rq.js → index-wrhf06ak.js} +7 -5
  34. package/dist/index-xxye8j3k.js +85 -0
  35. package/dist/{index-3hn10n4c.js → index-y91zd0ch.js} +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +213 -17
  39. package/dist/internal/optional-peer.d.ts +14 -0
  40. package/dist/internal/optional-peer.d.ts.map +1 -0
  41. package/dist/node.js +8 -7
  42. package/dist/observability/index.js +4 -3
  43. package/dist/realtime/contract.d.ts +7 -1
  44. package/dist/realtime/contract.d.ts.map +1 -1
  45. package/dist/realtime/index.d.ts +2 -1
  46. package/dist/realtime/index.d.ts.map +1 -1
  47. package/dist/realtime/rejected-frame.d.ts +86 -0
  48. package/dist/realtime/rejected-frame.d.ts.map +1 -0
  49. package/dist/realtime/request.d.ts +24 -0
  50. package/dist/realtime/request.d.ts.map +1 -1
  51. package/dist/realtime/socket.d.ts.map +1 -1
  52. package/dist/remote.js +4 -2
  53. package/dist/server/index.d.ts +1 -0
  54. package/dist/server/index.d.ts.map +1 -1
  55. package/dist/server/index.js +209 -15
  56. package/dist/server/socket-io.d.ts.map +1 -1
  57. package/dist/server/stream.d.ts.map +1 -1
  58. package/dist/server/streaming-route.d.ts +130 -0
  59. package/dist/server/streaming-route.d.ts.map +1 -0
  60. package/dist/testing.js +2 -1
  61. package/dist/tools.js +11 -9
  62. package/llms-full.txt +422 -79
  63. package/package.json +5 -5
@@ -0,0 +1,86 @@
1
+ /**
2
+ * A rejection the SENDER can see.
3
+ *
4
+ * A frame that fails the receiver's schema used to be dropped where it landed:
5
+ * the receiving side reported `onRejected` and the sending side learned
6
+ * nothing at all — it waited out its deadline and reported a timeout. For a
7
+ * distributed pair that is the worst diagnostic shape there is. The machines
8
+ * are healthy, the sockets are up, and every request times out in both
9
+ * directions at once, which reads as a network fault rather than as two peers
10
+ * disagreeing about a contract.
11
+ *
12
+ * It also quietly removed the point of putting a protocol generation in the
13
+ * envelope: the check ran, and its answer could not reach the only party able
14
+ * to act on it. There is no deployment order in which two generations coexist
15
+ * if neither can tell the other why it is being refused.
16
+ *
17
+ * So when a refused frame carries an acknowledgement callback — the one
18
+ * back-channel that already exists — the refusal is sent through it. A
19
+ * fire-and-forget event still has nowhere to answer; that boundary is real and
20
+ * is documented rather than papered over.
21
+ */
22
+ /**
23
+ * The reserved key. Namespaced because it travels on the application's own
24
+ * acknowledgement channel: this envelope is delivered INSTEAD of a value the
25
+ * application's `ack` schema would accept, and the sender recognises it before
26
+ * parsing. An application whose acknowledgement is an object carrying this
27
+ * exact key would be ambiguous — hence a key nobody writes by accident.
28
+ */
29
+ export declare const REALTIME_REJECTION_KEY = "@stitchkit/realtime-rejected";
30
+ /**
31
+ * One field the peer refused, already flattened.
32
+ *
33
+ * `path` is dotted and tuple-aware: the first payload's `v` field is `'0.v'`,
34
+ * because event arguments are a tuple. This is what replaces reading a
35
+ * `ZodError`'s internals on the receiving end — three conditions about somebody
36
+ * else's object shape, for a fact that is binary.
37
+ */
38
+ export interface RealtimeRejectionIssue {
39
+ path: string;
40
+ code: string;
41
+ message: string;
42
+ }
43
+ /**
44
+ * At most this many issues travel; a refusal is a signal, not a report.
45
+ *
46
+ * Applied on BOTH sides. On the reading side it bounds what a peer can make
47
+ * this process hold; on the writing side it bounds what a peer can make this
48
+ * process send — and that one matters more, because the number of issues is
49
+ * chosen by whoever sent the bad frame.
50
+ */
51
+ export declare const MAX_REJECTION_ISSUES = 20;
52
+ /**
53
+ * What the sender is told: which event, why, and the issues if there were any.
54
+ *
55
+ * `reason` is a union of one today, and deliberately a union: `invalid-arguments`
56
+ * is the only refusal that CAN be answered. An event the receiver's contract
57
+ * does not contain has no listener at all, so there is nothing on that side to
58
+ * answer with; a frame missing its acknowledgement callback has no channel by
59
+ * definition. Both stay reported locally, and both are honest gaps rather than
60
+ * reasons this envelope is never sent.
61
+ */
62
+ export interface RealtimeRejectionReport {
63
+ event: string;
64
+ /**
65
+ * Why the peer refused it. `invalid-arguments` is what this version sends and
66
+ * the shape a protocol-generation mismatch takes.
67
+ *
68
+ * Typed as a string rather than as a closed union **on the wire**, because a
69
+ * closed union is a mechanism that cannot version itself forward: a peer on a
70
+ * later release refusing for a reason this one has never heard of would fail
71
+ * recognition, fall through to the application's acknowledgement schema, and
72
+ * surface as "the peer answered with something invalid" — the precise
73
+ * mischaracterisation this envelope exists to prevent. An unknown reason is
74
+ * still a refusal, and is reported as one.
75
+ */
76
+ reason: string;
77
+ message: string;
78
+ issues?: RealtimeRejectionIssue[];
79
+ }
80
+ export interface RealtimeRejectionEnvelope {
81
+ [REALTIME_REJECTION_KEY]: RealtimeRejectionReport;
82
+ }
83
+ export declare function realtimeRejectionEnvelope(report: RealtimeRejectionReport): RealtimeRejectionEnvelope;
84
+ /** Whether an acknowledgement value is a peer's refusal rather than a value. */
85
+ export declare function asRealtimeRejection(value: unknown): RealtimeRejectionReport | null;
86
+ //# sourceMappingURL=rejected-frame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rejected-frame.d.ts","sourceRoot":"","sources":["../../src/realtime/rejected-frame.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AAErE;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;;;;;;GASG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;OAWG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,sBAAsB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,yBAAyB;IACxC,CAAC,sBAAsB,CAAC,EAAE,uBAAuB,CAAC;CACnD;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,uBAAuB,GAC9B,yBAAyB,CAE3B;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,GAAG,IAAI,CAgBlF"}
@@ -1,3 +1,4 @@
1
+ import type { RealtimeRejectionIssue } from './rejected-frame';
1
2
  export interface RealtimeRequestOptions {
2
3
  /** Maximum acknowledgement wait in milliseconds. Must be finite and > 0. */
3
4
  timeoutMs: number;
@@ -18,4 +19,27 @@ export declare class RealtimeRequestInvalidAcknowledgementError extends Error {
18
19
  readonly event: string;
19
20
  constructor(event: string, cause: unknown);
20
21
  }
22
+ /**
23
+ * The peer refused the frame against its own copy of the contract, and said so.
24
+ *
25
+ * Distinct from `RealtimeRequestTimeoutError` on purpose, and that distinction
26
+ * is the whole point: a refusal used to BE a timeout, so a version skew looked
27
+ * exactly like a network fault — symmetrically, on every plane at once. It is
28
+ * also distinct from `RealtimeRequestInvalidAcknowledgementError`, which means
29
+ * the peer answered with something its own contract does not allow; this one
30
+ * means the peer never got as far as answering.
31
+ */
32
+ export declare class RealtimeRequestRejectedError extends Error {
33
+ readonly code = "REALTIME_REQUEST_REJECTED";
34
+ readonly event: string;
35
+ /**
36
+ * Why the peer refused it. `invalid-arguments` is the version-skew shape and
37
+ * what a peer on this release sends; a later release may name others, so
38
+ * compare rather than exhaustively switch.
39
+ */
40
+ readonly reason: string;
41
+ /** The fields the peer refused, when it named any — validated on arrival. */
42
+ readonly issues: RealtimeRejectionIssue[] | undefined;
43
+ constructor(event: string, reason: string, detail: string, issues?: RealtimeRejectionIssue[]);
44
+ }
21
45
  //# sourceMappingURL=request.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/realtime/request.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,IAAI,8BAA8B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,YAAY,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAK3C;CACF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,IAAI,mCAAmC;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,YAAY,KAAK,EAAE,MAAM,EAIxB;CACF;AAED,qBAAa,0CAA2C,SAAQ,KAAK;IACnE,QAAQ,CAAC,IAAI,8CAA8C;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,YAAY,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAIxC;CACF"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/realtime/request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE/D,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,IAAI,8BAA8B;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,YAAY,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAK3C;CACF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,IAAI,mCAAmC;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,YAAY,KAAK,EAAE,MAAM,EAIxB;CACF;AAED,qBAAa,0CAA2C,SAAQ,KAAK;IACnE,QAAQ,CAAC,IAAI,8CAA8C;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,YAAY,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAIxC;CACF;AAED;;;;;;;;;GASG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,IAAI,+BAA+B;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,sBAAsB,EAAE,GAAG,SAAS,CAAC;IAEtD,YACE,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,sBAAsB,EAAE,EAOlC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/realtime/socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EACV,qBAAqB,EAErB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EAEvB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAIpB,UAAU,8BAA8B,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CAClF;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB;;;;;;;;;IAOhC,CAAC;AAEH,MAAM,WAAW,uBAAuB,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,EAAE,CAAC,MAAM,SAAS,MAAM,QAAQ,GAAG,MAAM,EACvC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAC9C,MAAM,IAAI,CAAC;IACd;;;;;;OAMG;IACH,IAAI,CAAC,MAAM,SAAS,MAAM,SAAS,GAAG,MAAM,EAC1C,KAAK,EAAE,MAAM,EACb,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAChD,OAAO,CAAC;CACZ;AA+DD,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,qBAAqB,EAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,uBAAuB,EAClC,IAAI,EAAE,OAAO,EAAE,GACd,OAAO,EAAE,CAuBX;AAED,wBAAgB,mCAAmC,CAAC,IAAI,SAAS,CAAC,CAAC,OAAO,EACxE,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,uBAAuB,EAClC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,yBAAyB,GAAG,SAAS,EAC3C,MAAM,EAAE,YAAY,GAAG,SAAS,GAC/B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAahB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,CAAC,QAAQ,SAAS,qBAAqB,EAC5C,KAAK,CAAC,SAAS,SAAS,qBAAqB,EAC7C,EACA,MAAM,EACN,OAAO,EACP,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,SAAS,GACV,EAAE,8BAA8B,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,uBAAuB,CAC9E,QAAQ,EACR,SAAS,CACV,CA+HA"}
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/realtime/socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EACV,qBAAqB,EAErB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EAEvB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAapB,UAAU,8BAA8B,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CAClF;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB;;;;;;;;;IAOhC,CAAC;AAEH,MAAM,WAAW,uBAAuB,CACtC,QAAQ,SAAS,qBAAqB,EACtC,SAAS,SAAS,qBAAqB;IAEvC,EAAE,CAAC,MAAM,SAAS,MAAM,QAAQ,GAAG,MAAM,EACvC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAC9C,MAAM,IAAI,CAAC;IACd;;;;;;OAMG;IACH,IAAI,CAAC,MAAM,SAAS,MAAM,SAAS,GAAG,MAAM,EAC1C,KAAK,EAAE,MAAM,EACb,GAAG,IAAI,EAAE,qBAAqB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAChD,OAAO,CAAC;CACZ;AA+GD,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,qBAAqB,EAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,uBAAuB,EAClC,IAAI,EAAE,OAAO,EAAE,GACd,OAAO,EAAE,CAuBX;AAED,wBAAgB,mCAAmC,CAAC,IAAI,SAAS,CAAC,CAAC,OAAO,EACxE,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,uBAAuB,EAClC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,yBAAyB,GAAG,SAAS,EAC3C,MAAM,EAAE,YAAY,GAAG,SAAS,GAC/B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAqChB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,CAAC,QAAQ,SAAS,qBAAqB,EAC5C,KAAK,CAAC,SAAS,SAAS,qBAAqB,EAC7C,EACA,MAAM,EACN,OAAO,EACP,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,MAAM,EACN,SAAS,GACV,EAAE,8BAA8B,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,uBAAuB,CAC9E,QAAQ,EACR,SAAS,CACV,CAwKA"}
package/dist/remote.js CHANGED
@@ -4,14 +4,16 @@ import {
4
4
  } from "./index-svqhcrrj.js";
5
5
  import"./index-48ffdxgk.js";
6
6
  import {
7
- AppError,
8
7
  mergeMeta
9
- } from "./index-v6e8hnkx.js";
8
+ } from "./index-wd8g8z6e.js";
10
9
  import"./index-6k1937bx.js";
11
10
  import"./index-pzyt11ch.js";
12
11
  import {
13
12
  isRecord
14
13
  } from "./index-smpbdg6k.js";
14
+ import {
15
+ AppError
16
+ } from "./index-xxye8j3k.js";
15
17
 
16
18
  // src/tools/remote.ts
17
19
  var HTTP_ONLY = Object.freeze(["HTTP"]);
@@ -25,6 +25,7 @@ export { type ManagedServerHandle, type ShutdownOptions, ShutdownOptionsSchema,
25
25
  export type { SocketIOHandshakeConfig, SocketIOPeerLoaders, SocketIORequestPolicy, SocketIOServerConfig, SocketIOServerHandle, SocketIOServerLifecycle, } from './socket-io';
26
26
  export { createSocketIOServer, socketIoLane } from './socket-io';
27
27
  export { type ParseSSEOptions, parseSSE, streamSSE } from './stream';
28
+ export { DEFAULT_STREAM_HEARTBEAT_MS, ndjsonRoute, type StreamingFormat, type StreamingRouteOptions, type StreamingSourceContext, sseRoute, streamingRoute, } from './streaming-route';
28
29
  export type { AuthorizationContext, EffectiveScope, EndpointHandlerContext, Handlers, LifecycleHooks, LoggingConfig, LogOutcome, MethodDef, MultipartFileMetadata, MultipartReceiver, MultipartReceiverResult, OperationIdentity, RouteGroup, ScopeContexts, ScopedHandlers, ServiceDef, StitchLogger, StreamingMultipartImplementation, } from './types';
29
30
  export { type ComposedLane, composeWebSocketHandlers, type WebSocketComposeConfig, type WebSocketLane, webSocketLane, } from './websocket';
30
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@ import {
7
7
  parseMultipart,
8
8
  socketIoLane,
9
9
  webSocketLane
10
- } from "../index-f7521k0x.js";
10
+ } from "../index-s1tywej8.js";
11
11
  import {
12
12
  composeAuthHooks,
13
13
  createAuthHook,
@@ -20,7 +20,7 @@ import {
20
20
  signJwt,
21
21
  verifyJwt,
22
22
  verifyPkce
23
- } from "../index-3w74r08v.js";
23
+ } from "../index-mfw1pec7.js";
24
24
  import {
25
25
  DEFAULT_CORS_ALLOW_HEADERS,
26
26
  DEFAULT_CORS_EXPOSE_HEADERS,
@@ -34,7 +34,7 @@ import {
34
34
  defineMultipartStream,
35
35
  implement,
36
36
  implementRegistry
37
- } from "../index-3hn10n4c.js";
37
+ } from "../index-y91zd0ch.js";
38
38
  import {
39
39
  isWithinDir,
40
40
  realPathWithinDir
@@ -65,7 +65,16 @@ import {
65
65
  resolveSocketIp,
66
66
  resolveTraceId,
67
67
  zodIssues
68
- } from "../index-6fbp58g8.js";
68
+ } from "../index-tvwcrx2d.js";
69
+ import"../index-wd8g8z6e.js";
70
+ import"../index-6k1937bx.js";
71
+ import {
72
+ joinRoutePath,
73
+ parseTrailingWildcard
74
+ } from "../index-pzyt11ch.js";
75
+ import {
76
+ isRecord
77
+ } from "../index-smpbdg6k.js";
69
78
  import {
70
79
  AppError,
71
80
  STITCH_ERROR_STATUS,
@@ -77,15 +86,7 @@ import {
77
86
  notFound,
78
87
  rateLimited,
79
88
  unauthorized
80
- } from "../index-v6e8hnkx.js";
81
- import"../index-6k1937bx.js";
82
- import {
83
- joinRoutePath,
84
- parseTrailingWildcard
85
- } from "../index-pzyt11ch.js";
86
- import {
87
- isRecord
88
- } from "../index-smpbdg6k.js";
89
+ } from "../index-xxye8j3k.js";
89
90
  // src/server/bun.ts
90
91
  import { chmodSync, statSync, unlinkSync } from "node:fs";
91
92
  function reclaimStaleUnixSocket(path) {
@@ -972,9 +973,11 @@ function streamSSE(generator) {
972
973
  controller.close();
973
974
  }
974
975
  },
975
- async cancel() {
976
+ cancel() {
976
977
  cancelled = true;
977
- await generator.return(undefined);
978
+ generator.return(undefined).catch(() => {
979
+ return;
980
+ });
978
981
  }
979
982
  });
980
983
  return new Response(stream, {
@@ -1018,10 +1021,198 @@ async function* parseSSE(response, options) {
1018
1021
  reader.releaseLock();
1019
1022
  }
1020
1023
  }
1024
+ // src/server/streaming-route.ts
1025
+ var DEFAULT_STREAM_HEARTBEAT_MS = 5000;
1026
+ var FRAMINGS = {
1027
+ ndjson: {
1028
+ contentType: "application/x-ndjson",
1029
+ keepAlive: `
1030
+ `,
1031
+ frame: (value) => `${JSON.stringify(value)}
1032
+ `
1033
+ },
1034
+ sse: {
1035
+ contentType: "text/event-stream",
1036
+ keepAlive: `: keep-alive
1037
+
1038
+ `,
1039
+ frame: (value) => `data: ${JSON.stringify(value)}
1040
+
1041
+ `,
1042
+ done: `data: [DONE]
1043
+
1044
+ `
1045
+ }
1046
+ };
1047
+ function applyIdleTimeout(server, request, seconds) {
1048
+ if (typeof server !== "object" || server === null)
1049
+ return;
1050
+ const timeout = Reflect.get(server, "timeout");
1051
+ if (typeof timeout !== "function")
1052
+ return;
1053
+ try {
1054
+ Reflect.apply(timeout, server, [request, seconds]);
1055
+ } catch {}
1056
+ }
1057
+ function unrefTimer(timer) {
1058
+ if (typeof timer !== "object" || timer === null)
1059
+ return;
1060
+ const unref = Reflect.get(timer, "unref");
1061
+ if (typeof unref === "function")
1062
+ Reflect.apply(unref, timer, []);
1063
+ }
1064
+ var MAX_BUFFERED_FRAMES = 16;
1065
+ function responseHeaders(framing, extra) {
1066
+ const headers = new Headers(extra);
1067
+ headers.set("Content-Type", framing.contentType);
1068
+ headers.set("Cache-Control", "no-cache");
1069
+ headers.set("Connection", "keep-alive");
1070
+ headers.set("X-Accel-Buffering", "no");
1071
+ return headers;
1072
+ }
1073
+ function streamingRoute(options) {
1074
+ const heartbeatMs = options.heartbeatMs ?? DEFAULT_STREAM_HEARTBEAT_MS;
1075
+ if (!Number.isFinite(heartbeatMs) || heartbeatMs <= 0) {
1076
+ throw new TypeError("heartbeatMs must be a finite positive number of milliseconds");
1077
+ }
1078
+ const idleTimeoutSeconds = options.idleTimeoutSeconds ?? 0;
1079
+ if (!Number.isInteger(idleTimeoutSeconds) || idleTimeoutSeconds < 0) {
1080
+ throw new TypeError("idleTimeoutSeconds must be a non-negative integer");
1081
+ }
1082
+ const framing = FRAMINGS[options.format ?? "ndjson"];
1083
+ return {
1084
+ method: options.method ?? "GET",
1085
+ path: options.path,
1086
+ handler: async (request, context) => {
1087
+ applyIdleTimeout(context.server, request, idleTimeoutSeconds);
1088
+ const departed = new AbortController;
1089
+ const iterable = await options.source(request, { ...context, signal: departed.signal });
1090
+ const iterator = iterable[Symbol.asyncIterator]();
1091
+ const encoder = new TextEncoder;
1092
+ let heartbeat = null;
1093
+ let closed = false;
1094
+ const stopHeartbeat = () => {
1095
+ if (heartbeat === null)
1096
+ return;
1097
+ clearInterval(heartbeat);
1098
+ heartbeat = null;
1099
+ };
1100
+ const release = () => {
1101
+ if (closed)
1102
+ return;
1103
+ closed = true;
1104
+ try {
1105
+ stopHeartbeat();
1106
+ signalDemand();
1107
+ departed.abort();
1108
+ Promise.resolve(iterator.return?.(undefined)).catch(() => {
1109
+ return;
1110
+ });
1111
+ } catch {}
1112
+ };
1113
+ let demand = null;
1114
+ const signalDemand = () => {
1115
+ const resolve2 = demand;
1116
+ demand = null;
1117
+ resolve2?.();
1118
+ };
1119
+ const stream = new ReadableStream({
1120
+ start(controller) {
1121
+ const send = (text) => {
1122
+ if (closed)
1123
+ return false;
1124
+ try {
1125
+ controller.enqueue(encoder.encode(text));
1126
+ return true;
1127
+ } catch {
1128
+ release();
1129
+ return false;
1130
+ }
1131
+ };
1132
+ const finish = () => {
1133
+ try {
1134
+ controller.close();
1135
+ } catch {}
1136
+ };
1137
+ if (request.signal.aborted) {
1138
+ release();
1139
+ finish();
1140
+ return;
1141
+ }
1142
+ request.signal.addEventListener("abort", () => {
1143
+ release();
1144
+ finish();
1145
+ });
1146
+ send(framing.keepAlive);
1147
+ heartbeat = setInterval(() => {
1148
+ if ((controller.desiredSize ?? 1) > 0)
1149
+ send(framing.keepAlive);
1150
+ }, heartbeatMs);
1151
+ unrefTimer(heartbeat);
1152
+ const awaitDemand = async () => {
1153
+ while (!closed && (controller.desiredSize ?? 1) <= 0) {
1154
+ await new Promise((resolve2) => {
1155
+ demand = resolve2;
1156
+ });
1157
+ }
1158
+ };
1159
+ let sinceYield = 0;
1160
+ (async () => {
1161
+ try {
1162
+ for (;; ) {
1163
+ await awaitDemand();
1164
+ if (closed)
1165
+ return;
1166
+ const next = await iterator.next();
1167
+ if (closed)
1168
+ return;
1169
+ if (next.done)
1170
+ break;
1171
+ if (!send(framing.frame(next.value)))
1172
+ return;
1173
+ sinceYield += 1;
1174
+ if (sinceYield >= MAX_BUFFERED_FRAMES) {
1175
+ sinceYield = 0;
1176
+ await new Promise((resolve2) => {
1177
+ setTimeout(resolve2, 0);
1178
+ });
1179
+ if (closed)
1180
+ return;
1181
+ }
1182
+ }
1183
+ if (framing.done)
1184
+ send(framing.done);
1185
+ } catch (error) {
1186
+ if (!closed)
1187
+ send(framing.frame(normalizeError(error).toJSON()));
1188
+ } finally {
1189
+ release();
1190
+ finish();
1191
+ }
1192
+ })();
1193
+ },
1194
+ pull() {
1195
+ signalDemand();
1196
+ },
1197
+ cancel() {
1198
+ release();
1199
+ }
1200
+ }, { highWaterMark: MAX_BUFFERED_FRAMES });
1201
+ return new Response(stream, { headers: responseHeaders(framing, options.headers) });
1202
+ }
1203
+ };
1204
+ }
1205
+ function ndjsonRoute(options) {
1206
+ return streamingRoute({ ...options, format: "ndjson" });
1207
+ }
1208
+ function sseRoute(options) {
1209
+ return streamingRoute({ ...options, format: "sse" });
1210
+ }
1021
1211
  export {
1022
1212
  AppError,
1023
1213
  DEFAULT_CORS_ALLOW_HEADERS,
1024
1214
  DEFAULT_CORS_EXPOSE_HEADERS,
1215
+ DEFAULT_STREAM_HEARTBEAT_MS,
1025
1216
  STITCH_ERROR_STATUS,
1026
1217
  ShutdownOptionsSchema,
1027
1218
  ShutdownResultSchema,
@@ -1068,6 +1259,7 @@ export {
1068
1259
  implementRegistry,
1069
1260
  isStitchErrorCode,
1070
1261
  isWithinDir,
1262
+ ndjsonRoute,
1071
1263
  normalizeError,
1072
1264
  notFound,
1073
1265
  openApiRoute,
@@ -1084,8 +1276,10 @@ export {
1084
1276
  serveFile,
1085
1277
  signJwt,
1086
1278
  socketIoLane,
1279
+ sseRoute,
1087
1280
  staticRoute,
1088
1281
  streamSSE,
1282
+ streamingRoute,
1089
1283
  unauthorized,
1090
1284
  verifyJwt,
1091
1285
  verifyPkce,
@@ -1 +1 @@
1
- {"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/server/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EACV,MAAM,IAAI,SAAS,EAEpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACV,gBAAgB,EAChB,MAAM,IAAI,cAAc,EAGzB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAA2B,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,aAAa,CAAC;AAc/D,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACzD;;;;;OAKG;IACH,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,6EAA6E;IAC7E,aAAa,IAAI,IAAI,CAAC;IACtB,8EAA8E;IAC9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sEAAsE;IACtE,WAAW,IAAI,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB,CACnC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EACpC,KAAK,GAAG,GAAG,CACX,SAAQ,uBAAuB;IAC/B,+EAA+E;IAC/E,EAAE,EAAE,cAAc,CAAC,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;CAC3E;AA0ID,wBAAsB,oBAAoB,CACxC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EAKpC,OAAO,GAAG,GAAG,EACb,KAAK,GAAG,OAAO,EAEf,MAAM,EAAE,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,GAC3C,OAAO,CAAC,oBAAoB,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,CAmKpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,oBAAoB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,WAAW,CAAC,GAC3E,YAAY,CAMd"}
1
+ {"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/server/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EACV,MAAM,IAAI,SAAS,EAEpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACV,gBAAgB,EAChB,MAAM,IAAI,cAAc,EAGzB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAA2B,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,aAAa,CAAC;AAc/D,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,uBAAuB;IACtC;;;;;OAKG;IACH,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACzD;;;;;OAKG;IACH,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,6EAA6E;IAC7E,aAAa,IAAI,IAAI,CAAC;IACtB,8EAA8E;IAC9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sEAAsE;IACtE,WAAW,IAAI,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB,CACnC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EACpC,KAAK,GAAG,GAAG,CACX,SAAQ,uBAAuB;IAC/B,+EAA+E;IAC/E,EAAE,EAAE,cAAc,CAAC,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;CAC3E;AA8HD,wBAAsB,oBAAoB,CACxC,aAAa,SAAS,cAAc,EACpC,aAAa,SAAS,cAAc,EAKpC,OAAO,GAAG,GAAG,EACb,KAAK,GAAG,OAAO,EAEf,MAAM,EAAE,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,GAC3C,OAAO,CAAC,oBAAoB,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,CAmKpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,oBAAoB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,WAAW,CAAC,GAC3E,YAAY,CAMd"}
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/server/stream.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,QAAQ,CAmCtE;AAED,8BAA8B;AAC9B,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpD;AAED;;;;GAIG;AACH,wBAAuB,QAAQ,CAAC,CAAC,EAC/B,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,CAAC,CAAC,CAmCnB"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/server/stream.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,QAAQ,CA2CtE;AAED,8BAA8B;AAC9B,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpD;AAED;;;;GAIG;AACH,wBAAuB,QAAQ,CAAC,CAAC,EAC/B,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,CAAC,CAAC,CAmCnB"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * A long-lived response, with the three things everyone has to remember.
3
+ *
4
+ * `RawRoute` + `ctx.server` already gave every capability needed to serve a
5
+ * continuing NDJSON or SSE body. The problem was never capability — it was that
6
+ * the author of each such route had to independently remember three unrelated
7
+ * things, and forgetting any one of them breaks the stream **silently**:
8
+ *
9
+ * 1. **Clear the generic HTTP idle timeout.** Without `server.timeout(req, 0)`
10
+ * Bun resets the connection after ten seconds. For a stream whose normal
11
+ * state is silence — a subscription to a rare event, the log of an idle
12
+ * process — that is a healthy connection being severed on a schedule.
13
+ * 2. **Send a heartbeat.** Even with the timeout cleared, intermediate proxies
14
+ * and client stacks are under no obligation to hold a connection carrying no
15
+ * bytes.
16
+ * 3. **Flush the headers at open.** A runtime does not send the response until
17
+ * the body produces something, so the consumer's `fetch` does not return
18
+ * until the first frame. On a quiet stream "subscribed and silent" becomes
19
+ * indistinguishable from "not answering" — and there is nothing to inspect,
20
+ * because there is no response yet.
21
+ *
22
+ * Each is obvious alone. Together they are a checklist that lived in the head
23
+ * of whoever wrote the route rather than in the types — and a route written
24
+ * later, doing the same job for another plane, got none of the three. Reviews
25
+ * did not catch it and neither did the tests, because every test published an
26
+ * event immediately and never lived long enough to reach the threshold. The
27
+ * shape of the defect is the point: not "done wrong", but "done incompletely,
28
+ * and the incompleteness is invisible".
29
+ *
30
+ * They are not independent, and the measurement is worth keeping: with a
31
+ * heartbeat under the threshold, point 1 does not change the outcome in
32
+ * process — either measure alone kept a connection alive through twelve
33
+ * seconds of silence, and only dropping both killed it. Point 1 earns its place
34
+ * against what a heartbeat cannot reach: a proxy or a client stack applying its
35
+ * own idle rule. Points 2 and 3 are each load-bearing on their own.
36
+ *
37
+ * A fourth thing is handled here that is easy to not even think of:
38
+ * **cancellation reaches the source.** When the consumer goes away, the async
39
+ * iterable is returned, so a departed subscriber does not leave live work
40
+ * running on the server.
41
+ */
42
+ import type { HttpMethod } from '../contract/define';
43
+ import type { RawRoute, RawRouteContext } from './types';
44
+ /** How a value becomes bytes on the wire. The only thing the two formats differ in. */
45
+ export type StreamingFormat = 'ndjson' | 'sse';
46
+ /**
47
+ * Default heartbeat, deliberately well under Bun's ten-second idle threshold.
48
+ *
49
+ * A default at or near the threshold does not protect anything: the first
50
+ * pulse would arrive at about the moment the connection was already being
51
+ * dropped, so the option would look configured and do nothing.
52
+ */
53
+ export declare const DEFAULT_STREAM_HEARTBEAT_MS = 5000;
54
+ export interface StreamingRouteOptions<TServer = unknown> {
55
+ path: string;
56
+ /** Default `GET` — a subscription is a read. */
57
+ method?: HttpMethod | 'ALL';
58
+ /** Wire framing. Default `ndjson`. */
59
+ format?: StreamingFormat;
60
+ /**
61
+ * Interval between keep-alive frames while the source is silent. Default
62
+ * `DEFAULT_STREAM_HEARTBEAT_MS`. Must be finite and positive.
63
+ */
64
+ heartbeatMs?: number;
65
+ /**
66
+ * Per-request idle timeout in **seconds**, applied through the runtime's own
67
+ * per-request control where it has one (Bun). Default `0` — no timeout.
68
+ *
69
+ * Zero by default and not by accident. The generic timeout exists to reap
70
+ * connections whose peer has gone quiet, and a stream whose normal state is
71
+ * silence is the one case where that inference is wrong — which is the reason
72
+ * this primitive is being reached for at all. It is still a field, because
73
+ * removing a general limit is a decision worth being able to see and to
74
+ * override.
75
+ */
76
+ idleTimeoutSeconds?: number;
77
+ /**
78
+ * The frames. Returned as an async iterable so a generator is the natural
79
+ * way to write one.
80
+ *
81
+ * **A source that waits must honour `context.signal`.** See
82
+ * `StreamingSourceContext` — this is the one part of cancellation the
83
+ * primitive cannot do on the source's behalf.
84
+ */
85
+ source: (request: Request, context: StreamingSourceContext<TServer>) => AsyncIterable<unknown> | Promise<AsyncIterable<unknown>>;
86
+ /** Extra response headers. The framing headers below cannot be overridden. */
87
+ headers?: Record<string, string>;
88
+ }
89
+ /**
90
+ * What a source is given, and the reason the signal is not optional.
91
+ *
92
+ * Closing an async iterator is not enough to stop a source, and the mechanism
93
+ * is worth stating because the failure is silent. An async generator serialises
94
+ * its requests: `return()` issued while a `next()` is still in flight is
95
+ * QUEUED behind it. A subscription source's `next()` is in flight almost all
96
+ * the time — that is what a subscription is — so the return is queued behind a
97
+ * promise that will only settle when the next event arrives, which for a quiet
98
+ * plane may be never. `iterator.return()` is still called, because it does
99
+ * close a source suspended at a `yield`; it simply cannot interrupt one that is
100
+ * waiting.
101
+ *
102
+ * The signal is what can. It is aborted the moment the consumer goes away —
103
+ * through either route, a request abort or a stream cancel, which are not the
104
+ * same event — and a source that awaits on it stops immediately:
105
+ *
106
+ * ```ts
107
+ * ndjsonRoute({
108
+ * path: '/events/subscribe',
109
+ * source: async function* (request, { signal }) {
110
+ * for await (const event of subscribe({ signal })) yield event
111
+ * },
112
+ * })
113
+ * ```
114
+ */
115
+ export interface StreamingSourceContext<TServer = unknown> extends RawRouteContext<TServer> {
116
+ /** Aborted when the consumer goes away. A waiting source must honour it. */
117
+ signal: AbortSignal;
118
+ }
119
+ /**
120
+ * A `RawRoute` serving a continuing body.
121
+ *
122
+ * @see ndjsonRoute
123
+ * @see sseRoute
124
+ */
125
+ export declare function streamingRoute<TServer = unknown>(options: StreamingRouteOptions<TServer>): RawRoute<TServer>;
126
+ /** A `streamingRoute` framed as newline-delimited JSON. Keep-alive is a blank line. */
127
+ export declare function ndjsonRoute<TServer = unknown>(options: Omit<StreamingRouteOptions<TServer>, 'format'>): RawRoute<TServer>;
128
+ /** A `streamingRoute` framed as Server-Sent Events — readable by `parseSSE`. */
129
+ export declare function sseRoute<TServer = unknown>(options: Omit<StreamingRouteOptions<TServer>, 'format'>): RawRoute<TServer>;
130
+ //# sourceMappingURL=streaming-route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming-route.d.ts","sourceRoot":"","sources":["../../src/server/streaming-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEzD,uFAAuF;AACvF,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AAEjD,MAAM,WAAW,qBAAqB,CAAC,OAAO,GAAG,OAAO;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,MAAM,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;IAC5B,sCAAsC;IACtC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;OAOG;IACH,MAAM,EAAE,CACN,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,sBAAsB,CAAC,OAAO,CAAC,KACrC,aAAa,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,sBAAsB,CAAC,OAAO,GAAG,OAAO,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IACzF,4EAA4E;IAC5E,MAAM,EAAE,WAAW,CAAC;CACrB;AAiGD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAG,OAAO,EAC9C,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,GACtC,QAAQ,CAAC,OAAO,CAAC,CAgNnB;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,OAAO,GAAG,OAAO,EAC3C,OAAO,EAAE,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,GACtD,QAAQ,CAAC,OAAO,CAAC,CAEnB;AAED,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,OAAO,GAAG,OAAO,EACxC,OAAO,EAAE,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,GACtD,QAAQ,CAAC,OAAO,CAAC,CAEnB"}
package/dist/testing.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  } from "./index-vtjgx3vv.js";
5
5
  import {
6
6
  createApplication
7
- } from "./index-1zencgcb.js";
7
+ } from "./index-eabpd4tb.js";
8
8
  import"./index-8eywc9zv.js";
9
9
  import {
10
10
  RealtimeRequestDisconnectedError,
@@ -32,6 +32,7 @@ import {
32
32
  import {
33
33
  isRecord
34
34
  } from "./index-smpbdg6k.js";
35
+ import"./index-xxye8j3k.js";
35
36
 
36
37
  // src/agent-runtime/testing.ts
37
38
  function createAgentRaceBarrier(timeoutMs = 5000) {