mulink 1.1.8 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/lib/{chunk-AHGDKSOY.js → chunk-2WVV6AOO.js} +418 -250
- package/dist/lib/chunk-2WVV6AOO.js.map +1 -0
- package/dist/lib/{chunk-SSMOIVFN.cjs → chunk-NC747MZJ.cjs} +418 -250
- package/dist/lib/chunk-NC747MZJ.cjs.map +1 -0
- package/dist/lib/cli.cjs +57 -29
- package/dist/lib/cli.cjs.map +1 -1
- package/dist/lib/cli.js +42 -14
- package/dist/lib/cli.js.map +1 -1
- package/dist/lib/client.cjs +20 -20
- package/dist/lib/client.cjs.map +1 -1
- package/dist/lib/client.d.cts +4 -4
- package/dist/lib/client.d.ts +4 -4
- package/dist/lib/client.js +4 -4
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/index.cjs +177 -15
- package/dist/lib/index.cjs.map +1 -1
- package/dist/lib/index.d.cts +211 -3
- package/dist/lib/index.d.ts +211 -3
- package/dist/lib/index.js +153 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/{version-checker-uF6o5ziX.d.cts → version-checker-DU88tpi8.d.cts} +152 -12
- package/dist/lib/{version-checker-uF6o5ziX.d.ts → version-checker-DU88tpi8.d.ts} +152 -12
- package/package.json +2 -2
- package/dist/lib/chunk-AHGDKSOY.js.map +0 -1
- package/dist/lib/chunk-SSMOIVFN.cjs.map +0 -1
|
@@ -7,17 +7,48 @@ var __defProp = Object.defineProperty;
|
|
|
7
7
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
8
|
|
|
9
9
|
// src/core/types.ts
|
|
10
|
-
var BridgeError = class extends Error {
|
|
10
|
+
var BridgeError = class _BridgeError extends Error {
|
|
11
11
|
static {
|
|
12
12
|
__name(this, "BridgeError");
|
|
13
13
|
}
|
|
14
14
|
code;
|
|
15
15
|
details;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
timestamp;
|
|
17
|
+
cause;
|
|
18
|
+
constructor(message, code, details, cause) {
|
|
19
|
+
super(message, { cause });
|
|
18
20
|
this.name = "BridgeError";
|
|
19
21
|
this.code = code;
|
|
20
22
|
this.details = details;
|
|
23
|
+
this.timestamp = Date.now();
|
|
24
|
+
this.cause = cause;
|
|
25
|
+
if (Error.captureStackTrace) {
|
|
26
|
+
Error.captureStackTrace(this, _BridgeError);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Converts the error to a JSON-serializable object
|
|
31
|
+
*
|
|
32
|
+
* @returns JSON representation of the error
|
|
33
|
+
*/
|
|
34
|
+
toJSON() {
|
|
35
|
+
return {
|
|
36
|
+
name: this.name,
|
|
37
|
+
message: this.message,
|
|
38
|
+
code: this.code,
|
|
39
|
+
details: this.details,
|
|
40
|
+
timestamp: this.timestamp,
|
|
41
|
+
stack: this.stack,
|
|
42
|
+
cause: this.cause?.message
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Checks if this error is retryable
|
|
47
|
+
*
|
|
48
|
+
* @returns True if the operation that caused this error can be retried
|
|
49
|
+
*/
|
|
50
|
+
isRetryable() {
|
|
51
|
+
return false;
|
|
21
52
|
}
|
|
22
53
|
};
|
|
23
54
|
var ValidationError = class extends BridgeError {
|
|
@@ -25,28 +56,42 @@ var ValidationError = class extends BridgeError {
|
|
|
25
56
|
__name(this, "ValidationError");
|
|
26
57
|
}
|
|
27
58
|
errors;
|
|
28
|
-
constructor(message, errors) {
|
|
29
|
-
super(message, "VALIDATION_ERROR", errors);
|
|
59
|
+
constructor(message, errors, cause) {
|
|
60
|
+
super(message, "VALIDATION_ERROR", errors, cause);
|
|
30
61
|
this.errors = errors;
|
|
31
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Gets formatted validation error messages
|
|
65
|
+
*
|
|
66
|
+
* @returns Array of formatted error messages
|
|
67
|
+
*/
|
|
68
|
+
getFormattedErrors() {
|
|
69
|
+
return this.errors.errors.map((err) => {
|
|
70
|
+
const path3 = err.path.join(".");
|
|
71
|
+
return `${path3}: ${err.message}`;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
32
74
|
};
|
|
33
75
|
var SchemaParseError = class extends BridgeError {
|
|
34
76
|
static {
|
|
35
77
|
__name(this, "SchemaParseError");
|
|
36
78
|
}
|
|
37
79
|
schemaUrl;
|
|
38
|
-
constructor(message, schemaUrl) {
|
|
39
|
-
super(message, "SCHEMA_PARSE_ERROR", { schemaUrl });
|
|
80
|
+
constructor(message, schemaUrl, cause) {
|
|
81
|
+
super(message, "SCHEMA_PARSE_ERROR", { schemaUrl }, cause);
|
|
40
82
|
this.schemaUrl = schemaUrl;
|
|
41
83
|
}
|
|
84
|
+
isRetryable() {
|
|
85
|
+
return this.cause instanceof TypeError && this.cause.message.includes("fetch");
|
|
86
|
+
}
|
|
42
87
|
};
|
|
43
88
|
var GenerationError = class extends BridgeError {
|
|
44
89
|
static {
|
|
45
90
|
__name(this, "GenerationError");
|
|
46
91
|
}
|
|
47
92
|
file;
|
|
48
|
-
constructor(message, file) {
|
|
49
|
-
super(message, "GENERATION_ERROR", { file });
|
|
93
|
+
constructor(message, file, cause) {
|
|
94
|
+
super(message, "GENERATION_ERROR", { file }, cause);
|
|
50
95
|
this.file = file;
|
|
51
96
|
}
|
|
52
97
|
};
|
|
@@ -134,8 +179,8 @@ var BridgeLogger = class {
|
|
|
134
179
|
if (!this.options.colors || !process.stdout.isTTY) {
|
|
135
180
|
console.log(message);
|
|
136
181
|
return {
|
|
137
|
-
succeed: /* @__PURE__ */ __name((msg) => console.log(colorize(`\u2713 ${msg
|
|
138
|
-
fail: /* @__PURE__ */ __name((msg) => console.error(colorize(`\u2717 ${msg
|
|
182
|
+
succeed: /* @__PURE__ */ __name((msg) => console.log(colorize(`\u2713 ${msg ?? message}`, "green")), "succeed"),
|
|
183
|
+
fail: /* @__PURE__ */ __name((msg) => console.error(colorize(`\u2717 ${msg ?? message}`, "red")), "fail"),
|
|
139
184
|
stop: /* @__PURE__ */ __name(() => {
|
|
140
185
|
}, "stop")
|
|
141
186
|
};
|
|
@@ -143,17 +188,20 @@ var BridgeLogger = class {
|
|
|
143
188
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
144
189
|
let i = 0;
|
|
145
190
|
const interval = setInterval(() => {
|
|
146
|
-
|
|
191
|
+
const frame = frames[i++ % frames.length];
|
|
192
|
+
if (frame) {
|
|
193
|
+
process.stdout.write(`\r${colorize(frame, "cyan")} ${message}`);
|
|
194
|
+
}
|
|
147
195
|
}, 100);
|
|
148
196
|
return {
|
|
149
197
|
succeed: /* @__PURE__ */ __name((msg) => {
|
|
150
198
|
clearInterval(interval);
|
|
151
|
-
process.stdout.write(`\r${colorize("\u2713", "green")} ${msg
|
|
199
|
+
process.stdout.write(`\r${colorize("\u2713", "green")} ${msg ?? message}
|
|
152
200
|
`);
|
|
153
201
|
}, "succeed"),
|
|
154
202
|
fail: /* @__PURE__ */ __name((msg) => {
|
|
155
203
|
clearInterval(interval);
|
|
156
|
-
process.stdout.write(`\r${colorize("\u2717", "red")} ${msg
|
|
204
|
+
process.stdout.write(`\r${colorize("\u2717", "red")} ${msg ?? message}
|
|
157
205
|
`);
|
|
158
206
|
}, "fail"),
|
|
159
207
|
stop: /* @__PURE__ */ __name(() => {
|
|
@@ -176,7 +224,7 @@ var VersionChecker = class {
|
|
|
176
224
|
constructor(packageName, currentVersion, logger) {
|
|
177
225
|
this.packageName = packageName;
|
|
178
226
|
this.currentVersion = currentVersion;
|
|
179
|
-
this.logger = logger
|
|
227
|
+
this.logger = logger ?? new BridgeLogger({ prefix: "\u{1F50D} Version Check" });
|
|
180
228
|
}
|
|
181
229
|
/**
|
|
182
230
|
* Check if a new version is available
|
|
@@ -231,7 +279,7 @@ var VersionChecker = class {
|
|
|
231
279
|
/**
|
|
232
280
|
* Get the appropriate upgrade command for the detected package manager
|
|
233
281
|
*/
|
|
234
|
-
getUpgradeCommand(
|
|
282
|
+
getUpgradeCommand(_versionInfo) {
|
|
235
283
|
const packageManager = this.detectPackageManager();
|
|
236
284
|
switch (packageManager) {
|
|
237
285
|
case "yarn":
|
|
@@ -305,8 +353,8 @@ var VersionChecker = class {
|
|
|
305
353
|
const currentParts = this.parseVersion(current);
|
|
306
354
|
const latestParts = this.parseVersion(latest);
|
|
307
355
|
for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
|
|
308
|
-
const currentPart = currentParts[i]
|
|
309
|
-
const latestPart = latestParts[i]
|
|
356
|
+
const currentPart = currentParts[i] ?? 0;
|
|
357
|
+
const latestPart = latestParts[i] ?? 0;
|
|
310
358
|
if (latestPart > currentPart) {
|
|
311
359
|
return true;
|
|
312
360
|
} else if (latestPart < currentPart) {
|
|
@@ -380,7 +428,7 @@ function createBridgeVersionChecker(logger) {
|
|
|
380
428
|
if (existsSync(pkgPath)) {
|
|
381
429
|
const pkgRaw = readFileSync(pkgPath, { encoding: "utf-8" });
|
|
382
430
|
const pkg = JSON.parse(pkgRaw);
|
|
383
|
-
if (pkg
|
|
431
|
+
if (pkg.version) {
|
|
384
432
|
currentVersion = pkg.version;
|
|
385
433
|
}
|
|
386
434
|
} else {
|
|
@@ -388,13 +436,13 @@ function createBridgeVersionChecker(logger) {
|
|
|
388
436
|
if (existsSync(cwdPkg)) {
|
|
389
437
|
const pkgRaw = readFileSync(cwdPkg, { encoding: "utf-8" });
|
|
390
438
|
const pkg = JSON.parse(pkgRaw);
|
|
391
|
-
if (pkg
|
|
439
|
+
if (pkg.version) {
|
|
392
440
|
currentVersion = pkg.version;
|
|
393
441
|
}
|
|
394
442
|
}
|
|
395
443
|
}
|
|
396
444
|
} catch (err) {
|
|
397
|
-
const l = logger
|
|
445
|
+
const l = logger ?? new BridgeLogger({ prefix: "\u{1F50D} Version Check" });
|
|
398
446
|
l.debug("Failed to read package.json for current version, falling back to default", err);
|
|
399
447
|
}
|
|
400
448
|
return new VersionChecker(packageName, currentVersion, logger);
|
|
@@ -432,7 +480,7 @@ var OpenApiSchemaParser = class {
|
|
|
432
480
|
async fetchSchema(schemaUrl) {
|
|
433
481
|
const versionChecker = createBridgeVersionChecker();
|
|
434
482
|
const currentVersion = versionChecker.getCurrentVersion();
|
|
435
|
-
if (!schemaUrl
|
|
483
|
+
if (!schemaUrl.trim()) {
|
|
436
484
|
throw new SchemaParseError("Schema URL is required and cannot be empty", schemaUrl);
|
|
437
485
|
}
|
|
438
486
|
if (schemaUrl.startsWith("http")) {
|
|
@@ -453,7 +501,7 @@ var OpenApiSchemaParser = class {
|
|
|
453
501
|
schemaUrl
|
|
454
502
|
);
|
|
455
503
|
}
|
|
456
|
-
const contentType = response.headers.get("content-type")
|
|
504
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
457
505
|
if (!contentType.includes("application/json") && !contentType.includes("application/yaml") && !contentType.includes("text/yaml")) {
|
|
458
506
|
throw new SchemaParseError(
|
|
459
507
|
`Unsupported content type: ${contentType}. Expected JSON or YAML.`,
|
|
@@ -483,10 +531,10 @@ var OpenApiSchemaParser = class {
|
|
|
483
531
|
);
|
|
484
532
|
}
|
|
485
533
|
}
|
|
486
|
-
|
|
534
|
+
parseDocument(document) {
|
|
487
535
|
const version = this.detectVersion(document);
|
|
488
536
|
const normalizedDocument = this.normalizeDocument(document, version);
|
|
489
|
-
return {
|
|
537
|
+
return Promise.resolve({
|
|
490
538
|
version,
|
|
491
539
|
document: normalizedDocument,
|
|
492
540
|
openApiSpec: normalizedDocument,
|
|
@@ -495,7 +543,7 @@ var OpenApiSchemaParser = class {
|
|
|
495
543
|
security: this.extractSecurity(normalizedDocument),
|
|
496
544
|
servers: this.extractServers(normalizedDocument, document),
|
|
497
545
|
metadata: this.extractMetadata(normalizedDocument)
|
|
498
|
-
};
|
|
546
|
+
});
|
|
499
547
|
}
|
|
500
548
|
detectVersion(document) {
|
|
501
549
|
if (!document || typeof document !== "object") {
|
|
@@ -530,7 +578,7 @@ var OpenApiSchemaParser = class {
|
|
|
530
578
|
info: v2Doc.info,
|
|
531
579
|
servers: v2Doc.host ? [
|
|
532
580
|
{
|
|
533
|
-
url: `${v2Doc.schemes?.[0]
|
|
581
|
+
url: `${v2Doc.schemes?.[0] ?? "https"}://${v2Doc.host}${v2Doc.basePath ?? ""}`
|
|
534
582
|
}
|
|
535
583
|
] : [],
|
|
536
584
|
paths: {},
|
|
@@ -675,20 +723,20 @@ var OpenApiSchemaParser = class {
|
|
|
675
723
|
flows: {
|
|
676
724
|
implicit: v2Scheme.flow === "implicit" ? {
|
|
677
725
|
authorizationUrl: v2Scheme.authorizationUrl,
|
|
678
|
-
scopes: v2Scheme.scopes
|
|
726
|
+
scopes: v2Scheme.scopes ?? {}
|
|
679
727
|
} : void 0,
|
|
680
728
|
password: v2Scheme.flow === "password" ? {
|
|
681
729
|
tokenUrl: v2Scheme.tokenUrl,
|
|
682
|
-
scopes: v2Scheme.scopes
|
|
730
|
+
scopes: v2Scheme.scopes ?? {}
|
|
683
731
|
} : void 0,
|
|
684
732
|
clientCredentials: v2Scheme.flow === "application" ? {
|
|
685
733
|
tokenUrl: v2Scheme.tokenUrl,
|
|
686
|
-
scopes: v2Scheme.scopes
|
|
734
|
+
scopes: v2Scheme.scopes ?? {}
|
|
687
735
|
} : void 0,
|
|
688
736
|
authorizationCode: v2Scheme.flow === "accessCode" ? {
|
|
689
737
|
authorizationUrl: v2Scheme.authorizationUrl,
|
|
690
738
|
tokenUrl: v2Scheme.tokenUrl,
|
|
691
|
-
scopes: v2Scheme.scopes
|
|
739
|
+
scopes: v2Scheme.scopes ?? {}
|
|
692
740
|
} : void 0
|
|
693
741
|
}
|
|
694
742
|
};
|
|
@@ -714,18 +762,18 @@ var OpenApiSchemaParser = class {
|
|
|
714
762
|
const operation = pathItem[method.toLowerCase()];
|
|
715
763
|
if (!operation) continue;
|
|
716
764
|
const endpoint = {
|
|
717
|
-
id: operation.operationId
|
|
765
|
+
id: operation.operationId ?? `${method.toLowerCase()}_${path3.replace(/[^a-zA-Z0-9]/g, "_")}`,
|
|
718
766
|
path: path3,
|
|
719
767
|
method,
|
|
720
768
|
operationId: operation.operationId,
|
|
721
769
|
summary: operation.summary,
|
|
722
770
|
description: operation.description,
|
|
723
|
-
tags: operation.tags
|
|
771
|
+
tags: operation.tags ?? [],
|
|
724
772
|
parameters: this.extractParameters(operation.parameters, pathItem.parameters, document),
|
|
725
773
|
requestBody: this.extractRequestBody(operation.requestBody, document),
|
|
726
774
|
responses: this.extractResponses(operation.responses, document),
|
|
727
|
-
security: operation.security
|
|
728
|
-
deprecated: operation.deprecated
|
|
775
|
+
security: operation.security ?? [],
|
|
776
|
+
deprecated: operation.deprecated ?? false,
|
|
729
777
|
metadata: this.extractEndpointMetadata(operation)
|
|
730
778
|
};
|
|
731
779
|
endpoints.push(endpoint);
|
|
@@ -735,7 +783,7 @@ var OpenApiSchemaParser = class {
|
|
|
735
783
|
}
|
|
736
784
|
extractParameters(operationParams, pathParams, document) {
|
|
737
785
|
const parameters = [];
|
|
738
|
-
const allParams = [...pathParams
|
|
786
|
+
const allParams = [...pathParams ?? [], ...operationParams ?? []];
|
|
739
787
|
for (const param of allParams) {
|
|
740
788
|
if (!param) continue;
|
|
741
789
|
if ("$ref" in param) {
|
|
@@ -745,11 +793,11 @@ var OpenApiSchemaParser = class {
|
|
|
745
793
|
const parameter = {
|
|
746
794
|
name: param.name,
|
|
747
795
|
in: param.in,
|
|
748
|
-
required: param.required
|
|
796
|
+
required: param.required ?? param.in === "path",
|
|
749
797
|
schema: this.convertSchemaToZod(param.schema, document),
|
|
750
798
|
description: param.description,
|
|
751
799
|
example: param.example,
|
|
752
|
-
deprecated: param.deprecated
|
|
800
|
+
deprecated: param.deprecated ?? false
|
|
753
801
|
};
|
|
754
802
|
parameters.push(parameter);
|
|
755
803
|
}
|
|
@@ -768,7 +816,7 @@ var OpenApiSchemaParser = class {
|
|
|
768
816
|
}
|
|
769
817
|
}
|
|
770
818
|
return {
|
|
771
|
-
required: requestBody.required
|
|
819
|
+
required: requestBody.required ?? false,
|
|
772
820
|
description: requestBody.description,
|
|
773
821
|
content
|
|
774
822
|
};
|
|
@@ -808,7 +856,7 @@ var OpenApiSchemaParser = class {
|
|
|
808
856
|
schema: this.convertSchemaToZod(schema, document),
|
|
809
857
|
description: schema.description,
|
|
810
858
|
example: schema.example,
|
|
811
|
-
deprecated: schema.deprecated
|
|
859
|
+
deprecated: schema.deprecated ?? false
|
|
812
860
|
});
|
|
813
861
|
}
|
|
814
862
|
}
|
|
@@ -842,7 +890,7 @@ var OpenApiSchemaParser = class {
|
|
|
842
890
|
const v2Doc = originalDoc;
|
|
843
891
|
return [
|
|
844
892
|
{
|
|
845
|
-
url: `${v2Doc.schemes?.[0]
|
|
893
|
+
url: `${v2Doc.schemes?.[0] ?? "https"}://${v2Doc.host}${v2Doc.basePath ?? ""}`,
|
|
846
894
|
description: "Converted from Swagger 2.0"
|
|
847
895
|
}
|
|
848
896
|
];
|
|
@@ -862,9 +910,9 @@ var OpenApiSchemaParser = class {
|
|
|
862
910
|
}
|
|
863
911
|
extractEndpointMetadata(operation) {
|
|
864
912
|
return {
|
|
865
|
-
requiresAuth: operation.security
|
|
913
|
+
requiresAuth: (operation.security?.length ?? 0) > 0,
|
|
866
914
|
cacheStrategy: "default",
|
|
867
|
-
revalidationTags: operation.tags
|
|
915
|
+
revalidationTags: operation.tags ?? [],
|
|
868
916
|
streaming: false,
|
|
869
917
|
fileUpload: this.hasFileUpload(operation)
|
|
870
918
|
};
|
|
@@ -872,7 +920,7 @@ var OpenApiSchemaParser = class {
|
|
|
872
920
|
hasFileUpload(operation) {
|
|
873
921
|
if (!operation.requestBody || "$ref" in operation.requestBody) return false;
|
|
874
922
|
const content = operation.requestBody.content;
|
|
875
|
-
return Object.keys(content
|
|
923
|
+
return Object.keys(content ?? {}).some(
|
|
876
924
|
(mediaType) => mediaType.includes("multipart/form-data") || mediaType.includes("application/octet-stream")
|
|
877
925
|
);
|
|
878
926
|
}
|
|
@@ -960,7 +1008,7 @@ var OpenApiSchemaParser = class {
|
|
|
960
1008
|
case "object":
|
|
961
1009
|
if (schema.properties) {
|
|
962
1010
|
const shape = {};
|
|
963
|
-
const required = schema.required
|
|
1011
|
+
const required = schema.required ?? [];
|
|
964
1012
|
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
965
1013
|
let propZodSchema = this.convertSchemaToZod(propSchema, document);
|
|
966
1014
|
if (!required.includes(propName)) {
|
|
@@ -992,7 +1040,7 @@ var ApiClientGenerator = class {
|
|
|
992
1040
|
* Generate import paths based on configuration
|
|
993
1041
|
*/
|
|
994
1042
|
buildImportPath(relativePath) {
|
|
995
|
-
const outputDirectory = this.configuration.outputDir
|
|
1043
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
996
1044
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
997
1045
|
let importBasePath = outputDirectory;
|
|
998
1046
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -1000,24 +1048,24 @@ var ApiClientGenerator = class {
|
|
|
1000
1048
|
}
|
|
1001
1049
|
return `@/${importBasePath}/${cleanPath}`;
|
|
1002
1050
|
}
|
|
1003
|
-
|
|
1051
|
+
generate(context) {
|
|
1004
1052
|
const { schema } = context;
|
|
1005
1053
|
const generatedFiles = [];
|
|
1006
1054
|
generatedFiles.push(this.generateEnhancedBaseClient());
|
|
1007
1055
|
generatedFiles.push(...this.generateEndpointClients(schema.endpoints));
|
|
1008
1056
|
generatedFiles.push(this.generateMainClient(schema.endpoints));
|
|
1009
1057
|
generatedFiles.push(this.generateClientUtilities());
|
|
1010
|
-
return generatedFiles;
|
|
1058
|
+
return Promise.resolve(generatedFiles);
|
|
1011
1059
|
}
|
|
1012
1060
|
generateEnhancedBaseClient() {
|
|
1013
1061
|
const { api, auth } = this.configuration;
|
|
1014
1062
|
const authUtilsImport = this.buildImportPath("auth/utils");
|
|
1015
|
-
const authPath = auth?.authPath
|
|
1016
|
-
const tokenGetter = auth?.tokenGetter
|
|
1063
|
+
const authPath = auth?.authPath ?? "@/lib/auth";
|
|
1064
|
+
const tokenGetter = auth?.tokenGetter ?? "auth";
|
|
1017
1065
|
const content = `/**
|
|
1018
1066
|
* The HTTP client is automatically created by "mulink"
|
|
1019
1067
|
*
|
|
1020
|
-
* Next.js 16.0.
|
|
1068
|
+
* Next.js 16.0.7 Best Practices:
|
|
1021
1069
|
* - Proper separation of client/server code
|
|
1022
1070
|
* - Dynamic imports for server-only modules
|
|
1023
1071
|
* - Works in both Server Components and Client Components
|
|
@@ -1028,7 +1076,7 @@ import { cache } from 'react'
|
|
|
1028
1076
|
|
|
1029
1077
|
/**
|
|
1030
1078
|
* Server-only modules interface
|
|
1031
|
-
* Next.js 16.0.
|
|
1079
|
+
* Next.js 16.0.7: These modules are only available on the server
|
|
1032
1080
|
* We use dynamic imports to avoid bundling them in the client
|
|
1033
1081
|
*/
|
|
1034
1082
|
type NextHeadersModule = typeof import('next/headers')
|
|
@@ -1052,7 +1100,7 @@ function toMutableHeaders(source: NextReadonlyHeaders) {
|
|
|
1052
1100
|
|
|
1053
1101
|
/**
|
|
1054
1102
|
* Lazy load server-only modules only when needed (server-side)
|
|
1055
|
-
* Next.js 16.0.
|
|
1103
|
+
* Next.js 16.0.7: This ensures server-only code is not bundled in the client
|
|
1056
1104
|
*
|
|
1057
1105
|
* @returns Server-only modules or undefined if on client-side
|
|
1058
1106
|
*/
|
|
@@ -1060,7 +1108,7 @@ async function getServerModules() {
|
|
|
1060
1108
|
if (serverOnlyModules !== null) return serverOnlyModules
|
|
1061
1109
|
|
|
1062
1110
|
// Only attempt to import on server-side
|
|
1063
|
-
// Next.js 16.0.
|
|
1111
|
+
// Next.js 16.0.7: typeof window check ensures we're on the server
|
|
1064
1112
|
if (typeof window === 'undefined') {
|
|
1065
1113
|
try {
|
|
1066
1114
|
const headersModule = await import('next/headers').catch(() => null)
|
|
@@ -1286,11 +1334,11 @@ export class BaseApiClient {
|
|
|
1286
1334
|
private readonly middleware: RequestMiddleware[] = []
|
|
1287
1335
|
|
|
1288
1336
|
constructor() {
|
|
1289
|
-
this.baseUrl = process.env.NEXT_PUBLIC_API_URL || process.env.API_BASE_URL || '${api
|
|
1290
|
-
this.defaultTimeout = ${api
|
|
1291
|
-
this.defaultRetries = ${api
|
|
1292
|
-
this.defaultHeaders = ${JSON.stringify(api
|
|
1293
|
-
this.defaultUserAgent = '${api
|
|
1337
|
+
this.baseUrl = process.env.NEXT_PUBLIC_API_URL || process.env.API_BASE_URL || '${api.baseUrl || "http://localhost:3000/api"}'
|
|
1338
|
+
this.defaultTimeout = ${api.timeout || 3e4}
|
|
1339
|
+
this.defaultRetries = ${api.retries || 3}
|
|
1340
|
+
this.defaultHeaders = ${JSON.stringify(api.headers || {}, null, 6)}
|
|
1341
|
+
this.defaultUserAgent = '${api.userAgent || "Mulink-Client/3.4.5"}'
|
|
1294
1342
|
|
|
1295
1343
|
// Add default middleware
|
|
1296
1344
|
this.addMiddleware({
|
|
@@ -1464,16 +1512,26 @@ export class BaseApiClient {
|
|
|
1464
1512
|
}
|
|
1465
1513
|
|
|
1466
1514
|
// Add query parameters with proper encoding
|
|
1515
|
+
// Filter out undefined, null, empty strings, and empty objects to prevent 422 errors
|
|
1467
1516
|
const searchParams = new URLSearchParams()
|
|
1468
1517
|
for (const [key, value] of Object.entries(queryParameters)) {
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1518
|
+
// Skip undefined, null, and empty strings
|
|
1519
|
+
if (value === undefined || value === null || value === '') {
|
|
1520
|
+
continue
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// Skip empty objects (like {})
|
|
1524
|
+
if (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
1525
|
+
continue
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
if (Array.isArray(value)) {
|
|
1529
|
+
value.forEach(v => searchParams.append(key, String(v)))
|
|
1530
|
+
} else if (typeof value === 'object') {
|
|
1531
|
+
// Only serialize non-empty objects
|
|
1532
|
+
searchParams.append(key, JSON.stringify(value))
|
|
1533
|
+
} else {
|
|
1534
|
+
searchParams.append(key, String(value))
|
|
1477
1535
|
}
|
|
1478
1536
|
}
|
|
1479
1537
|
|
|
@@ -1646,7 +1704,7 @@ export class BaseApiClient {
|
|
|
1646
1704
|
controller.abort()
|
|
1647
1705
|
}, timeout)
|
|
1648
1706
|
|
|
1649
|
-
// Next.js 16.0.
|
|
1707
|
+
// Next.js 16.0.7: Build fetch options with cache tags and connection
|
|
1650
1708
|
// Only include next options if we're on the server (Next.js App Router)
|
|
1651
1709
|
const fetchInit: RequestInit & { next?: { tags?: string[]; revalidate?: number | false; connection?: string } } = {
|
|
1652
1710
|
...requestConfig,
|
|
@@ -1654,7 +1712,7 @@ export class BaseApiClient {
|
|
|
1654
1712
|
}
|
|
1655
1713
|
|
|
1656
1714
|
// Add Next.js-specific options only if we have cache tags, revalidate, or connection
|
|
1657
|
-
// Next.js 16.0.
|
|
1715
|
+
// Next.js 16.0.7: Enhanced cache tag support with updateTag
|
|
1658
1716
|
if (cacheTags && cacheTags.length > 0 || revalidate !== undefined || connection) {
|
|
1659
1717
|
fetchInit.next = {}
|
|
1660
1718
|
|
|
@@ -1666,7 +1724,7 @@ export class BaseApiClient {
|
|
|
1666
1724
|
fetchInit.next.revalidate = revalidate === false ? false : revalidate
|
|
1667
1725
|
}
|
|
1668
1726
|
|
|
1669
|
-
// Next.js 16.0.
|
|
1727
|
+
// Next.js 16.0.7: Connection keep-alive for persistent connections
|
|
1670
1728
|
if (connection) {
|
|
1671
1729
|
fetchInit.next.connection = connection
|
|
1672
1730
|
}
|
|
@@ -1674,7 +1732,7 @@ export class BaseApiClient {
|
|
|
1674
1732
|
|
|
1675
1733
|
const response = await fetch(url, fetchInit)
|
|
1676
1734
|
|
|
1677
|
-
// Next.js 16.0.
|
|
1735
|
+
// Next.js 16.0.7: Update cache tags dynamically using updateTag from next/cache
|
|
1678
1736
|
// This allows for granular cache invalidation
|
|
1679
1737
|
if (cacheTags && cacheTags.length > 0) {
|
|
1680
1738
|
try {
|
|
@@ -1938,7 +1996,7 @@ async get<TData>(
|
|
|
1938
1996
|
}
|
|
1939
1997
|
generateClientUtilities() {
|
|
1940
1998
|
const { api } = this.configuration;
|
|
1941
|
-
const errorHandling = api
|
|
1999
|
+
const errorHandling = api.errorHandling;
|
|
1942
2000
|
const enableAuthErrorHandling = errorHandling?.enableAuthErrorHandling !== false;
|
|
1943
2001
|
const authErrorHandlerPath = errorHandling?.authErrorHandlerPath || "@/lib/auth-error-handler";
|
|
1944
2002
|
const authErrorMiddlewareCode = enableAuthErrorHandling ? `
|
|
@@ -2335,7 +2393,7 @@ ${clientMethods}
|
|
|
2335
2393
|
const requestOptionsString = requestOptions.join("\n");
|
|
2336
2394
|
const methodSignature = parameterTypes.length > 1 ? `options: {
|
|
2337
2395
|
${parameterTypes.join("\n ")}
|
|
2338
|
-
}` : parameterTypes.length === 1 && parameterTypes[0].includes("config?") ? "options?: { config?: RequestConfiguration }" : `options: { ${parameterTypes.join(", ")} }`;
|
|
2396
|
+
}` : parameterTypes.length === 1 && parameterTypes[0] && parameterTypes[0].includes("config?") ? "options?: { config?: RequestConfiguration }" : `options: { ${parameterTypes.join(", ")} }`;
|
|
2339
2397
|
if (isQuery) {
|
|
2340
2398
|
return `${documentation}
|
|
2341
2399
|
${methodName} = cache(async (${methodSignature}) => {
|
|
@@ -2606,7 +2664,7 @@ var SchemaGenerator = class {
|
|
|
2606
2664
|
visiting.add(schemaName);
|
|
2607
2665
|
const schema = schemaMap.get(schemaName);
|
|
2608
2666
|
if (schema) {
|
|
2609
|
-
const dependencies = dependencyGraph.get(schemaName)
|
|
2667
|
+
const dependencies = dependencyGraph.get(schemaName) ?? /* @__PURE__ */ new Set();
|
|
2610
2668
|
for (const dep of dependencies) {
|
|
2611
2669
|
if (schemaMap.has(dep)) {
|
|
2612
2670
|
visit(dep);
|
|
@@ -2639,13 +2697,13 @@ var SchemaGenerator = class {
|
|
|
2639
2697
|
findSchemaDependencies(schema) {
|
|
2640
2698
|
const dependencies = [];
|
|
2641
2699
|
const schemaObj = schema.schema;
|
|
2642
|
-
if (schemaObj
|
|
2700
|
+
if (schemaObj?._def) {
|
|
2643
2701
|
this.extractDependenciesFromZodSchema(schemaObj, dependencies);
|
|
2644
2702
|
}
|
|
2645
2703
|
return dependencies;
|
|
2646
2704
|
}
|
|
2647
2705
|
extractDependenciesFromZodSchema(zodSchema, dependencies, visited = /* @__PURE__ */ new Set()) {
|
|
2648
|
-
if (!zodSchema
|
|
2706
|
+
if (!zodSchema?._def) return;
|
|
2649
2707
|
const def = zodSchema._def;
|
|
2650
2708
|
if (def._schemaRef) {
|
|
2651
2709
|
const refName = def._schemaRef;
|
|
@@ -2668,7 +2726,7 @@ var SchemaGenerator = class {
|
|
|
2668
2726
|
case "ZodObject":
|
|
2669
2727
|
if (def.shape) {
|
|
2670
2728
|
const shape = def.shape();
|
|
2671
|
-
for (const [
|
|
2729
|
+
for (const [_key, value] of Object.entries(shape)) {
|
|
2672
2730
|
this.extractDependenciesFromZodSchema(value, dependencies, visited);
|
|
2673
2731
|
}
|
|
2674
2732
|
}
|
|
@@ -2700,7 +2758,7 @@ var SchemaGenerator = class {
|
|
|
2700
2758
|
break;
|
|
2701
2759
|
}
|
|
2702
2760
|
}
|
|
2703
|
-
|
|
2761
|
+
generateSchemasFile(context) {
|
|
2704
2762
|
const { schemas, endpoints } = context.schema;
|
|
2705
2763
|
const imports = ['import { z } from "zod"'];
|
|
2706
2764
|
const schemaExports = [];
|
|
@@ -2734,7 +2792,7 @@ var SchemaGenerator = class {
|
|
|
2734
2792
|
|
|
2735
2793
|
${content}`;
|
|
2736
2794
|
}
|
|
2737
|
-
return {
|
|
2795
|
+
return Promise.resolve({
|
|
2738
2796
|
path: "schemas/index.ts",
|
|
2739
2797
|
content,
|
|
2740
2798
|
type: "typescript",
|
|
@@ -2743,7 +2801,7 @@ ${content}`;
|
|
|
2743
2801
|
imports: ["zod"],
|
|
2744
2802
|
dependencies: []
|
|
2745
2803
|
}
|
|
2746
|
-
};
|
|
2804
|
+
});
|
|
2747
2805
|
}
|
|
2748
2806
|
generateEndpointSchemas(endpoint) {
|
|
2749
2807
|
const definitions = [];
|
|
@@ -2778,6 +2836,9 @@ ${content}`;
|
|
|
2778
2836
|
}
|
|
2779
2837
|
const exportName = `${operationName}RequestSchema`;
|
|
2780
2838
|
const primaryContent = endpoint.requestBody.content[0];
|
|
2839
|
+
if (!primaryContent) {
|
|
2840
|
+
throw new Error(`No content found for request body in ${endpoint.method} ${endpoint.path}`);
|
|
2841
|
+
}
|
|
2781
2842
|
const zodSchemaString = this.zodSchemaToString(primaryContent.schema);
|
|
2782
2843
|
const definition = [
|
|
2783
2844
|
`/**`,
|
|
@@ -2801,17 +2862,22 @@ ${content}`;
|
|
|
2801
2862
|
);
|
|
2802
2863
|
if (successResponses.length > 0) {
|
|
2803
2864
|
const successResponse = successResponses[0];
|
|
2865
|
+
if (!successResponse) {
|
|
2866
|
+
return { definitions, exports };
|
|
2867
|
+
}
|
|
2804
2868
|
let zodSchemaString = "z.void()";
|
|
2805
2869
|
if (successResponse.content && successResponse.content.length > 0) {
|
|
2806
2870
|
const primaryContent = successResponse.content[0];
|
|
2807
|
-
|
|
2871
|
+
if (primaryContent) {
|
|
2872
|
+
zodSchemaString = this.zodSchemaToString(primaryContent.schema);
|
|
2873
|
+
}
|
|
2808
2874
|
}
|
|
2809
2875
|
const exportName = `${operationName}ResponseSchema`;
|
|
2810
2876
|
const definition = [
|
|
2811
2877
|
`/**`,
|
|
2812
2878
|
` * Success response schema for ${endpoint.method} ${endpoint.path}`,
|
|
2813
2879
|
` * Status: ${successResponse.statusCode}`,
|
|
2814
|
-
` * ${successResponse.description}`,
|
|
2880
|
+
` * ${successResponse.description ?? ""}`,
|
|
2815
2881
|
` */`,
|
|
2816
2882
|
`export const ${exportName} = ${zodSchemaString}`,
|
|
2817
2883
|
"",
|
|
@@ -2822,15 +2888,18 @@ ${content}`;
|
|
|
2822
2888
|
}
|
|
2823
2889
|
if (errorResponses.length > 0) {
|
|
2824
2890
|
const errorResponse = errorResponses[0];
|
|
2825
|
-
if (errorResponse
|
|
2891
|
+
if (errorResponse?.content && errorResponse.content.length > 0) {
|
|
2826
2892
|
const exportName = `${operationName}ErrorSchema`;
|
|
2827
2893
|
const primaryContent = errorResponse.content[0];
|
|
2894
|
+
if (!primaryContent) {
|
|
2895
|
+
return { definitions, exports };
|
|
2896
|
+
}
|
|
2828
2897
|
const zodSchemaString = this.zodSchemaToString(primaryContent.schema);
|
|
2829
2898
|
const definition = [
|
|
2830
2899
|
`/**`,
|
|
2831
2900
|
` * Error response schema for ${endpoint.method} ${endpoint.path}`,
|
|
2832
2901
|
` * Status: ${errorResponse.statusCode}`,
|
|
2833
|
-
` * ${errorResponse.description}`,
|
|
2902
|
+
` * ${errorResponse.description ?? ""}`,
|
|
2834
2903
|
` */`,
|
|
2835
2904
|
`export const ${exportName} = ${zodSchemaString}`,
|
|
2836
2905
|
"",
|
|
@@ -2921,8 +2990,8 @@ ${schemaProperties.join(",\n")}
|
|
|
2921
2990
|
};
|
|
2922
2991
|
}
|
|
2923
2992
|
zodSchemaToString(schema, context) {
|
|
2924
|
-
if (!schema
|
|
2925
|
-
if (schema
|
|
2993
|
+
if (!schema?._def) {
|
|
2994
|
+
if (schema?._schemaRef) {
|
|
2926
2995
|
const refName = schema._schemaRef;
|
|
2927
2996
|
const registeredSchema = this.schemaRegistry.get(refName);
|
|
2928
2997
|
if (registeredSchema) {
|
|
@@ -3090,15 +3159,21 @@ export const errorMessages = {
|
|
|
3090
3159
|
const assignments = line.match(/(\w+)\s*[:=]/g);
|
|
3091
3160
|
if (assignments) {
|
|
3092
3161
|
assignments.forEach((match) => {
|
|
3093
|
-
const
|
|
3094
|
-
|
|
3162
|
+
const parts = match.split(/[:=]/);
|
|
3163
|
+
if (parts[0]) {
|
|
3164
|
+
const identifier = parts[0].trim();
|
|
3165
|
+
usedIdentifiers.add(identifier);
|
|
3166
|
+
}
|
|
3095
3167
|
});
|
|
3096
3168
|
}
|
|
3097
3169
|
const functionCalls = line.match(/(\w+)\s*\(/g);
|
|
3098
3170
|
if (functionCalls) {
|
|
3099
3171
|
functionCalls.forEach((match) => {
|
|
3100
|
-
const
|
|
3101
|
-
|
|
3172
|
+
const parts = match.split("(");
|
|
3173
|
+
if (parts[0]) {
|
|
3174
|
+
const identifier = parts[0].trim();
|
|
3175
|
+
usedIdentifiers.add(identifier);
|
|
3176
|
+
}
|
|
3102
3177
|
});
|
|
3103
3178
|
}
|
|
3104
3179
|
if (line.includes("z.infer")) {
|
|
@@ -3116,10 +3191,10 @@ export const errorMessages = {
|
|
|
3116
3191
|
continue;
|
|
3117
3192
|
}
|
|
3118
3193
|
const importMatch = line.match(/import\s*\{([^}]+)\}/);
|
|
3119
|
-
if (importMatch) {
|
|
3194
|
+
if (importMatch?.[1]) {
|
|
3120
3195
|
const imports = importMatch[1].split(",").map((imp) => imp.trim());
|
|
3121
3196
|
const usedImports = imports.filter((imp) => usedIdentifiers.has(imp));
|
|
3122
|
-
if (usedImports.length > 0) {
|
|
3197
|
+
if (usedImports.length > 0 && importMatch[1]) {
|
|
3123
3198
|
cleanedLines.push(line.replace(importMatch[1], usedImports.join(", ")));
|
|
3124
3199
|
} else {
|
|
3125
3200
|
continue;
|
|
@@ -3166,7 +3241,7 @@ var ActionGenerator = class {
|
|
|
3166
3241
|
if (!this.documentationEnabled) {
|
|
3167
3242
|
return "";
|
|
3168
3243
|
}
|
|
3169
|
-
const summary = endpoint.summary
|
|
3244
|
+
const summary = endpoint.summary ?? endpoint.description ?? `${endpoint.method} ${endpoint.path}`;
|
|
3170
3245
|
return `/**
|
|
3171
3246
|
* ${summary}
|
|
3172
3247
|
* @generated from ${endpoint.method} ${endpoint.path}
|
|
@@ -3308,7 +3383,7 @@ ${" ".repeat(indent + 2)}error: error instanceof Error ? error.message : 'Unknow
|
|
|
3308
3383
|
${" ".repeat(indent)}})`;
|
|
3309
3384
|
}
|
|
3310
3385
|
buildImportPath(relativePath) {
|
|
3311
|
-
const outputDirectory = this.configuration.outputDir
|
|
3386
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
3312
3387
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
3313
3388
|
let importBasePath = outputDirectory;
|
|
3314
3389
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -3316,7 +3391,7 @@ ${" ".repeat(indent)}})`;
|
|
|
3316
3391
|
}
|
|
3317
3392
|
return `@/${importBasePath}/${cleanPath}`;
|
|
3318
3393
|
}
|
|
3319
|
-
|
|
3394
|
+
generate(context) {
|
|
3320
3395
|
const { schema, config } = context;
|
|
3321
3396
|
const generatedFiles = [];
|
|
3322
3397
|
const endpointsByTag = this.groupEndpointsByTag(schema.endpoints);
|
|
@@ -3410,7 +3485,7 @@ ${actions}`;
|
|
|
3410
3485
|
dependencies: Object.keys(endpointsByTag).map((tag) => `./${toValidIdentifier(tag)}`)
|
|
3411
3486
|
}
|
|
3412
3487
|
});
|
|
3413
|
-
return generatedFiles;
|
|
3488
|
+
return Promise.resolve(generatedFiles);
|
|
3414
3489
|
}
|
|
3415
3490
|
getOperationName(endpoint) {
|
|
3416
3491
|
if (endpoint.operationId) {
|
|
@@ -3423,7 +3498,7 @@ ${actions}`;
|
|
|
3423
3498
|
const method = this.toPascalCase(endpoint.method.toLowerCase());
|
|
3424
3499
|
return [...pathParts, method].join("");
|
|
3425
3500
|
}
|
|
3426
|
-
generateOptimizedServerAction(endpoint,
|
|
3501
|
+
generateOptimizedServerAction(endpoint, _config) {
|
|
3427
3502
|
const actionName = toActionName(endpoint.operationId || endpoint.id);
|
|
3428
3503
|
const operationName = this.getOperationName(endpoint);
|
|
3429
3504
|
const hasRequestBody = !!endpoint.requestBody;
|
|
@@ -3697,7 +3772,7 @@ var HookGenerator = class {
|
|
|
3697
3772
|
__name(this, "HookGenerator");
|
|
3698
3773
|
}
|
|
3699
3774
|
buildImportPath(relativePath) {
|
|
3700
|
-
const outputDirectory = this.configuration.outputDir
|
|
3775
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
3701
3776
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
3702
3777
|
let importBasePath = outputDirectory;
|
|
3703
3778
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -3705,7 +3780,7 @@ var HookGenerator = class {
|
|
|
3705
3780
|
}
|
|
3706
3781
|
return `@/${importBasePath}/${cleanPath}`;
|
|
3707
3782
|
}
|
|
3708
|
-
|
|
3783
|
+
generate(context) {
|
|
3709
3784
|
const { schema } = context;
|
|
3710
3785
|
const generatedFiles = [];
|
|
3711
3786
|
const endpointsByTag = this.groupEndpointsByTag(schema.endpoints);
|
|
@@ -3838,7 +3913,7 @@ ${Object.keys(endpointsByTag).map((tag) => `export * from './${toValidIdentifier
|
|
|
3838
3913
|
dependencies: ["./useBridgeQuery", ...Object.keys(endpointsByTag).map((tag) => `./${toValidIdentifier(tag)}`)]
|
|
3839
3914
|
}
|
|
3840
3915
|
});
|
|
3841
|
-
return generatedFiles;
|
|
3916
|
+
return Promise.resolve(generatedFiles);
|
|
3842
3917
|
}
|
|
3843
3918
|
getOperationName(endpoint) {
|
|
3844
3919
|
if (endpoint.operationId) {
|
|
@@ -3855,62 +3930,65 @@ ${Object.keys(endpointsByTag).map((tag) => `export * from './${toValidIdentifier
|
|
|
3855
3930
|
const hookName = toHookName(endpoint.operationId || endpoint.id, true);
|
|
3856
3931
|
const actionName = toActionName(endpoint.operationId || endpoint.id);
|
|
3857
3932
|
const operationName = this.getOperationName(endpoint);
|
|
3858
|
-
const queryKey = this.generateQueryKey(endpoint);
|
|
3859
3933
|
const staleTime = this.getStaleTime(endpoint);
|
|
3860
3934
|
const pathParameters = endpoint.parameters.filter((parameter) => parameter.in === "path");
|
|
3861
3935
|
const queryParameters = endpoint.parameters.filter((parameter) => parameter.in === "query");
|
|
3862
3936
|
const hasPageParam = queryParameters.some((param) => param.name === "page");
|
|
3863
3937
|
const hasSearchParams = endpoint.path.includes("search") || endpoint.path.includes("list");
|
|
3864
|
-
|
|
3865
|
-
const
|
|
3938
|
+
const pathParamTypes = [];
|
|
3939
|
+
const queryParamTypes = [];
|
|
3866
3940
|
pathParameters.forEach((param) => {
|
|
3867
3941
|
const isRequired = param.required ? "" : "?";
|
|
3868
3942
|
const paramType = this.getTypeFromZodSchema(param.schema);
|
|
3869
|
-
|
|
3943
|
+
pathParamTypes.push(`${param.name}${isRequired}: ${paramType}`);
|
|
3870
3944
|
});
|
|
3871
3945
|
queryParameters.forEach((param) => {
|
|
3872
3946
|
const isRequired = param.required ? "" : "?";
|
|
3873
3947
|
const paramType = this.getTypeFromZodSchema(param.schema);
|
|
3874
|
-
|
|
3948
|
+
queryParamTypes.push(`${param.name}${isRequired}: ${paramType}`);
|
|
3875
3949
|
});
|
|
3876
3950
|
const returnType = `z.infer<typeof ${operationName}ResponseSchema>`;
|
|
3877
3951
|
const optionsType = `{ enabled?: boolean; suspense?: boolean; refetchInterval?: number; initialData?: ${returnType} }`;
|
|
3878
|
-
const
|
|
3879
|
-
|
|
3952
|
+
const paramsTypeParts = [];
|
|
3953
|
+
if (pathParameters.length > 0) {
|
|
3954
|
+
paramsTypeParts.push(`path: { ${pathParamTypes.join("; ")} }`);
|
|
3955
|
+
}
|
|
3956
|
+
if (queryParameters.length > 0) {
|
|
3957
|
+
paramsTypeParts.push(`query?: { ${queryParamTypes.join("; ")} }`);
|
|
3958
|
+
}
|
|
3959
|
+
const paramsType = paramsTypeParts.length > 0 ? `{ ${paramsTypeParts.join("; ")} }` : "{}";
|
|
3960
|
+
const enabledCondition = pathParameters.length > 0 && pathParameters[0] ? `!!params?.path?.${pathParameters[0].name}` : "true";
|
|
3961
|
+
const pathParamsBuild = pathParameters.length > 0 ? `{ ${pathParameters.map((p) => `${p.name}: params.path.${p.name}`).join(", ")} }` : "{}";
|
|
3962
|
+
const queryParamsBuild = queryParameters.length > 0 ? `{ ${queryParameters.map((p) => `${p.name}: params?.query?.${p.name}`).join(", ")} }` : "{}";
|
|
3880
3963
|
if (hasSearchParams) {
|
|
3881
|
-
const
|
|
3882
|
-
const isRequired = param.required;
|
|
3883
|
-
const paramType = this.getTypeFromZodSchema(param.schema);
|
|
3884
|
-
return `${param.name}${isRequired ? "" : "?"}: ${paramType}`;
|
|
3885
|
-
}).join("; ");
|
|
3886
|
-
const queryParamsBuild = queryParameters.length > 0 ? `// Build query params object with only the parameters the endpoint expects
|
|
3887
|
-
const queryParams: { ${queryParamTypes} } = {
|
|
3964
|
+
const queryParamsWithFallback = queryParameters.length > 0 ? `const queryParams = {
|
|
3888
3965
|
${queryParameters.map((param) => {
|
|
3889
3966
|
if (param.name === "query") {
|
|
3890
|
-
return `${param.name}:
|
|
3967
|
+
return `${param.name}: params?.query?.${param.name} || searchParams.search || ''`;
|
|
3891
3968
|
} else if (param.name === "limit") {
|
|
3892
|
-
return `${param.name}:
|
|
3969
|
+
return `${param.name}: params?.query?.${param.name} !== undefined ? params.query.${param.name} : searchParams.limit`;
|
|
3893
3970
|
} else {
|
|
3894
|
-
return `${param.name}:
|
|
3971
|
+
return `${param.name}: params?.query?.${param.name}`;
|
|
3895
3972
|
}
|
|
3896
3973
|
}).join(",\n ")}
|
|
3897
|
-
}` : "";
|
|
3898
|
-
const queryParamObject = queryParameters.length > 0 ? `{ ${queryParameters.map((param) => `${param.name}`).join(", ")} }` : "{}";
|
|
3974
|
+
}` : "const queryParams = {}";
|
|
3899
3975
|
return `/**
|
|
3900
3976
|
* Optimized query hook for ${endpoint.method} ${endpoint.path}
|
|
3901
3977
|
* Features: URL state sync, infinite loading, optimistic updates
|
|
3978
|
+
* @param params - Named parameters object with path and query parameters
|
|
3979
|
+
* @param options - Query options
|
|
3902
3980
|
* @returns useQuery result with data of type ${returnType}
|
|
3903
3981
|
*/
|
|
3904
|
-
export function ${hookName}(${
|
|
3982
|
+
export function ${hookName}(params${pathParameters.length > 0 ? "" : "?"}: ${paramsType}, options?: ${optionsType}) {
|
|
3905
3983
|
const [searchParams] = useQueryStates(searchParamsParser)
|
|
3906
3984
|
const { initialData, ...restOptions } = options ?? {}
|
|
3907
3985
|
|
|
3908
3986
|
return useQuery({
|
|
3909
|
-
queryKey: [
|
|
3987
|
+
queryKey: ['${toActionName(endpoint.operationId || endpoint.id)}', ${pathParameters.length > 0 ? "params?.path" : "null"}, params?.query, searchParams],
|
|
3910
3988
|
queryFn: async ({ signal }: { signal?: AbortSignal }) => {
|
|
3911
3989
|
try {
|
|
3912
|
-
${
|
|
3913
|
-
const result = await resolveActionResult<${returnType}>(${actionName}(${
|
|
3990
|
+
${queryParamsWithFallback}
|
|
3991
|
+
const result = await resolveActionResult<${returnType}>(${actionName}(${pathParameters.length > 0 ? `{ path: ${pathParamsBuild}, query: queryParams }` : "{ query: queryParams }"}))
|
|
3914
3992
|
return result
|
|
3915
3993
|
} catch (error) {
|
|
3916
3994
|
handleActionError(error)
|
|
@@ -3938,32 +4016,33 @@ export function ${hookName}(${parameterTypes.length > 0 ? `${parameterTypes.join
|
|
|
3938
4016
|
|
|
3939
4017
|
/**
|
|
3940
4018
|
* Infinite query version for paginated ${endpoint.path}
|
|
4019
|
+
* @param params - Named parameters object with path and query parameters
|
|
4020
|
+
* @param options - Query options
|
|
3941
4021
|
* @returns useInfiniteQuery result with data of type ${returnType}
|
|
3942
4022
|
*/
|
|
3943
|
-
export function ${hookName.replace("use", "useInfinite")}(${
|
|
4023
|
+
export function ${hookName.replace("use", "useInfinite")}(params${pathParameters.length > 0 ? "" : "?"}: ${paramsType}, options?: ${optionsType}) {
|
|
3944
4024
|
const [searchParams] = useQueryStates(searchParamsParser)
|
|
3945
4025
|
const { initialData, ...restOptions } = options ?? {}
|
|
3946
4026
|
|
|
3947
4027
|
return useInfiniteQuery({
|
|
3948
|
-
queryKey: [
|
|
4028
|
+
queryKey: ['${toActionName(endpoint.operationId || endpoint.id)}', ${pathParameters.length > 0 ? "params?.path" : "null"}, params?.query, 'infinite', searchParams],
|
|
3949
4029
|
initialPageParam: 1,
|
|
3950
4030
|
queryFn: async ({ pageParam = 1, signal }: { pageParam?: number; signal?: AbortSignal }) => {
|
|
3951
4031
|
try {
|
|
3952
|
-
|
|
3953
|
-
const queryParams: { ${queryParamTypes} } = {
|
|
4032
|
+
const queryParams = {
|
|
3954
4033
|
${queryParameters.map((param) => {
|
|
3955
4034
|
if (param.name === "page" && hasPageParam) {
|
|
3956
4035
|
return `${param.name}: pageParam`;
|
|
3957
4036
|
} else if (param.name === "query") {
|
|
3958
|
-
return `${param.name}:
|
|
4037
|
+
return `${param.name}: params?.query?.${param.name} || searchParams.search || ''`;
|
|
3959
4038
|
} else if (param.name === "limit") {
|
|
3960
|
-
return `${param.name}:
|
|
4039
|
+
return `${param.name}: params?.query?.${param.name} !== undefined ? params.query.${param.name} : searchParams.limit`;
|
|
3961
4040
|
} else {
|
|
3962
|
-
return `${param.name}:
|
|
4041
|
+
return `${param.name}: params?.query?.${param.name}`;
|
|
3963
4042
|
}
|
|
3964
4043
|
}).join(",\n ")}
|
|
3965
4044
|
}
|
|
3966
|
-
const result = await resolveActionResult<${returnType}>(${actionName}(${
|
|
4045
|
+
const result = await resolveActionResult<${returnType}>(${actionName}(${pathParameters.length > 0 ? `{ path: ${pathParamsBuild}, query: queryParams }` : "{ query: queryParams }"}))
|
|
3967
4046
|
return result
|
|
3968
4047
|
} catch (error) {
|
|
3969
4048
|
handleActionError(error)
|
|
@@ -4005,15 +4084,17 @@ export function ${hookName.replace("use", "useInfinite")}(${parameterTypes.lengt
|
|
|
4005
4084
|
|
|
4006
4085
|
/**
|
|
4007
4086
|
* Suspense version for ${endpoint.path} - use in Server Components
|
|
4087
|
+
* @param params - Named parameters object with path and query parameters
|
|
4088
|
+
* @param options - Query options
|
|
4008
4089
|
* @returns useSuspenseQuery result with data of type ${returnType}
|
|
4009
4090
|
*/
|
|
4010
|
-
export function ${hookName.replace("use", "useSuspense")}(${
|
|
4091
|
+
export function ${hookName.replace("use", "useSuspense")}(params${pathParameters.length > 0 ? "" : "?"}: ${paramsType}, options?: ${optionsType}) {
|
|
4011
4092
|
const { initialData, ...restOptions } = options ?? {}
|
|
4012
4093
|
|
|
4013
4094
|
return useSuspenseQuery({
|
|
4014
|
-
queryKey: ${
|
|
4095
|
+
queryKey: ['${toActionName(endpoint.operationId || endpoint.id)}', ${pathParameters.length > 0 ? "params?.path" : "null"}, params?.query],
|
|
4015
4096
|
queryFn: async () => {
|
|
4016
|
-
const result = await resolveActionResult<${returnType}>(${actionName}(${
|
|
4097
|
+
const result = await resolveActionResult<${returnType}>(${actionName}(${pathParameters.length > 0 ? `{ path: ${pathParamsBuild}, query: ${queryParamsBuild} }` : `{ query: ${queryParamsBuild} }`}))
|
|
4017
4098
|
return result
|
|
4018
4099
|
},
|
|
4019
4100
|
staleTime: ${staleTime},
|
|
@@ -4025,16 +4106,18 @@ export function ${hookName.replace("use", "useSuspense")}(${parameterTypes.lengt
|
|
|
4025
4106
|
return `/**
|
|
4026
4107
|
* Optimized query hook for ${endpoint.method} ${endpoint.path}
|
|
4027
4108
|
* Features: Smart caching, error handling, type safety
|
|
4109
|
+
* @param params - Named parameters object with path and query parameters
|
|
4110
|
+
* @param options - Query options
|
|
4028
4111
|
* @returns useQuery result with data of type ${returnType}
|
|
4029
4112
|
*/
|
|
4030
|
-
export function ${hookName}(${
|
|
4113
|
+
export function ${hookName}(params${pathParameters.length > 0 ? "" : "?"}: ${paramsType}, options?: ${optionsType}) {
|
|
4031
4114
|
const { initialData, ...restOptions } = options ?? {}
|
|
4032
4115
|
|
|
4033
4116
|
return useQuery({
|
|
4034
|
-
queryKey: ${
|
|
4117
|
+
queryKey: ['${toActionName(endpoint.operationId || endpoint.id)}', ${pathParameters.length > 0 ? "params?.path" : "null"}, params?.query],
|
|
4035
4118
|
queryFn: async ({ signal }: { signal?: AbortSignal }) => {
|
|
4036
4119
|
try {
|
|
4037
|
-
const result = await resolveActionResult<${returnType}>(${
|
|
4120
|
+
const result = await resolveActionResult<${returnType}>(${actionName}(${pathParameters.length > 0 ? `{ path: ${pathParamsBuild}, query: ${queryParamsBuild} }` : `{ query: ${queryParamsBuild} }`}))
|
|
4038
4121
|
return result
|
|
4039
4122
|
} catch (error) {
|
|
4040
4123
|
handleActionError(error)
|
|
@@ -4062,15 +4145,17 @@ export function ${hookName}(${parameterTypes.length > 0 ? `${parameterTypes.join
|
|
|
4062
4145
|
|
|
4063
4146
|
/**
|
|
4064
4147
|
* Suspense version for ${endpoint.path}
|
|
4148
|
+
* @param params - Named parameters object with path and query parameters
|
|
4149
|
+
* @param options - Query options
|
|
4065
4150
|
* @returns useSuspenseQuery result with data of type ${returnType}
|
|
4066
4151
|
*/
|
|
4067
|
-
export function ${hookName.replace("use", "useSuspense")}(${
|
|
4152
|
+
export function ${hookName.replace("use", "useSuspense")}(params${pathParameters.length > 0 ? "" : "?"}: ${paramsType}, options?: ${optionsType}) {
|
|
4068
4153
|
const { initialData, ...restOptions } = options ?? {}
|
|
4069
4154
|
|
|
4070
4155
|
return useSuspenseQuery({
|
|
4071
|
-
queryKey: ${
|
|
4156
|
+
queryKey: ['${toActionName(endpoint.operationId || endpoint.id)}', ${pathParameters.length > 0 ? "params?.path" : "null"}, params?.query],
|
|
4072
4157
|
queryFn: async () => {
|
|
4073
|
-
const result = await resolveActionResult<${returnType}>(${
|
|
4158
|
+
const result = await resolveActionResult<${returnType}>(${actionName}(${pathParameters.length > 0 ? `{ path: ${pathParamsBuild}, query: ${queryParamsBuild} }` : `{ query: ${queryParamsBuild} }`}))
|
|
4074
4159
|
return result
|
|
4075
4160
|
},
|
|
4076
4161
|
staleTime: ${staleTime},
|
|
@@ -4185,7 +4270,7 @@ ${invalidationCode}
|
|
|
4185
4270
|
* Find related queries that should be invalidated when this mutation runs
|
|
4186
4271
|
*/
|
|
4187
4272
|
findRelatedQueries(endpoint, context) {
|
|
4188
|
-
if (!context?.schema
|
|
4273
|
+
if (!context?.schema.endpoints) {
|
|
4189
4274
|
return [];
|
|
4190
4275
|
}
|
|
4191
4276
|
const relatedQueries = [];
|
|
@@ -4319,7 +4404,6 @@ ${invalidationCode}
|
|
|
4319
4404
|
buildActionCallParams(endpoint, isMutation) {
|
|
4320
4405
|
const pathParameters = endpoint.parameters.filter((parameter) => parameter.in === "path");
|
|
4321
4406
|
const queryParameters = endpoint.parameters.filter((parameter) => parameter.in === "query");
|
|
4322
|
-
!!endpoint.requestBody;
|
|
4323
4407
|
if (isMutation) {
|
|
4324
4408
|
return "variables";
|
|
4325
4409
|
}
|
|
@@ -4400,13 +4484,13 @@ ${invalidationCode}
|
|
|
4400
4484
|
import { useQuery, useMutation, useInfiniteQuery, useSuspenseQuery, type UseQueryOptions, type UseMutationOptions, type UseInfiniteQueryOptions, type UseSuspenseQueryOptions, type QueryKey, type QueryFunction } from '@tanstack/react-query'
|
|
4401
4485
|
|
|
4402
4486
|
/**
|
|
4403
|
-
* Enhanced React Query wrapper hook with Next.js 16.0.
|
|
4487
|
+
* Enhanced React Query wrapper hook with Next.js 16.0.7 optimizations
|
|
4404
4488
|
* Provides consistent defaults across all queries following best practices
|
|
4405
4489
|
*
|
|
4406
4490
|
* Features:
|
|
4407
4491
|
* - React Query v5: Uses gcTime instead of cacheTime
|
|
4408
4492
|
* - React Query v5: Uses placeholderData instead of keepPreviousData
|
|
4409
|
-
* - Next.js 16.0.
|
|
4493
|
+
* - Next.js 16.0.7: Optimized for App Router and Server Components
|
|
4410
4494
|
*/
|
|
4411
4495
|
export function useBridgeQuery<TData = unknown, TError = Error>(
|
|
4412
4496
|
queryKey: QueryKey,
|
|
@@ -4463,7 +4547,7 @@ export function useBridgeInfiniteQuery<TData = unknown, TError = Error, TPagePar
|
|
|
4463
4547
|
|
|
4464
4548
|
/**
|
|
4465
4549
|
* Enhanced suspense query wrapper
|
|
4466
|
-
* Next.js 16.0.
|
|
4550
|
+
* Next.js 16.0.7: Optimized for Server Components with Suspense
|
|
4467
4551
|
*/
|
|
4468
4552
|
export function useBridgeSuspenseQuery<TData = unknown, TError = Error>(
|
|
4469
4553
|
queryKey: QueryKey,
|
|
@@ -4519,7 +4603,7 @@ var AuthGenerator = class {
|
|
|
4519
4603
|
__name(this, "AuthGenerator");
|
|
4520
4604
|
}
|
|
4521
4605
|
buildImportPath(relativePath) {
|
|
4522
|
-
const outputDirectory = this.configuration.outputDir
|
|
4606
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
4523
4607
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
4524
4608
|
let importBasePath = outputDirectory;
|
|
4525
4609
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -4527,11 +4611,11 @@ var AuthGenerator = class {
|
|
|
4527
4611
|
}
|
|
4528
4612
|
return `@/${importBasePath}/${cleanPath}`;
|
|
4529
4613
|
}
|
|
4530
|
-
|
|
4614
|
+
generate(context) {
|
|
4531
4615
|
const { config, schema } = context;
|
|
4532
4616
|
const authConfig = config.auth;
|
|
4533
4617
|
if (!authConfig?.enabled) {
|
|
4534
|
-
return [];
|
|
4618
|
+
return Promise.resolve([]);
|
|
4535
4619
|
}
|
|
4536
4620
|
const files = [];
|
|
4537
4621
|
const authEndpoints = this.findAuthEndpoints(schema.endpoints);
|
|
@@ -4546,7 +4630,7 @@ var AuthGenerator = class {
|
|
|
4546
4630
|
files.push(...this.generateAuthComponents(authEndpoints));
|
|
4547
4631
|
files.push(this.generateAuthMiddleware());
|
|
4548
4632
|
files.push(this.generateAuthContext());
|
|
4549
|
-
return files;
|
|
4633
|
+
return Promise.resolve(files);
|
|
4550
4634
|
}
|
|
4551
4635
|
findAuthEndpoints(endpoints) {
|
|
4552
4636
|
const authEndpoints = {};
|
|
@@ -4579,12 +4663,12 @@ var AuthGenerator = class {
|
|
|
4579
4663
|
}
|
|
4580
4664
|
return userEndpoints;
|
|
4581
4665
|
}
|
|
4582
|
-
generateAuthSchemas(
|
|
4666
|
+
generateAuthSchemas(_authEndpoints, _schema) {
|
|
4583
4667
|
this.buildImportPath("schemas");
|
|
4584
|
-
const loginRequestSchema =
|
|
4668
|
+
const loginRequestSchema = _authEndpoints.login?.requestBody?.content?.find(
|
|
4585
4669
|
(c) => c.type === "application/json"
|
|
4586
4670
|
)?.schema;
|
|
4587
|
-
const loginResponseSchema =
|
|
4671
|
+
const loginResponseSchema = _authEndpoints.login?.responses?.find(
|
|
4588
4672
|
(r) => r.statusCode === "200"
|
|
4589
4673
|
)?.content?.[0]?.schema;
|
|
4590
4674
|
const content = `import { z } from "zod"
|
|
@@ -4685,7 +4769,7 @@ export type Session = z.infer<typeof sessionSchema>`;
|
|
|
4685
4769
|
}
|
|
4686
4770
|
};
|
|
4687
4771
|
}
|
|
4688
|
-
generateAuthTypes(
|
|
4772
|
+
generateAuthTypes(_authEndpoints, _schema) {
|
|
4689
4773
|
const schemasImport = this.buildImportPath("auth/schemas");
|
|
4690
4774
|
const content = `// Auto-generated authentication types
|
|
4691
4775
|
import type {
|
|
@@ -5231,7 +5315,7 @@ export const useRequireAuth = (redirectTo?: string) => {
|
|
|
5231
5315
|
}
|
|
5232
5316
|
};
|
|
5233
5317
|
}
|
|
5234
|
-
generateAuthActions(
|
|
5318
|
+
generateAuthActions(_authEndpoints, _userEndpoints) {
|
|
5235
5319
|
const safeActionImport = this.buildImportPath("lib/safe-action");
|
|
5236
5320
|
const schemasImport = this.buildImportPath("auth/schemas");
|
|
5237
5321
|
const clientImport = this.buildImportPath("auth/client");
|
|
@@ -5463,7 +5547,7 @@ export const useCredentialsLogin = () => {
|
|
|
5463
5547
|
}
|
|
5464
5548
|
};
|
|
5465
5549
|
}
|
|
5466
|
-
generateAuthComponents(
|
|
5550
|
+
generateAuthComponents(_authEndpoints) {
|
|
5467
5551
|
const loginForm = {
|
|
5468
5552
|
path: "auth/components/login-form.tsx",
|
|
5469
5553
|
content: `"use client"
|
|
@@ -5583,7 +5667,6 @@ export function LoginForm() {
|
|
|
5583
5667
|
return [loginForm];
|
|
5584
5668
|
}
|
|
5585
5669
|
generateAuthMiddleware() {
|
|
5586
|
-
this.buildImportPath("auth/utils");
|
|
5587
5670
|
const content = `import { NextResponse } from "next/server"
|
|
5588
5671
|
import type { NextRequest } from "next/server"
|
|
5589
5672
|
|
|
@@ -5951,9 +6034,10 @@ var SchemaAnalyzer = class {
|
|
|
5951
6034
|
}
|
|
5952
6035
|
if (response.description) {
|
|
5953
6036
|
const errorMatch = response.description.match(/error[_\s]?code[:\s]+(\w+)/i);
|
|
5954
|
-
if (errorMatch) {
|
|
5955
|
-
|
|
5956
|
-
|
|
6037
|
+
if (errorMatch?.[1]) {
|
|
6038
|
+
const errorCode = errorMatch[1];
|
|
6039
|
+
errorCodes.set(errorCode.toLowerCase(), {
|
|
6040
|
+
code: errorCode,
|
|
5957
6041
|
status,
|
|
5958
6042
|
message: response.description
|
|
5959
6043
|
});
|
|
@@ -6039,7 +6123,7 @@ var SchemaAnalyzer = class {
|
|
|
6039
6123
|
const endpoints = {};
|
|
6040
6124
|
for (const endpoint of this.schema.endpoints) {
|
|
6041
6125
|
const path3 = endpoint.path.toLowerCase();
|
|
6042
|
-
const operationId = (endpoint.operationId
|
|
6126
|
+
const operationId = (endpoint.operationId ?? "").toLowerCase();
|
|
6043
6127
|
if ((path3.includes("/auth/login/credentials") || operationId.includes("logincredentials") || operationId.includes("signin")) && endpoint.method === "POST") {
|
|
6044
6128
|
endpoints.loginCredentials = endpoint;
|
|
6045
6129
|
} else if ((path3.includes("/auth/login") || operationId.includes("login")) && endpoint.method === "POST" && !endpoints.loginCredentials) {
|
|
@@ -6087,12 +6171,12 @@ var SchemaAnalyzer = class {
|
|
|
6087
6171
|
extractSessionConfig() {
|
|
6088
6172
|
const config = {};
|
|
6089
6173
|
const sessionEndpoints = this.schema.endpoints.filter(
|
|
6090
|
-
(e) => e.path.toLowerCase().includes("/session") || (e.operationId
|
|
6174
|
+
(e) => e.path.toLowerCase().includes("/session") || (e.operationId ?? "").toLowerCase().includes("session")
|
|
6091
6175
|
);
|
|
6092
6176
|
for (const endpoint of sessionEndpoints) {
|
|
6093
6177
|
for (const response of endpoint.responses) {
|
|
6094
6178
|
if (response.headers) {
|
|
6095
|
-
for (const [headerName,
|
|
6179
|
+
for (const [headerName, _headerDef] of Object.entries(response.headers)) {
|
|
6096
6180
|
if (headerName.toLowerCase().includes("expires") || headerName.toLowerCase().includes("max-age")) ;
|
|
6097
6181
|
}
|
|
6098
6182
|
}
|
|
@@ -6172,7 +6256,7 @@ var SchemaAnalyzer = class {
|
|
|
6172
6256
|
/**
|
|
6173
6257
|
* Check if OAuth provider is supported
|
|
6174
6258
|
*/
|
|
6175
|
-
isOAuthProviderSupported(
|
|
6259
|
+
isOAuthProviderSupported(_provider) {
|
|
6176
6260
|
const extractedEndpoints = this.extractAuthEndpoints();
|
|
6177
6261
|
return !!(extractedEndpoints.oauthAuthorize && extractedEndpoints.oauthCallback);
|
|
6178
6262
|
}
|
|
@@ -6254,7 +6338,7 @@ var SchemaAnalyzer = class {
|
|
|
6254
6338
|
errorCodes.set(code.toLowerCase(), {
|
|
6255
6339
|
code,
|
|
6256
6340
|
status,
|
|
6257
|
-
message: schema.properties?.detail?.default
|
|
6341
|
+
message: schema.properties?.detail?.default ?? schema.properties?.message?.default ?? ""
|
|
6258
6342
|
});
|
|
6259
6343
|
});
|
|
6260
6344
|
}
|
|
@@ -6263,9 +6347,10 @@ var SchemaAnalyzer = class {
|
|
|
6263
6347
|
const detail = schema.properties.detail;
|
|
6264
6348
|
if (typeof detail === "string") {
|
|
6265
6349
|
const codeMatch = detail.match(/(\w+)[_\s]?error/i);
|
|
6266
|
-
if (codeMatch) {
|
|
6267
|
-
|
|
6268
|
-
|
|
6350
|
+
if (codeMatch?.[1]) {
|
|
6351
|
+
const errorCode = codeMatch[1];
|
|
6352
|
+
errorCodes.set(errorCode.toLowerCase(), {
|
|
6353
|
+
code: errorCode,
|
|
6269
6354
|
status,
|
|
6270
6355
|
message: detail
|
|
6271
6356
|
});
|
|
@@ -6277,11 +6362,11 @@ var SchemaAnalyzer = class {
|
|
|
6277
6362
|
if (!schema || typeof schema !== "object") return;
|
|
6278
6363
|
if (schema.properties?.file) {
|
|
6279
6364
|
const fileSchema = schema.properties.file;
|
|
6280
|
-
if (fileSchema.maxSize
|
|
6281
|
-
config.maxSize = fileSchema.maxSize
|
|
6365
|
+
if (fileSchema.maxSize ?? fileSchema["x-max-size"]) {
|
|
6366
|
+
config.maxSize = fileSchema.maxSize ?? fileSchema["x-max-size"];
|
|
6282
6367
|
}
|
|
6283
|
-
if (fileSchema.allowedTypes
|
|
6284
|
-
config.allowedTypes = fileSchema.allowedTypes
|
|
6368
|
+
if (fileSchema.allowedTypes ?? fileSchema["x-allowed-types"]) {
|
|
6369
|
+
config.allowedTypes = fileSchema.allowedTypes ?? fileSchema["x-allowed-types"];
|
|
6285
6370
|
}
|
|
6286
6371
|
}
|
|
6287
6372
|
if (schema["x-file-constraints"]) {
|
|
@@ -6301,7 +6386,7 @@ var NextAuthGenerator = class {
|
|
|
6301
6386
|
analyzer;
|
|
6302
6387
|
accountStatusPatterns;
|
|
6303
6388
|
buildImportPath(relativePath) {
|
|
6304
|
-
const outputDirectory = this.configuration.outputDir
|
|
6389
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
6305
6390
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
6306
6391
|
let importBasePath = outputDirectory;
|
|
6307
6392
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -6309,11 +6394,11 @@ var NextAuthGenerator = class {
|
|
|
6309
6394
|
}
|
|
6310
6395
|
return `@/${importBasePath}/${cleanPath}`;
|
|
6311
6396
|
}
|
|
6312
|
-
|
|
6397
|
+
generate(context) {
|
|
6313
6398
|
const { config, schema } = context;
|
|
6314
6399
|
const authConfig = config.auth;
|
|
6315
6400
|
if (!authConfig?.enabled || authConfig.provider !== "next-auth") {
|
|
6316
|
-
return [];
|
|
6401
|
+
return Promise.resolve([]);
|
|
6317
6402
|
}
|
|
6318
6403
|
this.analyzer = new SchemaAnalyzer(schema);
|
|
6319
6404
|
this.accountStatusPatterns = this.analyzer.extractAccountStatusPatterns();
|
|
@@ -6330,7 +6415,7 @@ var NextAuthGenerator = class {
|
|
|
6330
6415
|
console.warn("These features will be disabled in generated code.\n");
|
|
6331
6416
|
}
|
|
6332
6417
|
const detectedOAuthProviders = this.analyzer.extractOAuthProviders();
|
|
6333
|
-
const configuredOAuthProviders = authConfig.oauth?.providers
|
|
6418
|
+
const configuredOAuthProviders = authConfig.oauth?.providers ?? [];
|
|
6334
6419
|
const validOAuthProviders = configuredOAuthProviders.filter(
|
|
6335
6420
|
(provider) => this.analyzer.isOAuthProviderSupported(provider)
|
|
6336
6421
|
);
|
|
@@ -6341,7 +6426,7 @@ var NextAuthGenerator = class {
|
|
|
6341
6426
|
console.warn(
|
|
6342
6427
|
`\u26A0\uFE0F NextAuth is enabled but login endpoints are not found in OpenAPI schema. Expected endpoints: /auth/login or /auth/login/credentials. NextAuth configuration will not be generated.`
|
|
6343
6428
|
);
|
|
6344
|
-
return files;
|
|
6429
|
+
return Promise.resolve(files);
|
|
6345
6430
|
}
|
|
6346
6431
|
files.push(this.generateNextAuthConfig(
|
|
6347
6432
|
extractedEndpoints,
|
|
@@ -6354,7 +6439,7 @@ var NextAuthGenerator = class {
|
|
|
6354
6439
|
if (hasPasskeys) {
|
|
6355
6440
|
files.push(this.generatePasskeyUtils(extractedEndpoints));
|
|
6356
6441
|
}
|
|
6357
|
-
return files;
|
|
6442
|
+
return Promise.resolve(files);
|
|
6358
6443
|
}
|
|
6359
6444
|
findAuthEndpoints(endpoints) {
|
|
6360
6445
|
const authEndpoints = {};
|
|
@@ -6457,14 +6542,14 @@ var NextAuthGenerator = class {
|
|
|
6457
6542
|
}
|
|
6458
6543
|
generateNextAuthConfig(extractedEndpoints, oauthProviders, hasMFA, hasPasskeys) {
|
|
6459
6544
|
const authConfig = this.configuration.auth;
|
|
6460
|
-
const apiBaseUrl = this.configuration.api
|
|
6545
|
+
const apiBaseUrl = this.configuration.api.baseUrl || "http://localhost:8000";
|
|
6461
6546
|
const apiUrl = `process.env.NEXT_PUBLIC_API_URL || '${apiBaseUrl}'`;
|
|
6462
6547
|
const hasGoogle = oauthProviders.includes("google");
|
|
6463
6548
|
const hasGitHub = oauthProviders.includes("github");
|
|
6464
6549
|
oauthProviders.includes("discord");
|
|
6465
6550
|
oauthProviders.includes("microsoft");
|
|
6466
6551
|
oauthProviders.includes("apple");
|
|
6467
|
-
const { activeStatuses, inactiveStatuses, suspendedStatuses, lockedStatuses } = this.accountStatusPatterns;
|
|
6552
|
+
const { activeStatuses, inactiveStatuses, suspendedStatuses, lockedStatuses: _lockedStatuses } = this.accountStatusPatterns;
|
|
6468
6553
|
this.analyzer.extractErrorCodes();
|
|
6469
6554
|
const sessionStrategy = authConfig.session?.strategy || "jwt";
|
|
6470
6555
|
const sessionMaxAge = authConfig.session?.maxAge || 7 * 24 * 60 * 60;
|
|
@@ -7013,7 +7098,7 @@ export async function authenticateWithPasskey(email?: string) {
|
|
|
7013
7098
|
}
|
|
7014
7099
|
};
|
|
7015
7100
|
}
|
|
7016
|
-
generateAuthTypes(
|
|
7101
|
+
generateAuthTypes(_authEndpoints, _accountStatusPatterns) {
|
|
7017
7102
|
const content = `/**
|
|
7018
7103
|
* Authentication Types
|
|
7019
7104
|
* Auto-generated by Mulink
|
|
@@ -7084,7 +7169,7 @@ export class AccountInactiveError extends AuthError {
|
|
|
7084
7169
|
}
|
|
7085
7170
|
};
|
|
7086
7171
|
}
|
|
7087
|
-
generateAuthUtils(
|
|
7172
|
+
generateAuthUtils(_authEndpoints) {
|
|
7088
7173
|
const content = `/**
|
|
7089
7174
|
* Authentication Utilities
|
|
7090
7175
|
* Auto-generated by Mulink
|
|
@@ -7137,7 +7222,7 @@ export async function requireAuth() {
|
|
|
7137
7222
|
}
|
|
7138
7223
|
};
|
|
7139
7224
|
}
|
|
7140
|
-
generatePasskeyUtils(
|
|
7225
|
+
generatePasskeyUtils(_passkeyEndpoints) {
|
|
7141
7226
|
const content = `/**
|
|
7142
7227
|
* Passkey (WebAuthn) Utilities
|
|
7143
7228
|
* Auto-generated by Mulink
|
|
@@ -7190,7 +7275,7 @@ var MiddlewareGenerator = class {
|
|
|
7190
7275
|
__name(this, "MiddlewareGenerator");
|
|
7191
7276
|
}
|
|
7192
7277
|
buildImportPath(relativePath) {
|
|
7193
|
-
const outputDirectory = this.configuration.outputDir
|
|
7278
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
7194
7279
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
7195
7280
|
let importBasePath = outputDirectory;
|
|
7196
7281
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -7198,7 +7283,7 @@ var MiddlewareGenerator = class {
|
|
|
7198
7283
|
}
|
|
7199
7284
|
return `@/${importBasePath}/${cleanPath}`;
|
|
7200
7285
|
}
|
|
7201
|
-
|
|
7286
|
+
generate(_context) {
|
|
7202
7287
|
const files = [];
|
|
7203
7288
|
files.push(this.generateMainMiddleware());
|
|
7204
7289
|
files.push(this.generateRateLimitMiddleware());
|
|
@@ -7206,7 +7291,7 @@ var MiddlewareGenerator = class {
|
|
|
7206
7291
|
files.push(this.generateSecurityMiddleware());
|
|
7207
7292
|
files.push(this.generateLoggingMiddleware());
|
|
7208
7293
|
files.push(this.generateApiMiddleware());
|
|
7209
|
-
return files;
|
|
7294
|
+
return Promise.resolve(files);
|
|
7210
7295
|
}
|
|
7211
7296
|
generateMainMiddleware() {
|
|
7212
7297
|
const authImport = this.buildImportPath("auth/middleware");
|
|
@@ -7613,7 +7698,7 @@ var UploadGenerator = class {
|
|
|
7613
7698
|
}
|
|
7614
7699
|
analyzer;
|
|
7615
7700
|
buildImportPath(relativePath) {
|
|
7616
|
-
const outputDirectory = this.configuration.outputDir
|
|
7701
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
7617
7702
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
7618
7703
|
let importBasePath = outputDirectory;
|
|
7619
7704
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -7621,19 +7706,19 @@ var UploadGenerator = class {
|
|
|
7621
7706
|
}
|
|
7622
7707
|
return `@/${importBasePath}/${cleanPath}`;
|
|
7623
7708
|
}
|
|
7624
|
-
|
|
7709
|
+
generate(context) {
|
|
7625
7710
|
const { schema } = context;
|
|
7626
7711
|
const generatedFiles = [];
|
|
7627
7712
|
this.analyzer = new SchemaAnalyzer(schema);
|
|
7628
7713
|
const uploadEndpoints = schema.endpoints.filter(
|
|
7629
|
-
(endpoint) => endpoint.requestBody?.content
|
|
7714
|
+
(endpoint) => endpoint.requestBody?.content.some(
|
|
7630
7715
|
(content) => content.type === "multipart/form-data" || content.type === "application/octet-stream"
|
|
7631
7716
|
)
|
|
7632
7717
|
);
|
|
7633
7718
|
if (uploadEndpoints.length === 0 || !this.configuration.uploads?.enabled) {
|
|
7634
|
-
return generatedFiles;
|
|
7719
|
+
return Promise.resolve(generatedFiles);
|
|
7635
7720
|
}
|
|
7636
|
-
const presignedConfig = this.configuration.uploads
|
|
7721
|
+
const presignedConfig = this.configuration.uploads.presignedUploads;
|
|
7637
7722
|
if (presignedConfig?.enabled) {
|
|
7638
7723
|
const isPresignedSupported = this.analyzer.isPresignedUploadsSupported();
|
|
7639
7724
|
if (!isPresignedSupported) {
|
|
@@ -7644,14 +7729,14 @@ var UploadGenerator = class {
|
|
|
7644
7729
|
}
|
|
7645
7730
|
const extractedUploadConfig = this.analyzer.extractUploadConfig();
|
|
7646
7731
|
const presignedEnabled = presignedConfig?.enabled && this.analyzer.isPresignedUploadsSupported();
|
|
7647
|
-
const uploadProvider = this.configuration.uploads
|
|
7648
|
-
const uploadStrategy = presignedEnabled ? "presigned" : this.configuration.uploads
|
|
7732
|
+
const uploadProvider = this.configuration.uploads.provider || (extractedUploadConfig.presignedEndpoint ? "minio" : "standard");
|
|
7733
|
+
const uploadStrategy = presignedEnabled ? "presigned" : this.configuration.uploads.strategy || "standard";
|
|
7649
7734
|
presignedEnabled ? {
|
|
7650
|
-
presignEndpoint: extractedUploadConfig.presignedEndpoint || presignedConfig
|
|
7651
|
-
fallbackToBackend: presignedConfig
|
|
7735
|
+
presignEndpoint: extractedUploadConfig.presignedEndpoint || presignedConfig.presignEndpoint || "/api/v1/files/presign-upload",
|
|
7736
|
+
fallbackToBackend: presignedConfig.fallbackToBackend !== false
|
|
7652
7737
|
} : {
|
|
7653
7738
|
};
|
|
7654
|
-
const progressConfig = this.configuration.uploads
|
|
7739
|
+
const progressConfig = this.configuration.uploads.progressTracking || {
|
|
7655
7740
|
enabled: true,
|
|
7656
7741
|
useXHR: true
|
|
7657
7742
|
};
|
|
@@ -7668,7 +7753,7 @@ var UploadGenerator = class {
|
|
|
7668
7753
|
progressConfig
|
|
7669
7754
|
));
|
|
7670
7755
|
}
|
|
7671
|
-
return generatedFiles;
|
|
7756
|
+
return Promise.resolve(generatedFiles);
|
|
7672
7757
|
}
|
|
7673
7758
|
/**
|
|
7674
7759
|
* Find presigned upload endpoint in schema
|
|
@@ -7681,7 +7766,7 @@ var UploadGenerator = class {
|
|
|
7681
7766
|
return pathLower.includes("presign") || pathLower.includes("presigned") || operationIdLower.includes("presign") || operationIdLower.includes("presigned");
|
|
7682
7767
|
}) || null;
|
|
7683
7768
|
}
|
|
7684
|
-
generateUploadUtilities(
|
|
7769
|
+
generateUploadUtilities(_uploadProvider, _uploadStrategy, _presignedEndpoint) {
|
|
7685
7770
|
const { uploads } = this.configuration;
|
|
7686
7771
|
const extractedConfig = this.analyzer.extractUploadConfig();
|
|
7687
7772
|
const maxSize = uploads?.security?.maxSize || (extractedConfig.maxSize ? `${extractedConfig.maxSize}MB` : "10MB");
|
|
@@ -8032,8 +8117,8 @@ async function uploadViaBackendApi(
|
|
|
8032
8117
|
xhr.responseType = 'json'
|
|
8033
8118
|
// Use base URL from environment or configuration
|
|
8034
8119
|
const baseUrl = typeof window !== 'undefined'
|
|
8035
|
-
? (process.env.NEXT_PUBLIC_API_URL || '${this.configuration.api
|
|
8036
|
-
: '${this.configuration.api
|
|
8120
|
+
? (process.env.NEXT_PUBLIC_API_URL || '${this.configuration.api.baseUrl || "http://localhost:8000"}')
|
|
8121
|
+
: '${this.configuration.api.baseUrl || "http://localhost:8000"}'
|
|
8037
8122
|
xhr.open('POST', \`\${baseUrl}${endpoint.path}\`)
|
|
8038
8123
|
xhr.send(formData)
|
|
8039
8124
|
})
|
|
@@ -8308,8 +8393,8 @@ export function ${hookName}Upload(options?: {
|
|
|
8308
8393
|
}
|
|
8309
8394
|
generateUseUploadFileHook(uploadProvider, uploadStrategy, context) {
|
|
8310
8395
|
const uploadUtilsImport = this.buildImportPath("services/uploadUtils");
|
|
8311
|
-
const uploadEndpoints = context?.schema
|
|
8312
|
-
(e) => e.metadata
|
|
8396
|
+
const uploadEndpoints = context?.schema.endpoints.filter(
|
|
8397
|
+
(e) => e.metadata.fileUpload || e.path.toLowerCase().includes("upload") || e.operationId && e.operationId.toLowerCase().includes("upload")
|
|
8313
8398
|
) || [];
|
|
8314
8399
|
const firstUploadEndpoint = uploadEndpoints[0];
|
|
8315
8400
|
let uploadMethodName = "uploadFile";
|
|
@@ -8449,7 +8534,7 @@ var ErrorHandlerGenerator = class {
|
|
|
8449
8534
|
}
|
|
8450
8535
|
analyzer;
|
|
8451
8536
|
buildImportPath(relativePath) {
|
|
8452
|
-
const outputDirectory = this.configuration.outputDir
|
|
8537
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
8453
8538
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
8454
8539
|
let importBasePath = outputDirectory;
|
|
8455
8540
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -8457,18 +8542,18 @@ var ErrorHandlerGenerator = class {
|
|
|
8457
8542
|
}
|
|
8458
8543
|
return `@/${importBasePath}/${cleanPath}`;
|
|
8459
8544
|
}
|
|
8460
|
-
|
|
8545
|
+
generate(context) {
|
|
8461
8546
|
const files = [];
|
|
8462
|
-
const { schema
|
|
8547
|
+
const { schema } = context;
|
|
8463
8548
|
const { api } = this.configuration;
|
|
8464
|
-
const errorHandling = api
|
|
8549
|
+
const errorHandling = api.errorHandling;
|
|
8465
8550
|
this.analyzer = new SchemaAnalyzer(schema);
|
|
8466
8551
|
const errorCodes = this.analyzer.extractErrorCodes();
|
|
8467
8552
|
const accountStatusPatterns = this.analyzer.extractAccountStatusPatterns();
|
|
8468
8553
|
const extractedAuthEndpoints = this.analyzer.extractAuthEndpoints();
|
|
8469
8554
|
const hasAuthEndpoints = !!(extractedAuthEndpoints.login || extractedAuthEndpoints.loginCredentials);
|
|
8470
8555
|
const hasAuthErrors = errorCodes.size > 0 || (accountStatusPatterns.inactiveStatuses.length > 0 || accountStatusPatterns.suspendedStatuses.length > 0);
|
|
8471
|
-
const shouldGenerate = hasAuthEndpoints && (errorHandling?.generateAuthErrorHandler !== false && errorHandling?.enableAuthErrorHandling !== false || hasAuthErrors && errorHandling
|
|
8556
|
+
const shouldGenerate = hasAuthEndpoints && (errorHandling?.generateAuthErrorHandler !== false && errorHandling?.enableAuthErrorHandling !== false || hasAuthErrors && errorHandling.generateAuthErrorHandler !== false);
|
|
8472
8557
|
if (shouldGenerate) {
|
|
8473
8558
|
files.push(this.generateAuthErrorHandler(errorCodes, accountStatusPatterns));
|
|
8474
8559
|
} else if (errorHandling?.enableAuthErrorHandling === true && !hasAuthEndpoints) {
|
|
@@ -8476,11 +8561,11 @@ var ErrorHandlerGenerator = class {
|
|
|
8476
8561
|
`\u26A0\uFE0F Auth error handling is enabled but auth endpoints are not found in OpenAPI schema. Auth error handler will not be generated.`
|
|
8477
8562
|
);
|
|
8478
8563
|
}
|
|
8479
|
-
return files;
|
|
8564
|
+
return Promise.resolve(files);
|
|
8480
8565
|
}
|
|
8481
8566
|
generateAuthErrorHandler(errorCodes, accountStatusPatterns) {
|
|
8482
8567
|
const authPath = this.configuration.auth?.authPath || "@/lib/auth";
|
|
8483
|
-
const errorHandling = this.configuration.api
|
|
8568
|
+
const errorHandling = this.configuration.api.errorHandling;
|
|
8484
8569
|
const authErrorHandlerPath = errorHandling?.authErrorHandlerPath || "@/lib/auth-error-handler";
|
|
8485
8570
|
let handlerOutputPath = authErrorHandlerPath;
|
|
8486
8571
|
if (handlerOutputPath.startsWith("@/")) {
|
|
@@ -8693,7 +8778,7 @@ var SSEGenerator = class {
|
|
|
8693
8778
|
}
|
|
8694
8779
|
analyzer;
|
|
8695
8780
|
buildImportPath(relativePath) {
|
|
8696
|
-
const outputDirectory = this.configuration.outputDir
|
|
8781
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
8697
8782
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
8698
8783
|
let importBasePath = outputDirectory;
|
|
8699
8784
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -8725,11 +8810,11 @@ var SSEGenerator = class {
|
|
|
8725
8810
|
);
|
|
8726
8811
|
return hasEventStream;
|
|
8727
8812
|
}
|
|
8728
|
-
|
|
8813
|
+
generate(context) {
|
|
8729
8814
|
const { schema } = context;
|
|
8730
8815
|
const generatedFiles = [];
|
|
8731
8816
|
this.analyzer = new SchemaAnalyzer(schema);
|
|
8732
|
-
const streamingConfig = this.configuration.framework
|
|
8817
|
+
const streamingConfig = this.configuration.framework.streaming;
|
|
8733
8818
|
const hasStreamingEndpoints = schema.endpoints.some((endpoint) => this.isSSEEndpoint(endpoint));
|
|
8734
8819
|
if (streamingConfig?.enabled === true && !hasStreamingEndpoints) {
|
|
8735
8820
|
console.warn(
|
|
@@ -8738,11 +8823,11 @@ var SSEGenerator = class {
|
|
|
8738
8823
|
}
|
|
8739
8824
|
const shouldEnableStreaming = streamingConfig?.enabled === true ? hasStreamingEndpoints : streamingConfig?.enabled !== false && hasStreamingEndpoints;
|
|
8740
8825
|
if (!shouldEnableStreaming || streamingConfig?.sse?.enabled === false || !hasStreamingEndpoints) {
|
|
8741
|
-
return generatedFiles;
|
|
8826
|
+
return Promise.resolve(generatedFiles);
|
|
8742
8827
|
}
|
|
8743
8828
|
const sseEndpoints = schema.endpoints.filter((endpoint) => this.isSSEEndpoint(endpoint));
|
|
8744
8829
|
if (sseEndpoints.length === 0) {
|
|
8745
|
-
return generatedFiles;
|
|
8830
|
+
return Promise.resolve(generatedFiles);
|
|
8746
8831
|
}
|
|
8747
8832
|
for (const endpoint of sseEndpoints) {
|
|
8748
8833
|
generatedFiles.push(this.generateSSEClientMethod(endpoint));
|
|
@@ -8751,7 +8836,7 @@ var SSEGenerator = class {
|
|
|
8751
8836
|
for (const [tag, tagEndpoints] of Object.entries(endpointsByTag)) {
|
|
8752
8837
|
generatedFiles.push(this.generateSSEHooks(tag, tagEndpoints));
|
|
8753
8838
|
}
|
|
8754
|
-
return generatedFiles;
|
|
8839
|
+
return Promise.resolve(generatedFiles);
|
|
8755
8840
|
}
|
|
8756
8841
|
generateSSEClientMethod(endpoint) {
|
|
8757
8842
|
const operationId = endpoint.operationId || endpoint.id;
|
|
@@ -8786,8 +8871,8 @@ var SSEGenerator = class {
|
|
|
8786
8871
|
}): EventSource => {
|
|
8787
8872
|
${pathParamNames.length > 0 ? `const { ${pathParamNames.join(", ")}, ...restOptions } = options.params || {}
|
|
8788
8873
|
` : ""}const baseUrl = typeof window !== 'undefined'
|
|
8789
|
-
? (process.env.NEXT_PUBLIC_API_URL || '${this.configuration.api
|
|
8790
|
-
: '${this.configuration.api
|
|
8874
|
+
? (process.env.NEXT_PUBLIC_API_URL || '${this.configuration.api.baseUrl || "http://localhost:8000"}')
|
|
8875
|
+
: '${this.configuration.api.baseUrl || "http://localhost:8000"}'
|
|
8791
8876
|
const sseUrl = \`\${baseUrl}${urlConstruction}\`
|
|
8792
8877
|
|
|
8793
8878
|
// Create EventSource connection
|
|
@@ -8833,7 +8918,7 @@ var SSEGenerator = class {
|
|
|
8833
8918
|
generateSSEHooks(tag, endpoints) {
|
|
8834
8919
|
const tagName = toValidIdentifier(tag);
|
|
8835
8920
|
const clientImport = this.buildImportPath("client");
|
|
8836
|
-
const streamingConfig = this.configuration.framework
|
|
8921
|
+
const streamingConfig = this.configuration.framework.streaming?.sse;
|
|
8837
8922
|
const autoReconnect = streamingConfig?.autoReconnect !== false;
|
|
8838
8923
|
const reconnectDelay = streamingConfig?.reconnectDelay || 3e3;
|
|
8839
8924
|
const maxReconnectAttempts = streamingConfig?.maxReconnectAttempts || 5;
|
|
@@ -9026,7 +9111,7 @@ var NextJsCodeGenerator = class {
|
|
|
9026
9111
|
__name(this, "NextJsCodeGenerator");
|
|
9027
9112
|
}
|
|
9028
9113
|
buildImportPath(relativePath) {
|
|
9029
|
-
const outputDirectory = this.configuration.outputDir
|
|
9114
|
+
const outputDirectory = this.configuration.outputDir ?? "generated";
|
|
9030
9115
|
const cleanPath = relativePath.startsWith("/") ? relativePath.slice(1) : relativePath;
|
|
9031
9116
|
let importBasePath = outputDirectory;
|
|
9032
9117
|
if (importBasePath.startsWith("src/")) {
|
|
@@ -9040,9 +9125,9 @@ var NextJsCodeGenerator = class {
|
|
|
9040
9125
|
path: file.path,
|
|
9041
9126
|
metadata: {
|
|
9042
9127
|
...file.metadata,
|
|
9043
|
-
exports: file.metadata?.exports
|
|
9044
|
-
imports: file.metadata?.imports
|
|
9045
|
-
dependencies: file.metadata?.dependencies
|
|
9128
|
+
exports: file.metadata?.exports ?? [],
|
|
9129
|
+
imports: file.metadata?.imports ?? [],
|
|
9130
|
+
dependencies: file.metadata?.dependencies.map((dependency) => {
|
|
9046
9131
|
if (dependency.startsWith("@/generated/")) {
|
|
9047
9132
|
return dependency;
|
|
9048
9133
|
}
|
|
@@ -9051,7 +9136,7 @@ var NextJsCodeGenerator = class {
|
|
|
9051
9136
|
return `@/generated/${relativePart}`;
|
|
9052
9137
|
}
|
|
9053
9138
|
return dependency;
|
|
9054
|
-
})
|
|
9139
|
+
}) ?? []
|
|
9055
9140
|
}
|
|
9056
9141
|
}));
|
|
9057
9142
|
}
|
|
@@ -9084,11 +9169,11 @@ var NextJsCodeGenerator = class {
|
|
|
9084
9169
|
const uploadGenerator = new UploadGenerator(this.configuration);
|
|
9085
9170
|
generatedFiles.push(...await uploadGenerator.generate(context));
|
|
9086
9171
|
}
|
|
9087
|
-
if (this.configuration.api
|
|
9172
|
+
if (this.configuration.api.errorHandling?.generateAuthErrorHandler !== false) {
|
|
9088
9173
|
const errorHandlerGenerator = new ErrorHandlerGenerator(this.configuration);
|
|
9089
9174
|
generatedFiles.push(...await errorHandlerGenerator.generate(context));
|
|
9090
9175
|
}
|
|
9091
|
-
if (this.configuration.framework
|
|
9176
|
+
if (this.configuration.framework.streaming?.enabled) {
|
|
9092
9177
|
const sseGenerator = new SSEGenerator(this.configuration);
|
|
9093
9178
|
generatedFiles.push(...await sseGenerator.generate(context));
|
|
9094
9179
|
}
|
|
@@ -9098,14 +9183,14 @@ var NextJsCodeGenerator = class {
|
|
|
9098
9183
|
throw new GenerationError(`Failed to generate Next.js files: ${errorMessage}`);
|
|
9099
9184
|
}
|
|
9100
9185
|
}
|
|
9101
|
-
|
|
9186
|
+
generateSafeActionClient() {
|
|
9102
9187
|
const safeActionContent = `import { DEFAULT_SERVER_ERROR_MESSAGE, createSafeActionClient } from "next-safe-action";
|
|
9103
9188
|
import { headers } from "next/headers";
|
|
9104
9189
|
import { z } from "zod";
|
|
9105
9190
|
|
|
9106
9191
|
/**
|
|
9107
9192
|
* Enhanced Action Error class for better error handling
|
|
9108
|
-
* Follows Next.js 16.0.
|
|
9193
|
+
* Follows Next.js 16.0.7 best practices
|
|
9109
9194
|
*/
|
|
9110
9195
|
export class ActionError extends Error {
|
|
9111
9196
|
constructor(
|
|
@@ -9142,7 +9227,7 @@ export const actionClient = createSafeActionClient({
|
|
|
9142
9227
|
|
|
9143
9228
|
/**
|
|
9144
9229
|
* Enhanced action client with metadata support
|
|
9145
|
-
* Next.js 16.0.
|
|
9230
|
+
* Next.js 16.0.7: Supports metadata for better action tracking and rate limiting
|
|
9146
9231
|
*/
|
|
9147
9232
|
export const actionClientWithMeta = createSafeActionClient({
|
|
9148
9233
|
handleServerError(e) {
|
|
@@ -9163,7 +9248,7 @@ export const actionClientWithMeta = createSafeActionClient({
|
|
|
9163
9248
|
requests: z.number().int().positive().describe('Number of requests allowed'),
|
|
9164
9249
|
window: z.string().describe('Time window (e.g., "10s", "1m", "1h")'),
|
|
9165
9250
|
}).optional().describe('Rate limiting configuration'),
|
|
9166
|
-
cacheTags: z.array(z.string()).optional().describe('Cache tags for invalidation (Next.js 16.0.
|
|
9251
|
+
cacheTags: z.array(z.string()).optional().describe('Cache tags for invalidation (Next.js 16.0.7)'),
|
|
9167
9252
|
});
|
|
9168
9253
|
},
|
|
9169
9254
|
});
|
|
@@ -9254,7 +9339,7 @@ async function getCurrentUser() {
|
|
|
9254
9339
|
// Implement your authentication logic here
|
|
9255
9340
|
return null;
|
|
9256
9341
|
}`;
|
|
9257
|
-
return [
|
|
9342
|
+
return Promise.resolve([
|
|
9258
9343
|
{
|
|
9259
9344
|
path: "lib/safe-action.ts",
|
|
9260
9345
|
content: safeActionContent,
|
|
@@ -9265,7 +9350,7 @@ async function getCurrentUser() {
|
|
|
9265
9350
|
dependencies: []
|
|
9266
9351
|
}
|
|
9267
9352
|
}
|
|
9268
|
-
];
|
|
9353
|
+
]);
|
|
9269
9354
|
}
|
|
9270
9355
|
};
|
|
9271
9356
|
var FileSystemManager = class {
|
|
@@ -9273,7 +9358,7 @@ var FileSystemManager = class {
|
|
|
9273
9358
|
__name(this, "FileSystemManager");
|
|
9274
9359
|
}
|
|
9275
9360
|
async writeFile(filePath, content, options = {}) {
|
|
9276
|
-
if (!filePath
|
|
9361
|
+
if (!filePath.trim()) {
|
|
9277
9362
|
throw new Error("File path is required and cannot be empty");
|
|
9278
9363
|
}
|
|
9279
9364
|
if (typeof content !== "string") {
|
|
@@ -9310,7 +9395,7 @@ var FileSystemManager = class {
|
|
|
9310
9395
|
}
|
|
9311
9396
|
}
|
|
9312
9397
|
async readFile(filePath, encoding = "utf8") {
|
|
9313
|
-
if (!filePath
|
|
9398
|
+
if (!filePath.trim()) {
|
|
9314
9399
|
throw new Error("File path is required and cannot be empty");
|
|
9315
9400
|
}
|
|
9316
9401
|
try {
|
|
@@ -9337,7 +9422,7 @@ var FileSystemManager = class {
|
|
|
9337
9422
|
}
|
|
9338
9423
|
}
|
|
9339
9424
|
async getFileHash(filePath) {
|
|
9340
|
-
if (!filePath
|
|
9425
|
+
if (!filePath.trim()) {
|
|
9341
9426
|
throw new Error("File path is required and cannot be empty");
|
|
9342
9427
|
}
|
|
9343
9428
|
try {
|
|
@@ -9363,7 +9448,7 @@ var FileSystemManager = class {
|
|
|
9363
9448
|
}
|
|
9364
9449
|
}
|
|
9365
9450
|
async findFiles(dir, pattern, recursive = true) {
|
|
9366
|
-
if (!dir
|
|
9451
|
+
if (!dir.trim()) {
|
|
9367
9452
|
throw new Error("Directory path is required and cannot be empty");
|
|
9368
9453
|
}
|
|
9369
9454
|
if (!(pattern instanceof RegExp)) {
|
|
@@ -9406,16 +9491,52 @@ var BridgeCore = class {
|
|
|
9406
9491
|
logger;
|
|
9407
9492
|
schemaParser;
|
|
9408
9493
|
fileManager;
|
|
9494
|
+
/**
|
|
9495
|
+
* Creates a new instance of BridgeCore
|
|
9496
|
+
*
|
|
9497
|
+
* Initializes all required dependencies including logger, schema parser, and file manager.
|
|
9498
|
+
* All dependencies are readonly to ensure immutability and thread safety.
|
|
9499
|
+
*/
|
|
9409
9500
|
constructor() {
|
|
9410
9501
|
this.logger = new BridgeLogger({ prefix: "\u{1F517} Mulink" });
|
|
9411
9502
|
this.schemaParser = new OpenApiSchemaParser();
|
|
9412
9503
|
this.fileManager = new FileSystemManager();
|
|
9413
9504
|
}
|
|
9505
|
+
/**
|
|
9506
|
+
* Generates type-safe API client code from OpenAPI schema
|
|
9507
|
+
*
|
|
9508
|
+
* This is the main entry point for code generation. It validates the configuration,
|
|
9509
|
+
* parses the OpenAPI schema, generates all necessary files, and writes them to disk.
|
|
9510
|
+
*
|
|
9511
|
+
* The generated code follows Next.js 16.0.7 best practices including:
|
|
9512
|
+
* - Server Actions with type safety
|
|
9513
|
+
* - React Query hooks with proper caching
|
|
9514
|
+
* - Middleware support
|
|
9515
|
+
* - Error handling
|
|
9516
|
+
* - Cache tag management
|
|
9517
|
+
*
|
|
9518
|
+
* @param configuration - The bridge configuration containing schema URL, output directory, and framework settings
|
|
9519
|
+
* @returns Promise that resolves when generation is complete
|
|
9520
|
+
* @throws {ValidationError} When configuration is invalid
|
|
9521
|
+
* @throws {SchemaParseError} When OpenAPI schema cannot be parsed
|
|
9522
|
+
* @throws {GenerationError} When code generation fails
|
|
9523
|
+
*
|
|
9524
|
+
* @example
|
|
9525
|
+
* ```typescript
|
|
9526
|
+
* const config: BridgeConfiguration = {
|
|
9527
|
+
* schema: 'https://api.example.com/openapi.json',
|
|
9528
|
+
* outputDir: 'src/generated',
|
|
9529
|
+
* framework: { type: 'nextjs', router: 'app', features: {...} },
|
|
9530
|
+
* api: { baseUrl: 'https://api.example.com', timeout: 30000, retries: 3 }
|
|
9531
|
+
* };
|
|
9532
|
+
* await bridge.generate(config);
|
|
9533
|
+
* ```
|
|
9534
|
+
*/
|
|
9414
9535
|
async generate(configuration) {
|
|
9415
9536
|
const startTime = Date.now();
|
|
9416
9537
|
try {
|
|
9417
9538
|
this.logger.info("Starting code generation...");
|
|
9418
|
-
|
|
9539
|
+
this.validateConfiguration(configuration);
|
|
9419
9540
|
this.logger.info(`Parsing schema: ${configuration.schema}`);
|
|
9420
9541
|
const parsedSchema = await this.schemaParser.parse(configuration.schema);
|
|
9421
9542
|
this.logger.debug(
|
|
@@ -9444,16 +9565,17 @@ var BridgeCore = class {
|
|
|
9444
9565
|
throw error;
|
|
9445
9566
|
}
|
|
9446
9567
|
}
|
|
9447
|
-
|
|
9568
|
+
validateConfiguration(configuration) {
|
|
9448
9569
|
const errors = [];
|
|
9449
|
-
if (!configuration.schema
|
|
9570
|
+
if (!configuration.schema.trim()) {
|
|
9450
9571
|
errors.push("Schema URL is required and cannot be empty");
|
|
9451
9572
|
}
|
|
9452
|
-
if (!configuration.outputDir
|
|
9573
|
+
if (!configuration.outputDir.trim()) {
|
|
9453
9574
|
errors.push("Output directory is required and cannot be empty");
|
|
9454
9575
|
}
|
|
9455
9576
|
if (configuration.framework.type !== "nextjs") {
|
|
9456
|
-
|
|
9577
|
+
const frameworkType = configuration.framework.type;
|
|
9578
|
+
errors.push(`Only Next.js framework is currently supported, got: ${frameworkType}`);
|
|
9457
9579
|
}
|
|
9458
9580
|
if (errors.length > 0) {
|
|
9459
9581
|
throw new ValidationError(
|
|
@@ -9470,8 +9592,10 @@ var BridgeCore = class {
|
|
|
9470
9592
|
case "nextjs":
|
|
9471
9593
|
const nextJsGenerator = new NextJsCodeGenerator(config);
|
|
9472
9594
|
return await nextJsGenerator.generate(context);
|
|
9473
|
-
default:
|
|
9474
|
-
|
|
9595
|
+
default: {
|
|
9596
|
+
const frameworkType = config.framework.type;
|
|
9597
|
+
throw new GenerationError(`Unsupported framework: ${frameworkType}`);
|
|
9598
|
+
}
|
|
9475
9599
|
}
|
|
9476
9600
|
} catch (error) {
|
|
9477
9601
|
if (error instanceof GenerationError) {
|
|
@@ -9505,7 +9629,7 @@ var BridgeCore = class {
|
|
|
9505
9629
|
logGenerationSummary(files) {
|
|
9506
9630
|
const fileTypes = files.reduce(
|
|
9507
9631
|
(acc, file) => {
|
|
9508
|
-
acc[file.type] = (acc[file.type]
|
|
9632
|
+
acc[file.type] = (acc[file.type] ?? 0) + 1;
|
|
9509
9633
|
return acc;
|
|
9510
9634
|
},
|
|
9511
9635
|
{}
|
|
@@ -9524,9 +9648,24 @@ var BridgeCore = class {
|
|
|
9524
9648
|
});
|
|
9525
9649
|
}
|
|
9526
9650
|
}
|
|
9527
|
-
|
|
9651
|
+
/**
|
|
9652
|
+
* Validates an OpenAPI schema without generating code
|
|
9653
|
+
*
|
|
9654
|
+
* Useful for checking schema validity before running full generation.
|
|
9655
|
+
*
|
|
9656
|
+
* @param schemaUrl - URL or file path to the OpenAPI schema
|
|
9657
|
+
* @returns Promise resolving to true if schema is valid, false otherwise
|
|
9658
|
+
*
|
|
9659
|
+
* @example
|
|
9660
|
+
* ```typescript
|
|
9661
|
+
* const isValid = await bridge.validateSchema('https://api.example.com/openapi.json');
|
|
9662
|
+
* if (isValid) {
|
|
9663
|
+
* await bridge.generate(config);
|
|
9664
|
+
* }
|
|
9665
|
+
* ```
|
|
9666
|
+
*/
|
|
9528
9667
|
async validateSchema(schemaUrl) {
|
|
9529
|
-
if (!schemaUrl
|
|
9668
|
+
if (!schemaUrl.trim()) {
|
|
9530
9669
|
this.logger.warn("Schema URL is empty or invalid");
|
|
9531
9670
|
return false;
|
|
9532
9671
|
}
|
|
@@ -9540,8 +9679,25 @@ var BridgeCore = class {
|
|
|
9540
9679
|
return false;
|
|
9541
9680
|
}
|
|
9542
9681
|
}
|
|
9682
|
+
/**
|
|
9683
|
+
* Retrieves metadata from an OpenAPI schema
|
|
9684
|
+
*
|
|
9685
|
+
* Extracts schema metadata including title, version, description, and other
|
|
9686
|
+
* OpenAPI document information without parsing the entire schema.
|
|
9687
|
+
*
|
|
9688
|
+
* @param schemaUrl - URL or file path to the OpenAPI schema
|
|
9689
|
+
* @returns Promise resolving to schema metadata
|
|
9690
|
+
* @throws {BridgeError} When schema URL is invalid
|
|
9691
|
+
* @throws {SchemaParseError} When schema cannot be parsed
|
|
9692
|
+
*
|
|
9693
|
+
* @example
|
|
9694
|
+
* ```typescript
|
|
9695
|
+
* const metadata = await bridge.getSchemaInfo('https://api.example.com/openapi.json');
|
|
9696
|
+
* console.log(`Schema: ${metadata.title} v${metadata.version}`);
|
|
9697
|
+
* ```
|
|
9698
|
+
*/
|
|
9543
9699
|
async getSchemaInfo(schemaUrl) {
|
|
9544
|
-
if (!schemaUrl
|
|
9700
|
+
if (!schemaUrl.trim()) {
|
|
9545
9701
|
throw new BridgeError("Schema URL is required and cannot be empty", "INVALID_SCHEMA_URL");
|
|
9546
9702
|
}
|
|
9547
9703
|
try {
|
|
@@ -9553,6 +9709,18 @@ var BridgeCore = class {
|
|
|
9553
9709
|
throw new SchemaParseError(`Failed to parse schema: ${errorMessage}`, schemaUrl);
|
|
9554
9710
|
}
|
|
9555
9711
|
}
|
|
9712
|
+
/**
|
|
9713
|
+
* Clears the internal schema cache
|
|
9714
|
+
*
|
|
9715
|
+
* Useful when you need to force re-fetching of schemas or during development.
|
|
9716
|
+
* The cache is automatically managed, but this method allows manual invalidation.
|
|
9717
|
+
*
|
|
9718
|
+
* @example
|
|
9719
|
+
* ```typescript
|
|
9720
|
+
* bridge.clearCache();
|
|
9721
|
+
* await bridge.generate(config); // Will fetch fresh schema
|
|
9722
|
+
* ```
|
|
9723
|
+
*/
|
|
9556
9724
|
clearCache() {
|
|
9557
9725
|
try {
|
|
9558
9726
|
this.schemaParser.clearCache();
|
|
@@ -9651,7 +9819,7 @@ var ConfigurationLoader = class {
|
|
|
9651
9819
|
}
|
|
9652
9820
|
async load(configPath) {
|
|
9653
9821
|
if (!configPath?.trim()) {
|
|
9654
|
-
configPath = "
|
|
9822
|
+
configPath = "link.config.json";
|
|
9655
9823
|
}
|
|
9656
9824
|
const resolvedPath = path2.resolve(process.cwd(), configPath);
|
|
9657
9825
|
try {
|
|
@@ -9717,7 +9885,7 @@ ${errorMessages}`,
|
|
|
9717
9885
|
);
|
|
9718
9886
|
}
|
|
9719
9887
|
}
|
|
9720
|
-
|
|
9888
|
+
createDefault(framework = "nextjs") {
|
|
9721
9889
|
const defaultConfig = {
|
|
9722
9890
|
schema: "https://petstore3.swagger.io/api/v3/openapi.json",
|
|
9723
9891
|
outputDir: "src/generated",
|
|
@@ -9762,7 +9930,7 @@ ${errorMessages}`,
|
|
|
9762
9930
|
}
|
|
9763
9931
|
async save(config, configPath) {
|
|
9764
9932
|
if (!configPath?.trim()) {
|
|
9765
|
-
configPath = "
|
|
9933
|
+
configPath = "link.config.json";
|
|
9766
9934
|
}
|
|
9767
9935
|
const resolvedPath = path2.resolve(process.cwd(), configPath);
|
|
9768
9936
|
try {
|
|
@@ -9806,5 +9974,5 @@ ${errorMessages}`,
|
|
|
9806
9974
|
};
|
|
9807
9975
|
|
|
9808
9976
|
export { BridgeCore, BridgeError, BridgeLogger, ConfigurationLoader, FileSystemManager, GenerationError, LogLevel, NextJsCodeGenerator, OpenApiSchemaParser, SchemaParseError, ValidationError, VersionChecker, __name, checkAndNotifyUpdates, createBridgeVersionChecker };
|
|
9809
|
-
//# sourceMappingURL=chunk-
|
|
9810
|
-
//# sourceMappingURL=chunk-
|
|
9977
|
+
//# sourceMappingURL=chunk-2WVV6AOO.js.map
|
|
9978
|
+
//# sourceMappingURL=chunk-2WVV6AOO.js.map
|