@strapi/core 5.18.1 → 5.20.0
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/core-api/routes/index.d.ts +4 -22
- package/dist/core-api/routes/index.d.ts.map +1 -1
- package/dist/core-api/routes/index.js +150 -8
- package/dist/core-api/routes/index.js.map +1 -1
- package/dist/core-api/routes/index.mjs +131 -8
- package/dist/core-api/routes/index.mjs.map +1 -1
- package/dist/core-api/routes/validation/attributes.d.ts +244 -0
- package/dist/core-api/routes/validation/attributes.d.ts.map +1 -0
- package/dist/core-api/routes/validation/attributes.js +560 -0
- package/dist/core-api/routes/validation/attributes.js.map +1 -0
- package/dist/core-api/routes/validation/attributes.mjs +521 -0
- package/dist/core-api/routes/validation/attributes.mjs.map +1 -0
- package/dist/core-api/routes/validation/common.d.ts +105 -0
- package/dist/core-api/routes/validation/common.d.ts.map +1 -0
- package/dist/core-api/routes/validation/common.js +116 -0
- package/dist/core-api/routes/validation/common.js.map +1 -0
- package/dist/core-api/routes/validation/common.mjs +95 -0
- package/dist/core-api/routes/validation/common.mjs.map +1 -0
- package/dist/core-api/routes/validation/component.d.ts +34 -0
- package/dist/core-api/routes/validation/component.d.ts.map +1 -0
- package/dist/core-api/routes/validation/component.js +45 -0
- package/dist/core-api/routes/validation/component.js.map +1 -0
- package/dist/core-api/routes/validation/component.mjs +43 -0
- package/dist/core-api/routes/validation/component.mjs.map +1 -0
- package/dist/core-api/routes/validation/constants.d.ts +8 -0
- package/dist/core-api/routes/validation/constants.d.ts.map +1 -0
- package/dist/core-api/routes/validation/constants.js +18 -0
- package/dist/core-api/routes/validation/constants.js.map +1 -0
- package/dist/core-api/routes/validation/constants.mjs +16 -0
- package/dist/core-api/routes/validation/constants.mjs.map +1 -0
- package/dist/core-api/routes/validation/content-type.d.ts +128 -0
- package/dist/core-api/routes/validation/content-type.d.ts.map +1 -0
- package/dist/core-api/routes/validation/content-type.js +201 -0
- package/dist/core-api/routes/validation/content-type.js.map +1 -0
- package/dist/core-api/routes/validation/content-type.mjs +180 -0
- package/dist/core-api/routes/validation/content-type.mjs.map +1 -0
- package/dist/core-api/routes/validation/index.d.ts +5 -0
- package/dist/core-api/routes/validation/index.d.ts.map +1 -0
- package/dist/core-api/routes/validation/mappers.d.ts +105 -0
- package/dist/core-api/routes/validation/mappers.d.ts.map +1 -0
- package/dist/core-api/routes/validation/mappers.js +238 -0
- package/dist/core-api/routes/validation/mappers.js.map +1 -0
- package/dist/core-api/routes/validation/mappers.mjs +214 -0
- package/dist/core-api/routes/validation/mappers.mjs.map +1 -0
- package/dist/core-api/routes/validation/utils.d.ts +47 -0
- package/dist/core-api/routes/validation/utils.d.ts.map +1 -0
- package/dist/core-api/routes/validation/utils.js +112 -0
- package/dist/core-api/routes/validation/utils.js.map +1 -0
- package/dist/core-api/routes/validation/utils.mjs +90 -0
- package/dist/core-api/routes/validation/utils.mjs.map +1 -0
- package/dist/domain/module/index.d.ts.map +1 -1
- package/dist/domain/module/index.js +3 -0
- package/dist/domain/module/index.js.map +1 -1
- package/dist/domain/module/index.mjs +3 -0
- package/dist/domain/module/index.mjs.map +1 -1
- package/dist/factories.d.ts +3 -1
- package/dist/factories.d.ts.map +1 -1
- package/dist/factories.js +10 -2
- package/dist/factories.js.map +1 -1
- package/dist/factories.mjs +10 -3
- package/dist/factories.mjs.map +1 -1
- package/dist/middlewares/cors.d.ts +9 -1
- package/dist/middlewares/cors.d.ts.map +1 -1
- package/dist/middlewares/cors.js +39 -17
- package/dist/middlewares/cors.js.map +1 -1
- package/dist/middlewares/cors.mjs +39 -18
- package/dist/middlewares/cors.mjs.map +1 -1
- package/dist/package.json.js +13 -12
- package/dist/package.json.js.map +1 -1
- package/dist/package.json.mjs +13 -12
- package/dist/package.json.mjs.map +1 -1
- package/dist/services/metrics/index.d.ts +1 -1
- package/dist/services/metrics/index.d.ts.map +1 -1
- package/dist/services/metrics/index.js +9 -8
- package/dist/services/metrics/index.js.map +1 -1
- package/dist/services/metrics/index.mjs +9 -8
- package/dist/services/metrics/index.mjs.map +1 -1
- package/dist/services/metrics/sender.d.ts.map +1 -1
- package/dist/services/metrics/sender.js +2 -2
- package/dist/services/metrics/sender.js.map +1 -1
- package/dist/services/metrics/sender.mjs +2 -2
- package/dist/services/metrics/sender.mjs.map +1 -1
- package/dist/services/server/register-routes.js +22 -2
- package/dist/services/server/register-routes.js.map +1 -1
- package/dist/services/server/register-routes.mjs +22 -2
- package/dist/services/server/register-routes.mjs.map +1 -1
- package/dist/services/server/routing.d.ts +10 -0
- package/dist/services/server/routing.d.ts.map +1 -1
- package/dist/services/server/routing.js +7 -1
- package/dist/services/server/routing.js.map +1 -1
- package/dist/services/server/routing.mjs +7 -1
- package/dist/services/server/routing.mjs.map +1 -1
- package/package.json +13 -12
@@ -0,0 +1,128 @@
|
|
1
|
+
import type { UID } from '@strapi/types';
|
2
|
+
import * as z from 'zod/v4';
|
3
|
+
import { AbstractCoreRouteValidator } from './common';
|
4
|
+
export type QueryParam = 'fields' | 'populate' | 'sort' | 'status' | 'locale' | 'pagination' | 'filters' | '_q';
|
5
|
+
/**
|
6
|
+
* A validator for core content-type routes.
|
7
|
+
*
|
8
|
+
* Provides validation schemas and utilities for handling content-type-specific route validation.
|
9
|
+
* Extends the base AbstractRouteValidator with schema-aware validation for Strapi content types.
|
10
|
+
*
|
11
|
+
* @example
|
12
|
+
* ```ts
|
13
|
+
* const strapi = // ... strapi instance
|
14
|
+
* const uid = 'api::article.article'
|
15
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
16
|
+
*
|
17
|
+
* // Get validation schema for document
|
18
|
+
* const documentSchema = validator.document;
|
19
|
+
*
|
20
|
+
* // Validate query parameters with schema awareness
|
21
|
+
* const querySchema = validator.queryParams(['fields', 'populate', 'sort']);
|
22
|
+
* ```
|
23
|
+
*/
|
24
|
+
export declare class CoreContentTypeRouteValidator extends AbstractCoreRouteValidator<UID.ContentType> {
|
25
|
+
/**
|
26
|
+
* Generates a validation schema for document IDs
|
27
|
+
*
|
28
|
+
* @returns A schema that validates UUIDs
|
29
|
+
*
|
30
|
+
* @example
|
31
|
+
* ```ts
|
32
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
33
|
+
* const idSchema = validator.documentID;
|
34
|
+
* ```
|
35
|
+
*/
|
36
|
+
get documentID(): z.ZodUUID;
|
37
|
+
/**
|
38
|
+
* Generates a comprehensive validation schema for a single document.
|
39
|
+
*
|
40
|
+
* Combines scalar fields and populatable fields into a single schema.
|
41
|
+
*
|
42
|
+
* @returns A schema for validating complete documents
|
43
|
+
*
|
44
|
+
* @example
|
45
|
+
* ```ts
|
46
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
47
|
+
* const docSchema = validator.document;
|
48
|
+
* ```
|
49
|
+
*/
|
50
|
+
get document(): z.ZodObject<{
|
51
|
+
documentId: z.ZodUUID;
|
52
|
+
id: z.ZodNumber;
|
53
|
+
}, z.core.$strip>;
|
54
|
+
/**
|
55
|
+
* Generates a validation schema for an array of documents
|
56
|
+
*
|
57
|
+
* @returns A schema for validating arrays of documents
|
58
|
+
*
|
59
|
+
* @example
|
60
|
+
* ```ts
|
61
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
62
|
+
* const docsSchema = validator.documents;
|
63
|
+
* ```
|
64
|
+
*/
|
65
|
+
get documents(): z.ZodArray<z.ZodObject<{
|
66
|
+
documentId: z.ZodUUID;
|
67
|
+
id: z.ZodNumber;
|
68
|
+
}, z.core.$strip>>;
|
69
|
+
/**
|
70
|
+
* Schema-aware fields validation that restricts to actual model fields
|
71
|
+
*/
|
72
|
+
protected get schemaAwareQueryFields(): z.ZodReadonly<z.ZodArray<z.ZodEnum<{
|
73
|
+
[x: string]: string;
|
74
|
+
}>>>;
|
75
|
+
/**
|
76
|
+
* Schema-aware populate validation that restricts to actual populatable fields
|
77
|
+
*/
|
78
|
+
protected get schemaAwareQueryPopulate(): z.ZodUnion<readonly [z.ZodReadonly<z.ZodLiteral<"*">>, z.ZodReadonly<z.ZodEnum<{
|
79
|
+
[x: string]: string;
|
80
|
+
}>>, z.ZodArray<z.ZodEnum<{
|
81
|
+
[x: string]: string;
|
82
|
+
}>>]>;
|
83
|
+
/**
|
84
|
+
* Schema-aware sort validation that restricts to actual model fields
|
85
|
+
*/
|
86
|
+
protected get schemaAwareQuerySort(): z.ZodUnion<readonly [z.ZodEnum<{
|
87
|
+
[x: string]: string;
|
88
|
+
}>, z.ZodArray<z.ZodEnum<{
|
89
|
+
[x: string]: string;
|
90
|
+
}>>, z.ZodRecord<z.ZodEnum<{
|
91
|
+
[x: string]: string;
|
92
|
+
}>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>, z.ZodArray<z.ZodRecord<z.ZodEnum<{
|
93
|
+
[x: string]: string;
|
94
|
+
}>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>]>;
|
95
|
+
/**
|
96
|
+
* Schema-aware filters validation that restricts to actual model fields
|
97
|
+
*/
|
98
|
+
protected get schemaAwareFilters(): z.ZodRecord<z.ZodEnum<{
|
99
|
+
[x: string]: string;
|
100
|
+
}>, z.ZodAny>;
|
101
|
+
get locale(): z.ZodString;
|
102
|
+
get status(): z.ZodEnum<{
|
103
|
+
draft: "draft";
|
104
|
+
published: "published";
|
105
|
+
}>;
|
106
|
+
get data(): z.ZodObject<{}, z.core.$strip>;
|
107
|
+
get query(): z.ZodString;
|
108
|
+
get body(): z.ZodObject<{
|
109
|
+
data: z.ZodObject<{}, z.core.$strip>;
|
110
|
+
}, z.core.$strip>;
|
111
|
+
get partialBody(): z.ZodObject<{
|
112
|
+
data: z.ZodObject<{}, z.core.$strip>;
|
113
|
+
}, z.core.$strip>;
|
114
|
+
/**
|
115
|
+
* Creates validation schemas for query parameters
|
116
|
+
*
|
117
|
+
* @param params - Array of query parameters to validate ('fields', 'populate', 'sort', ...)
|
118
|
+
* @returns Object containing validation schemas for requested parameters
|
119
|
+
*
|
120
|
+
* @example
|
121
|
+
* ```ts
|
122
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
123
|
+
* const querySchemas = validator.queryParams(['fields', 'populate']);
|
124
|
+
* ```
|
125
|
+
*/
|
126
|
+
queryParams(params: QueryParam[]): Partial<Record<QueryParam, z.Schema>>;
|
127
|
+
}
|
128
|
+
//# sourceMappingURL=content-type.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"content-type.d.ts","sourceRoot":"","sources":["../../../../src/core-api/routes/validation/content-type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,GAAG,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAI5B,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAEtD,MAAM,MAAM,UAAU,GAClB,QAAQ,GACR,UAAU,GACV,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,IAAI,CAAC;AAET;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,6BAA8B,SAAQ,0BAA0B,CAAC,GAAG,CAAC,WAAW,CAAC;IAC5F;;;;;;;;;;OAUG;IACH,IAAI,UAAU,cAEb;IAED;;;;;;;;;;;;OAYG;IACH,IAAI,QAAQ;;;sBAgBX;IAED;;;;;;;;;;OAUG;IACH,IAAI,SAAS;;;uBAEZ;IAED;;OAEG;IACH,SAAS,KAAK,sBAAsB;;SAMnC;IAED;;OAEG;IACH,SAAS,KAAK,wBAAwB;;;;UAiBrC;IAED;;OAEG;IACH,SAAS,KAAK,oBAAoB;;;;;;;;oFAYjC;IAED;;OAEG;IACH,SAAS,KAAK,kBAAkB;;kBAE/B;IAED,IAAI,MAAM,gBAET;IAED,IAAI,MAAM;;;OAIT;IAED,IAAI,IAAI,mCAYP;IAED,IAAI,KAAK,gBAER;IAED,IAAI,IAAI;;sBAEP;IAED,IAAI,WAAW;;sBAEd;IAED;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;CAiBzE"}
|
@@ -0,0 +1,201 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
var strapiUtils = require('@strapi/utils');
|
4
|
+
var z = require('zod/v4');
|
5
|
+
var mappers = require('./mappers.js');
|
6
|
+
var common = require('./common.js');
|
7
|
+
|
8
|
+
function _interopNamespaceDefault(e) {
|
9
|
+
var n = Object.create(null);
|
10
|
+
if (e) {
|
11
|
+
Object.keys(e).forEach(function (k) {
|
12
|
+
if (k !== 'default') {
|
13
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
15
|
+
enumerable: true,
|
16
|
+
get: function () { return e[k]; }
|
17
|
+
});
|
18
|
+
}
|
19
|
+
});
|
20
|
+
}
|
21
|
+
n.default = e;
|
22
|
+
return Object.freeze(n);
|
23
|
+
}
|
24
|
+
|
25
|
+
var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
|
26
|
+
|
27
|
+
/**
|
28
|
+
* A validator for core content-type routes.
|
29
|
+
*
|
30
|
+
* Provides validation schemas and utilities for handling content-type-specific route validation.
|
31
|
+
* Extends the base AbstractRouteValidator with schema-aware validation for Strapi content types.
|
32
|
+
*
|
33
|
+
* @example
|
34
|
+
* ```ts
|
35
|
+
* const strapi = // ... strapi instance
|
36
|
+
* const uid = 'api::article.article'
|
37
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
38
|
+
*
|
39
|
+
* // Get validation schema for document
|
40
|
+
* const documentSchema = validator.document;
|
41
|
+
*
|
42
|
+
* // Validate query parameters with schema awareness
|
43
|
+
* const querySchema = validator.queryParams(['fields', 'populate', 'sort']);
|
44
|
+
* ```
|
45
|
+
*/ class CoreContentTypeRouteValidator extends common.AbstractCoreRouteValidator {
|
46
|
+
/**
|
47
|
+
* Generates a validation schema for document IDs
|
48
|
+
*
|
49
|
+
* @returns A schema that validates UUIDs
|
50
|
+
*
|
51
|
+
* @example
|
52
|
+
* ```ts
|
53
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
54
|
+
* const idSchema = validator.documentID;
|
55
|
+
* ```
|
56
|
+
*/ get documentID() {
|
57
|
+
return z__namespace.uuid().describe('The document ID, represented by a UUID');
|
58
|
+
}
|
59
|
+
/**
|
60
|
+
* Generates a comprehensive validation schema for a single document.
|
61
|
+
*
|
62
|
+
* Combines scalar fields and populatable fields into a single schema.
|
63
|
+
*
|
64
|
+
* @returns A schema for validating complete documents
|
65
|
+
*
|
66
|
+
* @example
|
67
|
+
* ```ts
|
68
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
69
|
+
* const docSchema = validator.document;
|
70
|
+
* ```
|
71
|
+
*/ get document() {
|
72
|
+
const entries = Object.entries({
|
73
|
+
...this._scalarFields,
|
74
|
+
...this._populatableFields
|
75
|
+
});
|
76
|
+
const sanitizedAttributes = entries// Remove passwords from the attribute list
|
77
|
+
.filter(([, attribute])=>![
|
78
|
+
'password'
|
79
|
+
].includes(attribute.type));
|
80
|
+
// Merge all attributes into a single schema
|
81
|
+
const attributesSchema = mappers.createAttributesSchema(sanitizedAttributes);
|
82
|
+
return z__namespace.object({
|
83
|
+
documentId: this.documentID,
|
84
|
+
id: z__namespace.number()
|
85
|
+
}).extend(attributesSchema.shape);
|
86
|
+
}
|
87
|
+
/**
|
88
|
+
* Generates a validation schema for an array of documents
|
89
|
+
*
|
90
|
+
* @returns A schema for validating arrays of documents
|
91
|
+
*
|
92
|
+
* @example
|
93
|
+
* ```ts
|
94
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
95
|
+
* const docsSchema = validator.documents;
|
96
|
+
* ```
|
97
|
+
*/ get documents() {
|
98
|
+
return z__namespace.array(this.document);
|
99
|
+
}
|
100
|
+
/**
|
101
|
+
* Schema-aware fields validation that restricts to actual model fields
|
102
|
+
*/ get schemaAwareQueryFields() {
|
103
|
+
return this.scalarFieldsArray.readonly().describe(`The fields to return, this doesn't include populatable fields like relations, components, files, or dynamic zones`);
|
104
|
+
}
|
105
|
+
/**
|
106
|
+
* Schema-aware populate validation that restricts to actual populatable fields
|
107
|
+
*/ get schemaAwareQueryPopulate() {
|
108
|
+
const wildcardPopulate = z__namespace.literal('*').readonly().describe('Populate all the first level relations, components, files, and dynamic zones for the entry');
|
109
|
+
const singleFieldPopulate = this.populatableFieldsEnum.readonly().describe('Populate a single relation, component, file, or dynamic zone');
|
110
|
+
const multiPopulate = this.populatableFieldsArray.describe('Populate a selection of multiple relations, components, files, or dynamic zones');
|
111
|
+
return z__namespace.union([
|
112
|
+
wildcardPopulate,
|
113
|
+
singleFieldPopulate,
|
114
|
+
multiPopulate
|
115
|
+
]);
|
116
|
+
}
|
117
|
+
/**
|
118
|
+
* Schema-aware sort validation that restricts to actual model fields
|
119
|
+
*/ get schemaAwareQuerySort() {
|
120
|
+
const orderDirection = z__namespace.enum([
|
121
|
+
'asc',
|
122
|
+
'desc'
|
123
|
+
]);
|
124
|
+
// TODO: Handle nested sorts but very low priority, very little usage
|
125
|
+
return z__namespace.union([
|
126
|
+
this.scalarFieldsEnum,
|
127
|
+
this.scalarFieldsArray,
|
128
|
+
this.fieldRecord(orderDirection),
|
129
|
+
z__namespace.array(this.fieldRecord(orderDirection))
|
130
|
+
]).describe('Sort the result');
|
131
|
+
}
|
132
|
+
/**
|
133
|
+
* Schema-aware filters validation that restricts to actual model fields
|
134
|
+
*/ get schemaAwareFilters() {
|
135
|
+
return z__namespace.record(this.scalarFieldsEnum, z__namespace.any()).describe('Filters to apply to the query');
|
136
|
+
}
|
137
|
+
get locale() {
|
138
|
+
return z__namespace.string().describe('Select a locale');
|
139
|
+
}
|
140
|
+
get status() {
|
141
|
+
return z__namespace.enum([
|
142
|
+
'draft',
|
143
|
+
'published'
|
144
|
+
]).describe('Fetch documents based on their status. Default to "published" if not specified.');
|
145
|
+
}
|
146
|
+
get data() {
|
147
|
+
const isWritableAttribute = ([attributeName])=>{
|
148
|
+
return strapiUtils.contentTypes.isWritableAttribute(this._schema, attributeName);
|
149
|
+
};
|
150
|
+
const entries = Object.entries({
|
151
|
+
...this._scalarFields,
|
152
|
+
...this._populatableFields
|
153
|
+
});
|
154
|
+
const sanitizedAttributes = entries// Remove non-writable attributes
|
155
|
+
.filter(isWritableAttribute);
|
156
|
+
return mappers.createAttributesInputSchema(sanitizedAttributes);
|
157
|
+
}
|
158
|
+
get query() {
|
159
|
+
return z__namespace.string();
|
160
|
+
}
|
161
|
+
get body() {
|
162
|
+
return z__namespace.object({
|
163
|
+
data: this.data
|
164
|
+
});
|
165
|
+
}
|
166
|
+
get partialBody() {
|
167
|
+
return z__namespace.object({
|
168
|
+
data: this.data.partial()
|
169
|
+
});
|
170
|
+
}
|
171
|
+
/**
|
172
|
+
* Creates validation schemas for query parameters
|
173
|
+
*
|
174
|
+
* @param params - Array of query parameters to validate ('fields', 'populate', 'sort', ...)
|
175
|
+
* @returns Object containing validation schemas for requested parameters
|
176
|
+
*
|
177
|
+
* @example
|
178
|
+
* ```ts
|
179
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
180
|
+
* const querySchemas = validator.queryParams(['fields', 'populate']);
|
181
|
+
* ```
|
182
|
+
*/ queryParams(params) {
|
183
|
+
const map = {
|
184
|
+
fields: ()=>this.schemaAwareQueryFields.optional(),
|
185
|
+
populate: ()=>this.schemaAwareQueryPopulate.optional(),
|
186
|
+
sort: ()=>this.schemaAwareQuerySort.optional(),
|
187
|
+
filters: ()=>this.schemaAwareFilters.optional(),
|
188
|
+
locale: ()=>this.locale.optional(),
|
189
|
+
pagination: ()=>this.pagination.optional(),
|
190
|
+
status: ()=>this.status.optional(),
|
191
|
+
_q: ()=>this.query.optional()
|
192
|
+
};
|
193
|
+
return params.reduce((acc, param)=>({
|
194
|
+
...acc,
|
195
|
+
[param]: map[param]()
|
196
|
+
}), {});
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
exports.CoreContentTypeRouteValidator = CoreContentTypeRouteValidator;
|
201
|
+
//# sourceMappingURL=content-type.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"content-type.js","sources":["../../../../src/core-api/routes/validation/content-type.ts"],"sourcesContent":["import type { Schema, UID } from '@strapi/types';\n\nimport { contentTypes } from '@strapi/utils';\nimport * as z from 'zod/v4';\n\n// eslint-disable-next-line import/no-cycle\nimport { createAttributesInputSchema, createAttributesSchema } from './mappers';\nimport { AbstractCoreRouteValidator } from './common';\n\nexport type QueryParam =\n | 'fields'\n | 'populate'\n | 'sort'\n | 'status'\n | 'locale'\n | 'pagination'\n | 'filters'\n | '_q';\n\n/**\n * A validator for core content-type routes.\n *\n * Provides validation schemas and utilities for handling content-type-specific route validation.\n * Extends the base AbstractRouteValidator with schema-aware validation for Strapi content types.\n *\n * @example\n * ```ts\n * const strapi = // ... strapi instance\n * const uid = 'api::article.article'\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n *\n * // Get validation schema for document\n * const documentSchema = validator.document;\n *\n * // Validate query parameters with schema awareness\n * const querySchema = validator.queryParams(['fields', 'populate', 'sort']);\n * ```\n */\nexport class CoreContentTypeRouteValidator extends AbstractCoreRouteValidator<UID.ContentType> {\n /**\n * Generates a validation schema for document IDs\n *\n * @returns A schema that validates UUIDs\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const idSchema = validator.documentID;\n * ```\n */\n get documentID() {\n return z.uuid().describe('The document ID, represented by a UUID');\n }\n\n /**\n * Generates a comprehensive validation schema for a single document.\n *\n * Combines scalar fields and populatable fields into a single schema.\n *\n * @returns A schema for validating complete documents\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const docSchema = validator.document;\n * ```\n */\n get document() {\n const entries = Object.entries({ ...this._scalarFields, ...this._populatableFields });\n\n const sanitizedAttributes = entries\n // Remove passwords from the attribute list\n .filter(([, attribute]) => !['password'].includes(attribute.type));\n\n // Merge all attributes into a single schema\n const attributesSchema = createAttributesSchema(sanitizedAttributes);\n\n return z\n .object({\n documentId: this.documentID,\n id: z.number(),\n })\n .extend(attributesSchema.shape);\n }\n\n /**\n * Generates a validation schema for an array of documents\n *\n * @returns A schema for validating arrays of documents\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const docsSchema = validator.documents;\n * ```\n */\n get documents() {\n return z.array(this.document);\n }\n\n /**\n * Schema-aware fields validation that restricts to actual model fields\n */\n protected get schemaAwareQueryFields() {\n return this.scalarFieldsArray\n .readonly()\n .describe(\n `The fields to return, this doesn't include populatable fields like relations, components, files, or dynamic zones`\n );\n }\n\n /**\n * Schema-aware populate validation that restricts to actual populatable fields\n */\n protected get schemaAwareQueryPopulate() {\n const wildcardPopulate = z\n .literal('*')\n .readonly()\n .describe(\n 'Populate all the first level relations, components, files, and dynamic zones for the entry'\n );\n\n const singleFieldPopulate = this.populatableFieldsEnum\n .readonly()\n .describe('Populate a single relation, component, file, or dynamic zone');\n\n const multiPopulate = this.populatableFieldsArray.describe(\n 'Populate a selection of multiple relations, components, files, or dynamic zones'\n );\n\n return z.union([wildcardPopulate, singleFieldPopulate, multiPopulate]);\n }\n\n /**\n * Schema-aware sort validation that restricts to actual model fields\n */\n protected get schemaAwareQuerySort() {\n const orderDirection = z.enum(['asc', 'desc']);\n\n // TODO: Handle nested sorts but very low priority, very little usage\n return z\n .union([\n this.scalarFieldsEnum, // 'name' | 'title'\n this.scalarFieldsArray, // ['name', 'title']\n this.fieldRecord(orderDirection), // { name: 'desc' } | { title: 'asc' }\n z.array(this.fieldRecord(orderDirection)), // [{ name: 'desc'}, { title: 'asc' }]\n ])\n .describe('Sort the result');\n }\n\n /**\n * Schema-aware filters validation that restricts to actual model fields\n */\n protected get schemaAwareFilters() {\n return z.record(this.scalarFieldsEnum, z.any()).describe('Filters to apply to the query');\n }\n\n get locale() {\n return z.string().describe('Select a locale');\n }\n\n get status() {\n return z\n .enum(['draft', 'published'])\n .describe('Fetch documents based on their status. Default to \"published\" if not specified.');\n }\n\n get data() {\n const isWritableAttribute = ([attributeName]: [string, Schema.Attribute.AnyAttribute]) => {\n return contentTypes.isWritableAttribute(this._schema, attributeName);\n };\n\n const entries = Object.entries({ ...this._scalarFields, ...this._populatableFields });\n\n const sanitizedAttributes = entries\n // Remove non-writable attributes\n .filter(isWritableAttribute);\n\n return createAttributesInputSchema(sanitizedAttributes);\n }\n\n get query() {\n return z.string();\n }\n\n get body() {\n return z.object({ data: this.data });\n }\n\n get partialBody() {\n return z.object({ data: this.data.partial() });\n }\n\n /**\n * Creates validation schemas for query parameters\n *\n * @param params - Array of query parameters to validate ('fields', 'populate', 'sort', ...)\n * @returns Object containing validation schemas for requested parameters\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const querySchemas = validator.queryParams(['fields', 'populate']);\n * ```\n */\n queryParams(params: QueryParam[]): Partial<Record<QueryParam, z.Schema>> {\n const map: Record<QueryParam, () => z.Schema> = {\n fields: () => this.schemaAwareQueryFields.optional(),\n populate: () => this.schemaAwareQueryPopulate.optional(),\n sort: () => this.schemaAwareQuerySort.optional(),\n filters: () => this.schemaAwareFilters.optional(),\n locale: () => this.locale.optional(),\n pagination: () => this.pagination.optional(),\n status: () => this.status.optional(),\n _q: () => this.query.optional(),\n } as const;\n\n return params.reduce(\n (acc, param) => ({ ...acc, [param]: map[param]() }),\n {} as Partial<Record<QueryParam, z.Schema>>\n );\n }\n}\n"],"names":["CoreContentTypeRouteValidator","AbstractCoreRouteValidator","documentID","z","uuid","describe","document","entries","Object","_scalarFields","_populatableFields","sanitizedAttributes","filter","attribute","includes","type","attributesSchema","createAttributesSchema","object","documentId","id","number","extend","shape","documents","array","schemaAwareQueryFields","scalarFieldsArray","readonly","schemaAwareQueryPopulate","wildcardPopulate","literal","singleFieldPopulate","populatableFieldsEnum","multiPopulate","populatableFieldsArray","union","schemaAwareQuerySort","orderDirection","enum","scalarFieldsEnum","fieldRecord","schemaAwareFilters","record","any","locale","string","status","data","isWritableAttribute","attributeName","contentTypes","_schema","createAttributesInputSchema","query","body","partialBody","partial","queryParams","params","map","fields","optional","populate","sort","filters","pagination","_q","reduce","acc","param"],"mappings":"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"}
|
@@ -0,0 +1,180 @@
|
|
1
|
+
import { contentTypes } from '@strapi/utils';
|
2
|
+
import * as z from 'zod/v4';
|
3
|
+
import { createAttributesSchema, createAttributesInputSchema } from './mappers.mjs';
|
4
|
+
import { AbstractCoreRouteValidator } from './common.mjs';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* A validator for core content-type routes.
|
8
|
+
*
|
9
|
+
* Provides validation schemas and utilities for handling content-type-specific route validation.
|
10
|
+
* Extends the base AbstractRouteValidator with schema-aware validation for Strapi content types.
|
11
|
+
*
|
12
|
+
* @example
|
13
|
+
* ```ts
|
14
|
+
* const strapi = // ... strapi instance
|
15
|
+
* const uid = 'api::article.article'
|
16
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
17
|
+
*
|
18
|
+
* // Get validation schema for document
|
19
|
+
* const documentSchema = validator.document;
|
20
|
+
*
|
21
|
+
* // Validate query parameters with schema awareness
|
22
|
+
* const querySchema = validator.queryParams(['fields', 'populate', 'sort']);
|
23
|
+
* ```
|
24
|
+
*/ class CoreContentTypeRouteValidator extends AbstractCoreRouteValidator {
|
25
|
+
/**
|
26
|
+
* Generates a validation schema for document IDs
|
27
|
+
*
|
28
|
+
* @returns A schema that validates UUIDs
|
29
|
+
*
|
30
|
+
* @example
|
31
|
+
* ```ts
|
32
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
33
|
+
* const idSchema = validator.documentID;
|
34
|
+
* ```
|
35
|
+
*/ get documentID() {
|
36
|
+
return z.uuid().describe('The document ID, represented by a UUID');
|
37
|
+
}
|
38
|
+
/**
|
39
|
+
* Generates a comprehensive validation schema for a single document.
|
40
|
+
*
|
41
|
+
* Combines scalar fields and populatable fields into a single schema.
|
42
|
+
*
|
43
|
+
* @returns A schema for validating complete documents
|
44
|
+
*
|
45
|
+
* @example
|
46
|
+
* ```ts
|
47
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
48
|
+
* const docSchema = validator.document;
|
49
|
+
* ```
|
50
|
+
*/ get document() {
|
51
|
+
const entries = Object.entries({
|
52
|
+
...this._scalarFields,
|
53
|
+
...this._populatableFields
|
54
|
+
});
|
55
|
+
const sanitizedAttributes = entries// Remove passwords from the attribute list
|
56
|
+
.filter(([, attribute])=>![
|
57
|
+
'password'
|
58
|
+
].includes(attribute.type));
|
59
|
+
// Merge all attributes into a single schema
|
60
|
+
const attributesSchema = createAttributesSchema(sanitizedAttributes);
|
61
|
+
return z.object({
|
62
|
+
documentId: this.documentID,
|
63
|
+
id: z.number()
|
64
|
+
}).extend(attributesSchema.shape);
|
65
|
+
}
|
66
|
+
/**
|
67
|
+
* Generates a validation schema for an array of documents
|
68
|
+
*
|
69
|
+
* @returns A schema for validating arrays of documents
|
70
|
+
*
|
71
|
+
* @example
|
72
|
+
* ```ts
|
73
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
74
|
+
* const docsSchema = validator.documents;
|
75
|
+
* ```
|
76
|
+
*/ get documents() {
|
77
|
+
return z.array(this.document);
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* Schema-aware fields validation that restricts to actual model fields
|
81
|
+
*/ get schemaAwareQueryFields() {
|
82
|
+
return this.scalarFieldsArray.readonly().describe(`The fields to return, this doesn't include populatable fields like relations, components, files, or dynamic zones`);
|
83
|
+
}
|
84
|
+
/**
|
85
|
+
* Schema-aware populate validation that restricts to actual populatable fields
|
86
|
+
*/ get schemaAwareQueryPopulate() {
|
87
|
+
const wildcardPopulate = z.literal('*').readonly().describe('Populate all the first level relations, components, files, and dynamic zones for the entry');
|
88
|
+
const singleFieldPopulate = this.populatableFieldsEnum.readonly().describe('Populate a single relation, component, file, or dynamic zone');
|
89
|
+
const multiPopulate = this.populatableFieldsArray.describe('Populate a selection of multiple relations, components, files, or dynamic zones');
|
90
|
+
return z.union([
|
91
|
+
wildcardPopulate,
|
92
|
+
singleFieldPopulate,
|
93
|
+
multiPopulate
|
94
|
+
]);
|
95
|
+
}
|
96
|
+
/**
|
97
|
+
* Schema-aware sort validation that restricts to actual model fields
|
98
|
+
*/ get schemaAwareQuerySort() {
|
99
|
+
const orderDirection = z.enum([
|
100
|
+
'asc',
|
101
|
+
'desc'
|
102
|
+
]);
|
103
|
+
// TODO: Handle nested sorts but very low priority, very little usage
|
104
|
+
return z.union([
|
105
|
+
this.scalarFieldsEnum,
|
106
|
+
this.scalarFieldsArray,
|
107
|
+
this.fieldRecord(orderDirection),
|
108
|
+
z.array(this.fieldRecord(orderDirection))
|
109
|
+
]).describe('Sort the result');
|
110
|
+
}
|
111
|
+
/**
|
112
|
+
* Schema-aware filters validation that restricts to actual model fields
|
113
|
+
*/ get schemaAwareFilters() {
|
114
|
+
return z.record(this.scalarFieldsEnum, z.any()).describe('Filters to apply to the query');
|
115
|
+
}
|
116
|
+
get locale() {
|
117
|
+
return z.string().describe('Select a locale');
|
118
|
+
}
|
119
|
+
get status() {
|
120
|
+
return z.enum([
|
121
|
+
'draft',
|
122
|
+
'published'
|
123
|
+
]).describe('Fetch documents based on their status. Default to "published" if not specified.');
|
124
|
+
}
|
125
|
+
get data() {
|
126
|
+
const isWritableAttribute = ([attributeName])=>{
|
127
|
+
return contentTypes.isWritableAttribute(this._schema, attributeName);
|
128
|
+
};
|
129
|
+
const entries = Object.entries({
|
130
|
+
...this._scalarFields,
|
131
|
+
...this._populatableFields
|
132
|
+
});
|
133
|
+
const sanitizedAttributes = entries// Remove non-writable attributes
|
134
|
+
.filter(isWritableAttribute);
|
135
|
+
return createAttributesInputSchema(sanitizedAttributes);
|
136
|
+
}
|
137
|
+
get query() {
|
138
|
+
return z.string();
|
139
|
+
}
|
140
|
+
get body() {
|
141
|
+
return z.object({
|
142
|
+
data: this.data
|
143
|
+
});
|
144
|
+
}
|
145
|
+
get partialBody() {
|
146
|
+
return z.object({
|
147
|
+
data: this.data.partial()
|
148
|
+
});
|
149
|
+
}
|
150
|
+
/**
|
151
|
+
* Creates validation schemas for query parameters
|
152
|
+
*
|
153
|
+
* @param params - Array of query parameters to validate ('fields', 'populate', 'sort', ...)
|
154
|
+
* @returns Object containing validation schemas for requested parameters
|
155
|
+
*
|
156
|
+
* @example
|
157
|
+
* ```ts
|
158
|
+
* const validator = new CoreContentTypeRouteValidator(strapi, uid);
|
159
|
+
* const querySchemas = validator.queryParams(['fields', 'populate']);
|
160
|
+
* ```
|
161
|
+
*/ queryParams(params) {
|
162
|
+
const map = {
|
163
|
+
fields: ()=>this.schemaAwareQueryFields.optional(),
|
164
|
+
populate: ()=>this.schemaAwareQueryPopulate.optional(),
|
165
|
+
sort: ()=>this.schemaAwareQuerySort.optional(),
|
166
|
+
filters: ()=>this.schemaAwareFilters.optional(),
|
167
|
+
locale: ()=>this.locale.optional(),
|
168
|
+
pagination: ()=>this.pagination.optional(),
|
169
|
+
status: ()=>this.status.optional(),
|
170
|
+
_q: ()=>this.query.optional()
|
171
|
+
};
|
172
|
+
return params.reduce((acc, param)=>({
|
173
|
+
...acc,
|
174
|
+
[param]: map[param]()
|
175
|
+
}), {});
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
export { CoreContentTypeRouteValidator };
|
180
|
+
//# sourceMappingURL=content-type.mjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"content-type.mjs","sources":["../../../../src/core-api/routes/validation/content-type.ts"],"sourcesContent":["import type { Schema, UID } from '@strapi/types';\n\nimport { contentTypes } from '@strapi/utils';\nimport * as z from 'zod/v4';\n\n// eslint-disable-next-line import/no-cycle\nimport { createAttributesInputSchema, createAttributesSchema } from './mappers';\nimport { AbstractCoreRouteValidator } from './common';\n\nexport type QueryParam =\n | 'fields'\n | 'populate'\n | 'sort'\n | 'status'\n | 'locale'\n | 'pagination'\n | 'filters'\n | '_q';\n\n/**\n * A validator for core content-type routes.\n *\n * Provides validation schemas and utilities for handling content-type-specific route validation.\n * Extends the base AbstractRouteValidator with schema-aware validation for Strapi content types.\n *\n * @example\n * ```ts\n * const strapi = // ... strapi instance\n * const uid = 'api::article.article'\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n *\n * // Get validation schema for document\n * const documentSchema = validator.document;\n *\n * // Validate query parameters with schema awareness\n * const querySchema = validator.queryParams(['fields', 'populate', 'sort']);\n * ```\n */\nexport class CoreContentTypeRouteValidator extends AbstractCoreRouteValidator<UID.ContentType> {\n /**\n * Generates a validation schema for document IDs\n *\n * @returns A schema that validates UUIDs\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const idSchema = validator.documentID;\n * ```\n */\n get documentID() {\n return z.uuid().describe('The document ID, represented by a UUID');\n }\n\n /**\n * Generates a comprehensive validation schema for a single document.\n *\n * Combines scalar fields and populatable fields into a single schema.\n *\n * @returns A schema for validating complete documents\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const docSchema = validator.document;\n * ```\n */\n get document() {\n const entries = Object.entries({ ...this._scalarFields, ...this._populatableFields });\n\n const sanitizedAttributes = entries\n // Remove passwords from the attribute list\n .filter(([, attribute]) => !['password'].includes(attribute.type));\n\n // Merge all attributes into a single schema\n const attributesSchema = createAttributesSchema(sanitizedAttributes);\n\n return z\n .object({\n documentId: this.documentID,\n id: z.number(),\n })\n .extend(attributesSchema.shape);\n }\n\n /**\n * Generates a validation schema for an array of documents\n *\n * @returns A schema for validating arrays of documents\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const docsSchema = validator.documents;\n * ```\n */\n get documents() {\n return z.array(this.document);\n }\n\n /**\n * Schema-aware fields validation that restricts to actual model fields\n */\n protected get schemaAwareQueryFields() {\n return this.scalarFieldsArray\n .readonly()\n .describe(\n `The fields to return, this doesn't include populatable fields like relations, components, files, or dynamic zones`\n );\n }\n\n /**\n * Schema-aware populate validation that restricts to actual populatable fields\n */\n protected get schemaAwareQueryPopulate() {\n const wildcardPopulate = z\n .literal('*')\n .readonly()\n .describe(\n 'Populate all the first level relations, components, files, and dynamic zones for the entry'\n );\n\n const singleFieldPopulate = this.populatableFieldsEnum\n .readonly()\n .describe('Populate a single relation, component, file, or dynamic zone');\n\n const multiPopulate = this.populatableFieldsArray.describe(\n 'Populate a selection of multiple relations, components, files, or dynamic zones'\n );\n\n return z.union([wildcardPopulate, singleFieldPopulate, multiPopulate]);\n }\n\n /**\n * Schema-aware sort validation that restricts to actual model fields\n */\n protected get schemaAwareQuerySort() {\n const orderDirection = z.enum(['asc', 'desc']);\n\n // TODO: Handle nested sorts but very low priority, very little usage\n return z\n .union([\n this.scalarFieldsEnum, // 'name' | 'title'\n this.scalarFieldsArray, // ['name', 'title']\n this.fieldRecord(orderDirection), // { name: 'desc' } | { title: 'asc' }\n z.array(this.fieldRecord(orderDirection)), // [{ name: 'desc'}, { title: 'asc' }]\n ])\n .describe('Sort the result');\n }\n\n /**\n * Schema-aware filters validation that restricts to actual model fields\n */\n protected get schemaAwareFilters() {\n return z.record(this.scalarFieldsEnum, z.any()).describe('Filters to apply to the query');\n }\n\n get locale() {\n return z.string().describe('Select a locale');\n }\n\n get status() {\n return z\n .enum(['draft', 'published'])\n .describe('Fetch documents based on their status. Default to \"published\" if not specified.');\n }\n\n get data() {\n const isWritableAttribute = ([attributeName]: [string, Schema.Attribute.AnyAttribute]) => {\n return contentTypes.isWritableAttribute(this._schema, attributeName);\n };\n\n const entries = Object.entries({ ...this._scalarFields, ...this._populatableFields });\n\n const sanitizedAttributes = entries\n // Remove non-writable attributes\n .filter(isWritableAttribute);\n\n return createAttributesInputSchema(sanitizedAttributes);\n }\n\n get query() {\n return z.string();\n }\n\n get body() {\n return z.object({ data: this.data });\n }\n\n get partialBody() {\n return z.object({ data: this.data.partial() });\n }\n\n /**\n * Creates validation schemas for query parameters\n *\n * @param params - Array of query parameters to validate ('fields', 'populate', 'sort', ...)\n * @returns Object containing validation schemas for requested parameters\n *\n * @example\n * ```ts\n * const validator = new CoreContentTypeRouteValidator(strapi, uid);\n * const querySchemas = validator.queryParams(['fields', 'populate']);\n * ```\n */\n queryParams(params: QueryParam[]): Partial<Record<QueryParam, z.Schema>> {\n const map: Record<QueryParam, () => z.Schema> = {\n fields: () => this.schemaAwareQueryFields.optional(),\n populate: () => this.schemaAwareQueryPopulate.optional(),\n sort: () => this.schemaAwareQuerySort.optional(),\n filters: () => this.schemaAwareFilters.optional(),\n locale: () => this.locale.optional(),\n pagination: () => this.pagination.optional(),\n status: () => this.status.optional(),\n _q: () => this.query.optional(),\n } as const;\n\n return params.reduce(\n (acc, param) => ({ ...acc, [param]: map[param]() }),\n {} as Partial<Record<QueryParam, z.Schema>>\n );\n }\n}\n"],"names":["CoreContentTypeRouteValidator","AbstractCoreRouteValidator","documentID","z","uuid","describe","document","entries","Object","_scalarFields","_populatableFields","sanitizedAttributes","filter","attribute","includes","type","attributesSchema","createAttributesSchema","object","documentId","id","number","extend","shape","documents","array","schemaAwareQueryFields","scalarFieldsArray","readonly","schemaAwareQueryPopulate","wildcardPopulate","literal","singleFieldPopulate","populatableFieldsEnum","multiPopulate","populatableFieldsArray","union","schemaAwareQuerySort","orderDirection","enum","scalarFieldsEnum","fieldRecord","schemaAwareFilters","record","any","locale","string","status","data","isWritableAttribute","attributeName","contentTypes","_schema","createAttributesInputSchema","query","body","partialBody","partial","queryParams","params","map","fields","optional","populate","sort","filters","pagination","_q","reduce","acc","param"],"mappings":"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"}
|
@@ -0,0 +1,5 @@
|
|
1
|
+
export { AbstractCoreRouteValidator } from './common';
|
2
|
+
export { CoreContentTypeRouteValidator } from './content-type';
|
3
|
+
export { CoreComponentRouteValidator } from './component';
|
4
|
+
export { createAttributesInputSchema, createAttributesSchema, mapAttributeToSchema, mapAttributeToInputSchema, } from './mappers';
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core-api/routes/validation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EACL,2BAA2B,EAC3B,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,WAAW,CAAC"}
|