@strapi/core 5.36.0 → 5.37.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.
Files changed (76) hide show
  1. package/dist/core-api/controller/index.d.ts.map +1 -1
  2. package/dist/core-api/controller/index.js +17 -16
  3. package/dist/core-api/controller/index.js.map +1 -1
  4. package/dist/core-api/controller/index.mjs +17 -16
  5. package/dist/core-api/controller/index.mjs.map +1 -1
  6. package/dist/core-api/routes/index.js +15 -2
  7. package/dist/core-api/routes/index.js.map +1 -1
  8. package/dist/core-api/routes/index.mjs +15 -2
  9. package/dist/core-api/routes/index.mjs.map +1 -1
  10. package/dist/core-api/routes/validation/content-type.d.ts +5 -1
  11. package/dist/core-api/routes/validation/content-type.d.ts.map +1 -1
  12. package/dist/core-api/routes/validation/content-type.js +10 -0
  13. package/dist/core-api/routes/validation/content-type.js.map +1 -1
  14. package/dist/core-api/routes/validation/content-type.mjs +10 -0
  15. package/dist/core-api/routes/validation/content-type.mjs.map +1 -1
  16. package/dist/migrations/database/5.0.0-discard-drafts.d.ts +21 -7
  17. package/dist/migrations/database/5.0.0-discard-drafts.d.ts.map +1 -1
  18. package/dist/migrations/database/5.0.0-discard-drafts.js +1936 -59
  19. package/dist/migrations/database/5.0.0-discard-drafts.js.map +1 -1
  20. package/dist/migrations/database/5.0.0-discard-drafts.mjs +1937 -60
  21. package/dist/migrations/database/5.0.0-discard-drafts.mjs.map +1 -1
  22. package/dist/package.json.js +19 -15
  23. package/dist/package.json.js.map +1 -1
  24. package/dist/package.json.mjs +19 -15
  25. package/dist/package.json.mjs.map +1 -1
  26. package/dist/services/content-api/index.d.ts +6 -3
  27. package/dist/services/content-api/index.d.ts.map +1 -1
  28. package/dist/services/content-api/index.js +165 -3
  29. package/dist/services/content-api/index.js.map +1 -1
  30. package/dist/services/content-api/index.mjs +147 -4
  31. package/dist/services/content-api/index.mjs.map +1 -1
  32. package/dist/services/cron.d.ts.map +1 -1
  33. package/dist/services/cron.js +3 -0
  34. package/dist/services/cron.js.map +1 -1
  35. package/dist/services/cron.mjs +3 -0
  36. package/dist/services/cron.mjs.map +1 -1
  37. package/dist/services/document-service/draft-and-publish.d.ts +16 -2
  38. package/dist/services/document-service/draft-and-publish.d.ts.map +1 -1
  39. package/dist/services/document-service/draft-and-publish.js +53 -0
  40. package/dist/services/document-service/draft-and-publish.js.map +1 -1
  41. package/dist/services/document-service/draft-and-publish.mjs +53 -2
  42. package/dist/services/document-service/draft-and-publish.mjs.map +1 -1
  43. package/dist/services/document-service/params.d.ts +24 -0
  44. package/dist/services/document-service/params.d.ts.map +1 -1
  45. package/dist/services/document-service/params.js +33 -0
  46. package/dist/services/document-service/params.js.map +1 -1
  47. package/dist/services/document-service/params.mjs +31 -1
  48. package/dist/services/document-service/params.mjs.map +1 -1
  49. package/dist/services/document-service/repository.d.ts.map +1 -1
  50. package/dist/services/document-service/repository.js +165 -4
  51. package/dist/services/document-service/repository.js.map +1 -1
  52. package/dist/services/document-service/repository.mjs +167 -6
  53. package/dist/services/document-service/repository.mjs.map +1 -1
  54. package/dist/services/document-service/transform/query.d.ts.map +1 -1
  55. package/dist/services/document-service/transform/query.js +39 -3
  56. package/dist/services/document-service/transform/query.js.map +1 -1
  57. package/dist/services/document-service/transform/query.mjs +37 -1
  58. package/dist/services/document-service/transform/query.mjs.map +1 -1
  59. package/dist/services/entity-validator/validators.d.ts.map +1 -1
  60. package/dist/services/entity-validator/validators.js +22 -5
  61. package/dist/services/entity-validator/validators.js.map +1 -1
  62. package/dist/services/entity-validator/validators.mjs +22 -5
  63. package/dist/services/entity-validator/validators.mjs.map +1 -1
  64. package/dist/services/server/register-routes.js +3 -0
  65. package/dist/services/server/register-routes.js.map +1 -1
  66. package/dist/services/server/register-routes.mjs +3 -0
  67. package/dist/services/server/register-routes.mjs.map +1 -1
  68. package/dist/services/webhook-runner.js +2 -2
  69. package/dist/services/webhook-runner.js.map +1 -1
  70. package/dist/services/webhook-runner.mjs +2 -2
  71. package/dist/services/webhook-runner.mjs.map +1 -1
  72. package/dist/services/worker-queue.js +2 -2
  73. package/dist/services/worker-queue.js.map +1 -1
  74. package/dist/services/worker-queue.mjs +2 -2
  75. package/dist/services/worker-queue.mjs.map +1 -1
  76. package/package.json +19 -15
