@mandujs/core 0.13.0 → 0.13.2
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.
- package/README.ko.md +4 -4
- package/README.md +653 -653
- package/package.json +1 -1
- package/src/bundler/build.ts +91 -91
- package/src/bundler/css.ts +302 -302
- package/src/client/Link.tsx +227 -227
- package/src/client/globals.ts +44 -44
- package/src/client/hooks.ts +267 -267
- package/src/client/index.ts +5 -5
- package/src/client/island.ts +8 -8
- package/src/client/router.ts +435 -435
- package/src/client/runtime.ts +23 -23
- package/src/client/serialize.ts +404 -404
- package/src/client/window-state.ts +101 -101
- package/src/config/mandu.ts +9 -0
- package/src/config/validate.ts +12 -0
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/content-layer.ts +314 -314
- package/src/content/content.test.ts +433 -433
- package/src/content/data-store.ts +245 -245
- package/src/content/digest.ts +133 -133
- package/src/content/index.ts +164 -164
- package/src/content/loader-context.ts +172 -172
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +169 -169
- package/src/content/loaders/glob.ts +252 -252
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/client.ts +16 -16
- package/src/contract/define.ts +459 -459
- package/src/contract/handler.ts +10 -10
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +404 -404
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/registry.ts +568 -568
- package/src/contract/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/contract/validator.ts +32 -32
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +465 -465
- package/src/devtools/client/catchers/error-catcher.ts +327 -327
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/catchers/network-proxy.ts +363 -363
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/kitchen-root.tsx +362 -362
- package/src/devtools/client/components/mandu-character.tsx +241 -241
- package/src/devtools/client/components/overlay.tsx +368 -368
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +244 -244
- package/src/devtools/client/components/panel/index.ts +32 -32
- package/src/devtools/client/components/panel/islands-panel.tsx +304 -304
- package/src/devtools/client/components/panel/network-panel.tsx +292 -292
- package/src/devtools/client/components/panel/panel-container.tsx +259 -259
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/client/persistence.ts +335 -335
- package/src/devtools/client/state-manager.ts +478 -478
- package/src/devtools/design-tokens.ts +263 -263
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +266 -266
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/server/source-context.ts +444 -444
- package/src/devtools/types.ts +319 -319
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +222 -222
- package/src/devtools/worker/worker-manager.ts +409 -409
- package/src/error/domains.ts +265 -265
- package/src/error/result.ts +46 -46
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/auth.ts +308 -308
- package/src/filling/context.ts +24 -1
- package/src/filling/deps.ts +238 -238
- package/src/filling/index.ts +4 -0
- package/src/filling/sse-catchup.test.ts +56 -0
- package/src/filling/sse-catchup.ts +67 -0
- package/src/filling/sse.test.ts +168 -0
- package/src/filling/sse.ts +162 -0
- package/src/generator/index.ts +3 -3
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/ast-analyzer.ts +806 -806
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/presets/index.ts +291 -291
- package/src/guard/reporter.ts +445 -445
- package/src/guard/rules.ts +12 -12
- package/src/guard/statistics.ts +578 -578
- package/src/guard/suggestions.ts +358 -358
- package/src/guard/types.ts +348 -348
- package/src/guard/validator.ts +834 -834
- package/src/guard/watcher.ts +404 -404
- package/src/index.ts +6 -1
- package/src/intent/index.ts +310 -310
- package/src/island/index.ts +304 -304
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/plugins/index.ts +38 -38
- package/src/plugins/registry.ts +377 -377
- package/src/plugins/types.ts +363 -363
- package/src/report/index.ts +1 -1
- package/src/router/fs-patterns.ts +387 -387
- package/src/router/fs-scanner.ts +497 -497
- package/src/runtime/boundary.tsx +232 -232
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/escape.ts +44 -0
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/logger.ts +677 -677
- package/src/runtime/router.test.ts +476 -476
- package/src/runtime/router.ts +105 -105
- package/src/runtime/security.ts +155 -155
- package/src/runtime/server.ts +257 -0
- package/src/runtime/session-key.ts +328 -328
- package/src/runtime/ssr.ts +16 -21
- package/src/runtime/streaming-ssr.ts +24 -33
- package/src/runtime/trace.ts +144 -144
- package/src/seo/index.ts +214 -214
- package/src/seo/integration/ssr.ts +307 -307
- package/src/seo/render/basic.ts +427 -427
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +191 -191
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +126 -126
- package/src/seo/resolve/index.ts +353 -353
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +97 -97
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +575 -575
- package/src/slot/validator.ts +39 -39
- package/src/spec/index.ts +3 -3
- package/src/spec/load.ts +76 -76
- package/src/spec/lock.ts +56 -56
- package/src/utils/bun.ts +8 -8
- package/src/utils/lru-cache.ts +75 -75
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect, mock } from "bun:test";
|
|
2
|
+
import { createSSEConnection } from "./sse";
|
|
3
|
+
import { ManduContext } from "./context";
|
|
4
|
+
|
|
5
|
+
async function readChunk(response: Response): Promise<string> {
|
|
6
|
+
const reader = response.body?.getReader();
|
|
7
|
+
if (!reader) throw new Error("Missing response body");
|
|
8
|
+
|
|
9
|
+
const { value, done } = await reader.read();
|
|
10
|
+
if (done || !value) return "";
|
|
11
|
+
return new TextDecoder().decode(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("SSEConnection", () => {
|
|
15
|
+
it("streams real-time chunks and finishes with done=true after close", async () => {
|
|
16
|
+
const server = Bun.serve({
|
|
17
|
+
port: 0,
|
|
18
|
+
fetch(req) {
|
|
19
|
+
const ctx = new ManduContext(req);
|
|
20
|
+
return ctx.sse(async (sse) => {
|
|
21
|
+
sse.event("tick", { step: 1 }, { id: "1" });
|
|
22
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
23
|
+
sse.event("tick", { step: 2 }, { id: "2" });
|
|
24
|
+
await sse.close();
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const response = await fetch(`http://127.0.0.1:${server.port}/stream`);
|
|
31
|
+
expect(response.headers.get("content-type")).toContain("text/event-stream");
|
|
32
|
+
|
|
33
|
+
const reader = response.body?.getReader();
|
|
34
|
+
if (!reader) throw new Error("Missing response body");
|
|
35
|
+
|
|
36
|
+
const firstRead = await reader.read();
|
|
37
|
+
expect(firstRead.done).toBe(false);
|
|
38
|
+
const firstChunk = new TextDecoder().decode(firstRead.value);
|
|
39
|
+
expect(firstChunk).toContain("event: tick");
|
|
40
|
+
expect(firstChunk).toContain('data: {"step":1}');
|
|
41
|
+
|
|
42
|
+
const secondRead = await reader.read();
|
|
43
|
+
expect(secondRead.done).toBe(false);
|
|
44
|
+
const secondChunk = new TextDecoder().decode(secondRead.value);
|
|
45
|
+
expect(secondChunk).toContain('data: {"step":2}');
|
|
46
|
+
|
|
47
|
+
const finalRead = await reader.read();
|
|
48
|
+
expect(finalRead.done).toBe(true);
|
|
49
|
+
} finally {
|
|
50
|
+
server.stop(true);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("closes stream when context-level SSE setup throws (error path)", async () => {
|
|
55
|
+
const ctx = new ManduContext(new Request("http://localhost/realtime-error"));
|
|
56
|
+
|
|
57
|
+
const response = ctx.sse(async () => {
|
|
58
|
+
throw new Error("setup failed");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const reader = response.body?.getReader();
|
|
62
|
+
if (!reader) throw new Error("Missing response body");
|
|
63
|
+
|
|
64
|
+
// setup error is swallowed intentionally, but stream must close cleanly.
|
|
65
|
+
await Promise.resolve();
|
|
66
|
+
const read = await reader.read();
|
|
67
|
+
expect(read.done).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
it("sends SSE event payload with metadata", async () => {
|
|
70
|
+
const sse = createSSEConnection();
|
|
71
|
+
|
|
72
|
+
sse.send({ ok: true }, { event: "ready", id: "1", retry: 3000 });
|
|
73
|
+
const chunk = await readChunk(sse.response);
|
|
74
|
+
|
|
75
|
+
expect(chunk).toContain("event: ready");
|
|
76
|
+
expect(chunk).toContain("id: 1");
|
|
77
|
+
expect(chunk).toContain("retry: 3000");
|
|
78
|
+
expect(chunk).toContain('data: {"ok":true}');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("sanitizes event/id fields to prevent SSE injection", async () => {
|
|
82
|
+
const sse = createSSEConnection();
|
|
83
|
+
|
|
84
|
+
sse.send("payload", {
|
|
85
|
+
event: "update\nretry:0",
|
|
86
|
+
id: "abc\r\ndata: injected",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const chunk = await readChunk(sse.response);
|
|
90
|
+
expect(chunk).toContain("event: update retry:0");
|
|
91
|
+
expect(chunk).toContain("id: abc data: injected");
|
|
92
|
+
expect(chunk).not.toContain("\nevent: update\nretry:0\n");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("normalizes payload lines across CR/LF variants", async () => {
|
|
96
|
+
const sse = createSSEConnection();
|
|
97
|
+
|
|
98
|
+
sse.send("a\rb\nc\r\nd");
|
|
99
|
+
const chunk = await readChunk(sse.response);
|
|
100
|
+
|
|
101
|
+
expect(chunk).toContain("data: a");
|
|
102
|
+
expect(chunk).toContain("data: b");
|
|
103
|
+
expect(chunk).toContain("data: c");
|
|
104
|
+
expect(chunk).toContain("data: d");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("registers heartbeat and cleanup on close", async () => {
|
|
108
|
+
const sse = createSSEConnection();
|
|
109
|
+
const cleanup = mock(() => {});
|
|
110
|
+
|
|
111
|
+
const stop = sse.heartbeat(1000, "ping");
|
|
112
|
+
sse.onClose(cleanup);
|
|
113
|
+
|
|
114
|
+
await sse.close();
|
|
115
|
+
|
|
116
|
+
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
117
|
+
expect(typeof stop).toBe("function");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("continues closing when cleanup handlers throw", async () => {
|
|
121
|
+
const sse = createSSEConnection();
|
|
122
|
+
const badCleanup = mock(() => {
|
|
123
|
+
throw new Error("cleanup failed");
|
|
124
|
+
});
|
|
125
|
+
const goodCleanup = mock(() => {});
|
|
126
|
+
|
|
127
|
+
sse.onClose(badCleanup);
|
|
128
|
+
sse.onClose(goodCleanup);
|
|
129
|
+
|
|
130
|
+
await expect(sse.close()).resolves.toBeUndefined();
|
|
131
|
+
expect(badCleanup).toHaveBeenCalledTimes(1);
|
|
132
|
+
expect(goodCleanup).toHaveBeenCalledTimes(1);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("does not throw when registering onClose after already closed", async () => {
|
|
136
|
+
const sse = createSSEConnection();
|
|
137
|
+
await sse.close();
|
|
138
|
+
|
|
139
|
+
const badCleanup = () => Promise.reject(new Error("late cleanup failed"));
|
|
140
|
+
expect(() => sse.onClose(badCleanup)).not.toThrow();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("closes automatically when request signal aborts", async () => {
|
|
144
|
+
const controller = new AbortController();
|
|
145
|
+
const sse = createSSEConnection(controller.signal);
|
|
146
|
+
const cleanup = mock(() => {});
|
|
147
|
+
|
|
148
|
+
sse.onClose(cleanup);
|
|
149
|
+
controller.abort();
|
|
150
|
+
|
|
151
|
+
await Promise.resolve();
|
|
152
|
+
|
|
153
|
+
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("supports context-level SSE response helper", async () => {
|
|
157
|
+
const ctx = new ManduContext(new Request("http://localhost/realtime"));
|
|
158
|
+
|
|
159
|
+
const response = ctx.sse((sse) => {
|
|
160
|
+
sse.event("message", "hello");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(response.headers.get("content-type")).toContain("text/event-stream");
|
|
164
|
+
const chunk = await readChunk(response);
|
|
165
|
+
expect(chunk).toContain("event: message");
|
|
166
|
+
expect(chunk).toContain("data: hello");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
export interface SSEOptions {
|
|
2
|
+
/** Additional headers merged into default SSE headers */
|
|
3
|
+
headers?: HeadersInit;
|
|
4
|
+
/** HTTP status code (default: 200) */
|
|
5
|
+
status?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface SSESendOptions {
|
|
9
|
+
event?: string;
|
|
10
|
+
id?: string;
|
|
11
|
+
retry?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type SSECleanup = () => void | Promise<void>;
|
|
15
|
+
|
|
16
|
+
function sanitizeSingleLineField(value: string): string {
|
|
17
|
+
return value.replace(/[\r\n]+/g, " ").trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function splitSSELines(value: string): string[] {
|
|
21
|
+
return value.split(/\r\n|[\r\n]/);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const DEFAULT_SSE_HEADERS: HeadersInit = {
|
|
25
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
26
|
+
"Cache-Control": "no-cache, no-transform",
|
|
27
|
+
Connection: "keep-alive",
|
|
28
|
+
"X-Accel-Buffering": "no",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export class SSEConnection {
|
|
32
|
+
readonly response: Response;
|
|
33
|
+
|
|
34
|
+
private controller: ReadableStreamDefaultController<Uint8Array> | null = null;
|
|
35
|
+
private encoder = new TextEncoder();
|
|
36
|
+
private pending: string[] = [];
|
|
37
|
+
private closed = false;
|
|
38
|
+
private cleanupHandlers: SSECleanup[] = [];
|
|
39
|
+
|
|
40
|
+
constructor(signal?: AbortSignal, options: SSEOptions = {}) {
|
|
41
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
42
|
+
start: (controller) => {
|
|
43
|
+
this.controller = controller;
|
|
44
|
+
for (const chunk of this.pending) {
|
|
45
|
+
controller.enqueue(this.encoder.encode(chunk));
|
|
46
|
+
}
|
|
47
|
+
this.pending = [];
|
|
48
|
+
},
|
|
49
|
+
cancel: () => {
|
|
50
|
+
this.close();
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const headers = new Headers(DEFAULT_SSE_HEADERS);
|
|
55
|
+
if (options.headers) {
|
|
56
|
+
const extra = new Headers(options.headers);
|
|
57
|
+
extra.forEach((value, key) => headers.set(key, value));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.response = new Response(stream, {
|
|
61
|
+
status: options.status ?? 200,
|
|
62
|
+
headers,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
signal?.addEventListener("abort", () => this.close(), { once: true });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
send(data: unknown, options: SSESendOptions = {}): void {
|
|
69
|
+
if (this.closed) return;
|
|
70
|
+
|
|
71
|
+
const lines: string[] = [];
|
|
72
|
+
|
|
73
|
+
if (options.event) {
|
|
74
|
+
const safeEvent = sanitizeSingleLineField(options.event);
|
|
75
|
+
if (safeEvent) lines.push(`event: ${safeEvent}`);
|
|
76
|
+
}
|
|
77
|
+
if (options.id) {
|
|
78
|
+
const safeId = sanitizeSingleLineField(options.id);
|
|
79
|
+
if (safeId) lines.push(`id: ${safeId}`);
|
|
80
|
+
}
|
|
81
|
+
if (typeof options.retry === "number") lines.push(`retry: ${Math.max(0, Math.floor(options.retry))}`);
|
|
82
|
+
|
|
83
|
+
const payload = typeof data === "string" ? data : JSON.stringify(data);
|
|
84
|
+
const payloadLines = splitSSELines(payload);
|
|
85
|
+
for (const line of payloadLines) {
|
|
86
|
+
lines.push(`data: ${line}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.enqueue(`${lines.join("\n")}\n\n`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
event(name: string, data: unknown, options: Omit<SSESendOptions, "event"> = {}): void {
|
|
93
|
+
this.send(data, { ...options, event: name });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
comment(text: string): void {
|
|
97
|
+
if (this.closed) return;
|
|
98
|
+
const lines = splitSSELines(text).map((line) => `: ${line}`);
|
|
99
|
+
this.enqueue(`${lines.join("\n")}\n\n`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
heartbeat(intervalMs = 15000, comment = "heartbeat"): () => void {
|
|
103
|
+
const timer = setInterval(() => {
|
|
104
|
+
if (this.closed) return;
|
|
105
|
+
this.comment(comment);
|
|
106
|
+
}, Math.max(1000, intervalMs));
|
|
107
|
+
|
|
108
|
+
const stop = () => clearInterval(timer);
|
|
109
|
+
this.onClose(stop);
|
|
110
|
+
return stop;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
onClose(handler: SSECleanup): void {
|
|
114
|
+
if (this.closed) {
|
|
115
|
+
void Promise.resolve(handler()).catch(() => {
|
|
116
|
+
// ignore cleanup errors after close
|
|
117
|
+
});
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
this.cleanupHandlers.push(handler);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async close(): Promise<void> {
|
|
124
|
+
if (this.closed) return;
|
|
125
|
+
this.closed = true;
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
this.controller?.close();
|
|
129
|
+
} catch {
|
|
130
|
+
// no-op
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const handlers = [...this.cleanupHandlers];
|
|
134
|
+
this.cleanupHandlers = [];
|
|
135
|
+
for (const handler of handlers) {
|
|
136
|
+
try {
|
|
137
|
+
await handler();
|
|
138
|
+
} catch {
|
|
139
|
+
// continue running remaining cleanup handlers
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private enqueue(chunk: string): void {
|
|
145
|
+
if (this.controller) {
|
|
146
|
+
try {
|
|
147
|
+
this.controller.enqueue(this.encoder.encode(chunk));
|
|
148
|
+
} catch {
|
|
149
|
+
void this.close();
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.pending.push(chunk);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Create a production-safe Server-Sent Events connection helper.
|
|
159
|
+
*/
|
|
160
|
+
export function createSSEConnection(signal?: AbortSignal, options: SSEOptions = {}): SSEConnection {
|
|
161
|
+
return new SSEConnection(signal, options);
|
|
162
|
+
}
|
package/src/generator/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from "./generate";
|
|
2
|
-
export * from "./templates";
|
|
3
|
-
export * from "./contract-glue";
|
|
1
|
+
export * from "./generate";
|
|
2
|
+
export * from "./templates";
|
|
3
|
+
export * from "./contract-glue";
|