stitchkit 0.5.0 → 0.7.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.
- package/dist/browser/client.d.ts +17 -5
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/contract/define.d.ts +16 -2
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/errors.d.ts +26 -1
- package/dist/contract/errors.d.ts.map +1 -1
- package/dist/contract/index.d.ts +2 -2
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js +5 -1
- package/dist/{index-vhdvv00d.js → index-4843j09b.js} +1 -1
- package/dist/{index-kgjnt3hn.js → index-8hsj2qm9.js} +102 -36
- package/dist/{index-afzt3nmx.js → index-9bk6r5ff.js} +8 -4
- package/dist/{index-1cf8jkhf.js → index-hty3443r.js} +1 -1
- package/dist/{index-78q1qm7v.js → index-kdkvp26v.js} +21 -12
- package/dist/{index-d4rwrjbc.js → index-mahbaen9.js} +1 -1
- package/dist/{index-0ma1eqv4.js → index-p8byjw3e.js} +3 -3
- package/dist/index-za2p453b.js +87 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/node.js +3 -3
- package/dist/observability/index.js +14 -86
- package/dist/server/context.d.ts +1 -1
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/file.d.ts +52 -0
- package/dist/server/file.d.ts.map +1 -0
- package/dist/server/implement.d.ts.map +1 -1
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +190 -5
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/mime.d.ts +3 -0
- package/dist/server/mime.d.ts.map +1 -0
- package/dist/server/raw.d.ts +36 -0
- package/dist/server/raw.d.ts.map +1 -0
- package/dist/server/router.d.ts +4 -3
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/socket-io.d.ts +10 -1
- package/dist/server/socket-io.d.ts.map +1 -1
- package/dist/server/types.d.ts +32 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/tools/execute.d.ts +2 -2
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/mcp.d.ts +5 -0
- package/dist/tools/mcp.d.ts.map +1 -1
- package/dist/tools/remote.d.ts.map +1 -1
- package/dist/tools.js +9 -5
- package/package.json +1 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getClientInfo,
|
|
3
|
+
resolveSocketIp
|
|
4
|
+
} from "./index-mwmpw6j1.js";
|
|
5
|
+
|
|
6
|
+
// src/observability/trace.ts
|
|
7
|
+
var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i;
|
|
8
|
+
function randomHex(bytes) {
|
|
9
|
+
const arr = new Uint8Array(bytes);
|
|
10
|
+
crypto.getRandomValues(arr);
|
|
11
|
+
let hex = "";
|
|
12
|
+
for (const byte of arr)
|
|
13
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
14
|
+
return hex;
|
|
15
|
+
}
|
|
16
|
+
function createTraceContext() {
|
|
17
|
+
return { traceId: randomHex(16), spanId: randomHex(8) };
|
|
18
|
+
}
|
|
19
|
+
function parseTraceparent(header) {
|
|
20
|
+
if (!header)
|
|
21
|
+
return null;
|
|
22
|
+
const match = TRACEPARENT_RE.exec(header.trim());
|
|
23
|
+
if (!match?.[1] || !match[2])
|
|
24
|
+
return null;
|
|
25
|
+
const traceId = match[1].toLowerCase();
|
|
26
|
+
const parentSpanId = match[2].toLowerCase();
|
|
27
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
|
|
28
|
+
return null;
|
|
29
|
+
return { traceId, spanId: randomHex(8), parentSpanId };
|
|
30
|
+
}
|
|
31
|
+
function formatTraceparent(ctx) {
|
|
32
|
+
return `00-${ctx.traceId}-${ctx.spanId}-01`;
|
|
33
|
+
}
|
|
34
|
+
function resolveTraceContext(req) {
|
|
35
|
+
return parseTraceparent(req.headers.get("traceparent")) ?? createTraceContext();
|
|
36
|
+
}
|
|
37
|
+
function childSpan(parent) {
|
|
38
|
+
return {
|
|
39
|
+
traceId: parent.traceId,
|
|
40
|
+
spanId: randomHex(8),
|
|
41
|
+
parentSpanId: parent.spanId
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/observability/context.ts
|
|
46
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
47
|
+
var storage = new AsyncLocalStorage;
|
|
48
|
+
function runWithRequestContext(ctx, fn) {
|
|
49
|
+
return storage.run(ctx, fn);
|
|
50
|
+
}
|
|
51
|
+
function getRequestContext() {
|
|
52
|
+
return storage.getStore();
|
|
53
|
+
}
|
|
54
|
+
function getTraceId() {
|
|
55
|
+
return storage.getStore()?.trace.traceId;
|
|
56
|
+
}
|
|
57
|
+
function getUserId() {
|
|
58
|
+
return storage.getStore()?.userId;
|
|
59
|
+
}
|
|
60
|
+
function setRequestUser(userId) {
|
|
61
|
+
const ctx = storage.getStore();
|
|
62
|
+
if (ctx)
|
|
63
|
+
ctx.userId = userId;
|
|
64
|
+
}
|
|
65
|
+
function setRequestError(error) {
|
|
66
|
+
const ctx = storage.getStore();
|
|
67
|
+
if (ctx)
|
|
68
|
+
ctx.error = error;
|
|
69
|
+
}
|
|
70
|
+
function wrapInRequestContext(handler, options = {}) {
|
|
71
|
+
return (req, server) => {
|
|
72
|
+
const ctx = {
|
|
73
|
+
trace: resolveTraceContext(req),
|
|
74
|
+
source: "http",
|
|
75
|
+
method: req.method,
|
|
76
|
+
path: new URL(req.url, "http://localhost").pathname,
|
|
77
|
+
startedAt: process.hrtime.bigint(),
|
|
78
|
+
...getClientInfo(req, {
|
|
79
|
+
trustProxy: options.trustProxy,
|
|
80
|
+
socketIp: resolveSocketIp(req, server)
|
|
81
|
+
})
|
|
82
|
+
};
|
|
83
|
+
return runWithRequestContext(ctx, () => handler(req, server));
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { createTraceContext, parseTraceparent, formatTraceparent, resolveTraceContext, childSpan, runWithRequestContext, getRequestContext, getTraceId, getUserId, setRequestUser, setRequestError, wrapInRequestContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createClient, createClients } from './browser/client';
|
|
1
|
+
export { type ClientConfig, type ContractClientConfig, createClient, createClients, } from './browser/client';
|
|
2
2
|
export { ApiError, type ApiEvent, type ApiEventListener, createHttpClient, type HeaderProvider, type HttpClient, type HttpClientConfig, type RequestOptions, } from './browser/http';
|
|
3
3
|
export type { SocketEventMap, SocketIOClient, SocketIOClientConfig, } from './browser/socket-io';
|
|
4
4
|
export { createSocketIOClient } from './browser/socket-io';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,YAAY,EACZ,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAClE,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,25 +3,27 @@ import {
|
|
|
3
3
|
createClient,
|
|
4
4
|
createClients,
|
|
5
5
|
createHttpClient
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-kdkvp26v.js";
|
|
7
7
|
import {
|
|
8
8
|
parseSSE
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-mahbaen9.js";
|
|
10
10
|
import"./index-48ffdxgk.js";
|
|
11
|
-
import"./index-
|
|
11
|
+
import"./index-4843j09b.js";
|
|
12
12
|
import {
|
|
13
13
|
ALL_TRANSPORTS,
|
|
14
14
|
AppError,
|
|
15
|
+
STITCH_ERROR_STATUS,
|
|
15
16
|
appError,
|
|
16
17
|
badRequest,
|
|
17
18
|
conflict,
|
|
18
19
|
defineContract,
|
|
19
20
|
forbidden,
|
|
21
|
+
isStitchErrorCode,
|
|
20
22
|
notFound,
|
|
21
23
|
paginatedSchema,
|
|
22
24
|
rateLimited,
|
|
23
25
|
unauthorized
|
|
24
|
-
} from "./index-
|
|
26
|
+
} from "./index-9bk6r5ff.js";
|
|
25
27
|
import"./index-809wc1tt.js";
|
|
26
28
|
import"./index-37x76zdn.js";
|
|
27
29
|
// src/browser/socket-io.ts
|
|
@@ -109,6 +111,7 @@ export {
|
|
|
109
111
|
parseSSE,
|
|
110
112
|
paginatedSchema,
|
|
111
113
|
notFound,
|
|
114
|
+
isStitchErrorCode,
|
|
112
115
|
forbidden,
|
|
113
116
|
defineContract,
|
|
114
117
|
createSocketIOClient,
|
|
@@ -118,6 +121,7 @@ export {
|
|
|
118
121
|
conflict,
|
|
119
122
|
badRequest,
|
|
120
123
|
appError,
|
|
124
|
+
STITCH_ERROR_STATUS,
|
|
121
125
|
AppError,
|
|
122
126
|
ApiError,
|
|
123
127
|
ALL_TRANSPORTS
|
package/dist/node.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
createImplement,
|
|
4
4
|
createSocketIOServer,
|
|
5
5
|
implement
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-8hsj2qm9.js";
|
|
7
7
|
import"./index-x3fcszf8.js";
|
|
8
|
-
import"./index-
|
|
8
|
+
import"./index-4843j09b.js";
|
|
9
9
|
import {
|
|
10
10
|
AppError,
|
|
11
11
|
appError,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
notFound,
|
|
16
16
|
rateLimited,
|
|
17
17
|
unauthorized
|
|
18
|
-
} from "./index-
|
|
18
|
+
} from "./index-9bk6r5ff.js";
|
|
19
19
|
import"./index-mwmpw6j1.js";
|
|
20
20
|
import"./index-kzfs85xp.js";
|
|
21
21
|
import"./index-809wc1tt.js";
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
childSpan,
|
|
3
|
+
createTraceContext,
|
|
4
|
+
formatTraceparent,
|
|
5
|
+
getRequestContext,
|
|
6
|
+
getTraceId,
|
|
7
|
+
getUserId,
|
|
8
|
+
parseTraceparent,
|
|
9
|
+
resolveTraceContext,
|
|
10
|
+
runWithRequestContext,
|
|
11
|
+
setRequestError,
|
|
12
|
+
setRequestUser,
|
|
13
|
+
wrapInRequestContext
|
|
14
|
+
} from "../index-za2p453b.js";
|
|
15
|
+
import"../index-mwmpw6j1.js";
|
|
5
16
|
import {
|
|
6
17
|
isUnsafeKey
|
|
7
18
|
} from "../index-kzfs85xp.js";
|
|
@@ -10,89 +21,6 @@ import {
|
|
|
10
21
|
} from "../index-809wc1tt.js";
|
|
11
22
|
import"../index-37x76zdn.js";
|
|
12
23
|
|
|
13
|
-
// src/observability/context.ts
|
|
14
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15
|
-
|
|
16
|
-
// src/observability/trace.ts
|
|
17
|
-
var TRACEPARENT_RE = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/i;
|
|
18
|
-
function randomHex(bytes) {
|
|
19
|
-
const arr = new Uint8Array(bytes);
|
|
20
|
-
crypto.getRandomValues(arr);
|
|
21
|
-
let hex = "";
|
|
22
|
-
for (const byte of arr)
|
|
23
|
-
hex += byte.toString(16).padStart(2, "0");
|
|
24
|
-
return hex;
|
|
25
|
-
}
|
|
26
|
-
function createTraceContext() {
|
|
27
|
-
return { traceId: randomHex(16), spanId: randomHex(8) };
|
|
28
|
-
}
|
|
29
|
-
function parseTraceparent(header) {
|
|
30
|
-
if (!header)
|
|
31
|
-
return null;
|
|
32
|
-
const match = TRACEPARENT_RE.exec(header.trim());
|
|
33
|
-
if (!match?.[1] || !match[2])
|
|
34
|
-
return null;
|
|
35
|
-
const traceId = match[1].toLowerCase();
|
|
36
|
-
const parentSpanId = match[2].toLowerCase();
|
|
37
|
-
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId))
|
|
38
|
-
return null;
|
|
39
|
-
return { traceId, spanId: randomHex(8), parentSpanId };
|
|
40
|
-
}
|
|
41
|
-
function formatTraceparent(ctx) {
|
|
42
|
-
return `00-${ctx.traceId}-${ctx.spanId}-01`;
|
|
43
|
-
}
|
|
44
|
-
function resolveTraceContext(req) {
|
|
45
|
-
return parseTraceparent(req.headers.get("traceparent")) ?? createTraceContext();
|
|
46
|
-
}
|
|
47
|
-
function childSpan(parent) {
|
|
48
|
-
return {
|
|
49
|
-
traceId: parent.traceId,
|
|
50
|
-
spanId: randomHex(8),
|
|
51
|
-
parentSpanId: parent.spanId
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/observability/context.ts
|
|
56
|
-
var storage = new AsyncLocalStorage;
|
|
57
|
-
function runWithRequestContext(ctx, fn) {
|
|
58
|
-
return storage.run(ctx, fn);
|
|
59
|
-
}
|
|
60
|
-
function getRequestContext() {
|
|
61
|
-
return storage.getStore();
|
|
62
|
-
}
|
|
63
|
-
function getTraceId() {
|
|
64
|
-
return storage.getStore()?.trace.traceId;
|
|
65
|
-
}
|
|
66
|
-
function getUserId() {
|
|
67
|
-
return storage.getStore()?.userId;
|
|
68
|
-
}
|
|
69
|
-
function setRequestUser(userId) {
|
|
70
|
-
const ctx = storage.getStore();
|
|
71
|
-
if (ctx)
|
|
72
|
-
ctx.userId = userId;
|
|
73
|
-
}
|
|
74
|
-
function setRequestError(error) {
|
|
75
|
-
const ctx = storage.getStore();
|
|
76
|
-
if (ctx)
|
|
77
|
-
ctx.error = error;
|
|
78
|
-
}
|
|
79
|
-
function wrapInRequestContext(handler, options = {}) {
|
|
80
|
-
return (req, server) => {
|
|
81
|
-
const ctx = {
|
|
82
|
-
trace: resolveTraceContext(req),
|
|
83
|
-
source: "http",
|
|
84
|
-
method: req.method,
|
|
85
|
-
path: new URL(req.url, "http://localhost").pathname,
|
|
86
|
-
startedAt: process.hrtime.bigint(),
|
|
87
|
-
...getClientInfo(req, {
|
|
88
|
-
trustProxy: options.trustProxy,
|
|
89
|
-
socketIp: resolveSocketIp(req, server)
|
|
90
|
-
})
|
|
91
|
-
};
|
|
92
|
-
return runWithRequestContext(ctx, () => handler(req, server));
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
24
|
// src/observability/sanitize.ts
|
|
97
25
|
var DEFAULT_SENSITIVE_KEYS = /(password|passwd|pwd|secret|token|apikey|api[-_ ]?key|auth|authorization|bearer|session|cookie|init[-_ ]?data|credential|private[-_ ]?key)/i;
|
|
98
26
|
var DEFAULT_MAX_BYTES = 16000;
|
package/dist/server/context.d.ts
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
import { type RuntimeContext } from '../contract';
|
|
6
6
|
import { type ClientIpOptions } from './request';
|
|
7
7
|
import type { MethodDef } from './types';
|
|
8
|
-
export declare function buildContext(req: Request, url: URL, method: MethodDef, pathParams: Record<string, string>, traceId: string, clientIp: ClientIpOptions): Promise<RuntimeContext>;
|
|
8
|
+
export declare function buildContext(req: Request, url: URL, method: MethodDef, pathParams: Record<string, string>, traceId: string, clientIp: ClientIpOptions, maxUploadBytes?: number): Promise<RuntimeContext>;
|
|
9
9
|
export declare function buildErrorContext(req: Request, url: URL, traceId: string, clientIp: ClientIpOptions): RuntimeContext;
|
|
10
10
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/server/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,WAAW,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAmCzC,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/server/context.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,WAAW,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAmCzC,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,EACzB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,cAAc,CAAC,CA8CzB;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,eAAe,GACxB,cAAc,CAWhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/server/create.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAEV,eAAe,EACf,aAAa,EAGd,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAgNxF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,uBAsBnD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** An inclusive byte range `[start, end]`. */
|
|
2
|
+
export interface ByteRange {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Parse a single-range `Range` header against a known `size`.
|
|
8
|
+
*
|
|
9
|
+
* - `null` — no header, malformed, or multiple ranges (caller serves the full
|
|
10
|
+
* `200` body; ignoring an unparseable Range is RFC-compliant).
|
|
11
|
+
* - `'unsatisfiable'` — a well-formed range that lies outside the file (the
|
|
12
|
+
* caller answers `416` with `Content-Range: bytes * /size`).
|
|
13
|
+
* - `{ start, end }` — an inclusive, clamped range to serve as `206`.
|
|
14
|
+
*
|
|
15
|
+
* Multiple ranges (`bytes=0-9,20-29`) are intentionally unsupported and return
|
|
16
|
+
* `null` (no `multipart/byteranges`). → ADR 0023.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseByteRange(header: string | null, size: number): ByteRange | 'unsatisfiable' | null;
|
|
19
|
+
/**
|
|
20
|
+
* A weak entity tag derived from size + mtime — cheap (no content hashing) and
|
|
21
|
+
* stable across requests. Weak because two files with the same size and mtime
|
|
22
|
+
* are treated as equivalent, which is the right trade for static media.
|
|
23
|
+
*/
|
|
24
|
+
export declare function weakETag(size: number, mtimeMs: number): string;
|
|
25
|
+
export interface ServeFileOptions {
|
|
26
|
+
/** Absolute (or cwd-relative) path to the file. The caller owns containment. */
|
|
27
|
+
path: string;
|
|
28
|
+
/** MIME type. Auto-detected from the path extension when omitted. */
|
|
29
|
+
contentType?: string;
|
|
30
|
+
/** Sets `Content-Disposition` with this filename. */
|
|
31
|
+
filename?: string;
|
|
32
|
+
/** `Content-Disposition` type. Defaults to `inline` (set with `filename`). */
|
|
33
|
+
disposition?: 'inline' | 'attachment';
|
|
34
|
+
/** Value for the `Cache-Control` header, verbatim. */
|
|
35
|
+
cacheControl?: string;
|
|
36
|
+
/** Emit a weak `ETag` (default `true`). */
|
|
37
|
+
etag?: boolean;
|
|
38
|
+
/** Emit `Last-Modified` (default `true`). */
|
|
39
|
+
lastModified?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Serve a file with full Range + conditional-request support. Returns:
|
|
43
|
+
* `405` (non GET/HEAD), `404` (missing), `304` (fresh per `If-None-Match` /
|
|
44
|
+
* `If-Modified-Since`), `200` (full — no/ignored Range), `206` (range), or `416`
|
|
45
|
+
* (unsatisfiable range). Always sets `Accept-Ranges: bytes` and `nosniff`; a
|
|
46
|
+
* `HEAD` returns every header with an empty body.
|
|
47
|
+
*
|
|
48
|
+
* Bun-first (`Bun.file`). The caller is responsible for path containment — for
|
|
49
|
+
* URL-derived paths use `staticRoute` or `isWithinDir`. → ADR 0023.
|
|
50
|
+
*/
|
|
51
|
+
export declare function serveFile(req: Request, opts: ServeFileOptions): Promise<Response>;
|
|
52
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/server/file.ts"],"names":[],"mappings":"AAaA,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,IAAI,EAAE,MAAM,GACX,SAAS,GAAG,eAAe,GAAG,IAAI,CAkCpC;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D;AA6ED,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IACtC,sDAAsD;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,6CAA6C;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwEvF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/server/implement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,KAAK,EAAE,QAAQ,EAAa,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,IAAI,SAAS,cAAc,GAAG,cAAc,EAC5C,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"implement.d.ts","sourceRoot":"","sources":["../../src/server/implement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5E,OAAO,KAAK,EAAE,QAAQ,EAAa,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,IAAI,SAAS,cAAc,GAAG,cAAc,EAC5C,QAAQ,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU,CA6C3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,cAAc,MACjD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,UAAU,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAChC,UAAU,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,KAC1B,UAAU,CACd"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { AppError, appError, badRequest, conflict, forbidden, notFound, rateLimited, unauthorized, } from '../contract';
|
|
1
|
+
export { AppError, appError, badRequest, conflict, forbidden, isStitchErrorCode, notFound, rateLimited, STITCH_ERROR_STATUS, type StitchErrorCode, unauthorized, } from '../contract';
|
|
2
2
|
export { cacheHeaders, createCache } from './cache';
|
|
3
3
|
export { createHandler, createServer } from './create';
|
|
4
4
|
export { createEventBus, type EventBus } from './event-bus';
|
|
5
|
+
export { type ByteRange, parseByteRange, type ServeFileOptions, serveFile, weakETag, } from './file';
|
|
5
6
|
export { createImplement, implement } from './implement';
|
|
6
7
|
export { type AuthHook, type AuthHookConfig, type AuthRule, type BearerResolverConfig, createAuthHook, createBearerResolver, extractToken, type JwtPayload, type SignJwtOptions, signJwt, verifyJwt, } from './middleware/auth';
|
|
7
8
|
export { type CookieDef, type CookieOptions, defineCookie, parseCookies, serializeCookie, } from './middleware/cookies';
|
|
@@ -10,6 +11,7 @@ export { deriveCodeChallenge, type PkceMethod, verifyPkce } from './middleware/p
|
|
|
10
11
|
export { parseMultipart } from './multipart';
|
|
11
12
|
export { generateOpenApiDocument, type OpenApiConfig, type OpenApiDocument, type OpenApiInfo, type OpenApiServer, openApiRoute, } from './openapi';
|
|
12
13
|
export { createRateLimiter, type RateLimitConfig } from './rate-limit';
|
|
14
|
+
export { errorResponse, parseBody, respondJson } from './raw';
|
|
13
15
|
export { type ClientIpOptions, extractIp, generateTraceId, getClientInfo, resolveSocketIp, resolveTraceId, } from './request';
|
|
14
16
|
export { staticRoute } from './router';
|
|
15
17
|
export type { SocketIOServerConfig, SocketIOServerHandle } from './socket-io';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,OAAO,EACP,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EACL,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,YAAY,EACjB,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,aAAa,GACd,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,KAAK,eAAe,EACpB,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,KAAK,SAAS,EACd,cAAc,EACd,KAAK,gBAAgB,EACrB,SAAS,EACT,QAAQ,GACT,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,oBAAoB,EACzB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,OAAO,EACP,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,UAAU,EACf,WAAW,EACX,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EACL,KAAK,eAAe,EACpB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,SAAS,EACT,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,YAAY,EACjB,wBAAwB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAClB,aAAa,GACd,MAAM,aAAa,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseSSE,
|
|
3
3
|
streamSSE
|
|
4
|
-
} from "../index-
|
|
4
|
+
} from "../index-mahbaen9.js";
|
|
5
5
|
import {
|
|
6
6
|
createAuthHook,
|
|
7
7
|
createBearerResolver,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
signJwt,
|
|
14
14
|
verifyJwt,
|
|
15
15
|
verifyPkce
|
|
16
|
-
} from "../index-
|
|
16
|
+
} from "../index-hty3443r.js";
|
|
17
17
|
import {
|
|
18
18
|
inputIsQuery
|
|
19
19
|
} from "../index-48ffdxgk.js";
|
|
@@ -21,6 +21,9 @@ import {
|
|
|
21
21
|
jsonSchemaFields,
|
|
22
22
|
toJsonSchema
|
|
23
23
|
} from "../index-0ed3bx43.js";
|
|
24
|
+
import {
|
|
25
|
+
getTraceId
|
|
26
|
+
} from "../index-za2p453b.js";
|
|
24
27
|
import {
|
|
25
28
|
composeWebSocketHandlers,
|
|
26
29
|
corsHeaders,
|
|
@@ -30,23 +33,28 @@ import {
|
|
|
30
33
|
createServer,
|
|
31
34
|
createSocketIOServer,
|
|
32
35
|
implement,
|
|
36
|
+
mimeForPath,
|
|
33
37
|
parseMultipart,
|
|
34
38
|
socketIoLane,
|
|
35
39
|
staticRoute,
|
|
36
40
|
webSocketLane
|
|
37
|
-
} from "../index-
|
|
41
|
+
} from "../index-8hsj2qm9.js";
|
|
38
42
|
import"../index-x3fcszf8.js";
|
|
39
|
-
import
|
|
43
|
+
import {
|
|
44
|
+
normalizeError
|
|
45
|
+
} from "../index-4843j09b.js";
|
|
40
46
|
import {
|
|
41
47
|
AppError,
|
|
48
|
+
STITCH_ERROR_STATUS,
|
|
42
49
|
appError,
|
|
43
50
|
badRequest,
|
|
44
51
|
conflict,
|
|
45
52
|
forbidden,
|
|
53
|
+
isStitchErrorCode,
|
|
46
54
|
notFound,
|
|
47
55
|
rateLimited,
|
|
48
56
|
unauthorized
|
|
49
|
-
} from "../index-
|
|
57
|
+
} from "../index-9bk6r5ff.js";
|
|
50
58
|
import {
|
|
51
59
|
extractIp,
|
|
52
60
|
generateTraceId,
|
|
@@ -169,6 +177,154 @@ function createEventBus(options = {}) {
|
|
|
169
177
|
}
|
|
170
178
|
};
|
|
171
179
|
}
|
|
180
|
+
// src/server/file.ts
|
|
181
|
+
function parseByteRange(header, size) {
|
|
182
|
+
if (!header)
|
|
183
|
+
return null;
|
|
184
|
+
const match = /^bytes=(.+)$/.exec(header.trim());
|
|
185
|
+
const rawSpec = match?.[1];
|
|
186
|
+
if (rawSpec === undefined)
|
|
187
|
+
return null;
|
|
188
|
+
const spec = rawSpec.trim();
|
|
189
|
+
if (spec.includes(","))
|
|
190
|
+
return null;
|
|
191
|
+
const dash = spec.indexOf("-");
|
|
192
|
+
if (dash === -1)
|
|
193
|
+
return null;
|
|
194
|
+
const startStr = spec.slice(0, dash).trim();
|
|
195
|
+
const endStr = spec.slice(dash + 1).trim();
|
|
196
|
+
if (startStr === "") {
|
|
197
|
+
if (!/^\d+$/.test(endStr))
|
|
198
|
+
return null;
|
|
199
|
+
const suffix = Number(endStr);
|
|
200
|
+
if (suffix === 0 || size === 0)
|
|
201
|
+
return "unsatisfiable";
|
|
202
|
+
return { start: Math.max(0, size - suffix), end: size - 1 };
|
|
203
|
+
}
|
|
204
|
+
if (!/^\d+$/.test(startStr))
|
|
205
|
+
return null;
|
|
206
|
+
const start = Number(startStr);
|
|
207
|
+
if (size === 0 || start >= size)
|
|
208
|
+
return "unsatisfiable";
|
|
209
|
+
if (endStr === "")
|
|
210
|
+
return { start, end: size - 1 };
|
|
211
|
+
if (!/^\d+$/.test(endStr))
|
|
212
|
+
return null;
|
|
213
|
+
const end = Number(endStr);
|
|
214
|
+
if (end < start)
|
|
215
|
+
return null;
|
|
216
|
+
return { start, end: end >= size ? size - 1 : end };
|
|
217
|
+
}
|
|
218
|
+
function weakETag(size, mtimeMs) {
|
|
219
|
+
return `W/"${size.toString(16)}-${Math.floor(mtimeMs).toString(16)}"`;
|
|
220
|
+
}
|
|
221
|
+
function leSeconds(aMs, bMs) {
|
|
222
|
+
return Math.floor(aMs / 1000) <= Math.floor(bMs / 1000);
|
|
223
|
+
}
|
|
224
|
+
function isNotModified(req, v) {
|
|
225
|
+
const inm = req.headers.get("if-none-match");
|
|
226
|
+
if (inm !== null) {
|
|
227
|
+
const value = inm.trim();
|
|
228
|
+
if (value === "*")
|
|
229
|
+
return true;
|
|
230
|
+
if (v.etag === undefined)
|
|
231
|
+
return false;
|
|
232
|
+
return value.split(",").map((t) => t.trim()).includes(v.etag);
|
|
233
|
+
}
|
|
234
|
+
const ims = req.headers.get("if-modified-since");
|
|
235
|
+
if (ims !== null) {
|
|
236
|
+
if (v.lastModifiedMs === undefined)
|
|
237
|
+
return false;
|
|
238
|
+
const since = Date.parse(ims);
|
|
239
|
+
if (Number.isNaN(since))
|
|
240
|
+
return false;
|
|
241
|
+
return leSeconds(v.lastModifiedMs, since);
|
|
242
|
+
}
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
function ifRangeMatches(req, v) {
|
|
246
|
+
const ir = req.headers.get("if-range");
|
|
247
|
+
if (ir === null)
|
|
248
|
+
return true;
|
|
249
|
+
const value = ir.trim();
|
|
250
|
+
if (v.etag !== undefined && value === v.etag)
|
|
251
|
+
return true;
|
|
252
|
+
if (v.lastModifiedMs !== undefined) {
|
|
253
|
+
const asDate = Date.parse(value);
|
|
254
|
+
if (!Number.isNaN(asDate))
|
|
255
|
+
return leSeconds(v.lastModifiedMs, asDate);
|
|
256
|
+
}
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
function asciiFilename(filename) {
|
|
260
|
+
let out = "";
|
|
261
|
+
for (let i = 0;i < filename.length; i++) {
|
|
262
|
+
const code = filename.charCodeAt(i);
|
|
263
|
+
out += code >= 32 && code < 127 && code !== 34 && code !== 92 ? filename.charAt(i) : "_";
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
}
|
|
267
|
+
function contentDisposition(disposition, filename) {
|
|
268
|
+
return `${disposition}; filename="${asciiFilename(filename)}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
269
|
+
}
|
|
270
|
+
async function serveFile(req, opts) {
|
|
271
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
272
|
+
return new Response("Method not allowed", {
|
|
273
|
+
status: 405,
|
|
274
|
+
headers: { Allow: "GET, HEAD" }
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
const file = Bun.file(opts.path);
|
|
278
|
+
if (!await file.exists()) {
|
|
279
|
+
return new Response("Not found", { status: 404 });
|
|
280
|
+
}
|
|
281
|
+
const size = file.size;
|
|
282
|
+
const mtimeMs = file.lastModified;
|
|
283
|
+
const contentType = opts.contentType ?? mimeForPath(opts.path);
|
|
284
|
+
const useEtag = opts.etag !== false;
|
|
285
|
+
const useLastModified = opts.lastModified !== false;
|
|
286
|
+
const etag = useEtag ? weakETag(size, mtimeMs) : undefined;
|
|
287
|
+
const validators = {
|
|
288
|
+
etag,
|
|
289
|
+
lastModifiedMs: useLastModified ? mtimeMs : undefined
|
|
290
|
+
};
|
|
291
|
+
const isHead = req.method === "HEAD";
|
|
292
|
+
const base = new Headers;
|
|
293
|
+
base.set("Accept-Ranges", "bytes");
|
|
294
|
+
base.set("X-Content-Type-Options", "nosniff");
|
|
295
|
+
if (etag)
|
|
296
|
+
base.set("ETag", etag);
|
|
297
|
+
if (useLastModified)
|
|
298
|
+
base.set("Last-Modified", new Date(mtimeMs).toUTCString());
|
|
299
|
+
if (opts.cacheControl)
|
|
300
|
+
base.set("Cache-Control", opts.cacheControl);
|
|
301
|
+
if (opts.filename) {
|
|
302
|
+
base.set("Content-Disposition", contentDisposition(opts.disposition ?? "inline", opts.filename));
|
|
303
|
+
} else if (opts.disposition) {
|
|
304
|
+
base.set("Content-Disposition", opts.disposition);
|
|
305
|
+
}
|
|
306
|
+
if ((useEtag || useLastModified) && isNotModified(req, validators)) {
|
|
307
|
+
return new Response(null, { status: 304, headers: base });
|
|
308
|
+
}
|
|
309
|
+
const rangeHeader = req.headers.get("range");
|
|
310
|
+
const range = rangeHeader !== null && ifRangeMatches(req, validators) ? parseByteRange(rangeHeader, size) : null;
|
|
311
|
+
if (range === "unsatisfiable") {
|
|
312
|
+
base.set("Content-Range", `bytes */${size}`);
|
|
313
|
+
base.set("Content-Type", contentType);
|
|
314
|
+
return new Response(null, { status: 416, headers: base });
|
|
315
|
+
}
|
|
316
|
+
if (range) {
|
|
317
|
+
const length = range.end - range.start + 1;
|
|
318
|
+
base.set("Content-Type", contentType);
|
|
319
|
+
base.set("Content-Range", `bytes ${range.start}-${range.end}/${size}`);
|
|
320
|
+
base.set("Content-Length", String(length));
|
|
321
|
+
const body = isHead ? null : file.slice(range.start, range.end + 1);
|
|
322
|
+
return new Response(body, { status: 206, headers: base });
|
|
323
|
+
}
|
|
324
|
+
base.set("Content-Type", contentType);
|
|
325
|
+
base.set("Content-Length", String(size));
|
|
326
|
+
return new Response(isHead ? null : file, { status: 200, headers: base });
|
|
327
|
+
}
|
|
172
328
|
// src/server/openapi.ts
|
|
173
329
|
var ERROR_ENVELOPE_SCHEMA = {
|
|
174
330
|
type: "object",
|
|
@@ -362,8 +518,30 @@ function createRateLimiter() {
|
|
|
362
518
|
}
|
|
363
519
|
};
|
|
364
520
|
}
|
|
521
|
+
// src/server/raw.ts
|
|
522
|
+
function respondJson(data) {
|
|
523
|
+
if (data === null || data === undefined)
|
|
524
|
+
return new Response(null, { status: 204 });
|
|
525
|
+
return Response.json(data);
|
|
526
|
+
}
|
|
527
|
+
function errorResponse2(error) {
|
|
528
|
+
const appErr = normalizeError(error);
|
|
529
|
+
const res = Response.json(appErr.toJSON(), { status: appErr.status });
|
|
530
|
+
const traceId = getTraceId();
|
|
531
|
+
if (traceId)
|
|
532
|
+
res.headers.set("x-request-id", traceId);
|
|
533
|
+
return res;
|
|
534
|
+
}
|
|
535
|
+
async function parseBody(req, schema) {
|
|
536
|
+
const raw = await req.json().catch(() => null);
|
|
537
|
+
if (raw === null)
|
|
538
|
+
return null;
|
|
539
|
+
const parsed = schema.safeParse(raw);
|
|
540
|
+
return parsed.success ? parsed.data : null;
|
|
541
|
+
}
|
|
365
542
|
export {
|
|
366
543
|
webSocketLane,
|
|
544
|
+
weakETag,
|
|
367
545
|
verifyPkce,
|
|
368
546
|
verifyJwt,
|
|
369
547
|
unauthorized,
|
|
@@ -371,15 +549,20 @@ export {
|
|
|
371
549
|
staticRoute,
|
|
372
550
|
socketIoLane,
|
|
373
551
|
signJwt,
|
|
552
|
+
serveFile,
|
|
374
553
|
serializeCookie,
|
|
554
|
+
respondJson,
|
|
375
555
|
resolveTraceId,
|
|
376
556
|
resolveSocketIp,
|
|
377
557
|
rateLimited,
|
|
378
558
|
parseSSE,
|
|
379
559
|
parseMultipart,
|
|
380
560
|
parseCookies,
|
|
561
|
+
parseByteRange,
|
|
562
|
+
parseBody,
|
|
381
563
|
openApiRoute,
|
|
382
564
|
notFound,
|
|
565
|
+
isStitchErrorCode,
|
|
383
566
|
implement,
|
|
384
567
|
getClientInfo,
|
|
385
568
|
generateTraceId,
|
|
@@ -387,6 +570,7 @@ export {
|
|
|
387
570
|
forbidden,
|
|
388
571
|
extractToken,
|
|
389
572
|
extractIp,
|
|
573
|
+
errorResponse2 as errorResponse,
|
|
390
574
|
deriveCodeChallenge,
|
|
391
575
|
defineCookie,
|
|
392
576
|
createSocketIOServer,
|
|
@@ -405,5 +589,6 @@ export {
|
|
|
405
589
|
cacheHeaders,
|
|
406
590
|
badRequest,
|
|
407
591
|
appError,
|
|
592
|
+
STITCH_ERROR_STATUS,
|
|
408
593
|
AppError
|
|
409
594
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAwCA,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/server/logger.ts"],"names":[],"mappings":"AAwCA,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD;AAoBD,yCAAyC;AACzC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAEvF;AA0BD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGnE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU,CASZ;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CAoBN"}
|