@zenstackhq/server 3.5.0 → 3.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.cjs +209 -5
- package/dist/api.cjs.map +1 -1
- package/dist/api.js +209 -5
- package/dist/api.js.map +1 -1
- package/package.json +7 -7
package/dist/api.js
CHANGED
|
@@ -353,6 +353,9 @@ var RestApiSpecGenerator = class {
|
|
|
353
353
|
get queryOptions() {
|
|
354
354
|
return this.handlerOptions?.queryOptions;
|
|
355
355
|
}
|
|
356
|
+
get nestedRoutes() {
|
|
357
|
+
return this.handlerOptions.nestedRoutes ?? false;
|
|
358
|
+
}
|
|
356
359
|
generateSpec(options) {
|
|
357
360
|
this.specOptions = options;
|
|
358
361
|
return {
|
|
@@ -408,7 +411,13 @@ var RestApiSpecGenerator = class {
|
|
|
408
411
|
if (!relModelDef) continue;
|
|
409
412
|
const relIdFields = this.getIdFields(relModelDef);
|
|
410
413
|
if (relIdFields.length === 0) continue;
|
|
411
|
-
paths[`/${modelPath}/{id}/${fieldName}`] = this.
|
|
414
|
+
paths[`/${modelPath}/{id}/${fieldName}`] = this.buildRelatedPath(modelName, fieldName, fieldDef, tag);
|
|
415
|
+
if (this.nestedRoutes && fieldDef.array) {
|
|
416
|
+
const nestedSinglePath = this.buildNestedSinglePath(modelName, fieldName, fieldDef, relModelDef, tag);
|
|
417
|
+
if (Object.keys(nestedSinglePath).length > 0) {
|
|
418
|
+
paths[`/${modelPath}/{id}/${fieldName}/{childId}`] = nestedSinglePath;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
412
421
|
paths[`/${modelPath}/{id}/relationships/${fieldName}`] = this.buildRelationshipPath(modelDef, fieldName, fieldDef, tag);
|
|
413
422
|
}
|
|
414
423
|
}
|
|
@@ -606,8 +615,9 @@ var RestApiSpecGenerator = class {
|
|
|
606
615
|
}
|
|
607
616
|
return result;
|
|
608
617
|
}
|
|
609
|
-
|
|
618
|
+
buildRelatedPath(modelName, fieldName, fieldDef, tag) {
|
|
610
619
|
const isCollection = !!fieldDef.array;
|
|
620
|
+
const relModelDef = this.schema.models[fieldDef.type];
|
|
611
621
|
const params = [
|
|
612
622
|
{
|
|
613
623
|
$ref: "#/components/parameters/id"
|
|
@@ -616,8 +626,7 @@ var RestApiSpecGenerator = class {
|
|
|
616
626
|
$ref: "#/components/parameters/include"
|
|
617
627
|
}
|
|
618
628
|
];
|
|
619
|
-
if (isCollection &&
|
|
620
|
-
const relModelDef = this.schema.models[fieldDef.type];
|
|
629
|
+
if (isCollection && relModelDef) {
|
|
621
630
|
params.push({
|
|
622
631
|
$ref: "#/components/parameters/sort"
|
|
623
632
|
}, {
|
|
@@ -626,7 +635,7 @@ var RestApiSpecGenerator = class {
|
|
|
626
635
|
$ref: "#/components/parameters/pageLimit"
|
|
627
636
|
}, ...this.buildFilterParams(fieldDef.type, relModelDef));
|
|
628
637
|
}
|
|
629
|
-
|
|
638
|
+
const pathItem = {
|
|
630
639
|
get: {
|
|
631
640
|
tags: [
|
|
632
641
|
tag
|
|
@@ -651,6 +660,201 @@ var RestApiSpecGenerator = class {
|
|
|
651
660
|
}
|
|
652
661
|
}
|
|
653
662
|
};
|
|
663
|
+
if (this.nestedRoutes && relModelDef) {
|
|
664
|
+
const mayDeny = this.mayDenyAccess(relModelDef, isCollection ? "create" : "update");
|
|
665
|
+
if (isCollection && isOperationIncluded(fieldDef.type, "create", this.queryOptions)) {
|
|
666
|
+
pathItem["post"] = {
|
|
667
|
+
tags: [
|
|
668
|
+
tag
|
|
669
|
+
],
|
|
670
|
+
summary: `Create a nested ${fieldDef.type} under ${modelName}`,
|
|
671
|
+
operationId: `create${modelName}_${fieldName}`,
|
|
672
|
+
parameters: [
|
|
673
|
+
{
|
|
674
|
+
$ref: "#/components/parameters/id"
|
|
675
|
+
}
|
|
676
|
+
],
|
|
677
|
+
requestBody: {
|
|
678
|
+
required: true,
|
|
679
|
+
content: {
|
|
680
|
+
"application/vnd.api+json": {
|
|
681
|
+
schema: {
|
|
682
|
+
$ref: `#/components/schemas/${fieldDef.type}CreateRequest`
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
responses: {
|
|
688
|
+
"201": {
|
|
689
|
+
description: `Created ${fieldDef.type} resource`,
|
|
690
|
+
content: {
|
|
691
|
+
"application/vnd.api+json": {
|
|
692
|
+
schema: {
|
|
693
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
"400": ERROR_400,
|
|
699
|
+
...mayDeny && {
|
|
700
|
+
"403": ERROR_403
|
|
701
|
+
},
|
|
702
|
+
"422": ERROR_422
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
} else if (!isCollection && isOperationIncluded(fieldDef.type, "update", this.queryOptions)) {
|
|
706
|
+
pathItem["patch"] = {
|
|
707
|
+
tags: [
|
|
708
|
+
tag
|
|
709
|
+
],
|
|
710
|
+
summary: `Update nested ${fieldDef.type} under ${modelName}`,
|
|
711
|
+
operationId: `update${modelName}_${fieldName}`,
|
|
712
|
+
parameters: [
|
|
713
|
+
{
|
|
714
|
+
$ref: "#/components/parameters/id"
|
|
715
|
+
}
|
|
716
|
+
],
|
|
717
|
+
requestBody: {
|
|
718
|
+
required: true,
|
|
719
|
+
content: {
|
|
720
|
+
"application/vnd.api+json": {
|
|
721
|
+
schema: {
|
|
722
|
+
$ref: `#/components/schemas/${fieldDef.type}UpdateRequest`
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
responses: {
|
|
728
|
+
"200": {
|
|
729
|
+
description: `Updated ${fieldDef.type} resource`,
|
|
730
|
+
content: {
|
|
731
|
+
"application/vnd.api+json": {
|
|
732
|
+
schema: {
|
|
733
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
"400": ERROR_400,
|
|
739
|
+
...mayDeny && {
|
|
740
|
+
"403": ERROR_403
|
|
741
|
+
},
|
|
742
|
+
"404": ERROR_404,
|
|
743
|
+
"422": ERROR_422
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return pathItem;
|
|
749
|
+
}
|
|
750
|
+
buildNestedSinglePath(modelName, fieldName, fieldDef, relModelDef, tag) {
|
|
751
|
+
const childIdParam = {
|
|
752
|
+
name: "childId",
|
|
753
|
+
in: "path",
|
|
754
|
+
required: true,
|
|
755
|
+
schema: {
|
|
756
|
+
type: "string"
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
const idParam = {
|
|
760
|
+
$ref: "#/components/parameters/id"
|
|
761
|
+
};
|
|
762
|
+
const mayDenyUpdate = this.mayDenyAccess(relModelDef, "update");
|
|
763
|
+
const mayDenyDelete = this.mayDenyAccess(relModelDef, "delete");
|
|
764
|
+
const result = {};
|
|
765
|
+
if (isOperationIncluded(fieldDef.type, "findUnique", this.queryOptions)) {
|
|
766
|
+
result["get"] = {
|
|
767
|
+
tags: [
|
|
768
|
+
tag
|
|
769
|
+
],
|
|
770
|
+
summary: `Get a nested ${fieldDef.type} by ID under ${modelName}`,
|
|
771
|
+
operationId: `get${modelName}_${fieldName}_single`,
|
|
772
|
+
parameters: [
|
|
773
|
+
idParam,
|
|
774
|
+
childIdParam,
|
|
775
|
+
{
|
|
776
|
+
$ref: "#/components/parameters/include"
|
|
777
|
+
}
|
|
778
|
+
],
|
|
779
|
+
responses: {
|
|
780
|
+
"200": {
|
|
781
|
+
description: `${fieldDef.type} resource`,
|
|
782
|
+
content: {
|
|
783
|
+
"application/vnd.api+json": {
|
|
784
|
+
schema: {
|
|
785
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
"404": ERROR_404
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
if (isOperationIncluded(fieldDef.type, "update", this.queryOptions)) {
|
|
795
|
+
result["patch"] = {
|
|
796
|
+
tags: [
|
|
797
|
+
tag
|
|
798
|
+
],
|
|
799
|
+
summary: `Update a nested ${fieldDef.type} by ID under ${modelName}`,
|
|
800
|
+
operationId: `update${modelName}_${fieldName}_single`,
|
|
801
|
+
parameters: [
|
|
802
|
+
idParam,
|
|
803
|
+
childIdParam
|
|
804
|
+
],
|
|
805
|
+
requestBody: {
|
|
806
|
+
required: true,
|
|
807
|
+
content: {
|
|
808
|
+
"application/vnd.api+json": {
|
|
809
|
+
schema: {
|
|
810
|
+
$ref: `#/components/schemas/${fieldDef.type}UpdateRequest`
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
},
|
|
815
|
+
responses: {
|
|
816
|
+
"200": {
|
|
817
|
+
description: `Updated ${fieldDef.type} resource`,
|
|
818
|
+
content: {
|
|
819
|
+
"application/vnd.api+json": {
|
|
820
|
+
schema: {
|
|
821
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
"400": ERROR_400,
|
|
827
|
+
...mayDenyUpdate && {
|
|
828
|
+
"403": ERROR_403
|
|
829
|
+
},
|
|
830
|
+
"404": ERROR_404,
|
|
831
|
+
"422": ERROR_422
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
if (isOperationIncluded(fieldDef.type, "delete", this.queryOptions)) {
|
|
836
|
+
result["delete"] = {
|
|
837
|
+
tags: [
|
|
838
|
+
tag
|
|
839
|
+
],
|
|
840
|
+
summary: `Delete a nested ${fieldDef.type} by ID under ${modelName}`,
|
|
841
|
+
operationId: `delete${modelName}_${fieldName}_single`,
|
|
842
|
+
parameters: [
|
|
843
|
+
idParam,
|
|
844
|
+
childIdParam
|
|
845
|
+
],
|
|
846
|
+
responses: {
|
|
847
|
+
"200": {
|
|
848
|
+
description: "Deleted successfully"
|
|
849
|
+
},
|
|
850
|
+
...mayDenyDelete && {
|
|
851
|
+
"403": ERROR_403
|
|
852
|
+
},
|
|
853
|
+
"404": ERROR_404
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
return result;
|
|
654
858
|
}
|
|
655
859
|
buildRelationshipPath(modelDef, fieldName, fieldDef, tag) {
|
|
656
860
|
const modelName = modelDef.name;
|