@ereo/server 0.2.36 → 0.2.38
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/dist/bun-server.d.ts +8 -0
- package/dist/bun-server.d.ts.map +1 -1
- package/dist/index.js +281 -120
- package/dist/middleware.d.ts.map +1 -1
- package/dist/static.d.ts.map +1 -1
- package/dist/streaming.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/bun-server.d.ts
CHANGED
|
@@ -80,6 +80,9 @@ export interface ServerOptions {
|
|
|
80
80
|
* Bun server instance.
|
|
81
81
|
*/
|
|
82
82
|
export declare class BunServer {
|
|
83
|
+
private static readonly HTTP_METHODS;
|
|
84
|
+
private static readonly METHOD_OVERRIDE_HEADER;
|
|
85
|
+
private static readonly METHOD_OVERRIDE_ALLOWED;
|
|
83
86
|
private server;
|
|
84
87
|
private app;
|
|
85
88
|
private router;
|
|
@@ -87,6 +90,7 @@ export declare class BunServer {
|
|
|
87
90
|
private staticHandler;
|
|
88
91
|
private options;
|
|
89
92
|
private wsUpgradeHandlers;
|
|
93
|
+
private fetchHandler;
|
|
90
94
|
constructor(options?: ServerOptions);
|
|
91
95
|
/**
|
|
92
96
|
* Setup default middleware.
|
|
@@ -171,6 +175,7 @@ export declare class BunServer {
|
|
|
171
175
|
* Render an error page.
|
|
172
176
|
*/
|
|
173
177
|
private renderErrorPage;
|
|
178
|
+
private getEffectiveMethod;
|
|
174
179
|
/**
|
|
175
180
|
* Build meta descriptors from route's meta function.
|
|
176
181
|
*/
|
|
@@ -186,6 +191,8 @@ export declare class BunServer {
|
|
|
186
191
|
/**
|
|
187
192
|
* Build HTML string for meta tags from descriptors.
|
|
188
193
|
*/
|
|
194
|
+
private static readonly ALLOWED_LINK_ATTRS;
|
|
195
|
+
private static escapeAttr;
|
|
189
196
|
private buildMetaHtml;
|
|
190
197
|
/**
|
|
191
198
|
* Inject route meta tags into layout-rendered HTML.
|
|
@@ -235,6 +242,7 @@ export declare class BunServer {
|
|
|
235
242
|
stop(): void;
|
|
236
243
|
/**
|
|
237
244
|
* Reload the server (for HMR).
|
|
245
|
+
* Reuses the full fetch handler to preserve WebSocket upgrade logic.
|
|
238
246
|
*/
|
|
239
247
|
reload(): Promise<void>;
|
|
240
248
|
/**
|
package/dist/bun-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-server.d.ts","sourceRoot":"","sources":["../src/bun-server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAClC,OAAO,KAAK,EAAmE,iBAAiB,EAA0C,MAAM,YAAY,CAAC;AAC7J,OAAO,EAAiC,OAAO,EAAiB,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,UAAU,EAAwD,MAAM,cAAc,CAAC;AAChG,OAAO,EAIL,IAAI,EACJ,eAAe,EAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAA+C,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"bun-server.d.ts","sourceRoot":"","sources":["../src/bun-server.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -28,8 +28,16 @@ class MiddlewareChain {
|
|
|
28
28
|
let index = 0;
|
|
29
29
|
const next = async () => {
|
|
30
30
|
if (index < applicable.length) {
|
|
31
|
-
const
|
|
32
|
-
|
|
31
|
+
const currentIndex = index++;
|
|
32
|
+
const middleware = applicable[currentIndex];
|
|
33
|
+
let called = false;
|
|
34
|
+
return middleware.handler(request, context, async () => {
|
|
35
|
+
if (called) {
|
|
36
|
+
throw new Error("next() called multiple times in middleware");
|
|
37
|
+
}
|
|
38
|
+
called = true;
|
|
39
|
+
return next();
|
|
40
|
+
});
|
|
33
41
|
}
|
|
34
42
|
return final();
|
|
35
43
|
};
|
|
@@ -70,6 +78,7 @@ function cors(options = {}) {
|
|
|
70
78
|
} = options;
|
|
71
79
|
return async (request, context, next) => {
|
|
72
80
|
const requestOrigin = request.headers.get("Origin");
|
|
81
|
+
const isWildcardOrigin = typeof origin === "string" && origin === "*";
|
|
73
82
|
let allowedOrigin = null;
|
|
74
83
|
if (typeof origin === "string") {
|
|
75
84
|
allowedOrigin = origin;
|
|
@@ -78,22 +87,47 @@ function cors(options = {}) {
|
|
|
78
87
|
} else if (typeof origin === "function") {
|
|
79
88
|
allowedOrigin = requestOrigin && origin(requestOrigin) ? requestOrigin : null;
|
|
80
89
|
}
|
|
90
|
+
const responseOrigin = (() => {
|
|
91
|
+
if (allowedOrigin === "*") {
|
|
92
|
+
if (credentials && requestOrigin) {
|
|
93
|
+
return requestOrigin;
|
|
94
|
+
}
|
|
95
|
+
return "*";
|
|
96
|
+
}
|
|
97
|
+
return allowedOrigin;
|
|
98
|
+
})();
|
|
99
|
+
const shouldVaryOrigin = !isWildcardOrigin || credentials && !!requestOrigin;
|
|
81
100
|
if (request.method === "OPTIONS") {
|
|
101
|
+
if (requestOrigin && !responseOrigin) {
|
|
102
|
+
return new Response(null, { status: 403 });
|
|
103
|
+
}
|
|
82
104
|
return new Response(null, {
|
|
83
105
|
status: 204,
|
|
84
106
|
headers: {
|
|
85
|
-
"Access-Control-Allow-Origin":
|
|
107
|
+
...responseOrigin ? { "Access-Control-Allow-Origin": responseOrigin } : {},
|
|
86
108
|
"Access-Control-Allow-Methods": methods.join(", "),
|
|
87
109
|
"Access-Control-Allow-Headers": allowedHeaders.join(", "),
|
|
88
110
|
"Access-Control-Max-Age": maxAge.toString(),
|
|
89
|
-
...credentials && { "Access-Control-Allow-Credentials": "true" }
|
|
111
|
+
...credentials && { "Access-Control-Allow-Credentials": "true" },
|
|
112
|
+
...shouldVaryOrigin ? { Vary: "Origin" } : {}
|
|
90
113
|
}
|
|
91
114
|
});
|
|
92
115
|
}
|
|
93
116
|
const response = await next();
|
|
94
117
|
const headers = new Headers(response.headers);
|
|
95
|
-
if (
|
|
96
|
-
headers.set("Access-Control-Allow-Origin",
|
|
118
|
+
if (responseOrigin) {
|
|
119
|
+
headers.set("Access-Control-Allow-Origin", responseOrigin);
|
|
120
|
+
if (shouldVaryOrigin) {
|
|
121
|
+
const existingVary = headers.get("Vary");
|
|
122
|
+
if (existingVary) {
|
|
123
|
+
const parts = existingVary.split(",").map((s) => s.trim().toLowerCase());
|
|
124
|
+
if (!parts.includes("origin")) {
|
|
125
|
+
headers.set("Vary", `${existingVary}, Origin`);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
headers.set("Vary", "Origin");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
97
131
|
}
|
|
98
132
|
if (exposedHeaders.length > 0) {
|
|
99
133
|
headers.set("Access-Control-Expose-Headers", exposedHeaders.join(", "));
|
|
@@ -190,6 +224,14 @@ function rateLimit(options = {}) {
|
|
|
190
224
|
for (const k of expired) {
|
|
191
225
|
requests.delete(k);
|
|
192
226
|
}
|
|
227
|
+
if (requests.size > MAX_ENTRIES) {
|
|
228
|
+
const entries = Array.from(requests.entries());
|
|
229
|
+
entries.sort((a, b) => a[1].resetTime - b[1].resetTime);
|
|
230
|
+
const toRemove = Math.max(1, Math.floor(entries.length * 0.2));
|
|
231
|
+
for (let i = 0;i < toRemove; i++) {
|
|
232
|
+
requests.delete(entries[i][0]);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
193
235
|
}
|
|
194
236
|
if (record.count > max) {
|
|
195
237
|
return new Response(JSON.stringify({ error: "Too many requests" }), {
|
|
@@ -306,6 +348,7 @@ function serveStatic(options) {
|
|
|
306
348
|
}
|
|
307
349
|
const resolvedRoot = resolve(root);
|
|
308
350
|
let filepath = resolve(root, normalize(pathname.replace(/^\//, "")));
|
|
351
|
+
const requestedExt = extname(filepath).toLowerCase();
|
|
309
352
|
if (!filepath.startsWith(resolvedRoot)) {
|
|
310
353
|
return new Response("Forbidden", { status: 403 });
|
|
311
354
|
}
|
|
@@ -344,8 +387,7 @@ function serveStatic(options) {
|
|
|
344
387
|
} else if (maxAge > 0) {
|
|
345
388
|
headers.set("Cache-Control", `public, max-age=${maxAge}`);
|
|
346
389
|
}
|
|
347
|
-
|
|
348
|
-
if (negotiateImageFormat && NEGOTIABLE_IMAGE_EXTENSIONS.includes(ext)) {
|
|
390
|
+
if (negotiateImageFormat && NEGOTIABLE_IMAGE_EXTENSIONS.includes(requestedExt)) {
|
|
349
391
|
headers.set("Vary", "Accept");
|
|
350
392
|
}
|
|
351
393
|
const ifNoneMatch = request.headers.get("If-None-Match");
|
|
@@ -456,7 +498,7 @@ function createShell(options) {
|
|
|
456
498
|
`);
|
|
457
499
|
const scriptTags = scripts.map((src) => `<script type="module" src="${escapeAttr(src)}"></script>`).join(`
|
|
458
500
|
`);
|
|
459
|
-
const loaderScript = loaderData ? `<script>window.__EREO_DATA__=${serializeLoaderData(loaderData)}</script
|
|
501
|
+
const loaderScript = loaderData === undefined ? "" : `<script>window.__EREO_DATA__=${serializeLoaderData(loaderData)}</script>`;
|
|
460
502
|
const head = `<!DOCTYPE html>
|
|
461
503
|
<html ${htmlAttrs}>
|
|
462
504
|
<head>
|
|
@@ -480,20 +522,23 @@ function createShell(options) {
|
|
|
480
522
|
async function renderToStream(element, options) {
|
|
481
523
|
const { renderToPipeableStream } = await import("react-dom/server");
|
|
482
524
|
const { shell, scripts = [], styles = [] } = options;
|
|
483
|
-
let loaderData =
|
|
525
|
+
let loaderData = undefined;
|
|
484
526
|
if (options.match.route.module?.loader) {
|
|
485
527
|
loaderData = await options.match.route.module.loader({
|
|
486
528
|
request: options.request ?? new Request("http://localhost"),
|
|
487
529
|
params: options.match.params,
|
|
488
530
|
context: options.context
|
|
489
531
|
});
|
|
532
|
+
if (loaderData === undefined) {
|
|
533
|
+
loaderData = null;
|
|
534
|
+
}
|
|
490
535
|
}
|
|
491
|
-
const hasDeferred = hasDeferredData(loaderData);
|
|
536
|
+
const hasDeferred = loaderData !== undefined && hasDeferredData(loaderData);
|
|
492
537
|
const { head, tail } = createShell({
|
|
493
538
|
shell,
|
|
494
539
|
scripts: [],
|
|
495
540
|
styles,
|
|
496
|
-
loaderData: hasDeferred ?
|
|
541
|
+
loaderData: hasDeferred ? undefined : loaderData
|
|
497
542
|
});
|
|
498
543
|
return new Promise((resolve2, reject) => {
|
|
499
544
|
const { PassThrough } = __require("stream");
|
|
@@ -579,15 +624,18 @@ async function renderToStream(element, options) {
|
|
|
579
624
|
async function renderToString(element, options) {
|
|
580
625
|
const { renderToString: reactRenderToString } = await import("react-dom/server");
|
|
581
626
|
const { shell, scripts = [], styles = [] } = options;
|
|
582
|
-
let loaderData =
|
|
627
|
+
let loaderData = undefined;
|
|
583
628
|
if (options.match.route.module?.loader) {
|
|
584
629
|
loaderData = await options.match.route.module.loader({
|
|
585
630
|
request: options.request ?? new Request("http://localhost"),
|
|
586
631
|
params: options.match.params,
|
|
587
632
|
context: options.context
|
|
588
633
|
});
|
|
634
|
+
if (loaderData === undefined) {
|
|
635
|
+
loaderData = null;
|
|
636
|
+
}
|
|
589
637
|
}
|
|
590
|
-
if (hasDeferredData(loaderData)) {
|
|
638
|
+
if (loaderData !== undefined && hasDeferredData(loaderData)) {
|
|
591
639
|
loaderData = await resolveAllDeferred(loaderData);
|
|
592
640
|
}
|
|
593
641
|
const { head, tail } = createShell({ shell, scripts, styles, loaderData });
|
|
@@ -669,31 +717,46 @@ async function enforceAuthConfig(authConfig, request, context, params) {
|
|
|
669
717
|
}
|
|
670
718
|
|
|
671
719
|
// src/bun-server.ts
|
|
720
|
+
var _cachedRenderer = null;
|
|
721
|
+
var _rendererPromise = null;
|
|
672
722
|
async function getStreamingRenderer() {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
723
|
+
if (_cachedRenderer)
|
|
724
|
+
return _cachedRenderer;
|
|
725
|
+
if (_rendererPromise)
|
|
726
|
+
return _rendererPromise;
|
|
727
|
+
_rendererPromise = (async () => {
|
|
728
|
+
try {
|
|
729
|
+
const browserServer = await import("react-dom/server.browser");
|
|
730
|
+
if (typeof browserServer.renderToReadableStream === "function") {
|
|
731
|
+
_cachedRenderer = {
|
|
732
|
+
renderToReadableStream: browserServer.renderToReadableStream,
|
|
733
|
+
renderToString: browserServer.renderToString
|
|
734
|
+
};
|
|
735
|
+
return _cachedRenderer;
|
|
736
|
+
}
|
|
737
|
+
} catch {}
|
|
738
|
+
try {
|
|
739
|
+
const server = await import("react-dom/server");
|
|
740
|
+
_cachedRenderer = {
|
|
741
|
+
renderToReadableStream: server.renderToReadableStream,
|
|
742
|
+
renderToString: server.renderToString
|
|
679
743
|
};
|
|
744
|
+
return _cachedRenderer;
|
|
745
|
+
} catch {
|
|
746
|
+
_cachedRenderer = {
|
|
747
|
+
renderToReadableStream: undefined,
|
|
748
|
+
renderToString: (await import("react-dom/server")).renderToString
|
|
749
|
+
};
|
|
750
|
+
return _cachedRenderer;
|
|
680
751
|
}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const server = await import("react-dom/server");
|
|
684
|
-
return {
|
|
685
|
-
renderToReadableStream: server.renderToReadableStream,
|
|
686
|
-
renderToString: server.renderToString
|
|
687
|
-
};
|
|
688
|
-
} catch {
|
|
689
|
-
return {
|
|
690
|
-
renderToReadableStream: undefined,
|
|
691
|
-
renderToString: (await import("react-dom/server")).renderToString
|
|
692
|
-
};
|
|
693
|
-
}
|
|
752
|
+
})();
|
|
753
|
+
return _rendererPromise;
|
|
694
754
|
}
|
|
695
755
|
|
|
696
756
|
class BunServer {
|
|
757
|
+
static HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"];
|
|
758
|
+
static METHOD_OVERRIDE_HEADER = "_method";
|
|
759
|
+
static METHOD_OVERRIDE_ALLOWED = new Set(["PUT", "PATCH", "DELETE"]);
|
|
697
760
|
server = null;
|
|
698
761
|
app = null;
|
|
699
762
|
router = null;
|
|
@@ -701,6 +764,7 @@ class BunServer {
|
|
|
701
764
|
staticHandler = null;
|
|
702
765
|
options;
|
|
703
766
|
wsUpgradeHandlers = [];
|
|
767
|
+
fetchHandler = null;
|
|
704
768
|
constructor(options = {}) {
|
|
705
769
|
this.options = {
|
|
706
770
|
port: 3000,
|
|
@@ -843,7 +907,8 @@ class BunServer {
|
|
|
843
907
|
});
|
|
844
908
|
return context.applyToResponse(response);
|
|
845
909
|
} catch (error) {
|
|
846
|
-
|
|
910
|
+
const errorResponse = this.handleError(error, context);
|
|
911
|
+
return context.applyToResponse(errorResponse);
|
|
847
912
|
}
|
|
848
913
|
}
|
|
849
914
|
async executeRouteMiddleware(request, context, middlewareChain, handler) {
|
|
@@ -878,22 +943,29 @@ class BunServer {
|
|
|
878
943
|
if (index >= middleware.length) {
|
|
879
944
|
return handler();
|
|
880
945
|
}
|
|
881
|
-
const
|
|
882
|
-
|
|
946
|
+
const currentIndex = index++;
|
|
947
|
+
const mw = middleware[currentIndex];
|
|
948
|
+
let called = false;
|
|
949
|
+
return mw(request, context, async () => {
|
|
950
|
+
if (called) {
|
|
951
|
+
throw new Error("next() called multiple times in middleware");
|
|
952
|
+
}
|
|
953
|
+
called = true;
|
|
954
|
+
return next();
|
|
955
|
+
});
|
|
883
956
|
};
|
|
884
957
|
return next();
|
|
885
958
|
}
|
|
886
959
|
async handleRouteInner(request, match, context) {
|
|
887
960
|
const module = match.route.module;
|
|
961
|
+
const httpMethod = await this.getEffectiveMethod(request);
|
|
888
962
|
const routeAuthConfig = match.route.config?.auth || module.config?.auth;
|
|
889
963
|
if (routeAuthConfig) {
|
|
890
964
|
const denied = await enforceAuthConfig(routeAuthConfig, request, context, match.params);
|
|
891
965
|
if (denied)
|
|
892
966
|
return denied;
|
|
893
967
|
}
|
|
894
|
-
|
|
895
|
-
const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"];
|
|
896
|
-
if (HTTP_METHODS.includes(httpMethod)) {
|
|
968
|
+
if (BunServer.HTTP_METHODS.includes(httpMethod)) {
|
|
897
969
|
const methodHandler = module[httpMethod];
|
|
898
970
|
if (typeof methodHandler === "function") {
|
|
899
971
|
const result = await methodHandler({ request, params: match.params, context });
|
|
@@ -920,7 +992,7 @@ class BunServer {
|
|
|
920
992
|
if (module.beforeLoad) {
|
|
921
993
|
await module.beforeLoad({ request, params: match.params, context });
|
|
922
994
|
}
|
|
923
|
-
if (
|
|
995
|
+
if (httpMethod !== "GET" && httpMethod !== "HEAD") {
|
|
924
996
|
if (module.action) {
|
|
925
997
|
const result = await module.action({
|
|
926
998
|
request,
|
|
@@ -941,20 +1013,23 @@ class BunServer {
|
|
|
941
1013
|
}
|
|
942
1014
|
const loaderArgs2 = { request, params: match.params, context };
|
|
943
1015
|
const loaderPromises2 = [];
|
|
944
|
-
loaderPromises2.push(module.loader ? Promise.resolve(module.loader(loaderArgs2)) : Promise.resolve(
|
|
1016
|
+
loaderPromises2.push(module.loader ? Promise.resolve(module.loader(loaderArgs2)) : Promise.resolve(undefined));
|
|
945
1017
|
for (const layout of layouts) {
|
|
946
|
-
loaderPromises2.push(layout.module?.loader ? Promise.resolve(layout.module.loader(loaderArgs2)) : Promise.resolve(
|
|
1018
|
+
loaderPromises2.push(layout.module?.loader ? Promise.resolve(layout.module.loader(loaderArgs2)) : Promise.resolve(undefined));
|
|
947
1019
|
}
|
|
948
1020
|
const loaderResults2 = await Promise.all(loaderPromises2);
|
|
949
|
-
const loaderData2 = loaderResults2[0];
|
|
1021
|
+
const loaderData2 = module.loader && loaderResults2[0] === undefined ? null : loaderResults2[0];
|
|
950
1022
|
if (loaderData2 instanceof Response)
|
|
951
1023
|
return loaderData2;
|
|
952
1024
|
const layoutLoaderData2 = new Map;
|
|
953
1025
|
for (let i = 0;i < layouts.length; i++) {
|
|
954
|
-
|
|
1026
|
+
let layoutData = loaderResults2[i + 1];
|
|
1027
|
+
if (layouts[i].module?.loader && layoutData === undefined) {
|
|
1028
|
+
layoutData = null;
|
|
1029
|
+
}
|
|
955
1030
|
if (layoutData instanceof Response)
|
|
956
1031
|
return layoutData;
|
|
957
|
-
if (layoutData !==
|
|
1032
|
+
if (layoutData !== undefined)
|
|
958
1033
|
layoutLoaderData2.set(layouts[i].id, layoutData);
|
|
959
1034
|
}
|
|
960
1035
|
const routeHeaders2 = this.buildRouteHeaders(match);
|
|
@@ -971,14 +1046,14 @@ class BunServer {
|
|
|
971
1046
|
const loaderFn = () => module.loader(loaderArgs);
|
|
972
1047
|
loaderPromises.push(activeSpan ? Promise.resolve(inst.traceLoader(activeSpan, match.route.id || "route", loaderFn)) : Promise.resolve(loaderFn()));
|
|
973
1048
|
} else {
|
|
974
|
-
loaderPromises.push(Promise.resolve(
|
|
1049
|
+
loaderPromises.push(Promise.resolve(undefined));
|
|
975
1050
|
}
|
|
976
1051
|
for (const layout of layouts) {
|
|
977
1052
|
if (layout.module?.loader) {
|
|
978
1053
|
const layoutLoaderFn = () => layout.module.loader(loaderArgs);
|
|
979
1054
|
loaderPromises.push(activeSpan ? Promise.resolve(inst.traceLoader(activeSpan, `layout:${layout.id}`, layoutLoaderFn)) : Promise.resolve(layoutLoaderFn()));
|
|
980
1055
|
} else {
|
|
981
|
-
loaderPromises.push(Promise.resolve(
|
|
1056
|
+
loaderPromises.push(Promise.resolve(undefined));
|
|
982
1057
|
}
|
|
983
1058
|
}
|
|
984
1059
|
let loaderResults;
|
|
@@ -997,23 +1072,26 @@ class BunServer {
|
|
|
997
1072
|
}
|
|
998
1073
|
throw thrownError;
|
|
999
1074
|
}
|
|
1000
|
-
const loaderData = loaderResults[0];
|
|
1075
|
+
const loaderData = module.loader && loaderResults[0] === undefined ? null : loaderResults[0];
|
|
1001
1076
|
if (loaderData instanceof Response) {
|
|
1002
1077
|
return loaderData;
|
|
1003
1078
|
}
|
|
1004
1079
|
const layoutLoaderData = new Map;
|
|
1005
1080
|
for (let i = 0;i < layouts.length; i++) {
|
|
1006
|
-
|
|
1081
|
+
let layoutData = loaderResults[i + 1];
|
|
1082
|
+
if (layouts[i].module?.loader && layoutData === undefined) {
|
|
1083
|
+
layoutData = null;
|
|
1084
|
+
}
|
|
1007
1085
|
if (layoutData instanceof Response) {
|
|
1008
1086
|
return layoutData;
|
|
1009
1087
|
}
|
|
1010
|
-
if (layoutData !==
|
|
1088
|
+
if (layoutData !== undefined) {
|
|
1011
1089
|
layoutLoaderData.set(layouts[i].id, layoutData);
|
|
1012
1090
|
}
|
|
1013
1091
|
}
|
|
1014
1092
|
const routeHeaders = this.buildRouteHeaders(match);
|
|
1015
1093
|
if (request.headers.get("Accept")?.includes("application/json")) {
|
|
1016
|
-
const resolvedLoaderData = hasDeferredData2(loaderData) ? await resolveAllDeferred2(loaderData) : loaderData;
|
|
1094
|
+
const resolvedLoaderData = loaderData === undefined ? null : hasDeferredData2(loaderData) ? await resolveAllDeferred2(loaderData) : loaderData;
|
|
1017
1095
|
const jsonPayload = {
|
|
1018
1096
|
data: resolvedLoaderData,
|
|
1019
1097
|
params: match.params
|
|
@@ -1131,7 +1209,8 @@ class BunServer {
|
|
|
1131
1209
|
const headBytes = encoder.encode(head);
|
|
1132
1210
|
const tailBytes = hasDeferred ? null : encoder.encode(tail);
|
|
1133
1211
|
const abortController = new AbortController;
|
|
1134
|
-
|
|
1212
|
+
const STREAM_TIMEOUT = 1e4;
|
|
1213
|
+
timeoutId = setTimeout(() => abortController.abort(), STREAM_TIMEOUT);
|
|
1135
1214
|
const reactStream = await renderToReadableStream(element, {
|
|
1136
1215
|
bootstrapModules: [clientEntry],
|
|
1137
1216
|
signal: abortController.signal,
|
|
@@ -1152,13 +1231,19 @@ class BunServer {
|
|
|
1152
1231
|
const { done, value } = await reader.read();
|
|
1153
1232
|
if (done) {
|
|
1154
1233
|
if (hasDeferred) {
|
|
1234
|
+
clearTimeout(timeoutId);
|
|
1155
1235
|
let resolvedData;
|
|
1236
|
+
let deferredTimeoutId;
|
|
1156
1237
|
try {
|
|
1157
1238
|
resolvedData = await Promise.race([
|
|
1158
1239
|
resolveAllDeferred2(loaderData),
|
|
1159
|
-
new Promise((_, reject) =>
|
|
1240
|
+
new Promise((_, reject) => {
|
|
1241
|
+
deferredTimeoutId = setTimeout(() => reject(new Error("Deferred data resolution timed out")), STREAM_TIMEOUT);
|
|
1242
|
+
})
|
|
1160
1243
|
]);
|
|
1244
|
+
clearTimeout(deferredTimeoutId);
|
|
1161
1245
|
} catch (error) {
|
|
1246
|
+
clearTimeout(deferredTimeoutId);
|
|
1162
1247
|
console.error("Deferred data resolution failed:", error);
|
|
1163
1248
|
resolvedData = null;
|
|
1164
1249
|
}
|
|
@@ -1231,7 +1316,8 @@ class BunServer {
|
|
|
1231
1316
|
const clientEntry = this.options.clientEntry;
|
|
1232
1317
|
const encoder = new TextEncoder;
|
|
1233
1318
|
const abortController = new AbortController;
|
|
1234
|
-
|
|
1319
|
+
const STREAM_TIMEOUT = 1e4;
|
|
1320
|
+
timeoutId = setTimeout(() => abortController.abort(), STREAM_TIMEOUT);
|
|
1235
1321
|
const reactStream = await renderToReadableStream(element, {
|
|
1236
1322
|
bootstrapModules: [clientEntry],
|
|
1237
1323
|
signal: abortController.signal,
|
|
@@ -1239,10 +1325,11 @@ class BunServer {
|
|
|
1239
1325
|
console.error("Streaming render error:", error);
|
|
1240
1326
|
}
|
|
1241
1327
|
});
|
|
1242
|
-
const loaderScript = !hasDeferred && loaderData ? encoder.encode(`${traceScript}<script>window.__EREO_DATA__=${serializeLoaderData2(loaderData)}</script>`) : traceScript ? encoder.encode(traceScript) : null;
|
|
1328
|
+
const loaderScript = !hasDeferred && loaderData !== undefined ? encoder.encode(`${traceScript}<script>window.__EREO_DATA__=${serializeLoaderData2(loaderData)}</script>`) : traceScript ? encoder.encode(traceScript) : null;
|
|
1243
1329
|
const metaHtml = metaDescriptors.length > 0 ? this.buildMetaHtml(metaDescriptors) : "";
|
|
1244
1330
|
let metaInjected = metaHtml.length === 0;
|
|
1245
1331
|
const decoder = new TextDecoder;
|
|
1332
|
+
let pendingChunk = "";
|
|
1246
1333
|
const reader = reactStream.getReader();
|
|
1247
1334
|
let done = false;
|
|
1248
1335
|
const self = this;
|
|
@@ -1252,14 +1339,25 @@ class BunServer {
|
|
|
1252
1339
|
return;
|
|
1253
1340
|
const result = await reader.read();
|
|
1254
1341
|
if (result.done) {
|
|
1342
|
+
if (pendingChunk) {
|
|
1343
|
+
controller.enqueue(encoder.encode(pendingChunk));
|
|
1344
|
+
pendingChunk = "";
|
|
1345
|
+
metaInjected = true;
|
|
1346
|
+
}
|
|
1255
1347
|
if (hasDeferred) {
|
|
1348
|
+
clearTimeout(timeoutId);
|
|
1256
1349
|
let resolvedData;
|
|
1350
|
+
let deferredTimeoutId;
|
|
1257
1351
|
try {
|
|
1258
1352
|
resolvedData = await Promise.race([
|
|
1259
1353
|
resolveAllDeferred2(loaderData),
|
|
1260
|
-
new Promise((_, reject) =>
|
|
1354
|
+
new Promise((_, reject) => {
|
|
1355
|
+
deferredTimeoutId = setTimeout(() => reject(new Error("Deferred data resolution timed out")), STREAM_TIMEOUT);
|
|
1356
|
+
})
|
|
1261
1357
|
]);
|
|
1358
|
+
clearTimeout(deferredTimeoutId);
|
|
1262
1359
|
} catch (error) {
|
|
1360
|
+
clearTimeout(deferredTimeoutId);
|
|
1263
1361
|
console.error("Deferred data resolution failed:", error);
|
|
1264
1362
|
resolvedData = null;
|
|
1265
1363
|
}
|
|
@@ -1272,13 +1370,30 @@ class BunServer {
|
|
|
1272
1370
|
done = true;
|
|
1273
1371
|
} else {
|
|
1274
1372
|
if (!metaInjected) {
|
|
1275
|
-
const chunk = decoder.decode(result.value, { stream: true });
|
|
1373
|
+
const chunk = pendingChunk + decoder.decode(result.value, { stream: true });
|
|
1374
|
+
pendingChunk = "";
|
|
1276
1375
|
if (chunk.includes("</head>")) {
|
|
1277
1376
|
const injected = self.injectMetaIntoHtml(chunk, metaDescriptors);
|
|
1278
1377
|
controller.enqueue(encoder.encode(injected));
|
|
1279
1378
|
metaInjected = true;
|
|
1280
1379
|
return;
|
|
1281
1380
|
}
|
|
1381
|
+
const tail = chunk.slice(-6);
|
|
1382
|
+
const headTag = "</head>";
|
|
1383
|
+
let bufferFrom = -1;
|
|
1384
|
+
for (let i = 1;i < headTag.length; i++) {
|
|
1385
|
+
if (chunk.endsWith(headTag.slice(0, i))) {
|
|
1386
|
+
bufferFrom = chunk.length - i;
|
|
1387
|
+
break;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
if (bufferFrom >= 0) {
|
|
1391
|
+
controller.enqueue(encoder.encode(chunk.slice(0, bufferFrom)));
|
|
1392
|
+
pendingChunk = chunk.slice(bufferFrom);
|
|
1393
|
+
} else {
|
|
1394
|
+
controller.enqueue(encoder.encode(chunk));
|
|
1395
|
+
}
|
|
1396
|
+
return;
|
|
1282
1397
|
}
|
|
1283
1398
|
controller.enqueue(result.value);
|
|
1284
1399
|
}
|
|
@@ -1308,7 +1423,7 @@ class BunServer {
|
|
|
1308
1423
|
if (metaDescriptors.length > 0) {
|
|
1309
1424
|
html = this.injectMetaIntoHtml(html, metaDescriptors);
|
|
1310
1425
|
}
|
|
1311
|
-
const loaderScript = resolvedData ? `${traceScript}<script>window.__EREO_DATA__=${serializeLoaderData2(resolvedData)}</script>` : traceScript;
|
|
1426
|
+
const loaderScript = resolvedData !== undefined ? `${traceScript}<script>window.__EREO_DATA__=${serializeLoaderData2(resolvedData)}</script>` : traceScript;
|
|
1312
1427
|
const clientScript = `<script type="module" src="${this.options.clientEntry}"></script>`;
|
|
1313
1428
|
if (html.includes("</body>")) {
|
|
1314
1429
|
html = html.replace("</body>", `${loaderScript}${clientScript}</body>`);
|
|
@@ -1386,6 +1501,33 @@ class BunServer {
|
|
|
1386
1501
|
}
|
|
1387
1502
|
});
|
|
1388
1503
|
}
|
|
1504
|
+
async getEffectiveMethod(request) {
|
|
1505
|
+
const method = request.method.toUpperCase();
|
|
1506
|
+
if (method !== "POST") {
|
|
1507
|
+
return method;
|
|
1508
|
+
}
|
|
1509
|
+
const headerOverride = request.headers.get("X-HTTP-Method-Override");
|
|
1510
|
+
if (headerOverride) {
|
|
1511
|
+
const normalized = headerOverride.toUpperCase();
|
|
1512
|
+
if (BunServer.METHOD_OVERRIDE_ALLOWED.has(normalized))
|
|
1513
|
+
return normalized;
|
|
1514
|
+
}
|
|
1515
|
+
const contentType = request.headers.get("Content-Type") || "";
|
|
1516
|
+
if (!contentType.includes("application/x-www-form-urlencoded")) {
|
|
1517
|
+
return method;
|
|
1518
|
+
}
|
|
1519
|
+
try {
|
|
1520
|
+
const formData = await request.clone().formData();
|
|
1521
|
+
const override = formData.get(BunServer.METHOD_OVERRIDE_HEADER);
|
|
1522
|
+
if (typeof override !== "string") {
|
|
1523
|
+
return method;
|
|
1524
|
+
}
|
|
1525
|
+
const normalized = override.toUpperCase();
|
|
1526
|
+
return BunServer.METHOD_OVERRIDE_ALLOWED.has(normalized) ? normalized : method;
|
|
1527
|
+
} catch {
|
|
1528
|
+
return method;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1389
1531
|
buildMeta(module, loaderData, params, url) {
|
|
1390
1532
|
if (!module.meta) {
|
|
1391
1533
|
return [];
|
|
@@ -1424,22 +1566,42 @@ class BunServer {
|
|
|
1424
1566
|
}
|
|
1425
1567
|
return tags;
|
|
1426
1568
|
}
|
|
1569
|
+
static ALLOWED_LINK_ATTRS = new Set([
|
|
1570
|
+
"rel",
|
|
1571
|
+
"href",
|
|
1572
|
+
"type",
|
|
1573
|
+
"media",
|
|
1574
|
+
"sizes",
|
|
1575
|
+
"crossorigin",
|
|
1576
|
+
"as",
|
|
1577
|
+
"hreflang",
|
|
1578
|
+
"title",
|
|
1579
|
+
"integrity",
|
|
1580
|
+
"referrerpolicy",
|
|
1581
|
+
"fetchpriority",
|
|
1582
|
+
"imagesizes",
|
|
1583
|
+
"imagesrcset",
|
|
1584
|
+
"disabled"
|
|
1585
|
+
]);
|
|
1586
|
+
static escapeAttr(s) {
|
|
1587
|
+
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1588
|
+
}
|
|
1427
1589
|
buildMetaHtml(meta) {
|
|
1428
1590
|
let html = "";
|
|
1429
1591
|
for (const descriptor of meta) {
|
|
1430
1592
|
if (descriptor.name && descriptor.content) {
|
|
1431
|
-
const name = descriptor.name
|
|
1432
|
-
const content = descriptor.content
|
|
1593
|
+
const name = BunServer.escapeAttr(descriptor.name);
|
|
1594
|
+
const content = BunServer.escapeAttr(descriptor.content);
|
|
1433
1595
|
html += `<meta name="${name}" content="${content}"/>`;
|
|
1434
1596
|
} else if (descriptor.property && descriptor.content) {
|
|
1435
|
-
const property = descriptor.property
|
|
1436
|
-
const content = descriptor.content
|
|
1597
|
+
const property = BunServer.escapeAttr(descriptor.property);
|
|
1598
|
+
const content = BunServer.escapeAttr(descriptor.content);
|
|
1437
1599
|
html += `<meta property="${property}" content="${content}"/>`;
|
|
1438
1600
|
} else if (descriptor["script:ld+json"]) {
|
|
1439
1601
|
const safeJsonLd = String(descriptor["script:ld+json"]).replace(/<\//g, "<\\/");
|
|
1440
1602
|
html += `<script type="application/ld+json">${safeJsonLd}</script>`;
|
|
1441
1603
|
} else if (descriptor.tagName === "link") {
|
|
1442
|
-
const attrs = Object.entries(descriptor).filter(([k]) => k !== "tagName").map(([k, v]) => `${k}="${String(v)
|
|
1604
|
+
const attrs = Object.entries(descriptor).filter(([k]) => k !== "tagName" && BunServer.ALLOWED_LINK_ATTRS.has(k)).map(([k, v]) => `${k}="${BunServer.escapeAttr(String(v))}"`).join(" ");
|
|
1443
1605
|
html += `<link ${attrs}/>`;
|
|
1444
1606
|
}
|
|
1445
1607
|
}
|
|
@@ -1692,70 +1854,69 @@ class BunServer {
|
|
|
1692
1854
|
resolveHandler(ws)?.drain?.(ws);
|
|
1693
1855
|
}
|
|
1694
1856
|
};
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1857
|
+
this.fetchHandler = async (request, server) => {
|
|
1858
|
+
const url = new URL(request.url);
|
|
1859
|
+
if (websocket && url.pathname === "/__hmr") {
|
|
1860
|
+
if (server.upgrade(request, { data: { _wsType: "hmr" } }))
|
|
1861
|
+
return;
|
|
1862
|
+
}
|
|
1863
|
+
if (url.pathname === "/__ereo/trace-ws" && typeof this.options.trace === "object" && this.options.trace.traceWebSocket) {
|
|
1864
|
+
const traceWsType = "__ereo_trace_ws";
|
|
1865
|
+
if (!upgradeHandlers.some((h) => h.path === traceWsType)) {
|
|
1866
|
+
upgradeHandlers.push({
|
|
1867
|
+
path: traceWsType,
|
|
1868
|
+
upgrader: () => true,
|
|
1869
|
+
wsConfig: this.options.trace.traceWebSocket.websocket
|
|
1870
|
+
});
|
|
1703
1871
|
}
|
|
1704
|
-
if (
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
}
|
|
1872
|
+
if (server.upgrade(request, { data: { _wsType: traceWsType } }))
|
|
1873
|
+
return;
|
|
1874
|
+
}
|
|
1875
|
+
const upgradeHeader = request.headers.get("Upgrade");
|
|
1876
|
+
if (upgradeHeader?.toLowerCase() === "websocket") {
|
|
1877
|
+
for (const handler of upgradeHandlers) {
|
|
1878
|
+
if (url.pathname === handler.path) {
|
|
1879
|
+
const data = { _wsType: handler.path, subscriptions: new Map, ctx: {}, originalRequest: request };
|
|
1880
|
+
if (server.upgrade(request, { data }))
|
|
1881
|
+
return;
|
|
1712
1882
|
}
|
|
1713
|
-
if (server.upgrade(request, { data: { _wsType: traceWsType } }))
|
|
1714
|
-
return;
|
|
1715
1883
|
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1884
|
+
if (this.router && typeof this.router.getRoutes === "function") {
|
|
1885
|
+
const routes = this.router.getRoutes();
|
|
1886
|
+
const matchResult = matchWithLayouts(url.pathname, routes);
|
|
1887
|
+
if (matchResult) {
|
|
1888
|
+
await this.router.loadModule(matchResult.route);
|
|
1889
|
+
const mod = matchResult.route.module;
|
|
1890
|
+
if (mod?.websocket) {
|
|
1891
|
+
const wsType = "route:" + url.pathname;
|
|
1892
|
+
if (!upgradeHandlers.some((h) => h.path === wsType)) {
|
|
1893
|
+
upgradeHandlers.push({
|
|
1894
|
+
path: wsType,
|
|
1895
|
+
upgrader: () => true,
|
|
1896
|
+
wsConfig: mod.websocket
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
if (typeof mod.GET === "function") {
|
|
1900
|
+
return this.handleRequest(request, wsType);
|
|
1901
|
+
}
|
|
1902
|
+
if (server.upgrade(request, { data: { _wsType: wsType } })) {
|
|
1722
1903
|
return;
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
if (this.router && typeof this.router.getRoutes === "function") {
|
|
1726
|
-
const routes = this.router.getRoutes();
|
|
1727
|
-
const matchResult = matchWithLayouts(url.pathname, routes);
|
|
1728
|
-
if (matchResult) {
|
|
1729
|
-
await this.router.loadModule(matchResult.route);
|
|
1730
|
-
const mod = matchResult.route.module;
|
|
1731
|
-
if (mod?.websocket) {
|
|
1732
|
-
const wsType = "route:" + url.pathname;
|
|
1733
|
-
if (!upgradeHandlers.some((h) => h.path === wsType)) {
|
|
1734
|
-
upgradeHandlers.push({
|
|
1735
|
-
path: wsType,
|
|
1736
|
-
upgrader: () => true,
|
|
1737
|
-
wsConfig: mod.websocket
|
|
1738
|
-
});
|
|
1739
|
-
}
|
|
1740
|
-
if (typeof mod.GET === "function") {
|
|
1741
|
-
return this.handleRequest(request, wsType);
|
|
1742
|
-
}
|
|
1743
|
-
if (server.upgrade(request, { data: { _wsType: wsType } })) {
|
|
1744
|
-
return;
|
|
1745
|
-
}
|
|
1746
|
-
return new Response("WebSocket upgrade failed", { status: 400 });
|
|
1747
1904
|
}
|
|
1905
|
+
return new Response("WebSocket upgrade failed", { status: 400 });
|
|
1748
1906
|
}
|
|
1749
1907
|
}
|
|
1750
1908
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1909
|
+
}
|
|
1910
|
+
return this.handleRequest(request);
|
|
1911
|
+
};
|
|
1912
|
+
const serverOptions = {
|
|
1913
|
+
port,
|
|
1914
|
+
hostname,
|
|
1915
|
+
fetch: this.fetchHandler,
|
|
1916
|
+
error: (error) => this.handleError(error, createContext(new Request("http://localhost/"))),
|
|
1917
|
+
websocket: mergedWebSocket,
|
|
1918
|
+
tls: tls || undefined
|
|
1754
1919
|
};
|
|
1755
|
-
if (tls) {
|
|
1756
|
-
serverOptions.tls = tls;
|
|
1757
|
-
}
|
|
1758
|
-
serverOptions.websocket = mergedWebSocket;
|
|
1759
1920
|
this.server = Bun.serve(serverOptions);
|
|
1760
1921
|
const protocol = tls ? "https" : "http";
|
|
1761
1922
|
console.log(`Server running at ${protocol}://${hostname}:${port}`);
|
|
@@ -1768,9 +1929,9 @@ class BunServer {
|
|
|
1768
1929
|
}
|
|
1769
1930
|
}
|
|
1770
1931
|
async reload() {
|
|
1771
|
-
if (this.server) {
|
|
1932
|
+
if (this.server && this.fetchHandler) {
|
|
1772
1933
|
this.server.reload({
|
|
1773
|
-
fetch:
|
|
1934
|
+
fetch: this.fetchHandler
|
|
1774
1935
|
});
|
|
1775
1936
|
}
|
|
1776
1937
|
}
|
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAC;AAG9E;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,6EAA6E;IAC7E,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,WAAW,CAA8B;IAEjD;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IACrC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAUnD;;;;;;;OAOG;IACG,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAC;AAG9E;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,6EAA6E;IAC7E,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,WAAW,CAA8B;IAEjD;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IACrC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAUnD;;;;;;;OAOG;IACG,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAC7B,OAAO,CAAC,QAAQ,CAAC;IAgCpB;;OAEG;IACH,OAAO,CAAC,SAAS;CAQlB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD;AAMD;;GAEG;AACH,wBAAgB,MAAM,IAAI,iBAAiB,CAc1C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;IAC3D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,iBAAiB,CAwFjE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,qBAAqB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACvC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,KAAK,CAAC;IAC9C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACpC;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,iBAAiB,CAmCvF;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CA+B5C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;CAC7C;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,iBAAiB,CAyE3E"}
|
package/dist/static.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuCH;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAwDD;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuCH;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAwDD;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAuJlG;AAiDD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,IAGvC,SAAS,OAAO,EAAE,SAAS,GAAG,EAAE,MAAM,MAAM,OAAO,CAAC,QAAQ,CAAC,uBAK5E"}
|
package/dist/streaming.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../src/streaming.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAS,UAAU,EAAE,UAAU,EAAkB,cAAc,EAAE,MAAM,YAAY,CAAC;AAGhG;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,kBAAkB;IAClB,KAAK,EAAE,UAAU,CAAC;IAClB,sBAAsB;IACtB,OAAO,EAAE,UAAU,CAAC;IACpB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qBAAqB;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,uBAAuB;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,uDAAuD;IACvD,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,mBAAmB;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6BAA6B;IAC7B,IAAI,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC1C,uBAAuB;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA+DjC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../src/streaming.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAS,UAAU,EAAE,UAAU,EAAkB,cAAc,EAAE,MAAM,YAAY,CAAC;AAGhG;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,kBAAkB;IAClB,KAAK,EAAE,UAAU,CAAC;IAClB,sBAAsB;IACtB,OAAO,EAAE,UAAU,CAAC;IACpB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qBAAqB;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,uBAAuB;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,uDAAuD;IACvD,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,mBAAmB;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6BAA6B;IAC7B,IAAI,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC1C,uBAAuB;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA+DjC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CA0HvB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAmCvB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,QAAQ,CAK7D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ereo/server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.38",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Enoch Kujem Abassey",
|
|
6
6
|
"homepage": "https://ereojs.github.io/ereoJS",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"typecheck": "tsc --noEmit"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@ereo/core": "
|
|
36
|
-
"@ereo/client": "
|
|
37
|
-
"@ereo/router": "
|
|
38
|
-
"@ereo/data": "
|
|
35
|
+
"@ereo/core": "workspace:*",
|
|
36
|
+
"@ereo/client": "workspace:*",
|
|
37
|
+
"@ereo/router": "workspace:*",
|
|
38
|
+
"@ereo/data": "workspace:*"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/bun": "^1.1.0",
|