@@ -1 +1 @@
1
- {"version":3,"file":"package.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"package.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,5 +1,5 @@
1
1
  import { sanitize, validate } from '@strapi/utils';
2
- import type { Core } from '@strapi/types';
2
+ import type { Core, Modules } from '@strapi/types';
3
3
  /**
4
4
  * Create a content API container that holds logic, tools and utils. (eg: permissions, ...)
5
5
  */
@@ -51,7 +51,7 @@ declare const createContentAPI: (strapi: Core.Strapi) => {
51
51
  sanitize: {
52
52
  input: sanitize.SanitizeFunc;
53
53
  output: sanitize.SanitizeFunc;
54
- query: (query: Record<string, unknown>, schema: import("@strapi/utils/dist/types").Model, { auth }?: sanitize.Options | undefined) => Promise<Record<string, unknown>>;
54
+ query: (query: Record<string, unknown>, schema: import("@strapi/utils/dist/types").Model, { auth, strictParams, route }?: sanitize.Options | undefined) => Promise<Record<string, unknown>>;
55
55
  filters: sanitize.SanitizeFunc;
56
56
  sort: sanitize.SanitizeFunc;
57
57
  fields: sanitize.SanitizeFunc;
@@ -59,12 +59,15 @@ declare const createContentAPI: (strapi: Core.Strapi) => {
59
59
  };
60
60
  validate: {
61
61
  input: validate.ValidateFunc;
62
- query: (query: Record<string, unknown>, schema: import("@strapi/utils/dist/types").Model, { auth }?: validate.Options | undefined) => Promise<void>;
62
+ query: (query: Record<string, unknown>, schema: import("@strapi/utils/dist/types").Model, { auth, strictParams, route }?: validate.Options | undefined) => Promise<void>;
63
63
  filters: validate.ValidateFunc;
64
64
  sort: validate.ValidateFunc;
65
65
  fields: validate.ValidateFunc;
66
66
  populate: validate.ValidateFunc;
67
67
  };
68
+ addQueryParams: (options: Modules.ContentAPI.AddQueryParamsOptions) => void;
69
+ addInputParams: (options: Modules.ContentAPI.AddInputParamsOptions) => void;
70
+ applyExtraParamsToRoutes: (routes: Core.Route[]) => void;
68
71
  };
69
72
  export default createContentAPI;
70
73
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/content-api/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAqC,MAAM,eAAe,CAAC;AAEtF,OAAO,KAAK,EAAE,IAAI,EAAO,MAAM,eAAe,CAAC;AAgB/C;;GAEG;AACH,QAAA,MAAM,gBAAgB,WAAY,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgF5C,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/content-api/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,EACR,QAAQ,EAIT,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAO,MAAM,eAAe,CAAC;AAiHxD;;GAEG;AACH,QAAA,MAAM,gBAAgB,WAAY,KAAK,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA0CV,QAAQ,UAAU,CAAC,qBAAqB;8BAQxC,QAAQ,UAAU,CAAC,qBAAqB;uCAK/B,KAAK,KAAK,EAAE,KAAG,IAAI;CA2F9D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -2,8 +2,28 @@
2
2
 
3
3
  var _ = require('lodash');
4
4
  var strapiUtils = require('@strapi/utils');
5
+ var z = require('zod/v4');
5
6
  var index = require('./permissions/index.js');
6
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
+
7
27
  const transformRoutePrefixFor = (pluginName)=>(route)=>{
8
28
  const prefix = route.config && route.config.prefix;
9
29
  const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;
@@ -13,9 +33,150 @@ const transformRoutePrefixFor = (pluginName)=>(route)=>{
13
33
  };
14
34
  };
15
35
  const filterContentAPI = (route)=>route.info.type === 'content-api';
36
+ /**
37
+ * Runtime check for addQueryParams: we only allow scalar or array-of-scalar schemas (no nested objects).
38
+ * We keep this in addition to the ZodQueryParamSchema type because: (1) TypeScript can be bypassed (JS,
39
+ * any, or schema from another Zod instance); (2) it gives a clear, immediate error at registration
40
+ * time instead of a later failure in validate/sanitize. This list is intentionally tied to Zod v4
41
+ * constructor names; if Zod changes internals, this may need updating.
42
+ * Compatibility: Zod 3 and Zod 4 Classic (zod/v4) both use these constructor names and
43
+ * expose ._def with .innerType / .element for Optional/Default/Array. Zod 4 Core/Mini use
44
+ * ._zod.def instead; we only accept schemas from the same zod/v4 instance used here.
45
+ */ const ALLOWED_QUERY_SCHEMA_NAMES = new Set([
46
+ 'ZodString',
47
+ 'ZodNumber',
48
+ 'ZodBoolean',
49
+ 'ZodEnum',
50
+ 'ZodOptional',
51
+ 'ZodDefault',
52
+ 'ZodArray'
53
+ ]);
54
+ function assertQueryParamSchema(schema, param) {
55
+ const name = schema?.constructor?.name ?? '';
56
+ if (!ALLOWED_QUERY_SCHEMA_NAMES.has(name)) {
57
+ throw new Error(`contentAPI.addQueryParams: param "${param}" schema must be a scalar (string, number, boolean, enum) or array of scalars; got ${name}. Use addInputParams for nested objects.`);
58
+ }
59
+ if (name === 'ZodOptional' || name === 'ZodDefault') {
60
+ const inner = schema?._def?.innerType;
61
+ if (inner) assertQueryParamSchema(inner, param);
62
+ return;
63
+ }
64
+ if (name === 'ZodArray') {
65
+ const element = schema?._def?.element;
66
+ if (element) assertQueryParamSchema(element, param);
67
+ }
68
+ }
69
+ function resolveSchema(schemaOrFactory) {
70
+ if (typeof schemaOrFactory === 'function') {
71
+ return schemaOrFactory(z__namespace);
72
+ }
73
+ return schemaOrFactory;
74
+ }
75
+ const mergeOneQueryParamIntoRoute = (route, param, schema, matchRoute)=>{
76
+ if (matchRoute && !matchRoute(route)) return;
77
+ const query = {
78
+ ...route.request?.query ?? {}
79
+ };
80
+ if (param in query) {
81
+ throw new Error(`contentAPI.addQueryParams: param "${param}" already exists on route ${route.method} ${route.path}`);
82
+ }
83
+ route.request = {
84
+ ...route.request,
85
+ query: {
86
+ ...query,
87
+ [param]: schema
88
+ }
89
+ };
90
+ };
91
+ const mergeOneInputParamIntoRoute = (route, param, schema, matchRoute)=>{
92
+ if (matchRoute && !matchRoute(route)) return;
93
+ const jsonKey = 'application/json';
94
+ const body = route.request?.body ? {
95
+ ...route.request.body
96
+ } : {};
97
+ const existing = body[jsonKey];
98
+ const base = existing && typeof existing === 'object' && 'shape' in existing ? existing.shape : {};
99
+ if (param in base) {
100
+ throw new Error(`contentAPI.addInputParams: param "${param}" already exists on route ${route.method} ${route.path}`);
101
+ }
102
+ body[jsonKey] = z__namespace.object({
103
+ ...base,
104
+ [param]: schema
105
+ });
106
+ route.request = {
107
+ ...route.request,
108
+ body
109
+ };
110
+ };
16
111
  /**
17
112
  * Create a content API container that holds logic, tools and utils. (eg: permissions, ...)
18
113
  */ const createContentAPI = (strapi)=>{
114
+ const extraQueryParams = [];
115
+ const extraInputParams = [];
116
+ const addQueryParam = (options)=>{
117
+ const { param, schema: schemaOrFactory, matchRoute } = options;
118
+ const schema = resolveSchema(schemaOrFactory);
119
+ assertQueryParamSchema(schema, param);
120
+ if (strapiUtils.ALLOWED_QUERY_PARAM_KEYS.includes(param)) {
121
+ throw new Error(`contentAPI.addQueryParams: param "${param}" is reserved by Strapi; use a different name`);
122
+ }
123
+ if (extraQueryParams.some((o)=>o.param === param)) {
124
+ throw new Error(`contentAPI.addQueryParams: param "${param}" has already been added`);
125
+ }
126
+ extraQueryParams.push({
127
+ param,
128
+ schema,
129
+ matchRoute
130
+ });
131
+ // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).
132
+ // We do not merge here: at register() time routes may not exist yet (lazy creation), and
133
+ // merging here would cause double-merge when initRouting runs and 400 "invalid param" or
134
+ // "param already exists" errors.
135
+ };
136
+ const addInputParam = (options)=>{
137
+ const { param, schema: schemaOrFactory, matchRoute } = options;
138
+ const schema = resolveSchema(schemaOrFactory);
139
+ if (strapiUtils.RESERVED_INPUT_PARAM_KEYS.includes(param)) {
140
+ throw new Error(`contentAPI.addInputParams: param "${param}" is reserved by Strapi; use a different name`);
141
+ }
142
+ if (extraInputParams.some((o)=>o.param === param)) {
143
+ throw new Error(`contentAPI.addInputParams: param "${param}" has already been added`);
144
+ }
145
+ extraInputParams.push({
146
+ param,
147
+ schema,
148
+ matchRoute
149
+ });
150
+ // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).
151
+ };
152
+ /**
153
+ * Register extra query params. Keys = param names; values = { schema, matchRoute? }.
154
+ * Schemas must be Zod scalar or array-of-scalars (enforced at runtime via assertQueryParamSchema).
155
+ */ const addQueryParams = (options)=>{
156
+ Object.entries(options).forEach(([param, rest])=>addQueryParam({
157
+ param,
158
+ ...rest
159
+ }));
160
+ };
161
+ /**
162
+ * Register extra input params (root-level body.data). Keys = param names; values = { schema, matchRoute? }.
163
+ * Any Zod type allowed; enforced at registration time.
164
+ */ const addInputParams = (options)=>{
165
+ Object.entries(options).forEach(([param, rest])=>addInputParam({
166
+ param,
167
+ ...rest
168
+ }));
169
+ };
170
+ /** Merge all registered extra params into the given routes (mutates in place). Called at route registration. Throws if a param key already exists. */ const applyExtraParamsToRoutes = (routes)=>{
171
+ routes.forEach((route)=>{
172
+ for (const { param, schema, matchRoute } of extraQueryParams){
173
+ mergeOneQueryParamIntoRoute(route, param, schema, matchRoute);
174
+ }
175
+ for (const { param, schema, matchRoute } of extraInputParams){
176
+ mergeOneInputParamIntoRoute(route, param, schema, matchRoute);
177
+ }
178
+ });
179
+ };
19
180
  const getRoutesMap = async ()=>{
20
181
  const routesMap = {};
21
182
  _.forEach(strapi.apis, (api, apiName)=>{
@@ -55,7 +216,6 @@ const filterContentAPI = (route)=>route.info.type === 'content-api';
55
216
  getModel (uid) {
56
217
  return strapi.getModel(uid);
57
218
  },
58
- // NOTE: use lazy access to allow registration of sanitizers after the creation of the container
59
219
  get sanitizers () {
60
220
  return {
61
221
  input: strapi.sanitizers.get('content-api.input'),
@@ -67,7 +227,6 @@ const filterContentAPI = (route)=>route.info.type === 'content-api';
67
227
  getModel (uid) {
68
228
  return strapi.getModel(uid);
69
229
  },
70
- // NOTE: use lazy access to allow registration of validators after the creation of the container
71
230
  get validators () {
72
231
  return {
73
232
  input: strapi.validators.get('content-api.input')
@@ -78,7 +237,10 @@ const filterContentAPI = (route)=>route.info.type === 'content-api';
78
237
  permissions: index(strapi),
79
238
  getRoutesMap,
80
239
  sanitize: sanitizer,
81
- validate: validator
240
+ validate: validator,
241
+ addQueryParams,
242
+ addInputParams,
243
+ applyExtraParamsToRoutes
82
244
  };
83
245
  };
84
246
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/services/content-api/index.ts"],"sourcesContent":["import _ from 'lodash';\nimport { sanitize, validate, sanitizeRoutesMapForSerialization } from '@strapi/utils';\n\nimport type { Core, UID } from '@strapi/types';\n\nimport instantiatePermissionsUtilities from './permissions';\n\nconst transformRoutePrefixFor = (pluginName: string) => (route: Core.Route) => {\n const prefix = route.config && route.config.prefix;\n const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;\n\n return {\n ...route,\n path,\n };\n};\n\nconst filterContentAPI = (route: Core.Route) => route.info.type === 'content-api';\n\n/**\n * Create a content API container that holds logic, tools and utils. (eg: permissions, ...)\n */\nconst createContentAPI = (strapi: Core.Strapi) => {\n const getRoutesMap = async () => {\n const routesMap: Record<string, Core.Route[]> = {};\n\n _.forEach(strapi.apis, (api, apiName) => {\n const routes = _.flatMap(api.routes, (route) => {\n if ('routes' in route) {\n return route.routes;\n }\n\n return route;\n }).filter(filterContentAPI);\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`api::${apiName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n _.forEach(strapi.plugins, (plugin, pluginName) => {\n const transformPrefix = transformRoutePrefixFor(pluginName);\n\n if (Array.isArray(plugin.routes)) {\n return plugin.routes.map(transformPrefix).filter(filterContentAPI);\n }\n\n const routes = _.flatMap(plugin.routes, (route) => route.routes.map(transformPrefix)).filter(\n filterContentAPI\n );\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`plugin::${pluginName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n return sanitizeRoutesMapForSerialization(routesMap);\n };\n\n const sanitizer = sanitize.createAPISanitizers({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n // NOTE: use lazy access to allow registration of sanitizers after the creation of the container\n get sanitizers() {\n return {\n input: strapi.sanitizers.get('content-api.input'),\n output: strapi.sanitizers.get('content-api.output'),\n };\n },\n });\n\n const validator = validate.createAPIValidators({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n // NOTE: use lazy access to allow registration of validators after the creation of the container\n get validators() {\n return {\n input: strapi.validators.get('content-api.input'),\n };\n },\n });\n\n return {\n permissions: instantiatePermissionsUtilities(strapi),\n getRoutesMap,\n sanitize: sanitizer,\n validate: validator,\n };\n};\n\nexport default createContentAPI;\n"],"names":["transformRoutePrefixFor","pluginName","route","prefix","config","path","undefined","filterContentAPI","info","type","createContentAPI","strapi","getRoutesMap","routesMap","_","forEach","apis","api","apiName","routes","flatMap","filter","length","apiPrefix","get","map","plugins","plugin","transformPrefix","Array","isArray","sanitizeRoutesMapForSerialization","sanitizer","sanitize","createAPISanitizers","getModel","uid","sanitizers","input","output","validator","validate","createAPIValidators","validators","permissions","instantiatePermissionsUtilities"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/services/content-api/index.ts"],"sourcesContent":["import _ from 'lodash';\nimport {\n sanitize,\n validate,\n sanitizeRoutesMapForSerialization,\n ALLOWED_QUERY_PARAM_KEYS,\n RESERVED_INPUT_PARAM_KEYS,\n} from '@strapi/utils';\nimport * as z from 'zod/v4';\n\nimport type { Core, Modules, UID } from '@strapi/types';\n\nimport instantiatePermissionsUtilities from './permissions';\n\nconst transformRoutePrefixFor = (pluginName: string) => (route: Core.Route) => {\n const prefix = route.config && route.config.prefix;\n const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;\n\n return {\n ...route,\n path,\n };\n};\n\nconst filterContentAPI = (route: Core.Route) => route.info.type === 'content-api';\n\n/**\n * Runtime check for addQueryParams: we only allow scalar or array-of-scalar schemas (no nested objects).\n * We keep this in addition to the ZodQueryParamSchema type because: (1) TypeScript can be bypassed (JS,\n * any, or schema from another Zod instance); (2) it gives a clear, immediate error at registration\n * time instead of a later failure in validate/sanitize. This list is intentionally tied to Zod v4\n * constructor names; if Zod changes internals, this may need updating.\n * Compatibility: Zod 3 and Zod 4 Classic (zod/v4) both use these constructor names and\n * expose ._def with .innerType / .element for Optional/Default/Array. Zod 4 Core/Mini use\n * ._zod.def instead; we only accept schemas from the same zod/v4 instance used here.\n */\nconst ALLOWED_QUERY_SCHEMA_NAMES = new Set([\n 'ZodString',\n 'ZodNumber',\n 'ZodBoolean',\n 'ZodEnum',\n 'ZodOptional',\n 'ZodDefault',\n 'ZodArray',\n]);\n\nfunction assertQueryParamSchema(schema: unknown, param: string): void {\n const name = (schema as { constructor?: { name?: string } })?.constructor?.name ?? '';\n if (!ALLOWED_QUERY_SCHEMA_NAMES.has(name)) {\n throw new Error(\n `contentAPI.addQueryParams: param \"${param}\" schema must be a scalar (string, number, boolean, enum) or array of scalars; got ${name}. Use addInputParams for nested objects.`\n );\n }\n if (name === 'ZodOptional' || name === 'ZodDefault') {\n const inner = (schema as { _def?: { innerType?: unknown } })?._def?.innerType;\n if (inner) assertQueryParamSchema(inner, param);\n return;\n }\n if (name === 'ZodArray') {\n const element = (schema as { _def?: { element?: unknown } })?._def?.element;\n if (element) assertQueryParamSchema(element, param);\n }\n}\n\nfunction resolveSchema<T>(schemaOrFactory: T | ((zInstance: typeof z) => T)): T {\n if (typeof schemaOrFactory === 'function') {\n return (schemaOrFactory as (zInstance: typeof z) => T)(z);\n }\n return schemaOrFactory;\n}\n\nconst mergeOneQueryParamIntoRoute = (\n route: Core.Route,\n param: string,\n schema: z.ZodType,\n matchRoute?: (route: Core.Route) => boolean\n): void => {\n if (matchRoute && !matchRoute(route)) return;\n const query = { ...(route.request?.query ?? {}) };\n if (param in query) {\n throw new Error(\n `contentAPI.addQueryParams: param \"${param}\" already exists on route ${route.method} ${route.path}`\n );\n }\n route.request = { ...route.request, query: { ...query, [param]: schema } };\n};\n\nconst mergeOneInputParamIntoRoute = (\n route: Core.Route,\n param: string,\n schema: z.ZodType,\n matchRoute?: (route: Core.Route) => boolean\n): void => {\n if (matchRoute && !matchRoute(route)) return;\n const jsonKey = 'application/json';\n type RouteBody = NonNullable<NonNullable<Core.Route['request']>['body']>;\n const body: RouteBody = route.request?.body ? { ...route.request.body } : ({} as RouteBody);\n const existing = body[jsonKey];\n const base =\n existing && typeof existing === 'object' && 'shape' in existing\n ? (existing as { shape: Record<string, z.ZodType> }).shape\n : {};\n if (param in base) {\n throw new Error(\n `contentAPI.addInputParams: param \"${param}\" already exists on route ${route.method} ${route.path}`\n );\n }\n body[jsonKey] = z.object({ ...base, [param]: schema }) as RouteBody[keyof RouteBody];\n route.request = { ...route.request, body };\n};\n\n/** Stored options with schema always resolved (never a function). */\ntype ResolvedQueryParamEntry = {\n param: string;\n schema: z.ZodType;\n matchRoute?: (route: Core.Route) => boolean;\n};\ntype ResolvedInputParamEntry = {\n param: string;\n schema: z.ZodType;\n matchRoute?: (route: Core.Route) => boolean;\n};\n\n/**\n * Create a content API container that holds logic, tools and utils. (eg: permissions, ...)\n */\nconst createContentAPI = (strapi: Core.Strapi) => {\n const extraQueryParams: ResolvedQueryParamEntry[] = [];\n const extraInputParams: ResolvedInputParamEntry[] = [];\n\n const addQueryParam = (options: Modules.ContentAPI.QueryParamEntry & { param: string }) => {\n const { param, schema: schemaOrFactory, matchRoute } = options;\n const schema = resolveSchema(schemaOrFactory);\n assertQueryParamSchema(schema, param);\n if ((ALLOWED_QUERY_PARAM_KEYS as readonly string[]).includes(param)) {\n throw new Error(\n `contentAPI.addQueryParams: param \"${param}\" is reserved by Strapi; use a different name`\n );\n }\n if (extraQueryParams.some((o) => o.param === param)) {\n throw new Error(`contentAPI.addQueryParams: param \"${param}\" has already been added`);\n }\n extraQueryParams.push({ param, schema, matchRoute });\n // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).\n // We do not merge here: at register() time routes may not exist yet (lazy creation), and\n // merging here would cause double-merge when initRouting runs and 400 \"invalid param\" or\n // \"param already exists\" errors.\n };\n\n const addInputParam = (options: Modules.ContentAPI.InputParamEntry & { param: string }) => {\n const { param, schema: schemaOrFactory, matchRoute } = options;\n const schema = resolveSchema(schemaOrFactory);\n if ((RESERVED_INPUT_PARAM_KEYS as readonly string[]).includes(param)) {\n throw new Error(\n `contentAPI.addInputParams: param \"${param}\" is reserved by Strapi; use a different name`\n );\n }\n if (extraInputParams.some((o) => o.param === param)) {\n throw new Error(`contentAPI.addInputParams: param \"${param}\" has already been added`);\n }\n extraInputParams.push({ param, schema, matchRoute });\n // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).\n };\n\n /**\n * Register extra query params. Keys = param names; values = { schema, matchRoute? }.\n * Schemas must be Zod scalar or array-of-scalars (enforced at runtime via assertQueryParamSchema).\n */\n const addQueryParams = (options: Modules.ContentAPI.AddQueryParamsOptions) => {\n Object.entries(options).forEach(([param, rest]) => addQueryParam({ param, ...rest }));\n };\n\n /**\n * Register extra input params (root-level body.data). Keys = param names; values = { schema, matchRoute? }.\n * Any Zod type allowed; enforced at registration time.\n */\n const addInputParams = (options: Modules.ContentAPI.AddInputParamsOptions) => {\n Object.entries(options).forEach(([param, rest]) => addInputParam({ param, ...rest }));\n };\n\n /** Merge all registered extra params into the given routes (mutates in place). Called at route registration. Throws if a param key already exists. */\n const applyExtraParamsToRoutes = (routes: Core.Route[]): void => {\n routes.forEach((route) => {\n for (const { param, schema, matchRoute } of extraQueryParams) {\n mergeOneQueryParamIntoRoute(route, param, schema, matchRoute);\n }\n for (const { param, schema, matchRoute } of extraInputParams) {\n mergeOneInputParamIntoRoute(route, param, schema, matchRoute);\n }\n });\n };\n\n const getRoutesMap = async () => {\n const routesMap: Record<string, Core.Route[]> = {};\n\n _.forEach(strapi.apis, (api, apiName) => {\n const routes = _.flatMap(api.routes, (route) => {\n if ('routes' in route) {\n return route.routes;\n }\n\n return route;\n }).filter(filterContentAPI);\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`api::${apiName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n _.forEach(strapi.plugins, (plugin, pluginName) => {\n const transformPrefix = transformRoutePrefixFor(pluginName);\n\n if (Array.isArray(plugin.routes)) {\n return plugin.routes.map(transformPrefix).filter(filterContentAPI);\n }\n\n const routes = _.flatMap(plugin.routes, (route) => route.routes.map(transformPrefix)).filter(\n filterContentAPI\n );\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`plugin::${pluginName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n return sanitizeRoutesMapForSerialization(routesMap);\n };\n\n const sanitizer = sanitize.createAPISanitizers({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n get sanitizers() {\n return {\n input: strapi.sanitizers.get('content-api.input'),\n output: strapi.sanitizers.get('content-api.output'),\n };\n },\n });\n\n const validator = validate.createAPIValidators({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n get validators() {\n return {\n input: strapi.validators.get('content-api.input'),\n };\n },\n });\n\n return {\n permissions: instantiatePermissionsUtilities(strapi),\n getRoutesMap,\n sanitize: sanitizer,\n validate: validator,\n addQueryParams,\n addInputParams,\n applyExtraParamsToRoutes,\n };\n};\n\nexport default createContentAPI;\n"],"names":["transformRoutePrefixFor","pluginName","route","prefix","config","path","undefined","filterContentAPI","info","type","ALLOWED_QUERY_SCHEMA_NAMES","Set","assertQueryParamSchema","schema","param","name","has","Error","inner","_def","innerType","element","resolveSchema","schemaOrFactory","z","mergeOneQueryParamIntoRoute","matchRoute","query","request","method","mergeOneInputParamIntoRoute","jsonKey","body","existing","base","shape","object","createContentAPI","strapi","extraQueryParams","extraInputParams","addQueryParam","options","ALLOWED_QUERY_PARAM_KEYS","includes","some","o","push","addInputParam","RESERVED_INPUT_PARAM_KEYS","addQueryParams","Object","entries","forEach","rest","addInputParams","applyExtraParamsToRoutes","routes","getRoutesMap","routesMap","_","apis","api","apiName","flatMap","filter","length","apiPrefix","get","map","plugins","plugin","transformPrefix","Array","isArray","sanitizeRoutesMapForSerialization","sanitizer","sanitize","createAPISanitizers","getModel","uid","sanitizers","input","output","validator","validate","createAPIValidators","validators","permissions","instantiatePermissionsUtilities"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import _ from 'lodash';
2
- import { sanitize, validate, sanitizeRoutesMapForSerialization } from '@strapi/utils';
2
+ import { sanitize, validate, sanitizeRoutesMapForSerialization, ALLOWED_QUERY_PARAM_KEYS, RESERVED_INPUT_PARAM_KEYS } from '@strapi/utils';
3
+ import * as z from 'zod/v4';
3
4
  import instantiatePermissionsUtilities from './permissions/index.mjs';
4
5
 
5
6
  const transformRoutePrefixFor = (pluginName)=>(route)=>{
@@ -11,9 +12,150 @@ const transformRoutePrefixFor = (pluginName)=>(route)=>{
11
12
  };
12
13
  };
13
14
  const filterContentAPI = (route)=>route.info.type === 'content-api';
15
+ /**
16
+ * Runtime check for addQueryParams: we only allow scalar or array-of-scalar schemas (no nested objects).
17
+ * We keep this in addition to the ZodQueryParamSchema type because: (1) TypeScript can be bypassed (JS,
18
+ * any, or schema from another Zod instance); (2) it gives a clear, immediate error at registration
19
+ * time instead of a later failure in validate/sanitize. This list is intentionally tied to Zod v4
20
+ * constructor names; if Zod changes internals, this may need updating.
21
+ * Compatibility: Zod 3 and Zod 4 Classic (zod/v4) both use these constructor names and
22
+ * expose ._def with .innerType / .element for Optional/Default/Array. Zod 4 Core/Mini use
23
+ * ._zod.def instead; we only accept schemas from the same zod/v4 instance used here.
24
+ */ const ALLOWED_QUERY_SCHEMA_NAMES = new Set([
25
+ 'ZodString',
26
+ 'ZodNumber',
27
+ 'ZodBoolean',
28
+ 'ZodEnum',
29
+ 'ZodOptional',
30
+ 'ZodDefault',
31
+ 'ZodArray'
32
+ ]);
33
+ function assertQueryParamSchema(schema, param) {
34
+ const name = schema?.constructor?.name ?? '';
35
+ if (!ALLOWED_QUERY_SCHEMA_NAMES.has(name)) {
36
+ throw new Error(`contentAPI.addQueryParams: param "${param}" schema must be a scalar (string, number, boolean, enum) or array of scalars; got ${name}. Use addInputParams for nested objects.`);
37
+ }
38
+ if (name === 'ZodOptional' || name === 'ZodDefault') {
39
+ const inner = schema?._def?.innerType;
40
+ if (inner) assertQueryParamSchema(inner, param);
41
+ return;
42
+ }
43
+ if (name === 'ZodArray') {
44
+ const element = schema?._def?.element;
45
+ if (element) assertQueryParamSchema(element, param);
46
+ }
47
+ }
48
+ function resolveSchema(schemaOrFactory) {
49
+ if (typeof schemaOrFactory === 'function') {
50
+ return schemaOrFactory(z);
51
+ }
52
+ return schemaOrFactory;
53
+ }
54
+ const mergeOneQueryParamIntoRoute = (route, param, schema, matchRoute)=>{
55
+ if (matchRoute && !matchRoute(route)) return;
56
+ const query = {
57
+ ...route.request?.query ?? {}
58
+ };
59
+ if (param in query) {
60
+ throw new Error(`contentAPI.addQueryParams: param "${param}" already exists on route ${route.method} ${route.path}`);
61
+ }
62
+ route.request = {
63
+ ...route.request,
64
+ query: {
65
+ ...query,
66
+ [param]: schema
67
+ }
68
+ };
69
+ };
70
+ const mergeOneInputParamIntoRoute = (route, param, schema, matchRoute)=>{
71
+ if (matchRoute && !matchRoute(route)) return;
72
+ const jsonKey = 'application/json';
73
+ const body = route.request?.body ? {
74
+ ...route.request.body
75
+ } : {};
76
+ const existing = body[jsonKey];
77
+ const base = existing && typeof existing === 'object' && 'shape' in existing ? existing.shape : {};
78
+ if (param in base) {
79
+ throw new Error(`contentAPI.addInputParams: param "${param}" already exists on route ${route.method} ${route.path}`);
80
+ }
81
+ body[jsonKey] = z.object({
82
+ ...base,
83
+ [param]: schema
84
+ });
85
+ route.request = {
86
+ ...route.request,
87
+ body
88
+ };
89
+ };
14
90
  /**
15
91
  * Create a content API container that holds logic, tools and utils. (eg: permissions, ...)
16
92
  */ const createContentAPI = (strapi)=>{
93
+ const extraQueryParams = [];
94
+ const extraInputParams = [];
95
+ const addQueryParam = (options)=>{
96
+ const { param, schema: schemaOrFactory, matchRoute } = options;
97
+ const schema = resolveSchema(schemaOrFactory);
98
+ assertQueryParamSchema(schema, param);
99
+ if (ALLOWED_QUERY_PARAM_KEYS.includes(param)) {
100
+ throw new Error(`contentAPI.addQueryParams: param "${param}" is reserved by Strapi; use a different name`);
101
+ }
102
+ if (extraQueryParams.some((o)=>o.param === param)) {
103
+ throw new Error(`contentAPI.addQueryParams: param "${param}" has already been added`);
104
+ }
105
+ extraQueryParams.push({
106
+ param,
107
+ schema,
108
+ matchRoute
109
+ });
110
+ // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).
111
+ // We do not merge here: at register() time routes may not exist yet (lazy creation), and
112
+ // merging here would cause double-merge when initRouting runs and 400 "invalid param" or
113
+ // "param already exists" errors.
114
+ };
115
+ const addInputParam = (options)=>{
116
+ const { param, schema: schemaOrFactory, matchRoute } = options;
117
+ const schema = resolveSchema(schemaOrFactory);
118
+ if (RESERVED_INPUT_PARAM_KEYS.includes(param)) {
119
+ throw new Error(`contentAPI.addInputParams: param "${param}" is reserved by Strapi; use a different name`);
120
+ }
121
+ if (extraInputParams.some((o)=>o.param === param)) {
122
+ throw new Error(`contentAPI.addInputParams: param "${param}" has already been added`);
123
+ }
124
+ extraInputParams.push({
125
+ param,
126
+ schema,
127
+ matchRoute
128
+ });
129
+ // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).
130
+ };
131
+ /**
132
+ * Register extra query params. Keys = param names; values = { schema, matchRoute? }.
133
+ * Schemas must be Zod scalar or array-of-scalars (enforced at runtime via assertQueryParamSchema).
134
+ */ const addQueryParams = (options)=>{
135
+ Object.entries(options).forEach(([param, rest])=>addQueryParam({
136
+ param,
137
+ ...rest
138
+ }));
139
+ };
140
+ /**
141
+ * Register extra input params (root-level body.data). Keys = param names; values = { schema, matchRoute? }.
142
+ * Any Zod type allowed; enforced at registration time.
143
+ */ const addInputParams = (options)=>{
144
+ Object.entries(options).forEach(([param, rest])=>addInputParam({
145
+ param,
146
+ ...rest
147
+ }));
148
+ };
149
+ /** Merge all registered extra params into the given routes (mutates in place). Called at route registration. Throws if a param key already exists. */ const applyExtraParamsToRoutes = (routes)=>{
150
+ routes.forEach((route)=>{
151
+ for (const { param, schema, matchRoute } of extraQueryParams){
152
+ mergeOneQueryParamIntoRoute(route, param, schema, matchRoute);
153
+ }
154
+ for (const { param, schema, matchRoute } of extraInputParams){
155
+ mergeOneInputParamIntoRoute(route, param, schema, matchRoute);
156
+ }
157
+ });
158
+ };
17
159
  const getRoutesMap = async ()=>{
18
160
  const routesMap = {};
19
161
  _.forEach(strapi.apis, (api, apiName)=>{
@@ -53,7 +195,6 @@ const filterContentAPI = (route)=>route.info.type === 'content-api';
53
195
  getModel (uid) {
54
196
  return strapi.getModel(uid);
55
197
  },
56
- // NOTE: use lazy access to allow registration of sanitizers after the creation of the container
57
198
  get sanitizers () {
58
199
  return {
59
200
  input: strapi.sanitizers.get('content-api.input'),
@@ -65,7 +206,6 @@ const filterContentAPI = (route)=>route.info.type === 'content-api';
65
206
  getModel (uid) {
66
207
  return strapi.getModel(uid);
67
208
  },
68
- // NOTE: use lazy access to allow registration of validators after the creation of the container
69
209
  get validators () {
70
210
  return {
71
211
  input: strapi.validators.get('content-api.input')
@@ -76,7 +216,10 @@ const filterContentAPI = (route)=>route.info.type === 'content-api';
76
216
  permissions: instantiatePermissionsUtilities(strapi),
77
217
  getRoutesMap,
78
218
  sanitize: sanitizer,
79
- validate: validator
219
+ validate: validator,
220
+ addQueryParams,
221
+ addInputParams,
222
+ applyExtraParamsToRoutes
80
223
  };
81
224
  };
82
225
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../../src/services/content-api/index.ts"],"sourcesContent":["import _ from 'lodash';\nimport { sanitize, validate, sanitizeRoutesMapForSerialization } from '@strapi/utils';\n\nimport type { Core, UID } from '@strapi/types';\n\nimport instantiatePermissionsUtilities from './permissions';\n\nconst transformRoutePrefixFor = (pluginName: string) => (route: Core.Route) => {\n const prefix = route.config && route.config.prefix;\n const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;\n\n return {\n ...route,\n path,\n };\n};\n\nconst filterContentAPI = (route: Core.Route) => route.info.type === 'content-api';\n\n/**\n * Create a content API container that holds logic, tools and utils. (eg: permissions, ...)\n */\nconst createContentAPI = (strapi: Core.Strapi) => {\n const getRoutesMap = async () => {\n const routesMap: Record<string, Core.Route[]> = {};\n\n _.forEach(strapi.apis, (api, apiName) => {\n const routes = _.flatMap(api.routes, (route) => {\n if ('routes' in route) {\n return route.routes;\n }\n\n return route;\n }).filter(filterContentAPI);\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`api::${apiName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n _.forEach(strapi.plugins, (plugin, pluginName) => {\n const transformPrefix = transformRoutePrefixFor(pluginName);\n\n if (Array.isArray(plugin.routes)) {\n return plugin.routes.map(transformPrefix).filter(filterContentAPI);\n }\n\n const routes = _.flatMap(plugin.routes, (route) => route.routes.map(transformPrefix)).filter(\n filterContentAPI\n );\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`plugin::${pluginName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n return sanitizeRoutesMapForSerialization(routesMap);\n };\n\n const sanitizer = sanitize.createAPISanitizers({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n // NOTE: use lazy access to allow registration of sanitizers after the creation of the container\n get sanitizers() {\n return {\n input: strapi.sanitizers.get('content-api.input'),\n output: strapi.sanitizers.get('content-api.output'),\n };\n },\n });\n\n const validator = validate.createAPIValidators({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n // NOTE: use lazy access to allow registration of validators after the creation of the container\n get validators() {\n return {\n input: strapi.validators.get('content-api.input'),\n };\n },\n });\n\n return {\n permissions: instantiatePermissionsUtilities(strapi),\n getRoutesMap,\n sanitize: sanitizer,\n validate: validator,\n };\n};\n\nexport default createContentAPI;\n"],"names":["transformRoutePrefixFor","pluginName","route","prefix","config","path","undefined","filterContentAPI","info","type","createContentAPI","strapi","getRoutesMap","routesMap","_","forEach","apis","api","apiName","routes","flatMap","filter","length","apiPrefix","get","map","plugins","plugin","transformPrefix","Array","isArray","sanitizeRoutesMapForSerialization","sanitizer","sanitize","createAPISanitizers","getModel","uid","sanitizers","input","output","validator","validate","createAPIValidators","validators","permissions","instantiatePermissionsUtilities"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../../src/services/content-api/index.ts"],"sourcesContent":["import _ from 'lodash';\nimport {\n sanitize,\n validate,\n sanitizeRoutesMapForSerialization,\n ALLOWED_QUERY_PARAM_KEYS,\n RESERVED_INPUT_PARAM_KEYS,\n} from '@strapi/utils';\nimport * as z from 'zod/v4';\n\nimport type { Core, Modules, UID } from '@strapi/types';\n\nimport instantiatePermissionsUtilities from './permissions';\n\nconst transformRoutePrefixFor = (pluginName: string) => (route: Core.Route) => {\n const prefix = route.config && route.config.prefix;\n const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;\n\n return {\n ...route,\n path,\n };\n};\n\nconst filterContentAPI = (route: Core.Route) => route.info.type === 'content-api';\n\n/**\n * Runtime check for addQueryParams: we only allow scalar or array-of-scalar schemas (no nested objects).\n * We keep this in addition to the ZodQueryParamSchema type because: (1) TypeScript can be bypassed (JS,\n * any, or schema from another Zod instance); (2) it gives a clear, immediate error at registration\n * time instead of a later failure in validate/sanitize. This list is intentionally tied to Zod v4\n * constructor names; if Zod changes internals, this may need updating.\n * Compatibility: Zod 3 and Zod 4 Classic (zod/v4) both use these constructor names and\n * expose ._def with .innerType / .element for Optional/Default/Array. Zod 4 Core/Mini use\n * ._zod.def instead; we only accept schemas from the same zod/v4 instance used here.\n */\nconst ALLOWED_QUERY_SCHEMA_NAMES = new Set([\n 'ZodString',\n 'ZodNumber',\n 'ZodBoolean',\n 'ZodEnum',\n 'ZodOptional',\n 'ZodDefault',\n 'ZodArray',\n]);\n\nfunction assertQueryParamSchema(schema: unknown, param: string): void {\n const name = (schema as { constructor?: { name?: string } })?.constructor?.name ?? '';\n if (!ALLOWED_QUERY_SCHEMA_NAMES.has(name)) {\n throw new Error(\n `contentAPI.addQueryParams: param \"${param}\" schema must be a scalar (string, number, boolean, enum) or array of scalars; got ${name}. Use addInputParams for nested objects.`\n );\n }\n if (name === 'ZodOptional' || name === 'ZodDefault') {\n const inner = (schema as { _def?: { innerType?: unknown } })?._def?.innerType;\n if (inner) assertQueryParamSchema(inner, param);\n return;\n }\n if (name === 'ZodArray') {\n const element = (schema as { _def?: { element?: unknown } })?._def?.element;\n if (element) assertQueryParamSchema(element, param);\n }\n}\n\nfunction resolveSchema<T>(schemaOrFactory: T | ((zInstance: typeof z) => T)): T {\n if (typeof schemaOrFactory === 'function') {\n return (schemaOrFactory as (zInstance: typeof z) => T)(z);\n }\n return schemaOrFactory;\n}\n\nconst mergeOneQueryParamIntoRoute = (\n route: Core.Route,\n param: string,\n schema: z.ZodType,\n matchRoute?: (route: Core.Route) => boolean\n): void => {\n if (matchRoute && !matchRoute(route)) return;\n const query = { ...(route.request?.query ?? {}) };\n if (param in query) {\n throw new Error(\n `contentAPI.addQueryParams: param \"${param}\" already exists on route ${route.method} ${route.path}`\n );\n }\n route.request = { ...route.request, query: { ...query, [param]: schema } };\n};\n\nconst mergeOneInputParamIntoRoute = (\n route: Core.Route,\n param: string,\n schema: z.ZodType,\n matchRoute?: (route: Core.Route) => boolean\n): void => {\n if (matchRoute && !matchRoute(route)) return;\n const jsonKey = 'application/json';\n type RouteBody = NonNullable<NonNullable<Core.Route['request']>['body']>;\n const body: RouteBody = route.request?.body ? { ...route.request.body } : ({} as RouteBody);\n const existing = body[jsonKey];\n const base =\n existing && typeof existing === 'object' && 'shape' in existing\n ? (existing as { shape: Record<string, z.ZodType> }).shape\n : {};\n if (param in base) {\n throw new Error(\n `contentAPI.addInputParams: param \"${param}\" already exists on route ${route.method} ${route.path}`\n );\n }\n body[jsonKey] = z.object({ ...base, [param]: schema }) as RouteBody[keyof RouteBody];\n route.request = { ...route.request, body };\n};\n\n/** Stored options with schema always resolved (never a function). */\ntype ResolvedQueryParamEntry = {\n param: string;\n schema: z.ZodType;\n matchRoute?: (route: Core.Route) => boolean;\n};\ntype ResolvedInputParamEntry = {\n param: string;\n schema: z.ZodType;\n matchRoute?: (route: Core.Route) => boolean;\n};\n\n/**\n * Create a content API container that holds logic, tools and utils. (eg: permissions, ...)\n */\nconst createContentAPI = (strapi: Core.Strapi) => {\n const extraQueryParams: ResolvedQueryParamEntry[] = [];\n const extraInputParams: ResolvedInputParamEntry[] = [];\n\n const addQueryParam = (options: Modules.ContentAPI.QueryParamEntry & { param: string }) => {\n const { param, schema: schemaOrFactory, matchRoute } = options;\n const schema = resolveSchema(schemaOrFactory);\n assertQueryParamSchema(schema, param);\n if ((ALLOWED_QUERY_PARAM_KEYS as readonly string[]).includes(param)) {\n throw new Error(\n `contentAPI.addQueryParams: param \"${param}\" is reserved by Strapi; use a different name`\n );\n }\n if (extraQueryParams.some((o) => o.param === param)) {\n throw new Error(`contentAPI.addQueryParams: param \"${param}\" has already been added`);\n }\n extraQueryParams.push({ param, schema, matchRoute });\n // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).\n // We do not merge here: at register() time routes may not exist yet (lazy creation), and\n // merging here would cause double-merge when initRouting runs and 400 \"invalid param\" or\n // \"param already exists\" errors.\n };\n\n const addInputParam = (options: Modules.ContentAPI.InputParamEntry & { param: string }) => {\n const { param, schema: schemaOrFactory, matchRoute } = options;\n const schema = resolveSchema(schemaOrFactory);\n if ((RESERVED_INPUT_PARAM_KEYS as readonly string[]).includes(param)) {\n throw new Error(\n `contentAPI.addInputParams: param \"${param}\" is reserved by Strapi; use a different name`\n );\n }\n if (extraInputParams.some((o) => o.param === param)) {\n throw new Error(`contentAPI.addInputParams: param \"${param}\" has already been added`);\n }\n extraInputParams.push({ param, schema, matchRoute });\n // Params are merged into routes when initRouting() runs (applyExtraParamsToRoutes).\n };\n\n /**\n * Register extra query params. Keys = param names; values = { schema, matchRoute? }.\n * Schemas must be Zod scalar or array-of-scalars (enforced at runtime via assertQueryParamSchema).\n */\n const addQueryParams = (options: Modules.ContentAPI.AddQueryParamsOptions) => {\n Object.entries(options).forEach(([param, rest]) => addQueryParam({ param, ...rest }));\n };\n\n /**\n * Register extra input params (root-level body.data). Keys = param names; values = { schema, matchRoute? }.\n * Any Zod type allowed; enforced at registration time.\n */\n const addInputParams = (options: Modules.ContentAPI.AddInputParamsOptions) => {\n Object.entries(options).forEach(([param, rest]) => addInputParam({ param, ...rest }));\n };\n\n /** Merge all registered extra params into the given routes (mutates in place). Called at route registration. Throws if a param key already exists. */\n const applyExtraParamsToRoutes = (routes: Core.Route[]): void => {\n routes.forEach((route) => {\n for (const { param, schema, matchRoute } of extraQueryParams) {\n mergeOneQueryParamIntoRoute(route, param, schema, matchRoute);\n }\n for (const { param, schema, matchRoute } of extraInputParams) {\n mergeOneInputParamIntoRoute(route, param, schema, matchRoute);\n }\n });\n };\n\n const getRoutesMap = async () => {\n const routesMap: Record<string, Core.Route[]> = {};\n\n _.forEach(strapi.apis, (api, apiName) => {\n const routes = _.flatMap(api.routes, (route) => {\n if ('routes' in route) {\n return route.routes;\n }\n\n return route;\n }).filter(filterContentAPI);\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`api::${apiName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n _.forEach(strapi.plugins, (plugin, pluginName) => {\n const transformPrefix = transformRoutePrefixFor(pluginName);\n\n if (Array.isArray(plugin.routes)) {\n return plugin.routes.map(transformPrefix).filter(filterContentAPI);\n }\n\n const routes = _.flatMap(plugin.routes, (route) => route.routes.map(transformPrefix)).filter(\n filterContentAPI\n );\n\n if (routes.length === 0) {\n return;\n }\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n routesMap[`plugin::${pluginName}`] = routes.map((route) => ({\n ...route,\n path: `${apiPrefix}${route.path}`,\n }));\n });\n\n return sanitizeRoutesMapForSerialization(routesMap);\n };\n\n const sanitizer = sanitize.createAPISanitizers({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n get sanitizers() {\n return {\n input: strapi.sanitizers.get('content-api.input'),\n output: strapi.sanitizers.get('content-api.output'),\n };\n },\n });\n\n const validator = validate.createAPIValidators({\n getModel(uid: string) {\n return strapi.getModel(uid as UID.Schema);\n },\n get validators() {\n return {\n input: strapi.validators.get('content-api.input'),\n };\n },\n });\n\n return {\n permissions: instantiatePermissionsUtilities(strapi),\n getRoutesMap,\n sanitize: sanitizer,\n validate: validator,\n addQueryParams,\n addInputParams,\n applyExtraParamsToRoutes,\n };\n};\n\nexport default createContentAPI;\n"],"names":["transformRoutePrefixFor","pluginName","route","prefix","config","path","undefined","filterContentAPI","info","type","ALLOWED_QUERY_SCHEMA_NAMES","Set","assertQueryParamSchema","schema","param","name","has","Error","inner","_def","innerType","element","resolveSchema","schemaOrFactory","z","mergeOneQueryParamIntoRoute","matchRoute","query","request","method","mergeOneInputParamIntoRoute","jsonKey","body","existing","base","shape","object","createContentAPI","strapi","extraQueryParams","extraInputParams","addQueryParam","options","ALLOWED_QUERY_PARAM_KEYS","includes","some","o","push","addInputParam","RESERVED_INPUT_PARAM_KEYS","addQueryParams","Object","entries","forEach","rest","addInputParams","applyExtraParamsToRoutes","routes","getRoutesMap","routesMap","_","apis","api","apiName","flatMap","filter","length","apiPrefix","get","map","plugins","plugin","transformPrefix","Array","isArray","sanitizeRoutesMapForSerialization","sanitizer","sanitize","createAPISanitizers","getModel","uid","sanitizers","input","output","validator","validate","createAPIValidators","validators","permissions","instantiatePermissionsUtilities"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../src/services/cron.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,UAAU,OAAO;IACf,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,KAAK,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE5F,KAAK,IAAI,GACL,MAAM,GACN;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAEN,UAAU,KAAK;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,iBAAiB;gBAKR,KAAK;iBAoCH,MAAM;;;;;CAgCtB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../src/services/cron.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,UAAU,OAAO;IACf,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,KAAK,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;CAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE5F,KAAK,IAAI,GACL,MAAM,GACN;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAEN,UAAU,KAAK;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,iBAAiB;gBAKR,KAAK;iBAuCH,MAAM;;;;;CAgCtB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -31,6 +31,9 @@ const createCronService = ()=>{
31
31
  }, ...args);
32
32
  // const job = new Job(null, fnWithStrapi);
33
33
  const job = new nodeSchedule.Job(fnWithStrapi);
34
+ job.on('error', (error)=>{
35
+ strapi.log.error(`Cron job "${taskName ?? taskExpression}" failed`, error);
36
+ });
34
37
  jobsSpecs.push({
35
38
  job,
36
39
  options,
@@ -1 +1 @@
1
- {"version":3,"file":"cron.js","sources":["../../src/services/cron.ts"],"sourcesContent":["import { Job, Spec } from 'node-schedule';\nimport { isFunction } from 'lodash/fp';\nimport type { Core } from '@strapi/types';\n\ninterface JobSpec {\n job: Job;\n options: Spec;\n name: string | null;\n}\n\ntype TaskFn = ({ strapi }: { strapi: Core.Strapi }, ...args: unknown[]) => Promise<unknown>;\n\ntype Task =\n | TaskFn\n | {\n task: TaskFn;\n options: Spec;\n };\n\ninterface Tasks {\n [key: string]: Task;\n}\n\nconst createCronService = () => {\n let jobsSpecs: JobSpec[] = [];\n let running = false;\n\n return {\n add(tasks: Tasks = {}) {\n for (const taskExpression of Object.keys(tasks)) {\n const taskValue = tasks[taskExpression];\n\n let fn: TaskFn;\n let options: Spec;\n let taskName: string | null;\n if (isFunction(taskValue)) {\n // don't use task name if key is the rule\n taskName = null;\n fn = taskValue.bind(tasks);\n options = taskExpression;\n } else if (isFunction(taskValue.task)) {\n // set task name if key is not the rule\n taskName = taskExpression;\n fn = taskValue.task.bind(taskValue);\n options = taskValue.options;\n } else {\n throw new Error(\n `Could not schedule a cron job for \"${taskExpression}\": no function found.`\n );\n }\n\n const fnWithStrapi = (...args: unknown[]) => fn({ strapi }, ...args);\n\n // const job = new Job(null, fnWithStrapi);\n const job = new Job(fnWithStrapi);\n jobsSpecs.push({ job, options, name: taskName });\n\n if (running) {\n job.schedule(options);\n }\n }\n return this;\n },\n\n remove(name: string) {\n if (!name) throw new Error('You must provide a name to remove a cron job.');\n const matchingJobsSpecs = jobsSpecs.filter(({ name: jobSpecName }, index) => {\n if (jobSpecName === name) {\n jobsSpecs.splice(index, 1);\n return true;\n }\n return false;\n });\n matchingJobsSpecs.forEach(({ job }) => job.cancel());\n return this;\n },\n\n start() {\n jobsSpecs.forEach(({ job, options }) => job.schedule(options));\n running = true;\n return this;\n },\n\n stop() {\n jobsSpecs.forEach(({ job }) => job.cancel());\n running = false;\n return this;\n },\n\n destroy() {\n this.stop();\n jobsSpecs = [];\n return this;\n },\n jobs: jobsSpecs,\n };\n};\n\nexport default createCronService;\n"],"names":["createCronService","jobsSpecs","running","add","tasks","taskExpression","Object","keys","taskValue","fn","options","taskName","isFunction","bind","task","Error","fnWithStrapi","args","strapi","job","Job","push","name","schedule","remove","matchingJobsSpecs","filter","jobSpecName","index","splice","forEach","cancel","start","stop","destroy","jobs"],"mappings":"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"}
1
+ {"version":3,"file":"cron.js","sources":["../../src/services/cron.ts"],"sourcesContent":["import { Job, Spec } from 'node-schedule';\nimport { isFunction } from 'lodash/fp';\nimport type { Core } from '@strapi/types';\n\ninterface JobSpec {\n job: Job;\n options: Spec;\n name: string | null;\n}\n\ntype TaskFn = ({ strapi }: { strapi: Core.Strapi }, ...args: unknown[]) => Promise<unknown>;\n\ntype Task =\n | TaskFn\n | {\n task: TaskFn;\n options: Spec;\n };\n\ninterface Tasks {\n [key: string]: Task;\n}\n\nconst createCronService = () => {\n let jobsSpecs: JobSpec[] = [];\n let running = false;\n\n return {\n add(tasks: Tasks = {}) {\n for (const taskExpression of Object.keys(tasks)) {\n const taskValue = tasks[taskExpression];\n\n let fn: TaskFn;\n let options: Spec;\n let taskName: string | null;\n if (isFunction(taskValue)) {\n // don't use task name if key is the rule\n taskName = null;\n fn = taskValue.bind(tasks);\n options = taskExpression;\n } else if (isFunction(taskValue.task)) {\n // set task name if key is not the rule\n taskName = taskExpression;\n fn = taskValue.task.bind(taskValue);\n options = taskValue.options;\n } else {\n throw new Error(\n `Could not schedule a cron job for \"${taskExpression}\": no function found.`\n );\n }\n\n const fnWithStrapi = (...args: unknown[]) => fn({ strapi }, ...args);\n\n // const job = new Job(null, fnWithStrapi);\n const job = new Job(fnWithStrapi);\n job.on('error', (error) => {\n strapi.log.error(`Cron job \"${taskName ?? taskExpression}\" failed`, error);\n });\n jobsSpecs.push({ job, options, name: taskName });\n\n if (running) {\n job.schedule(options);\n }\n }\n return this;\n },\n\n remove(name: string) {\n if (!name) throw new Error('You must provide a name to remove a cron job.');\n const matchingJobsSpecs = jobsSpecs.filter(({ name: jobSpecName }, index) => {\n if (jobSpecName === name) {\n jobsSpecs.splice(index, 1);\n return true;\n }\n return false;\n });\n matchingJobsSpecs.forEach(({ job }) => job.cancel());\n return this;\n },\n\n start() {\n jobsSpecs.forEach(({ job, options }) => job.schedule(options));\n running = true;\n return this;\n },\n\n stop() {\n jobsSpecs.forEach(({ job }) => job.cancel());\n running = false;\n return this;\n },\n\n destroy() {\n this.stop();\n jobsSpecs = [];\n return this;\n },\n jobs: jobsSpecs,\n };\n};\n\nexport default createCronService;\n"],"names":["createCronService","jobsSpecs","running","add","tasks","taskExpression","Object","keys","taskValue","fn","options","taskName","isFunction","bind","task","Error","fnWithStrapi","args","strapi","job","Job","on","error","log","push","name","schedule","remove","matchingJobsSpecs","filter","jobSpecName","index","splice","forEach","cancel","start","stop","destroy","jobs"],"mappings":"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"}
@@ -29,6 +29,9 @@ const createCronService = ()=>{
29
29
  }, ...args);
30
30
  // const job = new Job(null, fnWithStrapi);
31
31
  const job = new Job(fnWithStrapi);
32
+ job.on('error', (error)=>{
33
+ strapi.log.error(`Cron job "${taskName ?? taskExpression}" failed`, error);
34
+ });
32
35
  jobsSpecs.push({
33
36
  job,
34
37
  options,