@hebo-ai/gateway 0.4.1 → 0.5.0-beta.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/README.md +2 -3
- package/dist/endpoints/chat-completions/converters.d.ts +3 -1
- package/dist/endpoints/chat-completions/converters.js +121 -90
- package/dist/endpoints/chat-completions/handler.js +2 -4
- package/dist/endpoints/chat-completions/otel.js +7 -0
- package/dist/endpoints/chat-completions/schema.d.ts +400 -76
- package/dist/endpoints/chat-completions/schema.js +80 -36
- package/dist/endpoints/embeddings/handler.js +2 -4
- package/dist/endpoints/embeddings/schema.d.ts +1 -1
- package/dist/endpoints/embeddings/schema.js +1 -1
- package/dist/errors/gateway.js +1 -0
- package/dist/lifecycle.js +7 -12
- package/dist/logger/default.d.ts +0 -1
- package/dist/logger/default.js +30 -6
- package/dist/middleware/utils.js +1 -0
- package/dist/models/amazon/middleware.js +1 -0
- package/dist/models/anthropic/middleware.d.ts +2 -0
- package/dist/models/anthropic/middleware.js +77 -16
- package/dist/models/google/middleware.js +17 -0
- package/dist/models/google/presets.d.ts +387 -0
- package/dist/models/google/presets.js +9 -2
- package/dist/models/openai/middleware.js +1 -0
- package/dist/models/types.d.ts +1 -1
- package/dist/models/types.js +1 -0
- package/dist/providers/bedrock/index.d.ts +1 -0
- package/dist/providers/bedrock/index.js +1 -0
- package/dist/providers/bedrock/middleware.d.ts +2 -0
- package/dist/providers/bedrock/middleware.js +35 -0
- package/dist/telemetry/http.js +0 -3
- package/dist/types.d.ts +10 -20
- package/dist/utils/request.d.ts +1 -3
- package/dist/utils/request.js +3 -26
- package/dist/utils/response.d.ts +1 -1
- package/dist/utils/response.js +3 -3
- package/package.json +19 -21
- package/src/endpoints/chat-completions/converters.test.ts +219 -0
- package/src/endpoints/chat-completions/converters.ts +144 -104
- package/src/endpoints/chat-completions/handler.test.ts +87 -0
- package/src/endpoints/chat-completions/handler.ts +2 -5
- package/src/endpoints/chat-completions/otel.ts +6 -0
- package/src/endpoints/chat-completions/schema.ts +85 -43
- package/src/endpoints/embeddings/handler.ts +5 -5
- package/src/endpoints/embeddings/schema.ts +1 -1
- package/src/errors/gateway.ts +2 -0
- package/src/lifecycle.ts +7 -11
- package/src/logger/default.ts +34 -8
- package/src/middleware/utils.ts +1 -0
- package/src/models/amazon/middleware.ts +1 -0
- package/src/models/anthropic/middleware.test.ts +332 -1
- package/src/models/anthropic/middleware.ts +83 -19
- package/src/models/google/middleware.test.ts +31 -0
- package/src/models/google/middleware.ts +18 -0
- package/src/models/google/presets.ts +13 -2
- package/src/models/openai/middleware.ts +1 -0
- package/src/models/types.ts +1 -0
- package/src/providers/bedrock/index.ts +1 -0
- package/src/providers/bedrock/middleware.test.ts +73 -0
- package/src/providers/bedrock/middleware.ts +43 -0
- package/src/telemetry/http.ts +0 -3
- package/src/types.ts +19 -23
- package/src/utils/request.ts +5 -33
- package/src/utils/response.ts +3 -3
|
@@ -4,12 +4,13 @@ export const ChatCompletionsContentPartTextSchema = z.object({
|
|
|
4
4
|
type: z.literal("text"),
|
|
5
5
|
text: z.string(),
|
|
6
6
|
});
|
|
7
|
+
export type ChatCompletionsContentPartText = z.infer<typeof ChatCompletionsContentPartTextSchema>;
|
|
7
8
|
|
|
8
9
|
export const ChatCompletionsContentPartImageSchema = z.object({
|
|
9
10
|
type: z.literal("image_url"),
|
|
10
11
|
image_url: z.object({
|
|
11
12
|
url: z.string(),
|
|
12
|
-
detail: z.
|
|
13
|
+
detail: z.enum(["low", "high", "auto"]).optional(),
|
|
13
14
|
}),
|
|
14
15
|
});
|
|
15
16
|
|
|
@@ -22,11 +23,35 @@ export const ChatCompletionsContentPartFileSchema = z.object({
|
|
|
22
23
|
}),
|
|
23
24
|
});
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
export const ChatCompletionsContentPartAudioSchema = z.object({
|
|
27
|
+
type: z.literal("input_audio"),
|
|
28
|
+
input_audio: z.object({
|
|
29
|
+
data: z.string(),
|
|
30
|
+
// only wav and mp3 are official by OpenAI, rest is taken from Gemini support:
|
|
31
|
+
// https://docs.cloud.google.com/vertex-ai/generative-ai/docs/multimodal/audio-understanding
|
|
32
|
+
format: z.enum([
|
|
33
|
+
"x-aac",
|
|
34
|
+
"flac",
|
|
35
|
+
"mp3",
|
|
36
|
+
"m4a",
|
|
37
|
+
"mpeg",
|
|
38
|
+
"mpga",
|
|
39
|
+
"mp4",
|
|
40
|
+
"ogg",
|
|
41
|
+
"pcm",
|
|
42
|
+
"wav",
|
|
43
|
+
"webm",
|
|
44
|
+
]),
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const ChatCompletionsContentPartSchema = z.discriminatedUnion("type", [
|
|
49
|
+
ChatCompletionsContentPartTextSchema,
|
|
50
|
+
ChatCompletionsContentPartImageSchema,
|
|
51
|
+
ChatCompletionsContentPartFileSchema,
|
|
52
|
+
ChatCompletionsContentPartAudioSchema,
|
|
53
|
+
]);
|
|
54
|
+
export type ChatCompletionsContentPart = z.infer<typeof ChatCompletionsContentPartSchema>;
|
|
30
55
|
|
|
31
56
|
export const ChatCompletionsToolCallSchema = z.object({
|
|
32
57
|
type: z.literal("function"),
|
|
@@ -35,7 +60,10 @@ export const ChatCompletionsToolCallSchema = z.object({
|
|
|
35
60
|
arguments: z.string(),
|
|
36
61
|
name: z.string(),
|
|
37
62
|
}),
|
|
38
|
-
extra_content: z
|
|
63
|
+
extra_content: z
|
|
64
|
+
.record(z.string(), z.record(z.string(), z.unknown()))
|
|
65
|
+
.optional()
|
|
66
|
+
.meta({ extension: true }),
|
|
39
67
|
});
|
|
40
68
|
export type ChatCompletionsToolCall = z.infer<typeof ChatCompletionsToolCallSchema>;
|
|
41
69
|
|
|
@@ -48,16 +76,7 @@ export type ChatCompletionsSystemMessage = z.infer<typeof ChatCompletionsSystemM
|
|
|
48
76
|
|
|
49
77
|
export const ChatCompletionsUserMessageSchema = z.object({
|
|
50
78
|
role: z.literal("user"),
|
|
51
|
-
content: z.union([
|
|
52
|
-
z.string(),
|
|
53
|
-
z.array(
|
|
54
|
-
z.union([
|
|
55
|
-
ChatCompletionsContentPartTextSchema,
|
|
56
|
-
ChatCompletionsContentPartImageSchema,
|
|
57
|
-
ChatCompletionsContentPartFileSchema,
|
|
58
|
-
]),
|
|
59
|
-
),
|
|
60
|
-
]),
|
|
79
|
+
content: z.union([z.string(), z.array(ChatCompletionsContentPartSchema)]),
|
|
61
80
|
name: z.string().optional(),
|
|
62
81
|
});
|
|
63
82
|
export type ChatCompletionsUserMessage = z.infer<typeof ChatCompletionsUserMessageSchema>;
|
|
@@ -76,8 +95,9 @@ export type ChatCompletionsReasoningDetail = z.infer<typeof ChatCompletionsReaso
|
|
|
76
95
|
|
|
77
96
|
export const ChatCompletionsAssistantMessageSchema = z.object({
|
|
78
97
|
role: z.literal("assistant"),
|
|
79
|
-
|
|
80
|
-
|
|
98
|
+
content: z
|
|
99
|
+
.union([z.string(), z.null(), z.array(ChatCompletionsContentPartTextSchema)])
|
|
100
|
+
.optional(),
|
|
81
101
|
name: z.string().optional(),
|
|
82
102
|
// FUTURE: This should also support Custom Tool Calls
|
|
83
103
|
tool_calls: z.array(ChatCompletionsToolCallSchema).optional(),
|
|
@@ -87,19 +107,21 @@ export const ChatCompletionsAssistantMessageSchema = z.object({
|
|
|
87
107
|
.array(ChatCompletionsReasoningDetailSchema)
|
|
88
108
|
.optional()
|
|
89
109
|
.meta({ extension: true }),
|
|
90
|
-
extra_content: z
|
|
110
|
+
extra_content: z
|
|
111
|
+
.record(z.string(), z.record(z.string(), z.unknown()))
|
|
112
|
+
.optional()
|
|
113
|
+
.meta({ extension: true }),
|
|
91
114
|
});
|
|
92
115
|
export type ChatCompletionsAssistantMessage = z.infer<typeof ChatCompletionsAssistantMessageSchema>;
|
|
93
116
|
|
|
94
117
|
export const ChatCompletionsToolMessageSchema = z.object({
|
|
95
118
|
role: z.literal("tool"),
|
|
96
|
-
|
|
97
|
-
content: z.string(),
|
|
119
|
+
content: z.union([z.string(), z.array(ChatCompletionsContentPartTextSchema)]),
|
|
98
120
|
tool_call_id: z.string(),
|
|
99
121
|
});
|
|
100
122
|
export type ChatCompletionsToolMessage = z.infer<typeof ChatCompletionsToolMessageSchema>;
|
|
101
123
|
|
|
102
|
-
export const ChatCompletionsMessageSchema = z.
|
|
124
|
+
export const ChatCompletionsMessageSchema = z.discriminatedUnion("role", [
|
|
103
125
|
ChatCompletionsSystemMessageSchema,
|
|
104
126
|
ChatCompletionsUserMessageSchema,
|
|
105
127
|
ChatCompletionsAssistantMessageSchema,
|
|
@@ -112,16 +134,14 @@ export const ChatCompletionsToolSchema = z.object({
|
|
|
112
134
|
function: z.object({
|
|
113
135
|
name: z.string(),
|
|
114
136
|
description: z.string().optional(),
|
|
115
|
-
parameters: z.record(z.string(), z.
|
|
137
|
+
parameters: z.record(z.string(), z.unknown()),
|
|
116
138
|
// Missing strict parameter
|
|
117
139
|
}),
|
|
118
140
|
});
|
|
119
141
|
export type ChatCompletionsTool = z.infer<typeof ChatCompletionsToolSchema>;
|
|
120
142
|
|
|
121
143
|
export const ChatCompletionsToolChoiceSchema = z.union([
|
|
122
|
-
z.
|
|
123
|
-
z.literal("auto"),
|
|
124
|
-
z.literal("required"),
|
|
144
|
+
z.enum(["none", "auto", "required", "validated"]),
|
|
125
145
|
// FUTURE: missing AllowedTools and CustomToolChoice
|
|
126
146
|
z.object({
|
|
127
147
|
type: z.literal("function"),
|
|
@@ -132,13 +152,14 @@ export const ChatCompletionsToolChoiceSchema = z.union([
|
|
|
132
152
|
]);
|
|
133
153
|
export type ChatCompletionsToolChoice = z.infer<typeof ChatCompletionsToolChoiceSchema>;
|
|
134
154
|
|
|
135
|
-
export const ChatCompletionsReasoningEffortSchema = z.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
155
|
+
export const ChatCompletionsReasoningEffortSchema = z.enum([
|
|
156
|
+
"none",
|
|
157
|
+
"minimal",
|
|
158
|
+
"low",
|
|
159
|
+
"medium",
|
|
160
|
+
"high",
|
|
161
|
+
"xhigh",
|
|
162
|
+
"max",
|
|
142
163
|
]);
|
|
143
164
|
export type ChatCompletionsReasoningEffort = z.infer<typeof ChatCompletionsReasoningEffortSchema>;
|
|
144
165
|
|
|
@@ -150,6 +171,26 @@ export const ChatCompletionsReasoningConfigSchema = z.object({
|
|
|
150
171
|
});
|
|
151
172
|
export type ChatCompletionsReasoningConfig = z.infer<typeof ChatCompletionsReasoningConfigSchema>;
|
|
152
173
|
|
|
174
|
+
export const ChatCompletionsResponseFormatJsonSchema = z.object({
|
|
175
|
+
// FUTURE: consider support for legacy json_object (if demand)
|
|
176
|
+
type: z.literal("json_schema"),
|
|
177
|
+
json_schema: z.object({
|
|
178
|
+
name: z.string(),
|
|
179
|
+
description: z.string().optional(),
|
|
180
|
+
schema: z.record(z.string(), z.unknown()),
|
|
181
|
+
// FUTURE: consider support for non-strict mode (for providers that support it)
|
|
182
|
+
strict: z.boolean().optional(),
|
|
183
|
+
}),
|
|
184
|
+
});
|
|
185
|
+
export const ChatCompletionsResponseFormatTextSchema = z.object({
|
|
186
|
+
type: z.literal("text"),
|
|
187
|
+
});
|
|
188
|
+
export const ChatCompletionsResponseFormatSchema = z.discriminatedUnion("type", [
|
|
189
|
+
ChatCompletionsResponseFormatJsonSchema,
|
|
190
|
+
ChatCompletionsResponseFormatTextSchema,
|
|
191
|
+
]);
|
|
192
|
+
export type ChatCompletionsResponseFormat = z.infer<typeof ChatCompletionsResponseFormatSchema>;
|
|
193
|
+
|
|
153
194
|
const ChatCompletionsInputsSchema = z.object({
|
|
154
195
|
messages: z.array(ChatCompletionsMessageSchema),
|
|
155
196
|
tools: z
|
|
@@ -167,6 +208,7 @@ const ChatCompletionsInputsSchema = z.object({
|
|
|
167
208
|
seed: z.int().optional(),
|
|
168
209
|
stop: z.union([z.string(), z.array(z.string())]).optional(),
|
|
169
210
|
top_p: z.number().min(0).max(1.0).optional(),
|
|
211
|
+
response_format: ChatCompletionsResponseFormatSchema.optional(),
|
|
170
212
|
reasoning_effort: ChatCompletionsReasoningEffortSchema.optional(),
|
|
171
213
|
// Extensions
|
|
172
214
|
reasoning: ChatCompletionsReasoningConfigSchema.optional().meta({ extension: true }),
|
|
@@ -180,11 +222,11 @@ export const ChatCompletionsBodySchema = z.looseObject({
|
|
|
180
222
|
});
|
|
181
223
|
export type ChatCompletionsBody = z.infer<typeof ChatCompletionsBodySchema>;
|
|
182
224
|
|
|
183
|
-
export const ChatCompletionsFinishReasonSchema = z.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
225
|
+
export const ChatCompletionsFinishReasonSchema = z.enum([
|
|
226
|
+
"stop",
|
|
227
|
+
"length",
|
|
228
|
+
"content_filter",
|
|
229
|
+
"tool_calls",
|
|
188
230
|
]);
|
|
189
231
|
export type ChatCompletionsFinishReason = z.infer<typeof ChatCompletionsFinishReasonSchema>;
|
|
190
232
|
|
|
@@ -193,7 +235,7 @@ export const ChatCompletionsChoiceSchema = z.object({
|
|
|
193
235
|
message: ChatCompletionsAssistantMessageSchema,
|
|
194
236
|
finish_reason: ChatCompletionsFinishReasonSchema,
|
|
195
237
|
// FUTURE: model this out
|
|
196
|
-
logprobs: z.
|
|
238
|
+
logprobs: z.unknown().optional(),
|
|
197
239
|
});
|
|
198
240
|
export type ChatCompletionsChoice = z.infer<typeof ChatCompletionsChoiceSchema>;
|
|
199
241
|
|
|
@@ -224,7 +266,7 @@ export const ChatCompletionsSchema = z.object({
|
|
|
224
266
|
choices: z.array(ChatCompletionsChoiceSchema),
|
|
225
267
|
usage: ChatCompletionsUsageSchema.nullable(),
|
|
226
268
|
// Extensions
|
|
227
|
-
provider_metadata: z.
|
|
269
|
+
provider_metadata: z.unknown().optional().meta({ extension: true }),
|
|
228
270
|
});
|
|
229
271
|
export type ChatCompletions = z.infer<typeof ChatCompletionsSchema>;
|
|
230
272
|
|
|
@@ -246,7 +288,7 @@ export const ChatCompletionsChoiceDeltaSchema = z.object({
|
|
|
246
288
|
delta: ChatCompletionsAssistantMessageDeltaSchema,
|
|
247
289
|
finish_reason: ChatCompletionsFinishReasonSchema.nullable(),
|
|
248
290
|
// FUTURE: model this out
|
|
249
|
-
logprobs: z.
|
|
291
|
+
logprobs: z.unknown().optional(),
|
|
250
292
|
});
|
|
251
293
|
export type ChatCompletionsChoiceDelta = z.infer<typeof ChatCompletionsChoiceDeltaSchema>;
|
|
252
294
|
|
|
@@ -258,6 +300,6 @@ export const ChatCompletionsChunkSchema = z.object({
|
|
|
258
300
|
choices: z.array(ChatCompletionsChoiceDeltaSchema),
|
|
259
301
|
usage: ChatCompletionsUsageSchema.nullable(),
|
|
260
302
|
// Extensions
|
|
261
|
-
provider_metadata: z.
|
|
303
|
+
provider_metadata: z.unknown().optional().meta({ extension: true }),
|
|
262
304
|
});
|
|
263
305
|
export type ChatCompletionsChunk = z.infer<typeof ChatCompletionsChunkSchema>;
|
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
recordTokenUsage,
|
|
23
23
|
} from "../../telemetry/gen-ai";
|
|
24
24
|
import { addSpanEvent, setSpanAttributes } from "../../telemetry/span";
|
|
25
|
-
import { resolveRequestId } from "../../utils/headers";
|
|
26
25
|
import { prepareForwardHeaders } from "../../utils/request";
|
|
27
26
|
import { convertToEmbedCallOptions, toEmbeddings } from "./converters";
|
|
28
27
|
import {
|
|
@@ -45,8 +44,6 @@ export const embeddings = (config: GatewayConfig): Endpoint => {
|
|
|
45
44
|
throw new GatewayError("Method Not Allowed", 405);
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
const requestId = resolveRequestId(ctx.request);
|
|
49
|
-
|
|
50
47
|
// Parse + validate input.
|
|
51
48
|
try {
|
|
52
49
|
ctx.body = await ctx.request.json();
|
|
@@ -98,7 +95,10 @@ export const embeddings = (config: GatewayConfig): Endpoint => {
|
|
|
98
95
|
|
|
99
96
|
// Convert inputs to AI SDK call options.
|
|
100
97
|
const embedOptions = convertToEmbedCallOptions(inputs);
|
|
101
|
-
logger.trace(
|
|
98
|
+
logger.trace(
|
|
99
|
+
{ requestId: ctx.requestId, options: embedOptions },
|
|
100
|
+
"[embeddings] AI SDK options",
|
|
101
|
+
);
|
|
102
102
|
addSpanEvent("hebo.options.prepared");
|
|
103
103
|
setSpanAttributes(getEmbeddingsRequestAttributes(inputs, genAiSignalLevel));
|
|
104
104
|
|
|
@@ -116,7 +116,7 @@ export const embeddings = (config: GatewayConfig): Endpoint => {
|
|
|
116
116
|
abortSignal: ctx.request.signal,
|
|
117
117
|
...embedOptions,
|
|
118
118
|
});
|
|
119
|
-
logger.trace({ requestId, result }, "[embeddings] AI SDK result");
|
|
119
|
+
logger.trace({ requestId: ctx.requestId, result }, "[embeddings] AI SDK result");
|
|
120
120
|
addSpanEvent("hebo.ai-sdk.completed");
|
|
121
121
|
|
|
122
122
|
// Transform result.
|
|
@@ -31,6 +31,6 @@ export const EmbeddingsSchema = z.object({
|
|
|
31
31
|
model: z.string(),
|
|
32
32
|
usage: EmbeddingsUsageSchema.nullable(),
|
|
33
33
|
// Extensions
|
|
34
|
-
provider_metadata: z.
|
|
34
|
+
provider_metadata: z.unknown().optional().meta({ extension: true }),
|
|
35
35
|
});
|
|
36
36
|
export type Embeddings = z.infer<typeof EmbeddingsSchema>;
|
package/src/errors/gateway.ts
CHANGED
|
@@ -7,6 +7,8 @@ export class GatewayError extends Error {
|
|
|
7
7
|
constructor(error: unknown, status: number, code?: string, cause?: unknown) {
|
|
8
8
|
const isError = error instanceof Error;
|
|
9
9
|
super(isError ? error.message : String(error));
|
|
10
|
+
|
|
11
|
+
this.name = "GatewayError";
|
|
10
12
|
this.cause = cause ?? (isError ? error : undefined);
|
|
11
13
|
|
|
12
14
|
this.status = status;
|
package/src/lifecycle.ts
CHANGED
|
@@ -15,8 +15,7 @@ import { getRequestAttributes, getResponseAttributes } from "./telemetry/http";
|
|
|
15
15
|
import { recordV8jsMemory } from "./telemetry/memory";
|
|
16
16
|
import { addSpanEvent, setSpanEventsEnabled, setSpanTracer, startSpan } from "./telemetry/span";
|
|
17
17
|
import { wrapStream } from "./telemetry/stream";
|
|
18
|
-
import {
|
|
19
|
-
import { maybeApplyRequestPatch, prepareRequestHeaders } from "./utils/request";
|
|
18
|
+
import { resolveOrCreateRequestId } from "./utils/request";
|
|
20
19
|
import { prepareResponseInit, toResponse } from "./utils/response";
|
|
21
20
|
|
|
22
21
|
export const winterCgHandler = (
|
|
@@ -37,15 +36,14 @@ export const winterCgHandler = (
|
|
|
37
36
|
state: state ?? {},
|
|
38
37
|
providers: parsedConfig.providers,
|
|
39
38
|
models: parsedConfig.models,
|
|
39
|
+
requestId: resolveOrCreateRequestId(request),
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
const headers = prepareRequestHeaders(ctx.request);
|
|
43
|
-
if (headers) ctx.request = new Request(ctx.request, { headers });
|
|
44
|
-
|
|
45
42
|
const span = startSpan(ctx.request.url);
|
|
46
43
|
span.setAttributes(getBaggageAttributes(ctx.request));
|
|
47
44
|
if (!span.isExisting) {
|
|
48
45
|
span.setAttributes(getRequestAttributes(ctx.request, parsedConfig.telemetry?.signals?.http));
|
|
46
|
+
span.setAttributes({ "http.request.id": ctx.requestId });
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
const finalize = (status: number, reason?: unknown) => {
|
|
@@ -65,8 +63,8 @@ export const winterCgHandler = (
|
|
|
65
63
|
else if (status === 200 && ctx.response?.status) realStatus = ctx.response.status;
|
|
66
64
|
|
|
67
65
|
if (realStatus !== 200) {
|
|
68
|
-
|
|
69
|
-
requestId:
|
|
66
|
+
logger[realStatus >= 500 ? "error" : "warn"]({
|
|
67
|
+
requestId: ctx.requestId,
|
|
70
68
|
err: reason ?? ctx.request.signal.reason,
|
|
71
69
|
});
|
|
72
70
|
|
|
@@ -86,8 +84,6 @@ export const winterCgHandler = (
|
|
|
86
84
|
|
|
87
85
|
if (onRequest instanceof Response) {
|
|
88
86
|
ctx.response = onRequest;
|
|
89
|
-
} else if (onRequest) {
|
|
90
|
-
ctx.request = maybeApplyRequestPatch(ctx.request, onRequest);
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
|
|
@@ -98,7 +94,7 @@ export const winterCgHandler = (
|
|
|
98
94
|
ctx.result = wrapStream(ctx.result, { onDone: finalize });
|
|
99
95
|
}
|
|
100
96
|
|
|
101
|
-
ctx.response = toResponse(ctx.result!, prepareResponseInit(ctx.
|
|
97
|
+
ctx.response = toResponse(ctx.result!, prepareResponseInit(ctx.requestId));
|
|
102
98
|
}
|
|
103
99
|
|
|
104
100
|
if (parsedConfig.hooks?.onResponse) {
|
|
@@ -118,7 +114,7 @@ export const winterCgHandler = (
|
|
|
118
114
|
ctx.request.signal.aborted
|
|
119
115
|
? new GatewayError(error ?? ctx.request.signal.reason, 499)
|
|
120
116
|
: error,
|
|
121
|
-
prepareResponseInit(ctx.
|
|
117
|
+
prepareResponseInit(ctx.requestId),
|
|
122
118
|
);
|
|
123
119
|
finalize(ctx.response.status, error);
|
|
124
120
|
}
|
package/src/logger/default.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { serializeError } from "serialize-error";
|
|
2
|
-
|
|
3
1
|
import type { LogFn, LogLevel, Logger } from "./index";
|
|
4
2
|
|
|
5
3
|
import { isProduction, isTest } from "../utils/env";
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
const getDefaultLogLevel = (): LogLevel =>
|
|
8
6
|
isTest() ? "silent" : isProduction() ? "info" : "debug";
|
|
9
7
|
|
|
10
8
|
const noop: LogFn = () => {};
|
|
@@ -22,20 +20,48 @@ const LEVELS = Object.keys(LEVEL) as (keyof typeof LEVEL)[];
|
|
|
22
20
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
23
21
|
typeof value === "object" && value !== null && !(value instanceof Error);
|
|
24
22
|
|
|
23
|
+
function serializeError(err: unknown, _seen?: WeakSet<object>): Record<string, unknown> {
|
|
24
|
+
if (!(err instanceof Error)) return { message: String(err) };
|
|
25
|
+
|
|
26
|
+
const seen = _seen ?? new WeakSet();
|
|
27
|
+
if (seen.has(err)) return { name: err.name, message: err.message, circular: true };
|
|
28
|
+
seen.add(err);
|
|
29
|
+
|
|
30
|
+
const out: Record<string, unknown> = {};
|
|
31
|
+
|
|
32
|
+
for (const k of Object.getOwnPropertyNames(err)) {
|
|
33
|
+
if (k.startsWith("_")) continue;
|
|
34
|
+
|
|
35
|
+
let val: unknown;
|
|
36
|
+
try {
|
|
37
|
+
val = (err as any)[k];
|
|
38
|
+
} catch {
|
|
39
|
+
val = "[Unreadable]";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (typeof val === "bigint") val = `${val}n`;
|
|
43
|
+
|
|
44
|
+
// FUTURE: check for circular references within val
|
|
45
|
+
out[String(k)] = val instanceof Error ? serializeError(val, seen) : val;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
|
|
25
51
|
const buildLogObject = (level: LogLevel, args: unknown[]): Record<string, unknown> => {
|
|
26
52
|
if (args.length === 0) return {};
|
|
27
53
|
|
|
28
54
|
const [first, second] = args;
|
|
29
55
|
|
|
30
56
|
let obj: Record<string, unknown> | undefined;
|
|
31
|
-
let err: unknown;
|
|
57
|
+
let err: Record<string, unknown> | undefined;
|
|
32
58
|
let msg: string | undefined;
|
|
33
59
|
|
|
34
60
|
if (first instanceof Error) {
|
|
35
|
-
err = first;
|
|
61
|
+
err = serializeError(first);
|
|
36
62
|
} else if (isRecord(first)) {
|
|
37
63
|
if (first["err"] !== undefined) {
|
|
38
|
-
err = first["err"];
|
|
64
|
+
err = serializeError(first["err"]);
|
|
39
65
|
delete first["err"];
|
|
40
66
|
}
|
|
41
67
|
obj = first;
|
|
@@ -48,14 +74,14 @@ const buildLogObject = (level: LogLevel, args: unknown[]): Record<string, unknow
|
|
|
48
74
|
}
|
|
49
75
|
|
|
50
76
|
if (err && msg === undefined) {
|
|
51
|
-
msg = err
|
|
77
|
+
msg = err["message"] as string;
|
|
52
78
|
}
|
|
53
79
|
|
|
54
80
|
return {
|
|
55
81
|
level,
|
|
56
82
|
time: Date.now(),
|
|
57
83
|
...(msg ? { msg } : {}),
|
|
58
|
-
...(err ? { err
|
|
84
|
+
...(err ? { err } : {}),
|
|
59
85
|
...obj,
|
|
60
86
|
};
|
|
61
87
|
};
|
package/src/middleware/utils.ts
CHANGED