@spfn/core 0.1.0-alpha.65 → 0.1.0-alpha.68
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/codegen/generators/index.d.ts +7 -7
- package/dist/codegen/generators/index.js +36 -35
- package/dist/codegen/generators/index.js.map +1 -1
- package/dist/codegen/index.d.ts +64 -123
- package/dist/codegen/index.js +877 -958
- package/dist/codegen/index.js.map +1 -1
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/route/index.js +16 -5
- package/dist/route/index.js.map +1 -1
- package/dist/server/index.js +16 -5
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- /package/dist/{generator-DHiAqhKv.d.ts → index-DHiAqhKv.d.ts} +0 -0
package/dist/codegen/index.js
CHANGED
|
@@ -1,941 +1,431 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, accessSync, constants, writeFileSync, unlinkSync, readFileSync, createWriteStream, statSync, readdirSync, renameSync } from 'fs';
|
|
2
|
-
import { readdir, stat, mkdir, writeFile } from 'fs/promises';
|
|
3
|
-
import { join, dirname, relative } from 'path';
|
|
4
|
-
import * as ts from 'typescript';
|
|
5
1
|
import { watch } from 'chokidar';
|
|
6
|
-
import
|
|
2
|
+
import { join, relative } from 'path';
|
|
7
3
|
import mm from 'micromatch';
|
|
4
|
+
import pino from 'pino';
|
|
5
|
+
import { existsSync, mkdirSync, accessSync, constants, writeFileSync, unlinkSync, createWriteStream, statSync, readdirSync, renameSync, readFileSync } from 'fs';
|
|
6
|
+
import { readdir, stat, mkdir, writeFile } from 'fs/promises';
|
|
7
|
+
import * as ts from 'typescript';
|
|
8
8
|
import { createJiti } from 'jiti';
|
|
9
9
|
|
|
10
|
-
// src/codegen/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const contractExport = exports[j];
|
|
20
|
-
if (!contractExport.path.startsWith("/")) {
|
|
21
|
-
throw new Error(
|
|
22
|
-
`Contract '${contractExport.name}' in ${filePath} must use absolute path. Found: '${contractExport.path}'. Use '/your-path' instead.`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
const finalPath = packagePrefix ? `${packagePrefix}${contractExport.path}` : contractExport.path;
|
|
26
|
-
mappings.push({
|
|
27
|
-
method: contractExport.method,
|
|
28
|
-
path: finalPath,
|
|
29
|
-
contractName: contractExport.name,
|
|
30
|
-
contractImportPath: getImportPath(filePath),
|
|
31
|
-
routeFile: "",
|
|
32
|
-
contractFile: filePath,
|
|
33
|
-
hasQuery: contractExport.hasQuery,
|
|
34
|
-
hasBody: contractExport.hasBody,
|
|
35
|
-
hasParams: contractExport.hasParams
|
|
36
|
-
});
|
|
37
|
-
}
|
|
10
|
+
// src/codegen/core/orchestrator.ts
|
|
11
|
+
var PinoAdapter = class _PinoAdapter {
|
|
12
|
+
logger;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.logger = pino({
|
|
15
|
+
level: config.level,
|
|
16
|
+
// 기본 필드
|
|
17
|
+
base: config.module ? { module: config.module } : void 0
|
|
18
|
+
});
|
|
38
19
|
}
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
20
|
+
child(module) {
|
|
21
|
+
const childLogger = new _PinoAdapter({ level: this.logger.level, module });
|
|
22
|
+
childLogger.logger = this.logger.child({ module });
|
|
23
|
+
return childLogger;
|
|
24
|
+
}
|
|
25
|
+
debug(message, context) {
|
|
26
|
+
this.logger.debug(context || {}, message);
|
|
27
|
+
}
|
|
28
|
+
info(message, context) {
|
|
29
|
+
this.logger.info(context || {}, message);
|
|
30
|
+
}
|
|
31
|
+
warn(message, errorOrContext, context) {
|
|
32
|
+
if (errorOrContext instanceof Error) {
|
|
33
|
+
this.logger.warn({ err: errorOrContext, ...context }, message);
|
|
34
|
+
} else {
|
|
35
|
+
this.logger.warn(errorOrContext || {}, message);
|
|
55
36
|
}
|
|
56
|
-
} catch (error) {
|
|
57
37
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
filePath,
|
|
64
|
-
sourceCode,
|
|
65
|
-
ts.ScriptTarget.Latest,
|
|
66
|
-
true
|
|
67
|
-
);
|
|
68
|
-
const exports = [];
|
|
69
|
-
function visit(node) {
|
|
70
|
-
if (ts.isVariableStatement(node)) {
|
|
71
|
-
const hasExport = node.modifiers?.some(
|
|
72
|
-
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
73
|
-
);
|
|
74
|
-
if (hasExport && node.declarationList.declarations.length > 0) {
|
|
75
|
-
const declaration = node.declarationList.declarations[0];
|
|
76
|
-
if (ts.isVariableDeclaration(declaration) && ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
77
|
-
const name = declaration.name.text;
|
|
78
|
-
const hasSatisfiesRouteContract = checkSatisfiesRouteContract(declaration.initializer);
|
|
79
|
-
if (hasSatisfiesRouteContract) {
|
|
80
|
-
const objectLiteral = extractObjectLiteral(declaration.initializer);
|
|
81
|
-
if (objectLiteral) {
|
|
82
|
-
const contractData = extractContractData(objectLiteral);
|
|
83
|
-
if (contractData.method && contractData.path) {
|
|
84
|
-
exports.push({
|
|
85
|
-
name,
|
|
86
|
-
method: contractData.method,
|
|
87
|
-
path: contractData.path,
|
|
88
|
-
hasQuery: contractData.hasQuery,
|
|
89
|
-
hasBody: contractData.hasBody,
|
|
90
|
-
hasParams: contractData.hasParams
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (isContractName(name)) {
|
|
97
|
-
const objectLiteral = extractObjectLiteral(declaration.initializer);
|
|
98
|
-
if (objectLiteral) {
|
|
99
|
-
const contractData = extractContractData(objectLiteral);
|
|
100
|
-
if (contractData.method && contractData.path) {
|
|
101
|
-
exports.push({
|
|
102
|
-
name,
|
|
103
|
-
method: contractData.method,
|
|
104
|
-
path: contractData.path,
|
|
105
|
-
hasQuery: contractData.hasQuery,
|
|
106
|
-
hasBody: contractData.hasBody,
|
|
107
|
-
hasParams: contractData.hasParams
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
38
|
+
error(message, errorOrContext, context) {
|
|
39
|
+
if (errorOrContext instanceof Error) {
|
|
40
|
+
this.logger.error({ err: errorOrContext, ...context }, message);
|
|
41
|
+
} else {
|
|
42
|
+
this.logger.error(errorOrContext || {}, message);
|
|
114
43
|
}
|
|
115
|
-
ts.forEachChild(node, visit);
|
|
116
44
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
45
|
+
fatal(message, errorOrContext, context) {
|
|
46
|
+
if (errorOrContext instanceof Error) {
|
|
47
|
+
this.logger.fatal({ err: errorOrContext, ...context }, message);
|
|
48
|
+
} else {
|
|
49
|
+
this.logger.fatal(errorOrContext || {}, message);
|
|
50
|
+
}
|
|
123
51
|
}
|
|
124
|
-
|
|
125
|
-
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
126
|
-
return typeNode.typeName.text === "RouteContract";
|
|
52
|
+
async close() {
|
|
127
53
|
}
|
|
128
|
-
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// src/logger/types.ts
|
|
57
|
+
var LOG_LEVEL_PRIORITY = {
|
|
58
|
+
debug: 0,
|
|
59
|
+
info: 1,
|
|
60
|
+
warn: 2,
|
|
61
|
+
error: 3,
|
|
62
|
+
fatal: 4
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/logger/formatters.ts
|
|
66
|
+
var SENSITIVE_KEYS = [
|
|
67
|
+
"password",
|
|
68
|
+
"passwd",
|
|
69
|
+
"pwd",
|
|
70
|
+
"secret",
|
|
71
|
+
"token",
|
|
72
|
+
"apikey",
|
|
73
|
+
"api_key",
|
|
74
|
+
"accesstoken",
|
|
75
|
+
"access_token",
|
|
76
|
+
"refreshtoken",
|
|
77
|
+
"refresh_token",
|
|
78
|
+
"authorization",
|
|
79
|
+
"auth",
|
|
80
|
+
"cookie",
|
|
81
|
+
"session",
|
|
82
|
+
"sessionid",
|
|
83
|
+
"session_id",
|
|
84
|
+
"privatekey",
|
|
85
|
+
"private_key",
|
|
86
|
+
"creditcard",
|
|
87
|
+
"credit_card",
|
|
88
|
+
"cardnumber",
|
|
89
|
+
"card_number",
|
|
90
|
+
"cvv",
|
|
91
|
+
"ssn",
|
|
92
|
+
"pin"
|
|
93
|
+
];
|
|
94
|
+
var MASKED_VALUE = "***MASKED***";
|
|
95
|
+
function isSensitiveKey(key) {
|
|
96
|
+
const lowerKey = key.toLowerCase();
|
|
97
|
+
return SENSITIVE_KEYS.some((sensitive) => lowerKey.includes(sensitive));
|
|
129
98
|
}
|
|
130
|
-
function
|
|
131
|
-
if (
|
|
132
|
-
return
|
|
133
|
-
}
|
|
134
|
-
if (ts.isSatisfiesExpression(initializer)) {
|
|
135
|
-
return extractObjectLiteral(initializer.expression);
|
|
99
|
+
function maskSensitiveData(data) {
|
|
100
|
+
if (data === null || data === void 0) {
|
|
101
|
+
return data;
|
|
136
102
|
}
|
|
137
|
-
if (
|
|
138
|
-
return
|
|
103
|
+
if (Array.isArray(data)) {
|
|
104
|
+
return data.map((item) => maskSensitiveData(item));
|
|
139
105
|
}
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let value;
|
|
150
|
-
if (ts.isStringLiteral(prop.initializer)) {
|
|
151
|
-
value = prop.initializer.text;
|
|
152
|
-
} else if (ts.isAsExpression(prop.initializer) && ts.isStringLiteral(prop.initializer.expression)) {
|
|
153
|
-
value = prop.initializer.expression.text;
|
|
154
|
-
}
|
|
155
|
-
if (value) result.method = value;
|
|
156
|
-
} else if (propName === "path") {
|
|
157
|
-
let value;
|
|
158
|
-
if (ts.isStringLiteral(prop.initializer)) {
|
|
159
|
-
value = prop.initializer.text;
|
|
160
|
-
} else if (ts.isAsExpression(prop.initializer) && ts.isStringLiteral(prop.initializer.expression)) {
|
|
161
|
-
value = prop.initializer.expression.text;
|
|
162
|
-
}
|
|
163
|
-
if (value) result.path = value;
|
|
164
|
-
} else if (propName === "query") {
|
|
165
|
-
result.hasQuery = true;
|
|
166
|
-
} else if (propName === "body") {
|
|
167
|
-
result.hasBody = true;
|
|
168
|
-
} else if (propName === "params") {
|
|
169
|
-
result.hasParams = true;
|
|
106
|
+
if (typeof data === "object") {
|
|
107
|
+
const masked = {};
|
|
108
|
+
for (const [key, value] of Object.entries(data)) {
|
|
109
|
+
if (isSensitiveKey(key)) {
|
|
110
|
+
masked[key] = MASKED_VALUE;
|
|
111
|
+
} else if (typeof value === "object" && value !== null) {
|
|
112
|
+
masked[key] = maskSensitiveData(value);
|
|
113
|
+
} else {
|
|
114
|
+
masked[key] = value;
|
|
170
115
|
}
|
|
171
116
|
}
|
|
117
|
+
return masked;
|
|
172
118
|
}
|
|
173
|
-
return
|
|
174
|
-
}
|
|
175
|
-
function isContractName(name) {
|
|
176
|
-
return name.indexOf("Contract") !== -1 || name.indexOf("contract") !== -1 || name.endsWith("Schema") || name.endsWith("schema");
|
|
119
|
+
return data;
|
|
177
120
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
121
|
+
var COLORS = {
|
|
122
|
+
reset: "\x1B[0m",
|
|
123
|
+
bright: "\x1B[1m",
|
|
124
|
+
dim: "\x1B[2m",
|
|
125
|
+
// 로그 레벨 컬러
|
|
126
|
+
debug: "\x1B[36m",
|
|
127
|
+
// cyan
|
|
128
|
+
info: "\x1B[32m",
|
|
129
|
+
// green
|
|
130
|
+
warn: "\x1B[33m",
|
|
131
|
+
// yellow
|
|
132
|
+
error: "\x1B[31m",
|
|
133
|
+
// red
|
|
134
|
+
fatal: "\x1B[35m",
|
|
135
|
+
// magenta
|
|
136
|
+
// 추가 컬러
|
|
137
|
+
gray: "\x1B[90m"
|
|
138
|
+
};
|
|
139
|
+
function formatTimestamp(date) {
|
|
140
|
+
return date.toISOString();
|
|
195
141
|
}
|
|
196
|
-
function
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
cleanPath = cleanPath.slice(0, -3);
|
|
206
|
-
} else if (cleanPath.endsWith(".mjs")) {
|
|
207
|
-
cleanPath = cleanPath.slice(0, -4);
|
|
208
|
-
}
|
|
209
|
-
return "@/" + cleanPath;
|
|
142
|
+
function formatTimestampHuman(date) {
|
|
143
|
+
const year = date.getFullYear();
|
|
144
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
145
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
146
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
147
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
148
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
149
|
+
const ms = String(date.getMilliseconds()).padStart(3, "0");
|
|
150
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
|
|
210
151
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const resource = extractResourceName(mapping.path);
|
|
218
|
-
if (!grouped[resource]) {
|
|
219
|
-
grouped[resource] = [];
|
|
220
|
-
}
|
|
221
|
-
grouped[resource].push(mapping);
|
|
152
|
+
function formatError(error) {
|
|
153
|
+
const lines = [];
|
|
154
|
+
lines.push(`${error.name}: ${error.message}`);
|
|
155
|
+
if (error.stack) {
|
|
156
|
+
const stackLines = error.stack.split("\n").slice(1);
|
|
157
|
+
lines.push(...stackLines);
|
|
222
158
|
}
|
|
223
|
-
return
|
|
159
|
+
return lines.join("\n");
|
|
224
160
|
}
|
|
225
|
-
function
|
|
226
|
-
const
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
161
|
+
function formatConsole(metadata, colorize = true) {
|
|
162
|
+
const parts = [];
|
|
163
|
+
const timestamp = formatTimestampHuman(metadata.timestamp);
|
|
164
|
+
if (colorize) {
|
|
165
|
+
parts.push(`${COLORS.gray}[${timestamp}]${COLORS.reset}`);
|
|
166
|
+
} else {
|
|
167
|
+
parts.push(`[${timestamp}]`);
|
|
233
168
|
}
|
|
234
|
-
if (
|
|
235
|
-
|
|
169
|
+
if (metadata.module) {
|
|
170
|
+
if (colorize) {
|
|
171
|
+
parts.push(`${COLORS.dim}[module=${metadata.module}]${COLORS.reset}`);
|
|
172
|
+
} else {
|
|
173
|
+
parts.push(`[module=${metadata.module}]`);
|
|
174
|
+
}
|
|
236
175
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
176
|
+
if (metadata.context && Object.keys(metadata.context).length > 0) {
|
|
177
|
+
Object.entries(metadata.context).forEach(([key, value]) => {
|
|
178
|
+
const valueStr = typeof value === "string" ? value : String(value);
|
|
179
|
+
if (colorize) {
|
|
180
|
+
parts.push(`${COLORS.dim}[${key}=${valueStr}]${COLORS.reset}`);
|
|
181
|
+
} else {
|
|
182
|
+
parts.push(`[${key}=${valueStr}]`);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
240
185
|
}
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
|
|
186
|
+
const levelStr = metadata.level.toUpperCase();
|
|
187
|
+
if (colorize) {
|
|
188
|
+
const color = COLORS[metadata.level];
|
|
189
|
+
parts.push(`${color}(${levelStr})${COLORS.reset}:`);
|
|
190
|
+
} else {
|
|
191
|
+
parts.push(`(${levelStr}):`);
|
|
245
192
|
}
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (parts.length === 1) {
|
|
251
|
-
return capitalize2 ? str.charAt(0).toUpperCase() + str.slice(1) : str;
|
|
193
|
+
if (colorize) {
|
|
194
|
+
parts.push(`${COLORS.bright}${metadata.message}${COLORS.reset}`);
|
|
195
|
+
} else {
|
|
196
|
+
parts.push(metadata.message);
|
|
252
197
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (i === 0 && !capitalize2) {
|
|
257
|
-
result.push(part);
|
|
258
|
-
} else {
|
|
259
|
-
result.push(part.charAt(0).toUpperCase() + part.slice(1));
|
|
260
|
-
}
|
|
198
|
+
let output = parts.join(" ");
|
|
199
|
+
if (metadata.error) {
|
|
200
|
+
output += "\n" + formatError(metadata.error);
|
|
261
201
|
}
|
|
262
|
-
return
|
|
202
|
+
return output;
|
|
263
203
|
}
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return {
|
|
270
|
-
routesScanned: mappings.length,
|
|
271
|
-
contractsFound: mappings.length,
|
|
272
|
-
contractFiles: countUniqueContractFiles(mappings),
|
|
273
|
-
resourcesGenerated: resourceNames.length,
|
|
274
|
-
methodsGenerated: mappings.length,
|
|
275
|
-
duration: Date.now() - startTime
|
|
204
|
+
function formatJSON(metadata) {
|
|
205
|
+
const obj = {
|
|
206
|
+
timestamp: formatTimestamp(metadata.timestamp),
|
|
207
|
+
level: metadata.level,
|
|
208
|
+
message: metadata.message
|
|
276
209
|
};
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return `/**
|
|
280
|
-
* Auto-generated API Client
|
|
281
|
-
*
|
|
282
|
-
* Generated by @spfn/core codegen
|
|
283
|
-
* DO NOT EDIT MANUALLY
|
|
284
|
-
*
|
|
285
|
-
* @generated ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
286
|
-
*/
|
|
287
|
-
|
|
288
|
-
`;
|
|
289
|
-
}
|
|
290
|
-
function groupContractsByImportPath(mappings) {
|
|
291
|
-
const groups = {};
|
|
292
|
-
for (let i = 0; i < mappings.length; i++) {
|
|
293
|
-
const mapping = mappings[i];
|
|
294
|
-
const path = mapping.contractImportPath;
|
|
295
|
-
if (!groups[path]) {
|
|
296
|
-
groups[path] = /* @__PURE__ */ new Set();
|
|
297
|
-
}
|
|
298
|
-
groups[path].add(mapping.contractName);
|
|
299
|
-
}
|
|
300
|
-
const result = {};
|
|
301
|
-
const keys = Object.keys(groups);
|
|
302
|
-
for (let i = 0; i < keys.length; i++) {
|
|
303
|
-
const key = keys[i];
|
|
304
|
-
result[key] = Array.from(groups[key]);
|
|
210
|
+
if (metadata.module) {
|
|
211
|
+
obj.module = metadata.module;
|
|
305
212
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
function generateTypeName(mapping) {
|
|
309
|
-
let name = mapping.contractName;
|
|
310
|
-
if (name.endsWith("Contract")) {
|
|
311
|
-
name = name.slice(0, -8);
|
|
213
|
+
if (metadata.context) {
|
|
214
|
+
obj.context = metadata.context;
|
|
312
215
|
}
|
|
313
|
-
if (
|
|
314
|
-
|
|
216
|
+
if (metadata.error) {
|
|
217
|
+
obj.error = {
|
|
218
|
+
name: metadata.error.name,
|
|
219
|
+
message: metadata.error.message,
|
|
220
|
+
stack: metadata.error.stack
|
|
221
|
+
};
|
|
315
222
|
}
|
|
316
|
-
return
|
|
223
|
+
return JSON.stringify(obj);
|
|
317
224
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
`;
|
|
327
|
-
code += ` * ${mapping.method} ${mapping.path}
|
|
328
|
-
`;
|
|
329
|
-
code += ` */
|
|
330
|
-
`;
|
|
331
|
-
}
|
|
332
|
-
code += ` ${methodName}: (`;
|
|
333
|
-
const params = [];
|
|
334
|
-
const typeName = generateTypeName(mapping);
|
|
335
|
-
if (hasParams) {
|
|
336
|
-
params.push(`params: ${typeName}Params`);
|
|
225
|
+
|
|
226
|
+
// src/logger/logger.ts
|
|
227
|
+
var Logger = class _Logger {
|
|
228
|
+
config;
|
|
229
|
+
module;
|
|
230
|
+
constructor(config) {
|
|
231
|
+
this.config = config;
|
|
232
|
+
this.module = config.module;
|
|
337
233
|
}
|
|
338
|
-
|
|
339
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Get current log level
|
|
236
|
+
*/
|
|
237
|
+
get level() {
|
|
238
|
+
return this.config.level;
|
|
340
239
|
}
|
|
341
|
-
|
|
342
|
-
|
|
240
|
+
/**
|
|
241
|
+
* Create child logger (per module)
|
|
242
|
+
*/
|
|
243
|
+
child(module) {
|
|
244
|
+
return new _Logger({
|
|
245
|
+
...this.config,
|
|
246
|
+
module
|
|
247
|
+
});
|
|
343
248
|
}
|
|
344
|
-
|
|
345
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Debug log
|
|
251
|
+
*/
|
|
252
|
+
debug(message, context) {
|
|
253
|
+
this.log("debug", message, void 0, context);
|
|
346
254
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
code += `),
|
|
353
|
-
`;
|
|
354
|
-
return code;
|
|
355
|
-
}
|
|
356
|
-
function generateMethodName(mapping) {
|
|
357
|
-
const method = mapping.method.toLowerCase();
|
|
358
|
-
if (mapping.path === "/" || mapping.path.match(/^\/[\w-]+$/)) {
|
|
359
|
-
if (method === "get") {
|
|
360
|
-
return "list";
|
|
361
|
-
}
|
|
362
|
-
if (method === "post") {
|
|
363
|
-
return "create";
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
if (mapping.path.includes(":")) {
|
|
367
|
-
if (method === "get") {
|
|
368
|
-
return "getById";
|
|
369
|
-
}
|
|
370
|
-
if (method === "put" || method === "patch") {
|
|
371
|
-
return "update";
|
|
372
|
-
}
|
|
373
|
-
if (method === "delete") {
|
|
374
|
-
return "delete";
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
return method;
|
|
378
|
-
}
|
|
379
|
-
function countUniqueContractFiles(mappings) {
|
|
380
|
-
const files = /* @__PURE__ */ new Set();
|
|
381
|
-
for (let i = 0; i < mappings.length; i++) {
|
|
382
|
-
if (mappings[i].contractFile) {
|
|
383
|
-
files.add(mappings[i].contractFile);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return files.size;
|
|
387
|
-
}
|
|
388
|
-
async function generateSplitClient(_mappings, grouped, options) {
|
|
389
|
-
const outputPath = options.outputPath;
|
|
390
|
-
const outputDir = outputPath.endsWith(".ts") || outputPath.endsWith(".js") ? outputPath.replace(/\.[jt]s$/, "") : outputPath;
|
|
391
|
-
await mkdir(outputDir, { recursive: true });
|
|
392
|
-
const resourceNames = Object.keys(grouped);
|
|
393
|
-
for (let i = 0; i < resourceNames.length; i++) {
|
|
394
|
-
const resourceName = resourceNames[i];
|
|
395
|
-
const routes = grouped[resourceName];
|
|
396
|
-
const code = generateResourceFile(resourceName, routes, options);
|
|
397
|
-
const filePath = `${outputDir}/${resourceName}.ts`;
|
|
398
|
-
await writeFile(filePath, code, "utf-8");
|
|
399
|
-
}
|
|
400
|
-
const indexCode = generateIndexFile(resourceNames, options);
|
|
401
|
-
const indexPath = `${outputDir}/index.ts`;
|
|
402
|
-
await writeFile(indexPath, indexCode, "utf-8");
|
|
403
|
-
}
|
|
404
|
-
function generateResourceFile(resourceName, routes, options) {
|
|
405
|
-
let code = "";
|
|
406
|
-
code += generateHeader();
|
|
407
|
-
code += `import { client } from '@spfn/core/client';
|
|
408
|
-
`;
|
|
409
|
-
if (options.includeTypes !== false) {
|
|
410
|
-
code += `import type { InferContract } from '@spfn/core';
|
|
411
|
-
`;
|
|
412
|
-
}
|
|
413
|
-
code += `
|
|
414
|
-
`;
|
|
415
|
-
const importGroups = groupContractsByImportPath(routes);
|
|
416
|
-
const importPaths = Object.keys(importGroups);
|
|
417
|
-
for (let i = 0; i < importPaths.length; i++) {
|
|
418
|
-
const importPath = importPaths[i];
|
|
419
|
-
const contracts = importGroups[importPath];
|
|
420
|
-
code += `import { ${contracts.join(", ")} } from '${importPath}';
|
|
421
|
-
`;
|
|
422
|
-
}
|
|
423
|
-
code += `
|
|
424
|
-
`;
|
|
425
|
-
if (options.includeTypes !== false) {
|
|
426
|
-
code += `// ============================================
|
|
427
|
-
`;
|
|
428
|
-
code += `// Types
|
|
429
|
-
`;
|
|
430
|
-
code += `// ============================================
|
|
431
|
-
|
|
432
|
-
`;
|
|
433
|
-
for (let i = 0; i < routes.length; i++) {
|
|
434
|
-
const route = routes[i];
|
|
435
|
-
const typeName = generateTypeName(route);
|
|
436
|
-
const contractType = `typeof ${route.contractName}`;
|
|
437
|
-
code += `export type ${typeName}Response = InferContract<${contractType}>['response'];
|
|
438
|
-
`;
|
|
439
|
-
if (route.hasQuery) {
|
|
440
|
-
code += `export type ${typeName}Query = InferContract<${contractType}>['query'];
|
|
441
|
-
`;
|
|
442
|
-
}
|
|
443
|
-
if (route.hasParams || route.path.includes(":")) {
|
|
444
|
-
code += `export type ${typeName}Params = InferContract<${contractType}>['params'];
|
|
445
|
-
`;
|
|
446
|
-
}
|
|
447
|
-
if (route.hasBody) {
|
|
448
|
-
code += `export type ${typeName}Body = InferContract<${contractType}>['body'];
|
|
449
|
-
`;
|
|
450
|
-
}
|
|
451
|
-
code += `
|
|
452
|
-
`;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
code += `/**
|
|
456
|
-
`;
|
|
457
|
-
code += ` * ${resourceName} API
|
|
458
|
-
`;
|
|
459
|
-
code += ` */
|
|
460
|
-
`;
|
|
461
|
-
code += `export const ${resourceName} = {
|
|
462
|
-
`;
|
|
463
|
-
for (let i = 0; i < routes.length; i++) {
|
|
464
|
-
const route = routes[i];
|
|
465
|
-
code += generateMethodCode(route, options);
|
|
466
|
-
}
|
|
467
|
-
code += `} as const;
|
|
468
|
-
`;
|
|
469
|
-
return code;
|
|
470
|
-
}
|
|
471
|
-
function toCamelCase2(str) {
|
|
472
|
-
if (str.length === 0) {
|
|
473
|
-
return str;
|
|
474
|
-
}
|
|
475
|
-
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
476
|
-
}
|
|
477
|
-
function generateIndexFile(resourceNames, options) {
|
|
478
|
-
let code = "";
|
|
479
|
-
const apiName = options.apiName || "api";
|
|
480
|
-
code += generateHeader();
|
|
481
|
-
code += `export { client } from '@spfn/core/client';
|
|
482
|
-
|
|
483
|
-
`;
|
|
484
|
-
for (let i = 0; i < resourceNames.length; i++) {
|
|
485
|
-
const resourceName = resourceNames[i];
|
|
486
|
-
code += `export * from './${resourceName}.js';
|
|
487
|
-
`;
|
|
488
|
-
}
|
|
489
|
-
code += `
|
|
490
|
-
`;
|
|
491
|
-
for (let i = 0; i < resourceNames.length; i++) {
|
|
492
|
-
const resourceName = resourceNames[i];
|
|
493
|
-
code += `import { ${resourceName} } from './${resourceName}.js';
|
|
494
|
-
`;
|
|
495
|
-
}
|
|
496
|
-
code += `
|
|
497
|
-
`;
|
|
498
|
-
const resourceKeys = resourceNames.map((name) => toCamelCase2(name));
|
|
499
|
-
code += `/**
|
|
500
|
-
`;
|
|
501
|
-
code += ` * Type-safe API client
|
|
502
|
-
`;
|
|
503
|
-
code += ` */
|
|
504
|
-
`;
|
|
505
|
-
code += `export const ${apiName} = {
|
|
506
|
-
`;
|
|
507
|
-
for (let i = 0; i < resourceNames.length; i++) {
|
|
508
|
-
const resourceName = resourceNames[i];
|
|
509
|
-
const resourceKey = resourceKeys[i];
|
|
510
|
-
code += ` ${resourceKey}: ${resourceName}`;
|
|
511
|
-
if (i < resourceNames.length - 1) {
|
|
512
|
-
code += `,`;
|
|
513
|
-
}
|
|
514
|
-
code += `
|
|
515
|
-
`;
|
|
516
|
-
}
|
|
517
|
-
code += `} as const;
|
|
518
|
-
`;
|
|
519
|
-
return code;
|
|
520
|
-
}
|
|
521
|
-
var PinoAdapter = class _PinoAdapter {
|
|
522
|
-
logger;
|
|
523
|
-
constructor(config) {
|
|
524
|
-
this.logger = pino({
|
|
525
|
-
level: config.level,
|
|
526
|
-
// 기본 필드
|
|
527
|
-
base: config.module ? { module: config.module } : void 0
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
child(module) {
|
|
531
|
-
const childLogger = new _PinoAdapter({ level: this.logger.level, module });
|
|
532
|
-
childLogger.logger = this.logger.child({ module });
|
|
533
|
-
return childLogger;
|
|
534
|
-
}
|
|
535
|
-
debug(message, context) {
|
|
536
|
-
this.logger.debug(context || {}, message);
|
|
537
|
-
}
|
|
538
|
-
info(message, context) {
|
|
539
|
-
this.logger.info(context || {}, message);
|
|
255
|
+
/**
|
|
256
|
+
* Info log
|
|
257
|
+
*/
|
|
258
|
+
info(message, context) {
|
|
259
|
+
this.log("info", message, void 0, context);
|
|
540
260
|
}
|
|
541
261
|
warn(message, errorOrContext, context) {
|
|
542
262
|
if (errorOrContext instanceof Error) {
|
|
543
|
-
this.
|
|
263
|
+
this.log("warn", message, errorOrContext, context);
|
|
544
264
|
} else {
|
|
545
|
-
this.
|
|
265
|
+
this.log("warn", message, void 0, errorOrContext);
|
|
546
266
|
}
|
|
547
267
|
}
|
|
548
268
|
error(message, errorOrContext, context) {
|
|
549
269
|
if (errorOrContext instanceof Error) {
|
|
550
|
-
this.
|
|
270
|
+
this.log("error", message, errorOrContext, context);
|
|
551
271
|
} else {
|
|
552
|
-
this.
|
|
272
|
+
this.log("error", message, void 0, errorOrContext);
|
|
553
273
|
}
|
|
554
274
|
}
|
|
555
275
|
fatal(message, errorOrContext, context) {
|
|
556
276
|
if (errorOrContext instanceof Error) {
|
|
557
|
-
this.
|
|
277
|
+
this.log("fatal", message, errorOrContext, context);
|
|
558
278
|
} else {
|
|
559
|
-
this.
|
|
279
|
+
this.log("fatal", message, void 0, errorOrContext);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Log processing (internal)
|
|
284
|
+
*/
|
|
285
|
+
log(level, message, error, context) {
|
|
286
|
+
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.config.level]) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const metadata = {
|
|
290
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
291
|
+
level,
|
|
292
|
+
message,
|
|
293
|
+
module: this.module,
|
|
294
|
+
error,
|
|
295
|
+
// Mask sensitive information in context to prevent credential leaks
|
|
296
|
+
context: context ? maskSensitiveData(context) : void 0
|
|
297
|
+
};
|
|
298
|
+
this.processTransports(metadata);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Process Transports
|
|
302
|
+
*/
|
|
303
|
+
processTransports(metadata) {
|
|
304
|
+
const promises = this.config.transports.filter((transport) => transport.enabled).map((transport) => this.safeTransportLog(transport, metadata));
|
|
305
|
+
Promise.all(promises).catch((error) => {
|
|
306
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
307
|
+
process.stderr.write(`[Logger] Transport error: ${errorMessage}
|
|
308
|
+
`);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Transport log (error-safe)
|
|
313
|
+
*/
|
|
314
|
+
async safeTransportLog(transport, metadata) {
|
|
315
|
+
try {
|
|
316
|
+
await transport.log(metadata);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
319
|
+
process.stderr.write(`[Logger] Transport "${transport.name}" failed: ${errorMessage}
|
|
320
|
+
`);
|
|
560
321
|
}
|
|
561
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Close all Transports
|
|
325
|
+
*/
|
|
562
326
|
async close() {
|
|
327
|
+
const closePromises = this.config.transports.filter((transport) => transport.close).map((transport) => transport.close());
|
|
328
|
+
await Promise.all(closePromises);
|
|
563
329
|
}
|
|
564
330
|
};
|
|
565
331
|
|
|
566
|
-
// src/logger/
|
|
567
|
-
var
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
var SENSITIVE_KEYS = [
|
|
577
|
-
"password",
|
|
578
|
-
"passwd",
|
|
579
|
-
"pwd",
|
|
580
|
-
"secret",
|
|
581
|
-
"token",
|
|
582
|
-
"apikey",
|
|
583
|
-
"api_key",
|
|
584
|
-
"accesstoken",
|
|
585
|
-
"access_token",
|
|
586
|
-
"refreshtoken",
|
|
587
|
-
"refresh_token",
|
|
588
|
-
"authorization",
|
|
589
|
-
"auth",
|
|
590
|
-
"cookie",
|
|
591
|
-
"session",
|
|
592
|
-
"sessionid",
|
|
593
|
-
"session_id",
|
|
594
|
-
"privatekey",
|
|
595
|
-
"private_key",
|
|
596
|
-
"creditcard",
|
|
597
|
-
"credit_card",
|
|
598
|
-
"cardnumber",
|
|
599
|
-
"card_number",
|
|
600
|
-
"cvv",
|
|
601
|
-
"ssn",
|
|
602
|
-
"pin"
|
|
603
|
-
];
|
|
604
|
-
var MASKED_VALUE = "***MASKED***";
|
|
605
|
-
function isSensitiveKey(key) {
|
|
606
|
-
const lowerKey = key.toLowerCase();
|
|
607
|
-
return SENSITIVE_KEYS.some((sensitive) => lowerKey.includes(sensitive));
|
|
608
|
-
}
|
|
609
|
-
function maskSensitiveData(data) {
|
|
610
|
-
if (data === null || data === void 0) {
|
|
611
|
-
return data;
|
|
612
|
-
}
|
|
613
|
-
if (Array.isArray(data)) {
|
|
614
|
-
return data.map((item) => maskSensitiveData(item));
|
|
332
|
+
// src/logger/transports/console.ts
|
|
333
|
+
var ConsoleTransport = class {
|
|
334
|
+
name = "console";
|
|
335
|
+
level;
|
|
336
|
+
enabled;
|
|
337
|
+
colorize;
|
|
338
|
+
constructor(config) {
|
|
339
|
+
this.level = config.level;
|
|
340
|
+
this.enabled = config.enabled;
|
|
341
|
+
this.colorize = config.colorize ?? true;
|
|
615
342
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
if (isSensitiveKey(key)) {
|
|
620
|
-
masked[key] = MASKED_VALUE;
|
|
621
|
-
} else if (typeof value === "object" && value !== null) {
|
|
622
|
-
masked[key] = maskSensitiveData(value);
|
|
623
|
-
} else {
|
|
624
|
-
masked[key] = value;
|
|
625
|
-
}
|
|
343
|
+
async log(metadata) {
|
|
344
|
+
if (!this.enabled) {
|
|
345
|
+
return;
|
|
626
346
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
bright: "\x1B[1m",
|
|
634
|
-
dim: "\x1B[2m",
|
|
635
|
-
// 로그 레벨 컬러
|
|
636
|
-
debug: "\x1B[36m",
|
|
637
|
-
// cyan
|
|
638
|
-
info: "\x1B[32m",
|
|
639
|
-
// green
|
|
640
|
-
warn: "\x1B[33m",
|
|
641
|
-
// yellow
|
|
642
|
-
error: "\x1B[31m",
|
|
643
|
-
// red
|
|
644
|
-
fatal: "\x1B[35m",
|
|
645
|
-
// magenta
|
|
646
|
-
// 추가 컬러
|
|
647
|
-
gray: "\x1B[90m"
|
|
648
|
-
};
|
|
649
|
-
function formatTimestamp(date) {
|
|
650
|
-
return date.toISOString();
|
|
651
|
-
}
|
|
652
|
-
function formatTimestampHuman(date) {
|
|
653
|
-
const year = date.getFullYear();
|
|
654
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
655
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
656
|
-
const hours = String(date.getHours()).padStart(2, "0");
|
|
657
|
-
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
658
|
-
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
659
|
-
const ms = String(date.getMilliseconds()).padStart(3, "0");
|
|
660
|
-
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
|
|
661
|
-
}
|
|
662
|
-
function formatError(error) {
|
|
663
|
-
const lines = [];
|
|
664
|
-
lines.push(`${error.name}: ${error.message}`);
|
|
665
|
-
if (error.stack) {
|
|
666
|
-
const stackLines = error.stack.split("\n").slice(1);
|
|
667
|
-
lines.push(...stackLines);
|
|
668
|
-
}
|
|
669
|
-
return lines.join("\n");
|
|
670
|
-
}
|
|
671
|
-
function formatConsole(metadata, colorize = true) {
|
|
672
|
-
const parts = [];
|
|
673
|
-
const timestamp = formatTimestampHuman(metadata.timestamp);
|
|
674
|
-
if (colorize) {
|
|
675
|
-
parts.push(`${COLORS.gray}[${timestamp}]${COLORS.reset}`);
|
|
676
|
-
} else {
|
|
677
|
-
parts.push(`[${timestamp}]`);
|
|
678
|
-
}
|
|
679
|
-
if (metadata.module) {
|
|
680
|
-
if (colorize) {
|
|
681
|
-
parts.push(`${COLORS.dim}[module=${metadata.module}]${COLORS.reset}`);
|
|
347
|
+
if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level]) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const message = formatConsole(metadata, this.colorize);
|
|
351
|
+
if (metadata.level === "warn" || metadata.level === "error" || metadata.level === "fatal") {
|
|
352
|
+
console.error(message);
|
|
682
353
|
} else {
|
|
683
|
-
|
|
354
|
+
console.log(message);
|
|
684
355
|
}
|
|
685
356
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const levelStr = metadata.level.toUpperCase();
|
|
697
|
-
if (colorize) {
|
|
698
|
-
const color = COLORS[metadata.level];
|
|
699
|
-
parts.push(`${color}(${levelStr})${COLORS.reset}:`);
|
|
700
|
-
} else {
|
|
701
|
-
parts.push(`(${levelStr}):`);
|
|
702
|
-
}
|
|
703
|
-
if (colorize) {
|
|
704
|
-
parts.push(`${COLORS.bright}${metadata.message}${COLORS.reset}`);
|
|
705
|
-
} else {
|
|
706
|
-
parts.push(metadata.message);
|
|
707
|
-
}
|
|
708
|
-
let output = parts.join(" ");
|
|
709
|
-
if (metadata.error) {
|
|
710
|
-
output += "\n" + formatError(metadata.error);
|
|
711
|
-
}
|
|
712
|
-
return output;
|
|
713
|
-
}
|
|
714
|
-
function formatJSON(metadata) {
|
|
715
|
-
const obj = {
|
|
716
|
-
timestamp: formatTimestamp(metadata.timestamp),
|
|
717
|
-
level: metadata.level,
|
|
718
|
-
message: metadata.message
|
|
719
|
-
};
|
|
720
|
-
if (metadata.module) {
|
|
721
|
-
obj.module = metadata.module;
|
|
722
|
-
}
|
|
723
|
-
if (metadata.context) {
|
|
724
|
-
obj.context = metadata.context;
|
|
725
|
-
}
|
|
726
|
-
if (metadata.error) {
|
|
727
|
-
obj.error = {
|
|
728
|
-
name: metadata.error.name,
|
|
729
|
-
message: metadata.error.message,
|
|
730
|
-
stack: metadata.error.stack
|
|
731
|
-
};
|
|
732
|
-
}
|
|
733
|
-
return JSON.stringify(obj);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
// src/logger/logger.ts
|
|
737
|
-
var Logger = class _Logger {
|
|
738
|
-
config;
|
|
739
|
-
module;
|
|
357
|
+
};
|
|
358
|
+
var FileTransport = class {
|
|
359
|
+
name = "file";
|
|
360
|
+
level;
|
|
361
|
+
enabled;
|
|
362
|
+
logDir;
|
|
363
|
+
maxFileSize;
|
|
364
|
+
maxFiles;
|
|
365
|
+
currentStream = null;
|
|
366
|
+
currentFilename = null;
|
|
740
367
|
constructor(config) {
|
|
741
|
-
this.
|
|
742
|
-
this.
|
|
368
|
+
this.level = config.level;
|
|
369
|
+
this.enabled = config.enabled;
|
|
370
|
+
this.logDir = config.logDir;
|
|
371
|
+
this.maxFileSize = config.maxFileSize ?? 10 * 1024 * 1024;
|
|
372
|
+
this.maxFiles = config.maxFiles ?? 10;
|
|
373
|
+
if (!existsSync(this.logDir)) {
|
|
374
|
+
mkdirSync(this.logDir, { recursive: true });
|
|
375
|
+
}
|
|
743
376
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
377
|
+
async log(metadata) {
|
|
378
|
+
if (!this.enabled) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level]) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const message = formatJSON(metadata);
|
|
385
|
+
const filename = this.getLogFilename(metadata.timestamp);
|
|
386
|
+
if (this.currentFilename !== filename) {
|
|
387
|
+
await this.rotateStream(filename);
|
|
388
|
+
await this.cleanOldFiles();
|
|
389
|
+
} else if (this.currentFilename) {
|
|
390
|
+
await this.checkAndRotateBySize();
|
|
391
|
+
}
|
|
392
|
+
if (this.currentStream) {
|
|
393
|
+
return new Promise((resolve, reject) => {
|
|
394
|
+
this.currentStream.write(message + "\n", "utf-8", (error) => {
|
|
395
|
+
if (error) {
|
|
396
|
+
process.stderr.write(`[FileTransport] Failed to write log: ${error.message}
|
|
397
|
+
`);
|
|
398
|
+
reject(error);
|
|
399
|
+
} else {
|
|
400
|
+
resolve();
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
}
|
|
749
405
|
}
|
|
750
406
|
/**
|
|
751
|
-
*
|
|
407
|
+
* 스트림 교체 (날짜 변경 시)
|
|
752
408
|
*/
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
409
|
+
async rotateStream(filename) {
|
|
410
|
+
if (this.currentStream) {
|
|
411
|
+
await this.closeStream();
|
|
412
|
+
}
|
|
413
|
+
const filepath = join(this.logDir, filename);
|
|
414
|
+
this.currentStream = createWriteStream(filepath, {
|
|
415
|
+
flags: "a",
|
|
416
|
+
// append mode
|
|
417
|
+
encoding: "utf-8"
|
|
418
|
+
});
|
|
419
|
+
this.currentFilename = filename;
|
|
420
|
+
this.currentStream.on("error", (error) => {
|
|
421
|
+
process.stderr.write(`[FileTransport] Stream error: ${error.message}
|
|
422
|
+
`);
|
|
423
|
+
this.currentStream = null;
|
|
424
|
+
this.currentFilename = null;
|
|
757
425
|
});
|
|
758
426
|
}
|
|
759
427
|
/**
|
|
760
|
-
*
|
|
761
|
-
*/
|
|
762
|
-
debug(message, context) {
|
|
763
|
-
this.log("debug", message, void 0, context);
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Info log
|
|
767
|
-
*/
|
|
768
|
-
info(message, context) {
|
|
769
|
-
this.log("info", message, void 0, context);
|
|
770
|
-
}
|
|
771
|
-
warn(message, errorOrContext, context) {
|
|
772
|
-
if (errorOrContext instanceof Error) {
|
|
773
|
-
this.log("warn", message, errorOrContext, context);
|
|
774
|
-
} else {
|
|
775
|
-
this.log("warn", message, void 0, errorOrContext);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
error(message, errorOrContext, context) {
|
|
779
|
-
if (errorOrContext instanceof Error) {
|
|
780
|
-
this.log("error", message, errorOrContext, context);
|
|
781
|
-
} else {
|
|
782
|
-
this.log("error", message, void 0, errorOrContext);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
fatal(message, errorOrContext, context) {
|
|
786
|
-
if (errorOrContext instanceof Error) {
|
|
787
|
-
this.log("fatal", message, errorOrContext, context);
|
|
788
|
-
} else {
|
|
789
|
-
this.log("fatal", message, void 0, errorOrContext);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
/**
|
|
793
|
-
* Log processing (internal)
|
|
794
|
-
*/
|
|
795
|
-
log(level, message, error, context) {
|
|
796
|
-
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.config.level]) {
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
const metadata = {
|
|
800
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
801
|
-
level,
|
|
802
|
-
message,
|
|
803
|
-
module: this.module,
|
|
804
|
-
error,
|
|
805
|
-
// Mask sensitive information in context to prevent credential leaks
|
|
806
|
-
context: context ? maskSensitiveData(context) : void 0
|
|
807
|
-
};
|
|
808
|
-
this.processTransports(metadata);
|
|
809
|
-
}
|
|
810
|
-
/**
|
|
811
|
-
* Process Transports
|
|
812
|
-
*/
|
|
813
|
-
processTransports(metadata) {
|
|
814
|
-
const promises = this.config.transports.filter((transport) => transport.enabled).map((transport) => this.safeTransportLog(transport, metadata));
|
|
815
|
-
Promise.all(promises).catch((error) => {
|
|
816
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
817
|
-
process.stderr.write(`[Logger] Transport error: ${errorMessage}
|
|
818
|
-
`);
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* Transport log (error-safe)
|
|
823
|
-
*/
|
|
824
|
-
async safeTransportLog(transport, metadata) {
|
|
825
|
-
try {
|
|
826
|
-
await transport.log(metadata);
|
|
827
|
-
} catch (error) {
|
|
828
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
829
|
-
process.stderr.write(`[Logger] Transport "${transport.name}" failed: ${errorMessage}
|
|
830
|
-
`);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Close all Transports
|
|
835
|
-
*/
|
|
836
|
-
async close() {
|
|
837
|
-
const closePromises = this.config.transports.filter((transport) => transport.close).map((transport) => transport.close());
|
|
838
|
-
await Promise.all(closePromises);
|
|
839
|
-
}
|
|
840
|
-
};
|
|
841
|
-
|
|
842
|
-
// src/logger/transports/console.ts
|
|
843
|
-
var ConsoleTransport = class {
|
|
844
|
-
name = "console";
|
|
845
|
-
level;
|
|
846
|
-
enabled;
|
|
847
|
-
colorize;
|
|
848
|
-
constructor(config) {
|
|
849
|
-
this.level = config.level;
|
|
850
|
-
this.enabled = config.enabled;
|
|
851
|
-
this.colorize = config.colorize ?? true;
|
|
852
|
-
}
|
|
853
|
-
async log(metadata) {
|
|
854
|
-
if (!this.enabled) {
|
|
855
|
-
return;
|
|
856
|
-
}
|
|
857
|
-
if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level]) {
|
|
858
|
-
return;
|
|
859
|
-
}
|
|
860
|
-
const message = formatConsole(metadata, this.colorize);
|
|
861
|
-
if (metadata.level === "warn" || metadata.level === "error" || metadata.level === "fatal") {
|
|
862
|
-
console.error(message);
|
|
863
|
-
} else {
|
|
864
|
-
console.log(message);
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
|
-
var FileTransport = class {
|
|
869
|
-
name = "file";
|
|
870
|
-
level;
|
|
871
|
-
enabled;
|
|
872
|
-
logDir;
|
|
873
|
-
maxFileSize;
|
|
874
|
-
maxFiles;
|
|
875
|
-
currentStream = null;
|
|
876
|
-
currentFilename = null;
|
|
877
|
-
constructor(config) {
|
|
878
|
-
this.level = config.level;
|
|
879
|
-
this.enabled = config.enabled;
|
|
880
|
-
this.logDir = config.logDir;
|
|
881
|
-
this.maxFileSize = config.maxFileSize ?? 10 * 1024 * 1024;
|
|
882
|
-
this.maxFiles = config.maxFiles ?? 10;
|
|
883
|
-
if (!existsSync(this.logDir)) {
|
|
884
|
-
mkdirSync(this.logDir, { recursive: true });
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
async log(metadata) {
|
|
888
|
-
if (!this.enabled) {
|
|
889
|
-
return;
|
|
890
|
-
}
|
|
891
|
-
if (LOG_LEVEL_PRIORITY[metadata.level] < LOG_LEVEL_PRIORITY[this.level]) {
|
|
892
|
-
return;
|
|
893
|
-
}
|
|
894
|
-
const message = formatJSON(metadata);
|
|
895
|
-
const filename = this.getLogFilename(metadata.timestamp);
|
|
896
|
-
if (this.currentFilename !== filename) {
|
|
897
|
-
await this.rotateStream(filename);
|
|
898
|
-
await this.cleanOldFiles();
|
|
899
|
-
} else if (this.currentFilename) {
|
|
900
|
-
await this.checkAndRotateBySize();
|
|
901
|
-
}
|
|
902
|
-
if (this.currentStream) {
|
|
903
|
-
return new Promise((resolve, reject) => {
|
|
904
|
-
this.currentStream.write(message + "\n", "utf-8", (error) => {
|
|
905
|
-
if (error) {
|
|
906
|
-
process.stderr.write(`[FileTransport] Failed to write log: ${error.message}
|
|
907
|
-
`);
|
|
908
|
-
reject(error);
|
|
909
|
-
} else {
|
|
910
|
-
resolve();
|
|
911
|
-
}
|
|
912
|
-
});
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
/**
|
|
917
|
-
* 스트림 교체 (날짜 변경 시)
|
|
918
|
-
*/
|
|
919
|
-
async rotateStream(filename) {
|
|
920
|
-
if (this.currentStream) {
|
|
921
|
-
await this.closeStream();
|
|
922
|
-
}
|
|
923
|
-
const filepath = join(this.logDir, filename);
|
|
924
|
-
this.currentStream = createWriteStream(filepath, {
|
|
925
|
-
flags: "a",
|
|
926
|
-
// append mode
|
|
927
|
-
encoding: "utf-8"
|
|
928
|
-
});
|
|
929
|
-
this.currentFilename = filename;
|
|
930
|
-
this.currentStream.on("error", (error) => {
|
|
931
|
-
process.stderr.write(`[FileTransport] Stream error: ${error.message}
|
|
932
|
-
`);
|
|
933
|
-
this.currentStream = null;
|
|
934
|
-
this.currentFilename = null;
|
|
935
|
-
});
|
|
936
|
-
}
|
|
937
|
-
/**
|
|
938
|
-
* 현재 스트림 닫기
|
|
428
|
+
* 현재 스트림 닫기
|
|
939
429
|
*/
|
|
940
430
|
async closeStream() {
|
|
941
431
|
if (!this.currentStream) {
|
|
@@ -1284,91 +774,7 @@ function initializeLogger() {
|
|
|
1284
774
|
}
|
|
1285
775
|
var logger = initializeLogger();
|
|
1286
776
|
|
|
1287
|
-
// src/codegen/
|
|
1288
|
-
var codegenLogger = logger.child("codegen");
|
|
1289
|
-
async function generateOnce(options) {
|
|
1290
|
-
const cwd = process.cwd();
|
|
1291
|
-
const routesDir = options.routesDir ?? join(cwd, "src", "server", "routes");
|
|
1292
|
-
const outputPath = options.outputPath ?? join(cwd, "src", "lib", "api.ts");
|
|
1293
|
-
try {
|
|
1294
|
-
const contracts = await scanContracts(routesDir);
|
|
1295
|
-
if (contracts.length === 0) {
|
|
1296
|
-
if (options.debug) {
|
|
1297
|
-
codegenLogger.warn("No contracts found");
|
|
1298
|
-
}
|
|
1299
|
-
return null;
|
|
1300
|
-
}
|
|
1301
|
-
const stats = await generateClient(contracts, {
|
|
1302
|
-
outputPath,
|
|
1303
|
-
includeTypes: true,
|
|
1304
|
-
includeJsDoc: true
|
|
1305
|
-
});
|
|
1306
|
-
if (options.debug) {
|
|
1307
|
-
codegenLogger.info("Client generated", {
|
|
1308
|
-
endpoints: stats.methodsGenerated,
|
|
1309
|
-
resources: stats.resourcesGenerated,
|
|
1310
|
-
duration: stats.duration
|
|
1311
|
-
});
|
|
1312
|
-
}
|
|
1313
|
-
return stats;
|
|
1314
|
-
} catch (error) {
|
|
1315
|
-
codegenLogger.error(
|
|
1316
|
-
"Generation failed",
|
|
1317
|
-
error instanceof Error ? error : new Error(String(error))
|
|
1318
|
-
);
|
|
1319
|
-
return null;
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
async function watchAndGenerate(options = {}) {
|
|
1323
|
-
const cwd = process.cwd();
|
|
1324
|
-
const routesDir = options.routesDir ?? join(cwd, "src", "server", "routes");
|
|
1325
|
-
const outputPath = options.outputPath ?? join(cwd, "src", "lib", "api.ts");
|
|
1326
|
-
const watchMode = options.watch !== false;
|
|
1327
|
-
if (options.debug) {
|
|
1328
|
-
codegenLogger.info("Contract Watcher Started", { routesDir, outputPath, watch: watchMode });
|
|
1329
|
-
}
|
|
1330
|
-
await generateOnce(options);
|
|
1331
|
-
if (watchMode) {
|
|
1332
|
-
let isGenerating = false;
|
|
1333
|
-
let pendingRegeneration = false;
|
|
1334
|
-
const watcher = watch(routesDir, {
|
|
1335
|
-
ignored: /(^|[\/\\])\../,
|
|
1336
|
-
// ignore dotfiles
|
|
1337
|
-
persistent: true,
|
|
1338
|
-
ignoreInitial: true,
|
|
1339
|
-
awaitWriteFinish: {
|
|
1340
|
-
stabilityThreshold: 100,
|
|
1341
|
-
pollInterval: 50
|
|
1342
|
-
}
|
|
1343
|
-
});
|
|
1344
|
-
const regenerate = async () => {
|
|
1345
|
-
if (isGenerating) {
|
|
1346
|
-
pendingRegeneration = true;
|
|
1347
|
-
return;
|
|
1348
|
-
}
|
|
1349
|
-
isGenerating = true;
|
|
1350
|
-
pendingRegeneration = false;
|
|
1351
|
-
if (options.debug) {
|
|
1352
|
-
codegenLogger.info("Contracts changed, regenerating...");
|
|
1353
|
-
}
|
|
1354
|
-
await generateOnce(options);
|
|
1355
|
-
isGenerating = false;
|
|
1356
|
-
if (pendingRegeneration) {
|
|
1357
|
-
await regenerate();
|
|
1358
|
-
}
|
|
1359
|
-
};
|
|
1360
|
-
watcher.on("add", regenerate).on("change", regenerate).on("unlink", regenerate);
|
|
1361
|
-
process.on("SIGINT", () => {
|
|
1362
|
-
watcher.close();
|
|
1363
|
-
process.exit(0);
|
|
1364
|
-
});
|
|
1365
|
-
await new Promise(() => {
|
|
1366
|
-
});
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
1370
|
-
watchAndGenerate({ debug: true });
|
|
1371
|
-
}
|
|
777
|
+
// src/codegen/core/orchestrator.ts
|
|
1372
778
|
var orchestratorLogger = logger.child("orchestrator");
|
|
1373
779
|
var CodegenOrchestrator = class {
|
|
1374
780
|
generators;
|
|
@@ -1518,6 +924,518 @@ var CodegenOrchestrator = class {
|
|
|
1518
924
|
});
|
|
1519
925
|
}
|
|
1520
926
|
};
|
|
927
|
+
async function scanContracts(contractsDir, packagePrefix) {
|
|
928
|
+
const contractFiles = await scanContractFiles(contractsDir);
|
|
929
|
+
const mappings = [];
|
|
930
|
+
for (let i = 0; i < contractFiles.length; i++) {
|
|
931
|
+
const filePath = contractFiles[i];
|
|
932
|
+
const exports = extractContractExports(filePath);
|
|
933
|
+
for (let j = 0; j < exports.length; j++) {
|
|
934
|
+
const contractExport = exports[j];
|
|
935
|
+
if (!contractExport.path.startsWith("/")) {
|
|
936
|
+
throw new Error(
|
|
937
|
+
`Contract '${contractExport.name}' in ${filePath} must use absolute path. Found: '${contractExport.path}'. Use '/your-path' instead.`
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
if (packagePrefix && !contractExport.path.startsWith(packagePrefix)) {
|
|
941
|
+
throw new Error(
|
|
942
|
+
`Contract '${contractExport.name}' in ${filePath} must include package prefix. Expected path to start with '${packagePrefix}', but found: '${contractExport.path}'. Example: path: '${packagePrefix}/${contractExport.path}'`
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
mappings.push({
|
|
946
|
+
method: contractExport.method,
|
|
947
|
+
path: contractExport.path,
|
|
948
|
+
contractName: contractExport.name,
|
|
949
|
+
contractImportPath: getImportPath(filePath),
|
|
950
|
+
routeFile: "",
|
|
951
|
+
contractFile: filePath,
|
|
952
|
+
hasQuery: contractExport.hasQuery,
|
|
953
|
+
hasBody: contractExport.hasBody,
|
|
954
|
+
hasParams: contractExport.hasParams
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return mappings;
|
|
959
|
+
}
|
|
960
|
+
async function scanContractFiles(dir, files = []) {
|
|
961
|
+
try {
|
|
962
|
+
const entries = await readdir(dir);
|
|
963
|
+
for (let i = 0; i < entries.length; i++) {
|
|
964
|
+
const entry = entries[i];
|
|
965
|
+
const fullPath = join(dir, entry);
|
|
966
|
+
const fileStat = await stat(fullPath);
|
|
967
|
+
if (fileStat.isDirectory()) {
|
|
968
|
+
await scanContractFiles(fullPath, files);
|
|
969
|
+
} else {
|
|
970
|
+
if ((entry.endsWith(".ts") || entry.endsWith(".js") || entry.endsWith(".mjs")) && !entry.endsWith(".d.ts") && !entry.endsWith(".test.ts") && !entry.endsWith(".test.js") && !entry.endsWith(".test.mjs")) {
|
|
971
|
+
files.push(fullPath);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
} catch (error) {
|
|
976
|
+
}
|
|
977
|
+
return files;
|
|
978
|
+
}
|
|
979
|
+
function extractContractExports(filePath) {
|
|
980
|
+
const sourceCode = readFileSync(filePath, "utf-8");
|
|
981
|
+
const sourceFile = ts.createSourceFile(
|
|
982
|
+
filePath,
|
|
983
|
+
sourceCode,
|
|
984
|
+
ts.ScriptTarget.Latest,
|
|
985
|
+
true
|
|
986
|
+
);
|
|
987
|
+
const exports = [];
|
|
988
|
+
function visit(node) {
|
|
989
|
+
if (ts.isVariableStatement(node)) {
|
|
990
|
+
const hasExport = node.modifiers?.some(
|
|
991
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
992
|
+
);
|
|
993
|
+
if (hasExport && node.declarationList.declarations.length > 0) {
|
|
994
|
+
const declaration = node.declarationList.declarations[0];
|
|
995
|
+
if (ts.isVariableDeclaration(declaration) && ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
996
|
+
const name = declaration.name.text;
|
|
997
|
+
const hasSatisfiesRouteContract = checkSatisfiesRouteContract(declaration.initializer);
|
|
998
|
+
if (hasSatisfiesRouteContract) {
|
|
999
|
+
const objectLiteral = extractObjectLiteral(declaration.initializer);
|
|
1000
|
+
if (objectLiteral) {
|
|
1001
|
+
const contractData = extractContractData(objectLiteral);
|
|
1002
|
+
if (contractData.method && contractData.path) {
|
|
1003
|
+
exports.push({
|
|
1004
|
+
name,
|
|
1005
|
+
method: contractData.method,
|
|
1006
|
+
path: contractData.path,
|
|
1007
|
+
hasQuery: contractData.hasQuery,
|
|
1008
|
+
hasBody: contractData.hasBody,
|
|
1009
|
+
hasParams: contractData.hasParams
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
if (isContractName(name)) {
|
|
1016
|
+
const objectLiteral = extractObjectLiteral(declaration.initializer);
|
|
1017
|
+
if (objectLiteral) {
|
|
1018
|
+
const contractData = extractContractData(objectLiteral);
|
|
1019
|
+
if (contractData.method && contractData.path) {
|
|
1020
|
+
exports.push({
|
|
1021
|
+
name,
|
|
1022
|
+
method: contractData.method,
|
|
1023
|
+
path: contractData.path,
|
|
1024
|
+
hasQuery: contractData.hasQuery,
|
|
1025
|
+
hasBody: contractData.hasBody,
|
|
1026
|
+
hasParams: contractData.hasParams
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
ts.forEachChild(node, visit);
|
|
1035
|
+
}
|
|
1036
|
+
visit(sourceFile);
|
|
1037
|
+
return exports;
|
|
1038
|
+
}
|
|
1039
|
+
function checkSatisfiesRouteContract(initializer) {
|
|
1040
|
+
if (!ts.isSatisfiesExpression(initializer)) {
|
|
1041
|
+
return false;
|
|
1042
|
+
}
|
|
1043
|
+
const typeNode = initializer.type;
|
|
1044
|
+
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
1045
|
+
return typeNode.typeName.text === "RouteContract";
|
|
1046
|
+
}
|
|
1047
|
+
return false;
|
|
1048
|
+
}
|
|
1049
|
+
function extractObjectLiteral(initializer) {
|
|
1050
|
+
if (ts.isObjectLiteralExpression(initializer)) {
|
|
1051
|
+
return initializer;
|
|
1052
|
+
}
|
|
1053
|
+
if (ts.isSatisfiesExpression(initializer)) {
|
|
1054
|
+
return extractObjectLiteral(initializer.expression);
|
|
1055
|
+
}
|
|
1056
|
+
if (ts.isAsExpression(initializer)) {
|
|
1057
|
+
return extractObjectLiteral(initializer.expression);
|
|
1058
|
+
}
|
|
1059
|
+
return void 0;
|
|
1060
|
+
}
|
|
1061
|
+
function extractContractData(objectLiteral) {
|
|
1062
|
+
const result = {};
|
|
1063
|
+
for (let i = 0; i < objectLiteral.properties.length; i++) {
|
|
1064
|
+
const prop = objectLiteral.properties[i];
|
|
1065
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
1066
|
+
const propName = prop.name.text;
|
|
1067
|
+
if (propName === "method") {
|
|
1068
|
+
let value;
|
|
1069
|
+
if (ts.isStringLiteral(prop.initializer)) {
|
|
1070
|
+
value = prop.initializer.text;
|
|
1071
|
+
} else if (ts.isAsExpression(prop.initializer) && ts.isStringLiteral(prop.initializer.expression)) {
|
|
1072
|
+
value = prop.initializer.expression.text;
|
|
1073
|
+
}
|
|
1074
|
+
if (value) result.method = value;
|
|
1075
|
+
} else if (propName === "path") {
|
|
1076
|
+
let value;
|
|
1077
|
+
if (ts.isStringLiteral(prop.initializer)) {
|
|
1078
|
+
value = prop.initializer.text;
|
|
1079
|
+
} else if (ts.isAsExpression(prop.initializer) && ts.isStringLiteral(prop.initializer.expression)) {
|
|
1080
|
+
value = prop.initializer.expression.text;
|
|
1081
|
+
}
|
|
1082
|
+
if (value) result.path = value;
|
|
1083
|
+
} else if (propName === "query") {
|
|
1084
|
+
result.hasQuery = true;
|
|
1085
|
+
} else if (propName === "body") {
|
|
1086
|
+
result.hasBody = true;
|
|
1087
|
+
} else if (propName === "params") {
|
|
1088
|
+
result.hasParams = true;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return result;
|
|
1093
|
+
}
|
|
1094
|
+
function isContractName(name) {
|
|
1095
|
+
return name.indexOf("Contract") !== -1 || name.indexOf("contract") !== -1 || name.endsWith("Schema") || name.endsWith("schema");
|
|
1096
|
+
}
|
|
1097
|
+
function getImportPath(filePath) {
|
|
1098
|
+
const srcIndex = filePath.indexOf("/src/");
|
|
1099
|
+
if (srcIndex === -1) {
|
|
1100
|
+
throw new Error(`Cannot determine import path for ${filePath}: /src/ directory not found`);
|
|
1101
|
+
}
|
|
1102
|
+
let cleanPath = filePath.substring(srcIndex + 5);
|
|
1103
|
+
if (cleanPath.endsWith(".ts")) {
|
|
1104
|
+
cleanPath = cleanPath.slice(0, -3);
|
|
1105
|
+
} else if (cleanPath.endsWith(".js")) {
|
|
1106
|
+
cleanPath = cleanPath.slice(0, -3);
|
|
1107
|
+
} else if (cleanPath.endsWith(".mjs")) {
|
|
1108
|
+
cleanPath = cleanPath.slice(0, -4);
|
|
1109
|
+
}
|
|
1110
|
+
return "@/" + cleanPath;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
// src/codegen/built-in/contract/helpers.ts
|
|
1114
|
+
function groupByResource(mappings) {
|
|
1115
|
+
const grouped = {};
|
|
1116
|
+
for (let i = 0; i < mappings.length; i++) {
|
|
1117
|
+
const mapping = mappings[i];
|
|
1118
|
+
const resource = extractResourceName(mapping.path);
|
|
1119
|
+
if (!grouped[resource]) {
|
|
1120
|
+
grouped[resource] = [];
|
|
1121
|
+
}
|
|
1122
|
+
grouped[resource].push(mapping);
|
|
1123
|
+
}
|
|
1124
|
+
return grouped;
|
|
1125
|
+
}
|
|
1126
|
+
function extractResourceName(path) {
|
|
1127
|
+
let processedPath = path;
|
|
1128
|
+
if (!processedPath.startsWith("/")) {
|
|
1129
|
+
processedPath = "/" + processedPath;
|
|
1130
|
+
}
|
|
1131
|
+
const segments = processedPath.slice(1).split("/").filter((s) => s && s !== "*");
|
|
1132
|
+
const staticSegments = [];
|
|
1133
|
+
for (let i = 0; i < segments.length; i++) {
|
|
1134
|
+
const seg = segments[i];
|
|
1135
|
+
if (!seg.startsWith(":")) {
|
|
1136
|
+
staticSegments.push(seg);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
if (staticSegments.length === 0) {
|
|
1140
|
+
return "root";
|
|
1141
|
+
}
|
|
1142
|
+
const first = toCamelCase(staticSegments[0], false);
|
|
1143
|
+
if (staticSegments.length === 1) {
|
|
1144
|
+
return first;
|
|
1145
|
+
}
|
|
1146
|
+
const result = [first];
|
|
1147
|
+
for (let i = 1; i < staticSegments.length; i++) {
|
|
1148
|
+
const seg = staticSegments[i];
|
|
1149
|
+
result.push(toCamelCase(seg, true));
|
|
1150
|
+
}
|
|
1151
|
+
return result.join("");
|
|
1152
|
+
}
|
|
1153
|
+
function toCamelCase(str, capitalize2) {
|
|
1154
|
+
const parts = str.split(/[-_]/);
|
|
1155
|
+
if (parts.length === 1) {
|
|
1156
|
+
return capitalize2 ? str.charAt(0).toUpperCase() + str.slice(1) : str;
|
|
1157
|
+
}
|
|
1158
|
+
const result = [];
|
|
1159
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1160
|
+
const part = parts[i];
|
|
1161
|
+
if (i === 0 && !capitalize2) {
|
|
1162
|
+
result.push(part);
|
|
1163
|
+
} else {
|
|
1164
|
+
result.push(part.charAt(0).toUpperCase() + part.slice(1));
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return result.join("");
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// src/codegen/built-in/contract/emitter.ts
|
|
1171
|
+
async function generateClient(mappings, options) {
|
|
1172
|
+
const startTime = Date.now();
|
|
1173
|
+
const grouped = groupByResource(mappings);
|
|
1174
|
+
const resourceNames = Object.keys(grouped);
|
|
1175
|
+
await generateSplitClient(mappings, grouped, options);
|
|
1176
|
+
return {
|
|
1177
|
+
routesScanned: mappings.length,
|
|
1178
|
+
contractsFound: mappings.length,
|
|
1179
|
+
contractFiles: countUniqueContractFiles(mappings),
|
|
1180
|
+
resourcesGenerated: resourceNames.length,
|
|
1181
|
+
methodsGenerated: mappings.length,
|
|
1182
|
+
duration: Date.now() - startTime
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
function generateHeader() {
|
|
1186
|
+
return `/**
|
|
1187
|
+
* Auto-generated API Client
|
|
1188
|
+
*
|
|
1189
|
+
* Generated by @spfn/core codegen
|
|
1190
|
+
* DO NOT EDIT MANUALLY
|
|
1191
|
+
*
|
|
1192
|
+
* @generated ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1193
|
+
*/
|
|
1194
|
+
|
|
1195
|
+
`;
|
|
1196
|
+
}
|
|
1197
|
+
function groupContractsByImportPath(mappings) {
|
|
1198
|
+
const groups = {};
|
|
1199
|
+
for (let i = 0; i < mappings.length; i++) {
|
|
1200
|
+
const mapping = mappings[i];
|
|
1201
|
+
const path = mapping.contractImportPath;
|
|
1202
|
+
if (!groups[path]) {
|
|
1203
|
+
groups[path] = /* @__PURE__ */ new Set();
|
|
1204
|
+
}
|
|
1205
|
+
groups[path].add(mapping.contractName);
|
|
1206
|
+
}
|
|
1207
|
+
const result = {};
|
|
1208
|
+
const keys = Object.keys(groups);
|
|
1209
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1210
|
+
const key = keys[i];
|
|
1211
|
+
result[key] = Array.from(groups[key]);
|
|
1212
|
+
}
|
|
1213
|
+
return result;
|
|
1214
|
+
}
|
|
1215
|
+
function generateTypeName(mapping) {
|
|
1216
|
+
let name = mapping.contractName;
|
|
1217
|
+
if (name.endsWith("Contract")) {
|
|
1218
|
+
name = name.slice(0, -8);
|
|
1219
|
+
}
|
|
1220
|
+
if (name.length > 0) {
|
|
1221
|
+
name = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1222
|
+
}
|
|
1223
|
+
return name;
|
|
1224
|
+
}
|
|
1225
|
+
function generateMethodCode(mapping, options) {
|
|
1226
|
+
const methodName = generateMethodName(mapping);
|
|
1227
|
+
const hasParams = mapping.hasParams || mapping.path.includes(":");
|
|
1228
|
+
const hasQuery = mapping.hasQuery || false;
|
|
1229
|
+
const hasBody = mapping.hasBody || false;
|
|
1230
|
+
let code = "";
|
|
1231
|
+
if (options.includeJsDoc !== false) {
|
|
1232
|
+
code += ` /**
|
|
1233
|
+
`;
|
|
1234
|
+
code += ` * ${mapping.method} ${mapping.path}
|
|
1235
|
+
`;
|
|
1236
|
+
code += ` */
|
|
1237
|
+
`;
|
|
1238
|
+
}
|
|
1239
|
+
code += ` ${methodName}: (`;
|
|
1240
|
+
const params = [];
|
|
1241
|
+
const typeName = generateTypeName(mapping);
|
|
1242
|
+
if (hasParams) {
|
|
1243
|
+
params.push(`params: ${typeName}Params`);
|
|
1244
|
+
}
|
|
1245
|
+
if (hasQuery) {
|
|
1246
|
+
params.push(`query?: ${typeName}Query`);
|
|
1247
|
+
}
|
|
1248
|
+
if (hasBody) {
|
|
1249
|
+
params.push(`body: ${typeName}Body`);
|
|
1250
|
+
}
|
|
1251
|
+
if (params.length > 0) {
|
|
1252
|
+
code += `options: { ${params.join(", ")} }`;
|
|
1253
|
+
}
|
|
1254
|
+
code += `) => `;
|
|
1255
|
+
code += `client.call(${mapping.contractName}`;
|
|
1256
|
+
if (params.length > 0) {
|
|
1257
|
+
code += `, options`;
|
|
1258
|
+
}
|
|
1259
|
+
code += `),
|
|
1260
|
+
`;
|
|
1261
|
+
return code;
|
|
1262
|
+
}
|
|
1263
|
+
function generateMethodName(mapping) {
|
|
1264
|
+
const method = mapping.method.toLowerCase();
|
|
1265
|
+
if (mapping.path === "/" || mapping.path.match(/^\/[\w-]+$/)) {
|
|
1266
|
+
if (method === "get") {
|
|
1267
|
+
return "list";
|
|
1268
|
+
}
|
|
1269
|
+
if (method === "post") {
|
|
1270
|
+
return "create";
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
if (mapping.path.includes(":")) {
|
|
1274
|
+
if (method === "get") {
|
|
1275
|
+
return "getById";
|
|
1276
|
+
}
|
|
1277
|
+
if (method === "put" || method === "patch") {
|
|
1278
|
+
return "update";
|
|
1279
|
+
}
|
|
1280
|
+
if (method === "delete") {
|
|
1281
|
+
return "delete";
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return method;
|
|
1285
|
+
}
|
|
1286
|
+
function countUniqueContractFiles(mappings) {
|
|
1287
|
+
const files = /* @__PURE__ */ new Set();
|
|
1288
|
+
for (let i = 0; i < mappings.length; i++) {
|
|
1289
|
+
if (mappings[i].contractFile) {
|
|
1290
|
+
files.add(mappings[i].contractFile);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
return files.size;
|
|
1294
|
+
}
|
|
1295
|
+
function toKebabCase(str) {
|
|
1296
|
+
if (str.length === 0) {
|
|
1297
|
+
return str;
|
|
1298
|
+
}
|
|
1299
|
+
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
1300
|
+
}
|
|
1301
|
+
async function generateSplitClient(_mappings, grouped, options) {
|
|
1302
|
+
const outputPath = options.outputPath;
|
|
1303
|
+
const outputDir = outputPath.endsWith(".ts") || outputPath.endsWith(".js") ? outputPath.replace(/\.[jt]s$/, "") : outputPath;
|
|
1304
|
+
await mkdir(outputDir, { recursive: true });
|
|
1305
|
+
const resourceNames = Object.keys(grouped);
|
|
1306
|
+
for (let i = 0; i < resourceNames.length; i++) {
|
|
1307
|
+
const resourceName = resourceNames[i];
|
|
1308
|
+
const routes = grouped[resourceName];
|
|
1309
|
+
const code = generateResourceFile(resourceName, routes, options);
|
|
1310
|
+
const kebabName = toKebabCase(resourceName);
|
|
1311
|
+
const filePath = `${outputDir}/${kebabName}.ts`;
|
|
1312
|
+
await writeFile(filePath, code, "utf-8");
|
|
1313
|
+
}
|
|
1314
|
+
const indexCode = generateIndexFile(resourceNames, options);
|
|
1315
|
+
const indexPath = `${outputDir}/index.ts`;
|
|
1316
|
+
await writeFile(indexPath, indexCode, "utf-8");
|
|
1317
|
+
}
|
|
1318
|
+
function generateResourceFile(resourceName, routes, options) {
|
|
1319
|
+
let code = "";
|
|
1320
|
+
code += generateHeader();
|
|
1321
|
+
code += `import { client } from '@spfn/core/client';
|
|
1322
|
+
`;
|
|
1323
|
+
if (options.includeTypes !== false) {
|
|
1324
|
+
code += `import type { InferContract } from '@spfn/core';
|
|
1325
|
+
`;
|
|
1326
|
+
}
|
|
1327
|
+
code += `
|
|
1328
|
+
`;
|
|
1329
|
+
const importGroups = groupContractsByImportPath(routes);
|
|
1330
|
+
const importPaths = Object.keys(importGroups);
|
|
1331
|
+
for (let i = 0; i < importPaths.length; i++) {
|
|
1332
|
+
const importPath = importPaths[i];
|
|
1333
|
+
const contracts = importGroups[importPath];
|
|
1334
|
+
code += `import { ${contracts.join(", ")} } from '${importPath}';
|
|
1335
|
+
`;
|
|
1336
|
+
}
|
|
1337
|
+
code += `
|
|
1338
|
+
`;
|
|
1339
|
+
if (options.includeTypes !== false) {
|
|
1340
|
+
code += `// ============================================
|
|
1341
|
+
`;
|
|
1342
|
+
code += `// Types
|
|
1343
|
+
`;
|
|
1344
|
+
code += `// ============================================
|
|
1345
|
+
|
|
1346
|
+
`;
|
|
1347
|
+
for (let i = 0; i < routes.length; i++) {
|
|
1348
|
+
const route = routes[i];
|
|
1349
|
+
const typeName = generateTypeName(route);
|
|
1350
|
+
const contractType = `typeof ${route.contractName}`;
|
|
1351
|
+
code += `export type ${typeName}Response = InferContract<${contractType}>['response'];
|
|
1352
|
+
`;
|
|
1353
|
+
if (route.hasQuery) {
|
|
1354
|
+
code += `export type ${typeName}Query = InferContract<${contractType}>['query'];
|
|
1355
|
+
`;
|
|
1356
|
+
}
|
|
1357
|
+
if (route.hasParams || route.path.includes(":")) {
|
|
1358
|
+
code += `export type ${typeName}Params = InferContract<${contractType}>['params'];
|
|
1359
|
+
`;
|
|
1360
|
+
}
|
|
1361
|
+
if (route.hasBody) {
|
|
1362
|
+
code += `export type ${typeName}Body = InferContract<${contractType}>['body'];
|
|
1363
|
+
`;
|
|
1364
|
+
}
|
|
1365
|
+
code += `
|
|
1366
|
+
`;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
code += `/**
|
|
1370
|
+
`;
|
|
1371
|
+
code += ` * ${resourceName} API
|
|
1372
|
+
`;
|
|
1373
|
+
code += ` */
|
|
1374
|
+
`;
|
|
1375
|
+
code += `export const ${resourceName} = {
|
|
1376
|
+
`;
|
|
1377
|
+
for (let i = 0; i < routes.length; i++) {
|
|
1378
|
+
const route = routes[i];
|
|
1379
|
+
code += generateMethodCode(route, options);
|
|
1380
|
+
}
|
|
1381
|
+
code += `} as const;
|
|
1382
|
+
`;
|
|
1383
|
+
return code;
|
|
1384
|
+
}
|
|
1385
|
+
function toCamelCase2(str) {
|
|
1386
|
+
if (str.length === 0) {
|
|
1387
|
+
return str;
|
|
1388
|
+
}
|
|
1389
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
1390
|
+
}
|
|
1391
|
+
function generateIndexFile(resourceNames, options) {
|
|
1392
|
+
let code = "";
|
|
1393
|
+
const apiName = options.apiName || "api";
|
|
1394
|
+
code += generateHeader();
|
|
1395
|
+
code += `export { client } from '@spfn/core/client';
|
|
1396
|
+
|
|
1397
|
+
`;
|
|
1398
|
+
for (let i = 0; i < resourceNames.length; i++) {
|
|
1399
|
+
const resourceName = resourceNames[i];
|
|
1400
|
+
const kebabName = toKebabCase(resourceName);
|
|
1401
|
+
code += `export * from './${kebabName}.js';
|
|
1402
|
+
`;
|
|
1403
|
+
}
|
|
1404
|
+
code += `
|
|
1405
|
+
`;
|
|
1406
|
+
for (let i = 0; i < resourceNames.length; i++) {
|
|
1407
|
+
const resourceName = resourceNames[i];
|
|
1408
|
+
const kebabName = toKebabCase(resourceName);
|
|
1409
|
+
code += `import { ${resourceName} } from './${kebabName}.js';
|
|
1410
|
+
`;
|
|
1411
|
+
}
|
|
1412
|
+
code += `
|
|
1413
|
+
`;
|
|
1414
|
+
const resourceKeys = resourceNames.map((name) => toCamelCase2(name));
|
|
1415
|
+
code += `/**
|
|
1416
|
+
`;
|
|
1417
|
+
code += ` * Type-safe API client
|
|
1418
|
+
`;
|
|
1419
|
+
code += ` */
|
|
1420
|
+
`;
|
|
1421
|
+
code += `export const ${apiName} = {
|
|
1422
|
+
`;
|
|
1423
|
+
for (let i = 0; i < resourceNames.length; i++) {
|
|
1424
|
+
const resourceName = resourceNames[i];
|
|
1425
|
+
const resourceKey = resourceKeys[i];
|
|
1426
|
+
code += ` ${resourceKey}: ${resourceName}`;
|
|
1427
|
+
if (i < resourceNames.length - 1) {
|
|
1428
|
+
code += `,`;
|
|
1429
|
+
}
|
|
1430
|
+
code += `
|
|
1431
|
+
`;
|
|
1432
|
+
}
|
|
1433
|
+
code += `} as const;
|
|
1434
|
+
`;
|
|
1435
|
+
return code;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// src/codegen/built-in/contract/index.ts
|
|
1521
1439
|
var contractLogger = logger.child("contract-gen");
|
|
1522
1440
|
var DEFAULT_CONTRACTS_DIR = "src/lib/contracts";
|
|
1523
1441
|
var DEFAULT_OUTPUT_PATH = "src/lib/api";
|
|
@@ -1579,6 +1497,8 @@ function createContractGenerator(config = {}) {
|
|
|
1579
1497
|
const cwd = options.cwd;
|
|
1580
1498
|
const fullContractsDir = join(cwd, contractsDir);
|
|
1581
1499
|
const fullOutputPath = join(cwd, outputPath);
|
|
1500
|
+
const prefix = readPrefixFromPackageJson(cwd);
|
|
1501
|
+
const apiName = generateApiName(prefix);
|
|
1582
1502
|
try {
|
|
1583
1503
|
if (!existsSync(fullContractsDir)) {
|
|
1584
1504
|
if (options.debug) {
|
|
@@ -1600,6 +1520,7 @@ function createContractGenerator(config = {}) {
|
|
|
1600
1520
|
outputPath: fullOutputPath,
|
|
1601
1521
|
changedFilePath: changedFile.path,
|
|
1602
1522
|
baseUrl: config.baseUrl,
|
|
1523
|
+
apiName,
|
|
1603
1524
|
debug: options.debug
|
|
1604
1525
|
});
|
|
1605
1526
|
if (success) {
|
|
@@ -1612,7 +1533,7 @@ function createContractGenerator(config = {}) {
|
|
|
1612
1533
|
contractLogger.info("Incremental update failed, doing full regen");
|
|
1613
1534
|
}
|
|
1614
1535
|
}
|
|
1615
|
-
const allContracts = await scanContracts(fullContractsDir);
|
|
1536
|
+
const allContracts = await scanContracts(fullContractsDir, prefix);
|
|
1616
1537
|
if (allContracts.length === 0) {
|
|
1617
1538
|
if (options.debug) {
|
|
1618
1539
|
contractLogger.warn("No contracts found");
|
|
@@ -1620,8 +1541,6 @@ function createContractGenerator(config = {}) {
|
|
|
1620
1541
|
contractCache = null;
|
|
1621
1542
|
return;
|
|
1622
1543
|
}
|
|
1623
|
-
const prefix = readPrefixFromPackageJson(cwd);
|
|
1624
|
-
const apiName = generateApiName(prefix);
|
|
1625
1544
|
const clientOptions = createClientOptions(fullContractsDir, fullOutputPath, config.baseUrl, apiName);
|
|
1626
1545
|
const stats = await generateClient(allContracts, clientOptions);
|
|
1627
1546
|
contractCache = {
|
|
@@ -1645,7 +1564,7 @@ function createContractGenerator(config = {}) {
|
|
|
1645
1564
|
};
|
|
1646
1565
|
}
|
|
1647
1566
|
async function attemptIncrementalUpdate(options) {
|
|
1648
|
-
const { cwd, contractsDir, outputPath, changedFilePath, baseUrl, debug } = options;
|
|
1567
|
+
const { cwd, contractsDir, outputPath, changedFilePath, baseUrl, apiName, debug } = options;
|
|
1649
1568
|
if (!contractCache) {
|
|
1650
1569
|
return false;
|
|
1651
1570
|
}
|
|
@@ -1670,7 +1589,7 @@ async function attemptIncrementalUpdate(options) {
|
|
|
1670
1589
|
}
|
|
1671
1590
|
return true;
|
|
1672
1591
|
}
|
|
1673
|
-
const clientOptions = createClientOptions(contractsDir, outputPath, baseUrl);
|
|
1592
|
+
const clientOptions = createClientOptions(contractsDir, outputPath, baseUrl, apiName);
|
|
1674
1593
|
const stats = await generateClient(updatedContracts, clientOptions);
|
|
1675
1594
|
contractCache = {
|
|
1676
1595
|
contracts: updatedContracts,
|
|
@@ -1832,6 +1751,6 @@ async function createGeneratorsFromConfig(config, cwd) {
|
|
|
1832
1751
|
return generators;
|
|
1833
1752
|
}
|
|
1834
1753
|
|
|
1835
|
-
export { CodegenOrchestrator, createContractGenerator, createGeneratorsFromConfig,
|
|
1754
|
+
export { CodegenOrchestrator, createContractGenerator, createGeneratorsFromConfig, loadCodegenConfig };
|
|
1836
1755
|
//# sourceMappingURL=index.js.map
|
|
1837
1756
|
//# sourceMappingURL=index.js.map
|