babelgate 0.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +467 -1
  4. package/dist/app.js +40 -0
  5. package/dist/cli.js +203 -0
  6. package/dist/config/env-config.js +99 -0
  7. package/dist/index.js +60 -0
  8. package/dist/middleware/error-handler.js +158 -0
  9. package/dist/middleware/request-logger.js +66 -0
  10. package/dist/middleware/require-api-key.js +80 -0
  11. package/dist/middleware/resolve-source.js +28 -0
  12. package/dist/routes/proxy.js +74 -0
  13. package/dist/services/http-client.js +220 -0
  14. package/dist/services/proxy.service.js +329 -0
  15. package/dist/services/stream-pipeline.js +119 -0
  16. package/dist/services/upstream-errors.js +34 -0
  17. package/dist/transformers/adapters/anthropic.adapter.js +292 -0
  18. package/dist/transformers/adapters/anthropic.messages.js +261 -0
  19. package/dist/transformers/adapters/anthropic.stream.js +378 -0
  20. package/dist/transformers/adapters/gemini.adapter.js +418 -0
  21. package/dist/transformers/adapters/gemini.schema.js +61 -0
  22. package/dist/transformers/adapters/gemini.stream.js +341 -0
  23. package/dist/transformers/adapters/gemini.tools.js +246 -0
  24. package/dist/transformers/adapters/index.js +141 -0
  25. package/dist/transformers/adapters/ollama.adapter.js +288 -0
  26. package/dist/transformers/adapters/ollama.stream.js +294 -0
  27. package/dist/transformers/adapters/ollama.tools.js +107 -0
  28. package/dist/transformers/adapters/openai.adapter.js +460 -0
  29. package/dist/transformers/adapters/openai.stream.js +229 -0
  30. package/dist/transformers/index.js +110 -0
  31. package/dist/types/anthropic.types.js +2 -0
  32. package/dist/types/canonical.schema.js +160 -0
  33. package/dist/types/canonical.types.js +8 -0
  34. package/dist/types/gemini.types.js +2 -0
  35. package/dist/types/ollama.types.js +4 -0
  36. package/dist/types/openai.types.js +2 -0
  37. package/dist/utils/canonical-error.js +77 -0
  38. package/dist/utils/errors.js +95 -0
  39. package/dist/utils/ids.js +17 -0
  40. package/dist/utils/logger.js +34 -0
  41. package/dist/utils/model-map.js +39 -0
  42. package/dist/utils/sse.js +147 -0
  43. package/dist/utils/stream-reassemble.js +104 -0
  44. package/dist/utils/token-estimate.js +36 -0
  45. package/dist/utils/tool-args.js +26 -0
  46. package/package.json +55 -7
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.PROVIDER_ROUTES = exports.PROVIDER_PATHS = exports.adapters = void 0;
18
+ exports.transformRequest = transformRequest;
19
+ exports.transformResponse = transformResponse;
20
+ exports.getTransformers = getTransformers;
21
+ exports.toCanonical = toCanonical;
22
+ exports.fromCanonical = fromCanonical;
23
+ const errors_1 = require("../utils/errors");
24
+ const adapters_1 = require("./adapters");
25
+ // Re-export adapters
26
+ var adapters_2 = require("./adapters");
27
+ Object.defineProperty(exports, "adapters", { enumerable: true, get: function () { return adapters_2.adapters; } });
28
+ Object.defineProperty(exports, "PROVIDER_PATHS", { enumerable: true, get: function () { return adapters_2.PROVIDER_PATHS; } });
29
+ Object.defineProperty(exports, "PROVIDER_ROUTES", { enumerable: true, get: function () { return adapters_2.PROVIDER_ROUTES; } });
30
+ __exportStar(require("../types/canonical.types"), exports);
31
+ /**
32
+ * Transform a request from source provider format to target provider format.
33
+ * Uses canonical format as intermediate representation.
34
+ *
35
+ * Flow: Source Request → Canonical → Target Request
36
+ */
37
+ function transformRequest(sourceProvider, targetProvider, request) {
38
+ const sourceAdapter = adapters_1.adapters[sourceProvider];
39
+ const targetAdapter = adapters_1.adapters[targetProvider];
40
+ if (!sourceAdapter) {
41
+ throw new errors_1.ConfigurationError(`Unknown source provider: ${sourceProvider}`, {
42
+ availableProviders: Object.keys(adapters_1.adapters),
43
+ });
44
+ }
45
+ if (!targetAdapter) {
46
+ throw new errors_1.ConfigurationError(`Unknown target provider: ${targetProvider}`, {
47
+ availableProviders: Object.keys(adapters_1.adapters),
48
+ });
49
+ }
50
+ // Source → Canonical → Target
51
+ const canonical = sourceAdapter.toCanonicalRequest(request);
52
+ return targetAdapter.fromCanonicalRequest(canonical);
53
+ }
54
+ /**
55
+ * Transform a response from target provider format back to source provider format.
56
+ * Uses canonical format as intermediate representation.
57
+ *
58
+ * Flow: Target Response → Canonical → Source Response
59
+ */
60
+ function transformResponse(sourceProvider, targetProvider, response, model) {
61
+ const sourceAdapter = adapters_1.adapters[sourceProvider];
62
+ const targetAdapter = adapters_1.adapters[targetProvider];
63
+ if (!sourceAdapter) {
64
+ throw new errors_1.ConfigurationError(`Unknown source provider: ${sourceProvider}`, {
65
+ availableProviders: Object.keys(adapters_1.adapters),
66
+ });
67
+ }
68
+ if (!targetAdapter) {
69
+ throw new errors_1.ConfigurationError(`Unknown target provider: ${targetProvider}`, {
70
+ availableProviders: Object.keys(adapters_1.adapters),
71
+ });
72
+ }
73
+ // Target → Canonical → Source
74
+ const canonical = targetAdapter.toCanonicalResponse(response, model);
75
+ return sourceAdapter.fromCanonicalResponse(canonical);
76
+ }
77
+ /**
78
+ * Get transformer functions for a source-target pair.
79
+ * Returns functions that handle the full transformation pipeline.
80
+ */
81
+ function getTransformers(sourceProvider, targetProvider) {
82
+ return {
83
+ transformRequest: (request) => transformRequest(sourceProvider, targetProvider, request),
84
+ transformResponse: (response, model) => transformResponse(sourceProvider, targetProvider, response, model),
85
+ };
86
+ }
87
+ /**
88
+ * Convert any provider request to canonical format.
89
+ */
90
+ function toCanonical(provider, request) {
91
+ const adapter = adapters_1.adapters[provider];
92
+ if (!adapter) {
93
+ throw new errors_1.ConfigurationError(`Unknown provider: ${provider}`, {
94
+ availableProviders: Object.keys(adapters_1.adapters),
95
+ });
96
+ }
97
+ return adapter.toCanonicalRequest(request);
98
+ }
99
+ /**
100
+ * Convert canonical request to any provider format.
101
+ */
102
+ function fromCanonical(provider, request) {
103
+ const adapter = adapters_1.adapters[provider];
104
+ if (!adapter) {
105
+ throw new errors_1.ConfigurationError(`Unknown provider: ${provider}`, {
106
+ availableProviders: Object.keys(adapters_1.adapters),
107
+ });
108
+ }
109
+ return adapter.fromCanonicalRequest(request);
110
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.canonicalStreamEventSchema = exports.canonicalModelListSchema = exports.canonicalModelSchema = exports.canonicalErrorSchema = exports.canonicalErrorKindSchema = exports.canonicalResponseSchema = exports.canonicalUsageSchema = exports.finishReasonSchema = exports.canonicalRequestSchema = exports.canonicalToolChoiceSchema = exports.canonicalToolSchema = exports.canonicalConfigSchema = exports.canonicalMessageSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ /**
6
+ * Zod schemas mirroring canonical.types.ts.
7
+ * Used for runtime contract validation of adapter outputs.
8
+ */
9
+ const roleSchema = zod_1.z.enum(["system", "user", "assistant", "tool"]);
10
+ const mimeTypeSchema = zod_1.z.enum([
11
+ "image/jpeg",
12
+ "image/png",
13
+ "image/gif",
14
+ "image/webp",
15
+ ]);
16
+ const imageSchema = zod_1.z.object({
17
+ data: zod_1.z.string(),
18
+ mimeType: mimeTypeSchema,
19
+ });
20
+ const contentPartSchema = zod_1.z
21
+ .object({
22
+ type: zod_1.z.enum(["text", "image"]),
23
+ text: zod_1.z.string().optional(),
24
+ image: imageSchema.optional(),
25
+ })
26
+ .refine((p) => (p.type === "text" ? p.text !== undefined : true), {
27
+ message: "content part of type 'text' must have text",
28
+ });
29
+ const toolCallSchema = zod_1.z.object({
30
+ id: zod_1.z.string(),
31
+ type: zod_1.z.literal("function"),
32
+ function: zod_1.z.object({
33
+ name: zod_1.z.string(),
34
+ arguments: zod_1.z.string(),
35
+ }),
36
+ });
37
+ exports.canonicalMessageSchema = zod_1.z.object({
38
+ role: roleSchema,
39
+ content: zod_1.z.union([zod_1.z.string(), zod_1.z.array(contentPartSchema)]),
40
+ toolCalls: zod_1.z.array(toolCallSchema).optional(),
41
+ toolCallId: zod_1.z.string().optional(),
42
+ isError: zod_1.z.boolean().optional(),
43
+ name: zod_1.z.string().optional(),
44
+ });
45
+ exports.canonicalConfigSchema = zod_1.z.object({
46
+ temperature: zod_1.z.number().optional(),
47
+ maxTokens: zod_1.z.number().int().positive().optional(),
48
+ topP: zod_1.z.number().optional(),
49
+ topK: zod_1.z.number().int().positive().optional(),
50
+ stopSequences: zod_1.z.array(zod_1.z.string()).optional(),
51
+ candidateCount: zod_1.z.number().int().positive().optional(),
52
+ seed: zod_1.z.number().optional(),
53
+ frequencyPenalty: zod_1.z.number().optional(),
54
+ presencePenalty: zod_1.z.number().optional(),
55
+ contextWindow: zod_1.z.number().int().positive().optional(),
56
+ });
57
+ const functionSchema = zod_1.z.object({
58
+ name: zod_1.z.string(),
59
+ description: zod_1.z.string().optional(),
60
+ parameters: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
61
+ });
62
+ exports.canonicalToolSchema = zod_1.z.object({
63
+ type: zod_1.z.literal("function"),
64
+ function: functionSchema,
65
+ });
66
+ exports.canonicalToolChoiceSchema = zod_1.z.union([
67
+ zod_1.z.enum(["auto", "none", "required"]),
68
+ zod_1.z.object({
69
+ type: zod_1.z.literal("function"),
70
+ function: zod_1.z.object({ name: zod_1.z.string() }),
71
+ }),
72
+ ]);
73
+ exports.canonicalRequestSchema = zod_1.z.object({
74
+ model: zod_1.z.string().min(1),
75
+ messages: zod_1.z.array(exports.canonicalMessageSchema).min(1),
76
+ systemPrompt: zod_1.z.string().optional(),
77
+ config: exports.canonicalConfigSchema.optional(),
78
+ tools: zod_1.z.array(exports.canonicalToolSchema).optional(),
79
+ toolChoice: exports.canonicalToolChoiceSchema.optional(),
80
+ stream: zod_1.z.boolean().optional(),
81
+ });
82
+ exports.finishReasonSchema = zod_1.z.enum([
83
+ "stop",
84
+ "length",
85
+ "tool_call",
86
+ "content_filter",
87
+ "error",
88
+ "unknown",
89
+ ]);
90
+ exports.canonicalUsageSchema = zod_1.z.object({
91
+ inputTokens: zod_1.z.number().int().nonnegative(),
92
+ outputTokens: zod_1.z.number().int().nonnegative(),
93
+ totalTokens: zod_1.z.number().int().nonnegative(),
94
+ });
95
+ exports.canonicalResponseSchema = zod_1.z.object({
96
+ id: zod_1.z.string().min(1),
97
+ model: zod_1.z.string().min(1),
98
+ message: exports.canonicalMessageSchema,
99
+ finishReason: exports.finishReasonSchema,
100
+ usage: exports.canonicalUsageSchema.optional(),
101
+ created: zod_1.z.number().optional(),
102
+ });
103
+ // ============ ERRORS ============
104
+ exports.canonicalErrorKindSchema = zod_1.z.enum([
105
+ "invalid_request",
106
+ "authentication",
107
+ "permission",
108
+ "not_found",
109
+ "request_too_large",
110
+ "rate_limit",
111
+ "unsupported",
112
+ "upstream",
113
+ "unavailable",
114
+ "timeout",
115
+ "internal",
116
+ ]);
117
+ exports.canonicalErrorSchema = zod_1.z.object({
118
+ kind: exports.canonicalErrorKindSchema,
119
+ status: zod_1.z.number().int(),
120
+ message: zod_1.z.string(),
121
+ retryAfterSeconds: zod_1.z.number().optional(),
122
+ });
123
+ // ============ MODEL LIST ============
124
+ exports.canonicalModelSchema = zod_1.z.object({
125
+ id: zod_1.z.string().min(1),
126
+ displayName: zod_1.z.string().optional(),
127
+ created: zod_1.z.number().optional(),
128
+ ownedBy: zod_1.z.string().optional(),
129
+ });
130
+ exports.canonicalModelListSchema = zod_1.z.object({
131
+ models: zod_1.z.array(exports.canonicalModelSchema),
132
+ });
133
+ // ============ STREAMING ============
134
+ const streamIndexSchema = zod_1.z.number().int().nonnegative();
135
+ exports.canonicalStreamEventSchema = zod_1.z.discriminatedUnion("type", [
136
+ zod_1.z.object({
137
+ type: zod_1.z.literal("message_start"),
138
+ id: zod_1.z.string(),
139
+ model: zod_1.z.string(),
140
+ }),
141
+ zod_1.z.object({ type: zod_1.z.literal("text_delta"), text: zod_1.z.string() }),
142
+ zod_1.z.object({
143
+ type: zod_1.z.literal("tool_call_start"),
144
+ index: streamIndexSchema,
145
+ id: zod_1.z.string(),
146
+ name: zod_1.z.string(),
147
+ }),
148
+ zod_1.z.object({
149
+ type: zod_1.z.literal("tool_call_delta"),
150
+ index: streamIndexSchema,
151
+ argumentsDelta: zod_1.z.string(),
152
+ }),
153
+ zod_1.z.object({ type: zod_1.z.literal("tool_call_end"), index: streamIndexSchema }),
154
+ zod_1.z.object({ type: zod_1.z.literal("usage"), usage: exports.canonicalUsageSchema }),
155
+ zod_1.z.object({
156
+ type: zod_1.z.literal("message_end"),
157
+ finishReason: exports.finishReasonSchema,
158
+ }),
159
+ zod_1.z.object({ type: zod_1.z.literal("error"), error: exports.canonicalErrorSchema }),
160
+ ]);
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Canonical LLM API Types
4
+ *
5
+ * Provider-agnostic format that serves as the intermediate representation
6
+ * for transforming between different LLM API formats.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // Ollama API types
3
+ // Reference: https://github.com/ollama/ollama/blob/main/docs/api.md
4
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CANONICAL_ERROR_STATUS = void 0;
4
+ exports.kindFromStatus = kindFromStatus;
5
+ exports.makeCanonicalError = makeCanonicalError;
6
+ exports.parseRetryAfter = parseRetryAfter;
7
+ /** HTTP status the client sees for each canonical kind (spec §3.3). */
8
+ exports.CANONICAL_ERROR_STATUS = {
9
+ invalid_request: 400,
10
+ authentication: 401,
11
+ permission: 403,
12
+ not_found: 404,
13
+ request_too_large: 413,
14
+ rate_limit: 429,
15
+ internal: 500,
16
+ unsupported: 501,
17
+ upstream: 502,
18
+ unavailable: 503,
19
+ timeout: 504,
20
+ };
21
+ /** Map an HTTP status to the canonical kind (spec §3.3). */
22
+ function kindFromStatus(status) {
23
+ switch (status) {
24
+ case 400:
25
+ case 422:
26
+ return "invalid_request";
27
+ case 401:
28
+ return "authentication";
29
+ case 403:
30
+ return "permission";
31
+ case 404:
32
+ return "not_found";
33
+ case 413:
34
+ return "request_too_large";
35
+ case 429:
36
+ return "rate_limit";
37
+ case 500:
38
+ return "internal";
39
+ case 501:
40
+ return "unsupported";
41
+ case 503:
42
+ case 529:
43
+ return "unavailable";
44
+ case 504:
45
+ return "timeout";
46
+ default:
47
+ if (status >= 500)
48
+ return "upstream";
49
+ if (status >= 400)
50
+ return "invalid_request";
51
+ return "internal";
52
+ }
53
+ }
54
+ function makeCanonicalError(kind, message, retryAfterSeconds) {
55
+ return {
56
+ kind,
57
+ status: exports.CANONICAL_ERROR_STATUS[kind],
58
+ message,
59
+ ...(retryAfterSeconds !== undefined && { retryAfterSeconds }),
60
+ };
61
+ }
62
+ /**
63
+ * Parse an upstream `Retry-After` header into whole seconds.
64
+ * delta-seconds pass through; an HTTP-date becomes seconds from `now`
65
+ * (minimum 1); anything unrecognised is dropped.
66
+ */
67
+ function parseRetryAfter(header, now = new Date()) {
68
+ if (!header)
69
+ return undefined;
70
+ const trimmed = header.trim();
71
+ if (/^\d+$/.test(trimmed))
72
+ return parseInt(trimmed, 10);
73
+ const date = Date.parse(trimmed);
74
+ if (Number.isNaN(date))
75
+ return undefined;
76
+ return Math.max(1, Math.ceil((date - now.getTime()) / 1000));
77
+ }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigurationError = exports.AuthError = exports.NotSupportedError = exports.UpstreamError = exports.TransformError = exports.ValidationError = exports.ProxyError = void 0;
4
+ const canonical_error_1 = require("./canonical-error");
5
+ class ProxyError extends Error {
6
+ statusCode;
7
+ code;
8
+ context;
9
+ constructor(message, statusCode = 500, code = "PROXY_ERROR", context) {
10
+ super(message);
11
+ this.statusCode = statusCode;
12
+ this.code = code;
13
+ this.context = context;
14
+ this.name = this.constructor.name;
15
+ Error.captureStackTrace(this, this.constructor);
16
+ }
17
+ /** Canonical form used to render this error in the client's dialect. */
18
+ toCanonical() {
19
+ return (0, canonical_error_1.makeCanonicalError)((0, canonical_error_1.kindFromStatus)(this.statusCode), this.message);
20
+ }
21
+ toJSON() {
22
+ return {
23
+ error: {
24
+ message: this.message,
25
+ code: this.code,
26
+ status: this.statusCode,
27
+ ...(process.env.NODE_ENV !== "production" && this.context
28
+ ? { details: this.context }
29
+ : {}),
30
+ },
31
+ };
32
+ }
33
+ }
34
+ exports.ProxyError = ProxyError;
35
+ class ValidationError extends ProxyError {
36
+ constructor(message, context) {
37
+ super(message, 400, "VALIDATION_ERROR", context);
38
+ }
39
+ }
40
+ exports.ValidationError = ValidationError;
41
+ class TransformError extends ProxyError {
42
+ constructor(message, context) {
43
+ super(message, 500, "TRANSFORM_ERROR", context);
44
+ }
45
+ }
46
+ exports.TransformError = TransformError;
47
+ class UpstreamError extends ProxyError {
48
+ upstreamStatus;
49
+ upstreamBody;
50
+ /**
51
+ * Client-facing rendering computed by proxy.service's upstream mapping
52
+ * (spec §3.3). When set it wins over the default status-derived kind.
53
+ */
54
+ clientError;
55
+ /** Seconds from the upstream Retry-After header (set on 429/503). */
56
+ retryAfterSeconds;
57
+ constructor(message, upstreamStatus, upstreamBody, context, statusCode = 502) {
58
+ // upstreamBody stays a field (for the §3.3 log summary) but is kept
59
+ // out of `context`: context is serialized into non-production
60
+ // `details` and an upstream body may echo keys or completion text.
61
+ super(message, statusCode, "UPSTREAM_ERROR", {
62
+ ...context,
63
+ upstreamStatus,
64
+ });
65
+ this.upstreamStatus = upstreamStatus;
66
+ this.upstreamBody = upstreamBody;
67
+ }
68
+ toCanonical() {
69
+ return this.clientError ?? super.toCanonical();
70
+ }
71
+ }
72
+ exports.UpstreamError = UpstreamError;
73
+ /**
74
+ * 501 — the client asked for something the proxy refuses by design
75
+ * (streaming, unsupported provider methods). Canonical kind
76
+ * `unsupported` via the default toCanonical().
77
+ */
78
+ class NotSupportedError extends ProxyError {
79
+ constructor(message, context) {
80
+ super(message, 501, "NOT_SUPPORTED", context);
81
+ }
82
+ }
83
+ exports.NotSupportedError = NotSupportedError;
84
+ class AuthError extends ProxyError {
85
+ constructor(message, context) {
86
+ super(message, 401, "UNAUTHORIZED", context);
87
+ }
88
+ }
89
+ exports.AuthError = AuthError;
90
+ class ConfigurationError extends ProxyError {
91
+ constructor(message, context) {
92
+ super(message, 500, "CONFIGURATION_ERROR", context);
93
+ }
94
+ }
95
+ exports.ConfigurationError = ConfigurationError;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createIdGenerator = createIdGenerator;
4
+ exports.sequentialIds = sequentialIds;
5
+ const crypto_1 = require("crypto");
6
+ /**
7
+ * Random-suffix ID generator (spec §3.4: `call_<n>`-style generated
8
+ * tool-call IDs) — the default injected into decoders/adapters.
9
+ */
10
+ function createIdGenerator(prefix = "call_") {
11
+ return () => `${prefix}${(0, crypto_1.randomBytes)(9).toString("base64url")}`;
12
+ }
13
+ /** Deterministic `call_0`, `call_1`, … — used in tests and fixtures. */
14
+ function sequentialIds(prefix = "call_") {
15
+ let next = 0;
16
+ return () => `${prefix}${next++}`;
17
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logger = void 0;
7
+ exports.loggerOptions = loggerOptions;
8
+ const pino_1 = __importDefault(require("pino"));
9
+ function canResolvePinoPretty() {
10
+ try {
11
+ require.resolve("pino-pretty");
12
+ return true;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ function loggerOptions(env, canResolve) {
19
+ const isProduction = env.NODE_ENV === "production";
20
+ return {
21
+ level: env.LOG_LEVEL || (isProduction ? "info" : "debug"),
22
+ transport: !isProduction && canResolve()
23
+ ? {
24
+ target: "pino-pretty",
25
+ options: {
26
+ colorize: true,
27
+ translateTime: "SYS:standard",
28
+ ignore: "pid,hostname",
29
+ },
30
+ }
31
+ : undefined,
32
+ };
33
+ }
34
+ exports.logger = (0, pino_1.default)(loggerOptions(process.env, canResolvePinoPretty));
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseModelMap = parseModelMap;
4
+ exports.applyModelMap = applyModelMap;
5
+ const errors_1 = require("./errors");
6
+ /** `*` matches any run of characters; every other character is literal. */
7
+ function globToRegExp(pattern) {
8
+ const escaped = pattern
9
+ .replace(/[.+?^${}()|[\]\\]/g, "\\$&")
10
+ .replace(/\*/g, ".*");
11
+ return new RegExp(`^${escaped}$`);
12
+ }
13
+ /**
14
+ * Comma-separated `glob=model` entries → ordered rules. An entry that
15
+ * isn't `glob=model` (empty pattern or model, no `=`) is a configuration
16
+ * error — it fails at startup, not at request time.
17
+ */
18
+ function parseModelMap(value) {
19
+ if (value === undefined || value.trim() === "")
20
+ return [];
21
+ return value.split(",").map((raw) => {
22
+ const entry = raw.trim();
23
+ const eq = entry.indexOf("=");
24
+ const pattern = eq === -1 ? "" : entry.slice(0, eq).trim();
25
+ const model = eq === -1 ? "" : entry.slice(eq + 1).trim();
26
+ if (pattern === "" || model === "") {
27
+ throw new errors_1.ConfigurationError(`MODEL_MAP entry "${entry}" must be glob=model`);
28
+ }
29
+ return { pattern, model };
30
+ });
31
+ }
32
+ /** First matching rule wins; no match leaves the model unchanged. */
33
+ function applyModelMap(model, rules) {
34
+ for (const rule of rules) {
35
+ if (globToRegExp(rule.pattern).test(model))
36
+ return rule.model;
37
+ }
38
+ return model;
39
+ }