@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.cjs
CHANGED
|
@@ -388,6 +388,9 @@ var RestApiSpecGenerator = class {
|
|
|
388
388
|
get queryOptions() {
|
|
389
389
|
return this.handlerOptions?.queryOptions;
|
|
390
390
|
}
|
|
391
|
+
get nestedRoutes() {
|
|
392
|
+
return this.handlerOptions.nestedRoutes ?? false;
|
|
393
|
+
}
|
|
391
394
|
generateSpec(options) {
|
|
392
395
|
this.specOptions = options;
|
|
393
396
|
return {
|
|
@@ -443,7 +446,13 @@ var RestApiSpecGenerator = class {
|
|
|
443
446
|
if (!relModelDef) continue;
|
|
444
447
|
const relIdFields = this.getIdFields(relModelDef);
|
|
445
448
|
if (relIdFields.length === 0) continue;
|
|
446
|
-
paths[`/${modelPath}/{id}/${fieldName}`] = this.
|
|
449
|
+
paths[`/${modelPath}/{id}/${fieldName}`] = this.buildRelatedPath(modelName, fieldName, fieldDef, tag);
|
|
450
|
+
if (this.nestedRoutes && fieldDef.array) {
|
|
451
|
+
const nestedSinglePath = this.buildNestedSinglePath(modelName, fieldName, fieldDef, relModelDef, tag);
|
|
452
|
+
if (Object.keys(nestedSinglePath).length > 0) {
|
|
453
|
+
paths[`/${modelPath}/{id}/${fieldName}/{childId}`] = nestedSinglePath;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
447
456
|
paths[`/${modelPath}/{id}/relationships/${fieldName}`] = this.buildRelationshipPath(modelDef, fieldName, fieldDef, tag);
|
|
448
457
|
}
|
|
449
458
|
}
|
|
@@ -641,8 +650,9 @@ var RestApiSpecGenerator = class {
|
|
|
641
650
|
}
|
|
642
651
|
return result;
|
|
643
652
|
}
|
|
644
|
-
|
|
653
|
+
buildRelatedPath(modelName, fieldName, fieldDef, tag) {
|
|
645
654
|
const isCollection = !!fieldDef.array;
|
|
655
|
+
const relModelDef = this.schema.models[fieldDef.type];
|
|
646
656
|
const params = [
|
|
647
657
|
{
|
|
648
658
|
$ref: "#/components/parameters/id"
|
|
@@ -651,8 +661,7 @@ var RestApiSpecGenerator = class {
|
|
|
651
661
|
$ref: "#/components/parameters/include"
|
|
652
662
|
}
|
|
653
663
|
];
|
|
654
|
-
if (isCollection &&
|
|
655
|
-
const relModelDef = this.schema.models[fieldDef.type];
|
|
664
|
+
if (isCollection && relModelDef) {
|
|
656
665
|
params.push({
|
|
657
666
|
$ref: "#/components/parameters/sort"
|
|
658
667
|
}, {
|
|
@@ -661,7 +670,7 @@ var RestApiSpecGenerator = class {
|
|
|
661
670
|
$ref: "#/components/parameters/pageLimit"
|
|
662
671
|
}, ...this.buildFilterParams(fieldDef.type, relModelDef));
|
|
663
672
|
}
|
|
664
|
-
|
|
673
|
+
const pathItem = {
|
|
665
674
|
get: {
|
|
666
675
|
tags: [
|
|
667
676
|
tag
|
|
@@ -686,6 +695,201 @@ var RestApiSpecGenerator = class {
|
|
|
686
695
|
}
|
|
687
696
|
}
|
|
688
697
|
};
|
|
698
|
+
if (this.nestedRoutes && relModelDef) {
|
|
699
|
+
const mayDeny = this.mayDenyAccess(relModelDef, isCollection ? "create" : "update");
|
|
700
|
+
if (isCollection && isOperationIncluded(fieldDef.type, "create", this.queryOptions)) {
|
|
701
|
+
pathItem["post"] = {
|
|
702
|
+
tags: [
|
|
703
|
+
tag
|
|
704
|
+
],
|
|
705
|
+
summary: `Create a nested ${fieldDef.type} under ${modelName}`,
|
|
706
|
+
operationId: `create${modelName}_${fieldName}`,
|
|
707
|
+
parameters: [
|
|
708
|
+
{
|
|
709
|
+
$ref: "#/components/parameters/id"
|
|
710
|
+
}
|
|
711
|
+
],
|
|
712
|
+
requestBody: {
|
|
713
|
+
required: true,
|
|
714
|
+
content: {
|
|
715
|
+
"application/vnd.api+json": {
|
|
716
|
+
schema: {
|
|
717
|
+
$ref: `#/components/schemas/${fieldDef.type}CreateRequest`
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
responses: {
|
|
723
|
+
"201": {
|
|
724
|
+
description: `Created ${fieldDef.type} resource`,
|
|
725
|
+
content: {
|
|
726
|
+
"application/vnd.api+json": {
|
|
727
|
+
schema: {
|
|
728
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
"400": ERROR_400,
|
|
734
|
+
...mayDeny && {
|
|
735
|
+
"403": ERROR_403
|
|
736
|
+
},
|
|
737
|
+
"422": ERROR_422
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
} else if (!isCollection && isOperationIncluded(fieldDef.type, "update", this.queryOptions)) {
|
|
741
|
+
pathItem["patch"] = {
|
|
742
|
+
tags: [
|
|
743
|
+
tag
|
|
744
|
+
],
|
|
745
|
+
summary: `Update nested ${fieldDef.type} under ${modelName}`,
|
|
746
|
+
operationId: `update${modelName}_${fieldName}`,
|
|
747
|
+
parameters: [
|
|
748
|
+
{
|
|
749
|
+
$ref: "#/components/parameters/id"
|
|
750
|
+
}
|
|
751
|
+
],
|
|
752
|
+
requestBody: {
|
|
753
|
+
required: true,
|
|
754
|
+
content: {
|
|
755
|
+
"application/vnd.api+json": {
|
|
756
|
+
schema: {
|
|
757
|
+
$ref: `#/components/schemas/${fieldDef.type}UpdateRequest`
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
},
|
|
762
|
+
responses: {
|
|
763
|
+
"200": {
|
|
764
|
+
description: `Updated ${fieldDef.type} resource`,
|
|
765
|
+
content: {
|
|
766
|
+
"application/vnd.api+json": {
|
|
767
|
+
schema: {
|
|
768
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
},
|
|
773
|
+
"400": ERROR_400,
|
|
774
|
+
...mayDeny && {
|
|
775
|
+
"403": ERROR_403
|
|
776
|
+
},
|
|
777
|
+
"404": ERROR_404,
|
|
778
|
+
"422": ERROR_422
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return pathItem;
|
|
784
|
+
}
|
|
785
|
+
buildNestedSinglePath(modelName, fieldName, fieldDef, relModelDef, tag) {
|
|
786
|
+
const childIdParam = {
|
|
787
|
+
name: "childId",
|
|
788
|
+
in: "path",
|
|
789
|
+
required: true,
|
|
790
|
+
schema: {
|
|
791
|
+
type: "string"
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
const idParam = {
|
|
795
|
+
$ref: "#/components/parameters/id"
|
|
796
|
+
};
|
|
797
|
+
const mayDenyUpdate = this.mayDenyAccess(relModelDef, "update");
|
|
798
|
+
const mayDenyDelete = this.mayDenyAccess(relModelDef, "delete");
|
|
799
|
+
const result = {};
|
|
800
|
+
if (isOperationIncluded(fieldDef.type, "findUnique", this.queryOptions)) {
|
|
801
|
+
result["get"] = {
|
|
802
|
+
tags: [
|
|
803
|
+
tag
|
|
804
|
+
],
|
|
805
|
+
summary: `Get a nested ${fieldDef.type} by ID under ${modelName}`,
|
|
806
|
+
operationId: `get${modelName}_${fieldName}_single`,
|
|
807
|
+
parameters: [
|
|
808
|
+
idParam,
|
|
809
|
+
childIdParam,
|
|
810
|
+
{
|
|
811
|
+
$ref: "#/components/parameters/include"
|
|
812
|
+
}
|
|
813
|
+
],
|
|
814
|
+
responses: {
|
|
815
|
+
"200": {
|
|
816
|
+
description: `${fieldDef.type} resource`,
|
|
817
|
+
content: {
|
|
818
|
+
"application/vnd.api+json": {
|
|
819
|
+
schema: {
|
|
820
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
},
|
|
825
|
+
"404": ERROR_404
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
if (isOperationIncluded(fieldDef.type, "update", this.queryOptions)) {
|
|
830
|
+
result["patch"] = {
|
|
831
|
+
tags: [
|
|
832
|
+
tag
|
|
833
|
+
],
|
|
834
|
+
summary: `Update a nested ${fieldDef.type} by ID under ${modelName}`,
|
|
835
|
+
operationId: `update${modelName}_${fieldName}_single`,
|
|
836
|
+
parameters: [
|
|
837
|
+
idParam,
|
|
838
|
+
childIdParam
|
|
839
|
+
],
|
|
840
|
+
requestBody: {
|
|
841
|
+
required: true,
|
|
842
|
+
content: {
|
|
843
|
+
"application/vnd.api+json": {
|
|
844
|
+
schema: {
|
|
845
|
+
$ref: `#/components/schemas/${fieldDef.type}UpdateRequest`
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
responses: {
|
|
851
|
+
"200": {
|
|
852
|
+
description: `Updated ${fieldDef.type} resource`,
|
|
853
|
+
content: {
|
|
854
|
+
"application/vnd.api+json": {
|
|
855
|
+
schema: {
|
|
856
|
+
$ref: `#/components/schemas/${fieldDef.type}Response`
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
"400": ERROR_400,
|
|
862
|
+
...mayDenyUpdate && {
|
|
863
|
+
"403": ERROR_403
|
|
864
|
+
},
|
|
865
|
+
"404": ERROR_404,
|
|
866
|
+
"422": ERROR_422
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
if (isOperationIncluded(fieldDef.type, "delete", this.queryOptions)) {
|
|
871
|
+
result["delete"] = {
|
|
872
|
+
tags: [
|
|
873
|
+
tag
|
|
874
|
+
],
|
|
875
|
+
summary: `Delete a nested ${fieldDef.type} by ID under ${modelName}`,
|
|
876
|
+
operationId: `delete${modelName}_${fieldName}_single`,
|
|
877
|
+
parameters: [
|
|
878
|
+
idParam,
|
|
879
|
+
childIdParam
|
|
880
|
+
],
|
|
881
|
+
responses: {
|
|
882
|
+
"200": {
|
|
883
|
+
description: "Deleted successfully"
|
|
884
|
+
},
|
|
885
|
+
...mayDenyDelete && {
|
|
886
|
+
"403": ERROR_403
|
|
887
|
+
},
|
|
888
|
+
"404": ERROR_404
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
return result;
|
|
689
893
|
}
|
|
690
894
|
buildRelationshipPath(modelDef, fieldName, fieldDef, tag) {
|
|
691
895
|
const modelName = modelDef.name;
|