@strapi/plugin-documentation 5.0.0-beta.0 → 5.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/_chunks/{index-D1KkfApT.js → App-Dsqz1mTz.js} +74 -22
- package/dist/_chunks/App-Dsqz1mTz.js.map +1 -0
- package/dist/_chunks/{index-7xstUX8_.mjs → App-mrzd5Xqj.mjs} +49 -16
- package/dist/_chunks/App-mrzd5Xqj.mjs.map +1 -0
- package/dist/_chunks/{index-VpLAJXMs.mjs → Settings-8v7IbdtY.mjs} +64 -33
- package/dist/_chunks/Settings-8v7IbdtY.mjs.map +1 -0
- package/dist/_chunks/{index-NbPCucJl.js → Settings-wdLQpouP.js} +69 -37
- package/dist/_chunks/Settings-wdLQpouP.js.map +1 -0
- package/dist/_chunks/getTrad-SeEDjZbP.mjs +6 -0
- package/dist/_chunks/getTrad-SeEDjZbP.mjs.map +1 -0
- package/dist/_chunks/getTrad-xlpeC9HP.js +5 -0
- package/dist/_chunks/getTrad-xlpeC9HP.js.map +1 -0
- package/{server/public/index.html → dist/_chunks/index-MKWIGajW.mjs} +9 -4
- package/dist/_chunks/index-MKWIGajW.mjs.map +1 -0
- package/dist/_chunks/index-WbbYm9_u.js +75 -0
- package/dist/_chunks/index-WbbYm9_u.js.map +1 -0
- package/dist/_chunks/{index-r7HsQTou.js → index-_yYcImHU.js} +126 -119
- package/dist/_chunks/index-_yYcImHU.js.map +1 -0
- package/dist/_chunks/{index-NvJ4m2q5.mjs → index-mXCyE3EQ.mjs} +128 -121
- package/dist/_chunks/index-mXCyE3EQ.mjs.map +1 -0
- package/dist/_chunks/login-HAajOKpu.js +150 -0
- package/dist/_chunks/login-HAajOKpu.js.map +1 -0
- package/{server/public/login.html → dist/_chunks/login-slUa679p.mjs} +6 -1
- package/dist/_chunks/login-slUa679p.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +2 -2
- package/dist/admin/src/components/SettingsForm.d.ts +8 -0
- package/dist/admin/src/constants.d.ts +18 -0
- package/dist/admin/src/index.d.ts +14 -0
- package/dist/admin/src/pages/App.d.ts +2 -0
- package/dist/admin/src/pages/Settings.d.ts +2 -0
- package/dist/admin/src/pluginId.d.ts +1 -0
- package/dist/admin/src/services/api.d.ts +25 -0
- package/dist/admin/src/types.d.ts +16 -0
- package/dist/admin/src/utils/baseQuery.d.ts +20 -0
- package/dist/admin/src/utils/getTrad.d.ts +1 -0
- package/dist/admin/src/utils/index.d.ts +2 -0
- package/dist/admin/src/utils/prefixPluginTranslations.d.ts +2 -0
- package/dist/server/index.js +1263 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +1238 -0
- package/dist/server/index.mjs.map +1 -0
- package/dist/server/src/bootstrap.d.ts +5 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -0
- package/dist/server/src/config/default-plugin-config.d.ts +3 -0
- package/dist/server/src/config/default-plugin-config.d.ts.map +1 -0
- package/dist/server/src/config/index.d.ts +4 -0
- package/dist/server/src/config/index.d.ts.map +1 -0
- package/dist/server/src/controllers/documentation.d.ts +12 -0
- package/dist/server/src/controllers/documentation.d.ts.map +1 -0
- package/dist/server/src/controllers/index.d.ts +14 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -0
- package/dist/server/src/index.d.ts +91 -0
- package/dist/server/src/index.d.ts.map +1 -0
- package/dist/server/src/middlewares/documentation.d.ts +5 -0
- package/dist/server/src/middlewares/documentation.d.ts.map +1 -0
- package/dist/server/src/middlewares/restrict-access.d.ts +4 -0
- package/dist/server/src/middlewares/restrict-access.d.ts.map +1 -0
- package/dist/server/src/register.d.ts +5 -0
- package/dist/server/src/register.d.ts.map +1 -0
- package/dist/server/src/routes/index.d.ts +36 -0
- package/dist/server/src/routes/index.d.ts.map +1 -0
- package/dist/server/src/services/__mocks__/mock-content-types.d.ts +449 -0
- package/dist/server/src/services/__mocks__/mock-content-types.d.ts.map +1 -0
- package/dist/server/src/services/__mocks__/mock-strapi-data.d.ts +592 -0
- package/dist/server/src/services/__mocks__/mock-strapi-data.d.ts.map +1 -0
- package/dist/server/src/services/documentation.d.ts +36 -0
- package/dist/server/src/services/documentation.d.ts.map +1 -0
- package/dist/server/src/services/helpers/build-api-endpoint-path.d.ts +7 -0
- package/dist/server/src/services/helpers/build-api-endpoint-path.d.ts.map +1 -0
- package/dist/server/src/services/helpers/build-component-schema.d.ts +4 -0
- package/dist/server/src/services/helpers/build-component-schema.d.ts.map +1 -0
- package/dist/server/src/services/helpers/index.d.ts +4 -0
- package/dist/server/src/services/helpers/index.d.ts.map +1 -0
- package/dist/server/src/services/helpers/utils/clean-schema-attributes.d.ts +15 -0
- package/dist/server/src/services/helpers/utils/clean-schema-attributes.d.ts.map +1 -0
- package/dist/server/src/services/helpers/utils/get-api-responses.d.ts +15 -0
- package/dist/server/src/services/helpers/utils/get-api-responses.d.ts.map +1 -0
- package/dist/server/src/services/helpers/utils/get-schema-data.d.ts +12 -0
- package/dist/server/src/services/helpers/utils/get-schema-data.d.ts.map +1 -0
- package/dist/server/src/services/helpers/utils/loop-content-type-names.d.ts +7 -0
- package/dist/server/src/services/helpers/utils/loop-content-type-names.d.ts.map +1 -0
- package/dist/server/src/services/helpers/utils/pascal-case.d.ts +3 -0
- package/dist/server/src/services/helpers/utils/pascal-case.d.ts.map +1 -0
- package/dist/server/src/services/helpers/utils/query-params.d.ts +4 -0
- package/dist/server/src/services/helpers/utils/query-params.d.ts.map +1 -0
- package/dist/server/src/services/helpers/utils/routes.d.ts +3 -0
- package/dist/server/src/services/helpers/utils/routes.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +43 -0
- package/dist/server/src/services/index.d.ts.map +1 -0
- package/dist/server/src/services/override.d.ts +21 -0
- package/dist/server/src/services/override.d.ts.map +1 -0
- package/dist/server/src/services/utils/get-plugins-that-need-documentation.d.ts +4 -0
- package/dist/server/src/services/utils/get-plugins-that-need-documentation.d.ts.map +1 -0
- package/dist/server/src/types.d.ts +28 -0
- package/dist/server/src/types.d.ts.map +1 -0
- package/dist/server/src/utils.d.ts +12 -0
- package/dist/server/src/utils.d.ts.map +1 -0
- package/package.json +33 -16
- package/strapi-server.js +1 -1
- package/.eslintignore +0 -1
- package/.eslintrc +0 -17
- package/admin/src/constants.js +0 -17
- package/admin/src/hooks/useDocumentation.js +0 -81
- package/admin/src/index.js +0 -62
- package/admin/src/pages/PluginPage/index.jsx +0 -212
- package/admin/src/pages/PluginPage/tests/index.test.jsx +0 -160
- package/admin/src/pages/SettingsPage/index.jsx +0 -202
- package/admin/src/pages/SettingsPage/tests/index.test.jsx +0 -72
- package/admin/src/pluginId.js +0 -5
- package/admin/src/translations/ar.json +0 -20
- package/admin/src/translations/cs.json +0 -21
- package/admin/src/translations/de.json +0 -26
- package/admin/src/translations/dk.json +0 -39
- package/admin/src/translations/en.json +0 -39
- package/admin/src/translations/es.json +0 -39
- package/admin/src/translations/fr.json +0 -26
- package/admin/src/translations/id.json +0 -24
- package/admin/src/translations/it.json +0 -26
- package/admin/src/translations/ko.json +0 -39
- package/admin/src/translations/ms.json +0 -23
- package/admin/src/translations/nl.json +0 -21
- package/admin/src/translations/pl.json +0 -39
- package/admin/src/translations/pt-BR.json +0 -21
- package/admin/src/translations/pt.json +0 -21
- package/admin/src/translations/ru.json +0 -39
- package/admin/src/translations/sk.json +0 -24
- package/admin/src/translations/sv.json +0 -39
- package/admin/src/translations/th.json +0 -24
- package/admin/src/translations/tr.json +0 -39
- package/admin/src/translations/uk.json +0 -23
- package/admin/src/translations/vi.json +0 -24
- package/admin/src/translations/zh-Hans.json +0 -28
- package/admin/src/translations/zh.json +0 -39
- package/admin/src/utils/getTrad.js +0 -5
- package/admin/src/utils/index.js +0 -2
- package/admin/src/utils/prefixPluginTranslations.js +0 -13
- package/dist/_chunks/index-7xstUX8_.mjs.map +0 -1
- package/dist/_chunks/index-D1KkfApT.js.map +0 -1
- package/dist/_chunks/index-NbPCucJl.js.map +0 -1
- package/dist/_chunks/index-NvJ4m2q5.mjs.map +0 -1
- package/dist/_chunks/index-VpLAJXMs.mjs.map +0 -1
- package/dist/_chunks/index-r7HsQTou.js.map +0 -1
- package/dist/_chunks/useDocumentation-6Ks-_Ms6.mjs +0 -68
- package/dist/_chunks/useDocumentation-6Ks-_Ms6.mjs.map +0 -1
- package/dist/_chunks/useDocumentation-S0e4mU-U.js +0 -67
- package/dist/_chunks/useDocumentation-S0e4mU-U.js.map +0 -1
- package/jest.config.front.js +0 -7
- package/jest.config.js +0 -6
- package/packup.config.ts +0 -22
- package/server/bootstrap.js +0 -54
- package/server/config/default-plugin-config.js +0 -35
- package/server/config/index.js +0 -7
- package/server/controllers/documentation.js +0 -241
- package/server/controllers/index.js +0 -7
- package/server/index.js +0 -17
- package/server/middlewares/documentation.js +0 -25
- package/server/middlewares/index.js +0 -7
- package/server/middlewares/restrict-access.js +0 -24
- package/server/register.js +0 -11
- package/server/routes/index.js +0 -84
- package/server/services/__mocks__/mock-content-types.js +0 -264
- package/server/services/__mocks__/mock-strapi-data.js +0 -183
- package/server/services/__tests__/build-component-schema.test.js +0 -761
- package/server/services/__tests__/documentation.test.js +0 -481
- package/server/services/__tests__/override.test.js +0 -85
- package/server/services/documentation.js +0 -246
- package/server/services/helpers/build-api-endpoint-path.js +0 -186
- package/server/services/helpers/build-component-schema.js +0 -254
- package/server/services/helpers/index.js +0 -9
- package/server/services/helpers/utils/clean-schema-attributes.js +0 -246
- package/server/services/helpers/utils/get-api-responses.js +0 -105
- package/server/services/helpers/utils/get-schema-data.js +0 -32
- package/server/services/helpers/utils/loop-content-type-names.js +0 -55
- package/server/services/helpers/utils/pascal-case.js +0 -9
- package/server/services/helpers/utils/query-params.js +0 -105
- package/server/services/helpers/utils/routes.js +0 -10
- package/server/services/index.js +0 -9
- package/server/services/override.js +0 -52
- package/server/services/utils/default-openapi-components.js +0 -40
- package/server/services/utils/get-plugins-that-need-documentation.js +0 -24
- package/tests/server.js +0 -37
- package/tests/setup.js +0 -15
|
@@ -0,0 +1,1263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const koaStatic = require("koa-static");
|
|
4
|
+
const swaggerUi = require("swagger-ui-dist");
|
|
5
|
+
const fs = require("fs-extra");
|
|
6
|
+
const immer = require("immer");
|
|
7
|
+
const _ = require("lodash");
|
|
8
|
+
const pathToRegexp = require("path-to-regexp");
|
|
9
|
+
const bcrypt = require("bcryptjs");
|
|
10
|
+
const utils = require("@strapi/utils");
|
|
11
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
12
|
+
function _interopNamespace(e) {
|
|
13
|
+
if (e && e.__esModule)
|
|
14
|
+
return e;
|
|
15
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
16
|
+
if (e) {
|
|
17
|
+
for (const k in e) {
|
|
18
|
+
if (k !== "default") {
|
|
19
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: () => e[k]
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
const path__default = /* @__PURE__ */ _interopDefault(path);
|
|
31
|
+
const koaStatic__default = /* @__PURE__ */ _interopDefault(koaStatic);
|
|
32
|
+
const swaggerUi__default = /* @__PURE__ */ _interopDefault(swaggerUi);
|
|
33
|
+
const fs__default = /* @__PURE__ */ _interopDefault(fs);
|
|
34
|
+
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
35
|
+
const pathToRegexp__namespace = /* @__PURE__ */ _interopNamespace(pathToRegexp);
|
|
36
|
+
const bcrypt__default = /* @__PURE__ */ _interopDefault(bcrypt);
|
|
37
|
+
const getService = (name, { strapi: strapi2 } = { strapi: global.strapi }) => {
|
|
38
|
+
return strapi2.plugin("documentation").service(name);
|
|
39
|
+
};
|
|
40
|
+
const RBAC_ACTIONS = [
|
|
41
|
+
{
|
|
42
|
+
section: "plugins",
|
|
43
|
+
displayName: "Access the Documentation",
|
|
44
|
+
uid: "read",
|
|
45
|
+
pluginName: "documentation"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
section: "plugins",
|
|
49
|
+
displayName: "Update and delete",
|
|
50
|
+
uid: "settings.update",
|
|
51
|
+
pluginName: "documentation"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
section: "plugins",
|
|
55
|
+
displayName: "Regenerate",
|
|
56
|
+
uid: "settings.regenerate",
|
|
57
|
+
pluginName: "documentation"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
section: "settings",
|
|
61
|
+
displayName: "Access the documentation settings page",
|
|
62
|
+
uid: "settings.read",
|
|
63
|
+
pluginName: "documentation",
|
|
64
|
+
category: "documentation"
|
|
65
|
+
}
|
|
66
|
+
];
|
|
67
|
+
async function bootstrap({ strapi: strapi2 }) {
|
|
68
|
+
await strapi2.admin?.services.permission.actionProvider.registerMany(RBAC_ACTIONS);
|
|
69
|
+
const pluginStore = strapi2.store({
|
|
70
|
+
environment: "",
|
|
71
|
+
type: "plugin",
|
|
72
|
+
name: "documentation"
|
|
73
|
+
});
|
|
74
|
+
const config2 = await pluginStore.get({ key: "config" });
|
|
75
|
+
if (!config2) {
|
|
76
|
+
pluginStore.set({ key: "config", value: { restrictedAccess: false } });
|
|
77
|
+
}
|
|
78
|
+
await getService("documentation").generateFullDoc();
|
|
79
|
+
}
|
|
80
|
+
const addDocumentMiddlewares = async ({ strapi: strapi2 }) => {
|
|
81
|
+
strapi2.server.routes([
|
|
82
|
+
{
|
|
83
|
+
method: "GET",
|
|
84
|
+
path: "/plugins/documentation/(.*)",
|
|
85
|
+
async handler(ctx, next) {
|
|
86
|
+
ctx.url = path__default.default.basename(ctx.url);
|
|
87
|
+
return koaStatic__default.default(swaggerUi__default.default.getAbsoluteFSPath(), {
|
|
88
|
+
maxage: 864e5,
|
|
89
|
+
defer: true
|
|
90
|
+
})(ctx, next);
|
|
91
|
+
},
|
|
92
|
+
config: {
|
|
93
|
+
auth: false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
]);
|
|
97
|
+
};
|
|
98
|
+
async function register({ strapi: strapi2 }) {
|
|
99
|
+
await addDocumentMiddlewares({ strapi: strapi2 });
|
|
100
|
+
}
|
|
101
|
+
const pascalCase = (string) => {
|
|
102
|
+
return ___default.default.upperFirst(___default.default.camelCase(string));
|
|
103
|
+
};
|
|
104
|
+
const params = [
|
|
105
|
+
{
|
|
106
|
+
name: "sort",
|
|
107
|
+
in: "query",
|
|
108
|
+
description: "Sort by attributes ascending (asc) or descending (desc)",
|
|
109
|
+
deprecated: false,
|
|
110
|
+
required: false,
|
|
111
|
+
schema: {
|
|
112
|
+
type: "string"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "pagination[withCount]",
|
|
117
|
+
in: "query",
|
|
118
|
+
description: "Return page/pageSize (default: true)",
|
|
119
|
+
deprecated: false,
|
|
120
|
+
required: false,
|
|
121
|
+
schema: {
|
|
122
|
+
type: "boolean"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "pagination[page]",
|
|
127
|
+
in: "query",
|
|
128
|
+
description: "Page number (default: 0)",
|
|
129
|
+
deprecated: false,
|
|
130
|
+
required: false,
|
|
131
|
+
schema: {
|
|
132
|
+
type: "integer"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "pagination[pageSize]",
|
|
137
|
+
in: "query",
|
|
138
|
+
description: "Page size (default: 25)",
|
|
139
|
+
deprecated: false,
|
|
140
|
+
required: false,
|
|
141
|
+
schema: {
|
|
142
|
+
type: "integer"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "pagination[start]",
|
|
147
|
+
in: "query",
|
|
148
|
+
description: "Offset value (default: 0)",
|
|
149
|
+
deprecated: false,
|
|
150
|
+
required: false,
|
|
151
|
+
schema: {
|
|
152
|
+
type: "integer"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "pagination[limit]",
|
|
157
|
+
in: "query",
|
|
158
|
+
description: "Number of entities to return (default: 25)",
|
|
159
|
+
deprecated: false,
|
|
160
|
+
required: false,
|
|
161
|
+
schema: {
|
|
162
|
+
type: "integer"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: "fields",
|
|
167
|
+
in: "query",
|
|
168
|
+
description: "Fields to return (ex: title,author)",
|
|
169
|
+
deprecated: false,
|
|
170
|
+
required: false,
|
|
171
|
+
schema: {
|
|
172
|
+
type: "string"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "populate",
|
|
177
|
+
in: "query",
|
|
178
|
+
description: "Relations to return",
|
|
179
|
+
deprecated: false,
|
|
180
|
+
required: false,
|
|
181
|
+
schema: {
|
|
182
|
+
type: "string"
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: "filters",
|
|
187
|
+
in: "query",
|
|
188
|
+
description: "Filters to apply",
|
|
189
|
+
deprecated: false,
|
|
190
|
+
required: false,
|
|
191
|
+
schema: {
|
|
192
|
+
type: "object"
|
|
193
|
+
},
|
|
194
|
+
style: "deepObject"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "locale",
|
|
198
|
+
in: "query",
|
|
199
|
+
description: "Locale to apply",
|
|
200
|
+
deprecated: false,
|
|
201
|
+
required: false,
|
|
202
|
+
schema: {
|
|
203
|
+
type: "string"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
];
|
|
207
|
+
const loopContentTypeNames = (api, callback) => {
|
|
208
|
+
let result = {};
|
|
209
|
+
for (const contentTypeName of api.ctNames) {
|
|
210
|
+
const uid = `${api.getter}::${api.name}.${contentTypeName}`;
|
|
211
|
+
const { attributes, info: contentTypeInfo, kind } = strapi.contentType(uid);
|
|
212
|
+
const routeInfo = api.getter === "plugin" ? (
|
|
213
|
+
// @ts-expect-error - This is a valid check
|
|
214
|
+
strapi.plugin(api.name).routes["content-api"]
|
|
215
|
+
) : strapi.api(api.name).routes[contentTypeName];
|
|
216
|
+
if (!routeInfo) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const apiName = ___default.default.upperFirst(api.name);
|
|
220
|
+
const uniqueName = api.name === contentTypeName ? apiName : `${apiName} - ${___default.default.upperFirst(contentTypeName)}`;
|
|
221
|
+
const apiInfo = {
|
|
222
|
+
...api,
|
|
223
|
+
routeInfo,
|
|
224
|
+
attributes,
|
|
225
|
+
uniqueName,
|
|
226
|
+
contentTypeInfo,
|
|
227
|
+
kind
|
|
228
|
+
};
|
|
229
|
+
result = {
|
|
230
|
+
...result,
|
|
231
|
+
...callback(apiInfo)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
};
|
|
236
|
+
const getApiResponse = ({
|
|
237
|
+
uniqueName,
|
|
238
|
+
route,
|
|
239
|
+
isListOfEntities = false
|
|
240
|
+
}) => {
|
|
241
|
+
const getSchema = () => {
|
|
242
|
+
if (route.method === "DELETE") {
|
|
243
|
+
return {
|
|
244
|
+
type: "integer",
|
|
245
|
+
format: "int64"
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
if (isListOfEntities) {
|
|
249
|
+
return { $ref: `#/components/schemas/${pascalCase(uniqueName)}ListResponse` };
|
|
250
|
+
}
|
|
251
|
+
return { $ref: `#/components/schemas/${pascalCase(uniqueName)}Response` };
|
|
252
|
+
};
|
|
253
|
+
const schema = getSchema();
|
|
254
|
+
return {
|
|
255
|
+
200: {
|
|
256
|
+
description: "OK",
|
|
257
|
+
content: {
|
|
258
|
+
"application/json": {
|
|
259
|
+
schema
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
400: {
|
|
264
|
+
description: "Bad Request",
|
|
265
|
+
content: {
|
|
266
|
+
"application/json": {
|
|
267
|
+
schema: {
|
|
268
|
+
$ref: "#/components/schemas/Error"
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
401: {
|
|
274
|
+
description: "Unauthorized",
|
|
275
|
+
content: {
|
|
276
|
+
"application/json": {
|
|
277
|
+
schema: {
|
|
278
|
+
$ref: "#/components/schemas/Error"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
403: {
|
|
284
|
+
description: "Forbidden",
|
|
285
|
+
content: {
|
|
286
|
+
"application/json": {
|
|
287
|
+
schema: {
|
|
288
|
+
$ref: "#/components/schemas/Error"
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
404: {
|
|
294
|
+
description: "Not Found",
|
|
295
|
+
content: {
|
|
296
|
+
"application/json": {
|
|
297
|
+
schema: {
|
|
298
|
+
$ref: "#/components/schemas/Error"
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
500: {
|
|
304
|
+
description: "Internal Server Error",
|
|
305
|
+
content: {
|
|
306
|
+
"application/json": {
|
|
307
|
+
schema: {
|
|
308
|
+
$ref: "#/components/schemas/Error"
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
const hasFindMethod = (handler) => {
|
|
316
|
+
if (typeof handler === "string") {
|
|
317
|
+
return handler.split(".").pop() === "find";
|
|
318
|
+
}
|
|
319
|
+
return false;
|
|
320
|
+
};
|
|
321
|
+
const parsePathWithVariables = (routePath) => {
|
|
322
|
+
return pathToRegexp__namespace.parse(routePath).map((token) => {
|
|
323
|
+
if (___default.default.isObject(token)) {
|
|
324
|
+
return `${token.prefix}{${token.name}}`;
|
|
325
|
+
}
|
|
326
|
+
return token;
|
|
327
|
+
}).join("");
|
|
328
|
+
};
|
|
329
|
+
const getPathParams = (routePath) => {
|
|
330
|
+
return pathToRegexp__namespace.parse(routePath).reduce((acc, param) => {
|
|
331
|
+
if (!(typeof param === "object")) {
|
|
332
|
+
return acc;
|
|
333
|
+
}
|
|
334
|
+
acc.push({
|
|
335
|
+
name: `${param.name}`,
|
|
336
|
+
in: "path",
|
|
337
|
+
description: "",
|
|
338
|
+
deprecated: false,
|
|
339
|
+
required: true,
|
|
340
|
+
schema: { type: "number" }
|
|
341
|
+
});
|
|
342
|
+
return acc;
|
|
343
|
+
}, []);
|
|
344
|
+
};
|
|
345
|
+
const getPathWithPrefix = (prefix, route) => {
|
|
346
|
+
if (prefix && !___default.default.has(route.config, "prefix")) {
|
|
347
|
+
return prefix.concat(route.path);
|
|
348
|
+
}
|
|
349
|
+
return route.path;
|
|
350
|
+
};
|
|
351
|
+
const getPaths = ({ routeInfo, uniqueName, contentTypeInfo, kind }) => {
|
|
352
|
+
const contentTypeRoutes = routeInfo.routes.filter((route) => {
|
|
353
|
+
return route.path.includes(contentTypeInfo.pluralName) || route.path.includes(contentTypeInfo.singularName);
|
|
354
|
+
});
|
|
355
|
+
const paths = contentTypeRoutes.reduce((acc, route) => {
|
|
356
|
+
const isListOfEntities = hasFindMethod(route.handler);
|
|
357
|
+
const methodVerb = route.method.toLowerCase();
|
|
358
|
+
const hasPathParams = route.path.includes("/:");
|
|
359
|
+
const pathWithPrefix = getPathWithPrefix(routeInfo.prefix, route);
|
|
360
|
+
const routePath = hasPathParams ? parsePathWithVariables(pathWithPrefix) : pathWithPrefix;
|
|
361
|
+
const responses = getApiResponse({
|
|
362
|
+
uniqueName,
|
|
363
|
+
route,
|
|
364
|
+
isListOfEntities: kind !== "singleType" && isListOfEntities
|
|
365
|
+
});
|
|
366
|
+
const swaggerConfig = {
|
|
367
|
+
responses,
|
|
368
|
+
tags: [___default.default.upperFirst(uniqueName)],
|
|
369
|
+
parameters: [],
|
|
370
|
+
operationId: `${methodVerb}${routePath}`
|
|
371
|
+
};
|
|
372
|
+
if (isListOfEntities) {
|
|
373
|
+
swaggerConfig.parameters?.push(...params);
|
|
374
|
+
}
|
|
375
|
+
if (hasPathParams) {
|
|
376
|
+
const pathParams = getPathParams(route.path);
|
|
377
|
+
swaggerConfig.parameters?.push(...pathParams);
|
|
378
|
+
}
|
|
379
|
+
if (["post", "put"].includes(methodVerb)) {
|
|
380
|
+
const refName = "Request";
|
|
381
|
+
const requestBody = {
|
|
382
|
+
required: true,
|
|
383
|
+
content: {
|
|
384
|
+
"application/json": {
|
|
385
|
+
schema: {
|
|
386
|
+
$ref: `#/components/schemas/${pascalCase(uniqueName)}${refName}`
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
swaggerConfig.requestBody = requestBody;
|
|
392
|
+
}
|
|
393
|
+
___default.default.set(acc, `${routePath}.${methodVerb}`, swaggerConfig);
|
|
394
|
+
return acc;
|
|
395
|
+
}, {});
|
|
396
|
+
return paths;
|
|
397
|
+
};
|
|
398
|
+
const buildApiEndpointPath = (api) => {
|
|
399
|
+
return loopContentTypeNames(api, getPaths);
|
|
400
|
+
};
|
|
401
|
+
const getSchemaData = (isListOfEntities, attributes) => {
|
|
402
|
+
if (isListOfEntities) {
|
|
403
|
+
return {
|
|
404
|
+
type: "array",
|
|
405
|
+
items: {
|
|
406
|
+
type: "object",
|
|
407
|
+
properties: {
|
|
408
|
+
id: { type: "number" },
|
|
409
|
+
documentId: { type: "string" },
|
|
410
|
+
...attributes
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
type: "object",
|
|
417
|
+
properties: {
|
|
418
|
+
id: { type: "number" },
|
|
419
|
+
documentId: { type: "string" },
|
|
420
|
+
...attributes
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
};
|
|
424
|
+
const cleanSchemaAttributes = (attributes, { typeMap = /* @__PURE__ */ new Map(), isRequest = false, didAddStrapiComponentsToSchemas }) => {
|
|
425
|
+
const schemaAttributes = {};
|
|
426
|
+
for (const prop of Object.keys(attributes)) {
|
|
427
|
+
const attribute = attributes[prop];
|
|
428
|
+
switch (attribute.type) {
|
|
429
|
+
case "password": {
|
|
430
|
+
if (!isRequest) {
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
schemaAttributes[prop] = { type: "string", format: "password", example: "*******" };
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
case "email": {
|
|
437
|
+
schemaAttributes[prop] = { type: "string", format: "email" };
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
case "string":
|
|
441
|
+
case "text":
|
|
442
|
+
case "richtext": {
|
|
443
|
+
schemaAttributes[prop] = { type: "string" };
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
case "timestamp": {
|
|
447
|
+
schemaAttributes[prop] = { type: "string", format: "timestamp", example: Date.now() };
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
case "time": {
|
|
451
|
+
schemaAttributes[prop] = { type: "string", format: "time", example: "12:54.000" };
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
case "date": {
|
|
455
|
+
schemaAttributes[prop] = { type: "string", format: "date" };
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
case "datetime": {
|
|
459
|
+
schemaAttributes[prop] = { type: "string", format: "date-time" };
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
case "boolean": {
|
|
463
|
+
schemaAttributes[prop] = { type: "boolean" };
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
case "enumeration": {
|
|
467
|
+
schemaAttributes[prop] = { type: "string", enum: [...attribute.enum] };
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
case "decimal":
|
|
471
|
+
case "float": {
|
|
472
|
+
schemaAttributes[prop] = { type: "number", format: "float" };
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
case "integer": {
|
|
476
|
+
schemaAttributes[prop] = { type: "integer" };
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case "biginteger": {
|
|
480
|
+
schemaAttributes[prop] = { type: "string", pattern: "^\\d*$", example: "123456789" };
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
case "json":
|
|
484
|
+
case "blocks": {
|
|
485
|
+
schemaAttributes[prop] = {};
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
case "uid": {
|
|
489
|
+
schemaAttributes[prop] = { type: "string" };
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
case "component": {
|
|
493
|
+
const componentAttributes = strapi.components[attribute.component].attributes;
|
|
494
|
+
const rawComponentSchema = {
|
|
495
|
+
type: "object",
|
|
496
|
+
properties: {
|
|
497
|
+
...isRequest ? {} : { id: { type: "number" } },
|
|
498
|
+
...cleanSchemaAttributes(componentAttributes, {
|
|
499
|
+
typeMap,
|
|
500
|
+
isRequest,
|
|
501
|
+
didAddStrapiComponentsToSchemas
|
|
502
|
+
})
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
const refComponentSchema = {
|
|
506
|
+
$ref: `#/components/schemas/${pascalCase(attribute.component)}Component`
|
|
507
|
+
};
|
|
508
|
+
const componentExists = didAddStrapiComponentsToSchemas(
|
|
509
|
+
`${pascalCase(attribute.component)}Component`,
|
|
510
|
+
rawComponentSchema
|
|
511
|
+
);
|
|
512
|
+
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
|
|
513
|
+
if (attribute.repeatable) {
|
|
514
|
+
schemaAttributes[prop] = {
|
|
515
|
+
type: "array",
|
|
516
|
+
items: finalComponentSchema
|
|
517
|
+
};
|
|
518
|
+
} else {
|
|
519
|
+
schemaAttributes[prop] = finalComponentSchema;
|
|
520
|
+
}
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
case "dynamiczone": {
|
|
524
|
+
const components = attribute.components.map((component) => {
|
|
525
|
+
const componentAttributes = strapi.components[component].attributes;
|
|
526
|
+
const rawComponentSchema = {
|
|
527
|
+
type: "object",
|
|
528
|
+
properties: {
|
|
529
|
+
...isRequest ? {} : { id: { type: "number" } },
|
|
530
|
+
__component: { type: "string" },
|
|
531
|
+
...cleanSchemaAttributes(componentAttributes, {
|
|
532
|
+
typeMap,
|
|
533
|
+
isRequest,
|
|
534
|
+
didAddStrapiComponentsToSchemas
|
|
535
|
+
})
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
const refComponentSchema = {
|
|
539
|
+
$ref: `#/components/schemas/${pascalCase(component)}Component`
|
|
540
|
+
};
|
|
541
|
+
const componentExists = didAddStrapiComponentsToSchemas(
|
|
542
|
+
`${pascalCase(component)}Component`,
|
|
543
|
+
rawComponentSchema
|
|
544
|
+
);
|
|
545
|
+
const finalComponentSchema = componentExists ? refComponentSchema : rawComponentSchema;
|
|
546
|
+
return finalComponentSchema;
|
|
547
|
+
});
|
|
548
|
+
schemaAttributes[prop] = {
|
|
549
|
+
type: "array",
|
|
550
|
+
items: {
|
|
551
|
+
anyOf: components
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
case "media": {
|
|
557
|
+
const imageAttributes = strapi.contentType("plugin::upload.file").attributes;
|
|
558
|
+
const isListOfEntities = attribute.multiple ?? false;
|
|
559
|
+
if (isRequest) {
|
|
560
|
+
const oneOfType = {
|
|
561
|
+
oneOf: [{ type: "integer" }, { type: "string" }],
|
|
562
|
+
example: "string or id"
|
|
563
|
+
};
|
|
564
|
+
schemaAttributes[prop] = isListOfEntities ? { type: "array", items: oneOfType } : oneOfType;
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
schemaAttributes[prop] = getSchemaData(
|
|
568
|
+
isListOfEntities,
|
|
569
|
+
cleanSchemaAttributes(imageAttributes, { typeMap, didAddStrapiComponentsToSchemas })
|
|
570
|
+
);
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
case "relation": {
|
|
574
|
+
const isListOfEntities = attribute.relation.includes("ToMany");
|
|
575
|
+
if (isRequest) {
|
|
576
|
+
const oneOfType = {
|
|
577
|
+
oneOf: [{ type: "integer" }, { type: "string" }],
|
|
578
|
+
example: "string or id"
|
|
579
|
+
};
|
|
580
|
+
schemaAttributes[prop] = isListOfEntities ? { type: "array", items: oneOfType } : oneOfType;
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
if (!("target" in attribute) || !attribute.target || typeMap.has(attribute.target)) {
|
|
584
|
+
schemaAttributes[prop] = getSchemaData(isListOfEntities, {});
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
typeMap.set(attribute.target, true);
|
|
588
|
+
const targetAttributes = strapi.contentType(attribute.target).attributes;
|
|
589
|
+
schemaAttributes[prop] = getSchemaData(
|
|
590
|
+
isListOfEntities,
|
|
591
|
+
cleanSchemaAttributes(targetAttributes, {
|
|
592
|
+
typeMap,
|
|
593
|
+
isRequest,
|
|
594
|
+
didAddStrapiComponentsToSchemas
|
|
595
|
+
})
|
|
596
|
+
);
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
default: {
|
|
600
|
+
throw new Error(`Invalid type ${attribute.type} while generating open api schema.`);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return schemaAttributes;
|
|
605
|
+
};
|
|
606
|
+
const getRequiredAttributes = (allAttributes) => {
|
|
607
|
+
const requiredAttributes = [];
|
|
608
|
+
for (const key in allAttributes) {
|
|
609
|
+
if (allAttributes[key].required) {
|
|
610
|
+
requiredAttributes.push(key);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return requiredAttributes;
|
|
614
|
+
};
|
|
615
|
+
const getAllSchemasForContentType = ({ routeInfo, attributes, uniqueName }) => {
|
|
616
|
+
let strapiComponentSchemas = {};
|
|
617
|
+
const schemas = {};
|
|
618
|
+
const typeName = pascalCase(uniqueName);
|
|
619
|
+
const didAddStrapiComponentsToSchemas = (schemaName, schema) => {
|
|
620
|
+
if (!Object.keys(schema) || !Object.keys(schema.properties))
|
|
621
|
+
return false;
|
|
622
|
+
strapiComponentSchemas = {
|
|
623
|
+
...strapiComponentSchemas,
|
|
624
|
+
[schemaName]: schema
|
|
625
|
+
};
|
|
626
|
+
return true;
|
|
627
|
+
};
|
|
628
|
+
const routeMethods = routeInfo.routes.map((route) => route.method);
|
|
629
|
+
const attributesToOmit = [
|
|
630
|
+
"createdAt",
|
|
631
|
+
"updatedAt",
|
|
632
|
+
"publishedAt",
|
|
633
|
+
"publishedBy",
|
|
634
|
+
"updatedBy",
|
|
635
|
+
"createdBy"
|
|
636
|
+
];
|
|
637
|
+
const attributesForRequest = ___default.default.omit(attributes, attributesToOmit);
|
|
638
|
+
const requiredRequestAttributes = getRequiredAttributes(attributesForRequest);
|
|
639
|
+
if (routeMethods.includes("POST") || routeMethods.includes("PUT")) {
|
|
640
|
+
Object.assign(schemas, {
|
|
641
|
+
[`${typeName}Request`]: {
|
|
642
|
+
type: "object",
|
|
643
|
+
required: ["data"],
|
|
644
|
+
properties: {
|
|
645
|
+
data: {
|
|
646
|
+
...requiredRequestAttributes.length && { required: requiredRequestAttributes },
|
|
647
|
+
type: "object",
|
|
648
|
+
properties: cleanSchemaAttributes(attributesForRequest, {
|
|
649
|
+
isRequest: true,
|
|
650
|
+
didAddStrapiComponentsToSchemas
|
|
651
|
+
})
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
const hasListOfEntities = routeInfo.routes.filter(
|
|
658
|
+
(route) => hasFindMethod(route.handler)
|
|
659
|
+
).length;
|
|
660
|
+
if (hasListOfEntities) {
|
|
661
|
+
Object.assign(schemas, {
|
|
662
|
+
[`${typeName}ListResponse`]: {
|
|
663
|
+
type: "object",
|
|
664
|
+
properties: {
|
|
665
|
+
data: {
|
|
666
|
+
type: "array",
|
|
667
|
+
items: {
|
|
668
|
+
$ref: `#/components/schemas/${typeName}`
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
meta: {
|
|
672
|
+
type: "object",
|
|
673
|
+
properties: {
|
|
674
|
+
pagination: {
|
|
675
|
+
type: "object",
|
|
676
|
+
properties: {
|
|
677
|
+
page: { type: "integer" },
|
|
678
|
+
pageSize: { type: "integer", minimum: 25 },
|
|
679
|
+
pageCount: { type: "integer", maximum: 1 },
|
|
680
|
+
total: { type: "integer" }
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
const requiredAttributes = getRequiredAttributes(attributes);
|
|
690
|
+
Object.assign(schemas, {
|
|
691
|
+
[`${typeName}`]: {
|
|
692
|
+
type: "object",
|
|
693
|
+
...requiredAttributes.length && { required: requiredAttributes },
|
|
694
|
+
properties: {
|
|
695
|
+
id: { type: "number" },
|
|
696
|
+
documentId: { type: "string" },
|
|
697
|
+
...cleanSchemaAttributes(attributes, { didAddStrapiComponentsToSchemas })
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
[`${typeName}Response`]: {
|
|
701
|
+
type: "object",
|
|
702
|
+
properties: {
|
|
703
|
+
data: {
|
|
704
|
+
$ref: `#/components/schemas/${typeName}`
|
|
705
|
+
},
|
|
706
|
+
meta: { type: "object" }
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
return { ...schemas, ...strapiComponentSchemas };
|
|
711
|
+
};
|
|
712
|
+
const buildComponentSchema = (api) => {
|
|
713
|
+
return loopContentTypeNames(api, getAllSchemasForContentType);
|
|
714
|
+
};
|
|
715
|
+
const getPluginsThatNeedDocumentation = (config2) => {
|
|
716
|
+
const defaultPlugins = ["upload", "users-permissions"];
|
|
717
|
+
const userPluginsConfig = config2["x-strapi-config"].plugins;
|
|
718
|
+
if (userPluginsConfig === null) {
|
|
719
|
+
return defaultPlugins;
|
|
720
|
+
}
|
|
721
|
+
if (userPluginsConfig.length) {
|
|
722
|
+
return userPluginsConfig;
|
|
723
|
+
}
|
|
724
|
+
return [];
|
|
725
|
+
};
|
|
726
|
+
const createService$1 = ({ strapi: strapi2 }) => {
|
|
727
|
+
const config2 = strapi2.config.get("plugin::documentation");
|
|
728
|
+
const pluginsThatNeedDocumentation = getPluginsThatNeedDocumentation(config2);
|
|
729
|
+
const overrideService = getService("override");
|
|
730
|
+
return {
|
|
731
|
+
getDocumentationVersion() {
|
|
732
|
+
return config2.info.version;
|
|
733
|
+
},
|
|
734
|
+
getFullDocumentationPath() {
|
|
735
|
+
return path__default.default.join(strapi2.dirs.app.extensions, "documentation", "documentation");
|
|
736
|
+
},
|
|
737
|
+
getDocumentationVersions() {
|
|
738
|
+
return fs__default.default.readdirSync(this.getFullDocumentationPath()).map((version) => {
|
|
739
|
+
try {
|
|
740
|
+
const filePath = path__default.default.resolve(
|
|
741
|
+
this.getFullDocumentationPath(),
|
|
742
|
+
version,
|
|
743
|
+
"full_documentation.json"
|
|
744
|
+
);
|
|
745
|
+
const doc = JSON.parse(fs__default.default.readFileSync(filePath).toString());
|
|
746
|
+
const generatedDate = doc.info["x-generation-date"];
|
|
747
|
+
return { version, generatedDate, url: "" };
|
|
748
|
+
} catch (err) {
|
|
749
|
+
return null;
|
|
750
|
+
}
|
|
751
|
+
}).filter((x) => x);
|
|
752
|
+
},
|
|
753
|
+
/**
|
|
754
|
+
* Returns settings stored in core-store
|
|
755
|
+
*/
|
|
756
|
+
async getDocumentationAccess() {
|
|
757
|
+
const { restrictedAccess } = await strapi2.store({
|
|
758
|
+
environment: "",
|
|
759
|
+
type: "plugin",
|
|
760
|
+
name: "documentation",
|
|
761
|
+
key: "config"
|
|
762
|
+
}).get();
|
|
763
|
+
return { restrictedAccess };
|
|
764
|
+
},
|
|
765
|
+
getApiDocumentationPath(api) {
|
|
766
|
+
if (api.getter === "plugin") {
|
|
767
|
+
return path__default.default.join(strapi2.dirs.app.extensions, api.name, "documentation");
|
|
768
|
+
}
|
|
769
|
+
return path__default.default.join(strapi2.dirs.app.api, api.name, "documentation");
|
|
770
|
+
},
|
|
771
|
+
async deleteDocumentation(version) {
|
|
772
|
+
const apis = this.getPluginAndApiInfo();
|
|
773
|
+
for (const api of apis) {
|
|
774
|
+
await fs__default.default.remove(path__default.default.join(this.getApiDocumentationPath(api), version));
|
|
775
|
+
}
|
|
776
|
+
await fs__default.default.remove(path__default.default.join(this.getFullDocumentationPath(), version));
|
|
777
|
+
},
|
|
778
|
+
getPluginAndApiInfo() {
|
|
779
|
+
const pluginsToDocument = pluginsThatNeedDocumentation.map((plugin) => {
|
|
780
|
+
return {
|
|
781
|
+
name: plugin,
|
|
782
|
+
getter: "plugin",
|
|
783
|
+
ctNames: Object.keys(strapi2.plugin(plugin).contentTypes)
|
|
784
|
+
};
|
|
785
|
+
});
|
|
786
|
+
const apisToDocument = Object.keys(strapi2.apis).map((api) => {
|
|
787
|
+
return {
|
|
788
|
+
name: api,
|
|
789
|
+
getter: "api",
|
|
790
|
+
ctNames: Object.keys(strapi2.api(api).contentTypes)
|
|
791
|
+
};
|
|
792
|
+
});
|
|
793
|
+
return [...apisToDocument, ...pluginsToDocument];
|
|
794
|
+
},
|
|
795
|
+
/**
|
|
796
|
+
* @description - Creates the Swagger json files
|
|
797
|
+
*/
|
|
798
|
+
async generateFullDoc(versionOpt) {
|
|
799
|
+
const version = versionOpt ?? this.getDocumentationVersion();
|
|
800
|
+
const apis = this.getPluginAndApiInfo();
|
|
801
|
+
const apisThatNeedGeneratedDocumentation = apis.filter(
|
|
802
|
+
({ name }) => !overrideService.isEnabled(name)
|
|
803
|
+
);
|
|
804
|
+
const generatedDocumentation = await immer.produce(config2, async (draft) => {
|
|
805
|
+
if (draft.servers?.length === 0) {
|
|
806
|
+
const serverUrl = strapi2.config.get("server.absoluteUrl");
|
|
807
|
+
const apiPath = strapi2.config.get("api.rest.prefix");
|
|
808
|
+
draft.servers = [
|
|
809
|
+
{
|
|
810
|
+
url: `${serverUrl}${apiPath}`,
|
|
811
|
+
description: "Development server"
|
|
812
|
+
}
|
|
813
|
+
];
|
|
814
|
+
}
|
|
815
|
+
if (!draft.components) {
|
|
816
|
+
draft.components = {};
|
|
817
|
+
}
|
|
818
|
+
draft.info["x-generation-date"] = (/* @__PURE__ */ new Date()).toISOString();
|
|
819
|
+
draft["x-strapi-config"].plugins = pluginsThatNeedDocumentation;
|
|
820
|
+
delete draft["x-strapi-config"].mutateDocumentation;
|
|
821
|
+
for (const api of apisThatNeedGeneratedDocumentation) {
|
|
822
|
+
const newApiPath = buildApiEndpointPath(api);
|
|
823
|
+
const generatedSchemas = buildComponentSchema(api);
|
|
824
|
+
if (generatedSchemas) {
|
|
825
|
+
draft.components.schemas = { ...draft.components.schemas, ...generatedSchemas };
|
|
826
|
+
}
|
|
827
|
+
if (newApiPath) {
|
|
828
|
+
draft.paths = { ...draft.paths, ...newApiPath };
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
if (overrideService.registeredOverrides.length > 0) {
|
|
832
|
+
overrideService.registeredOverrides.forEach((override) => {
|
|
833
|
+
if (!override?.info?.version || override.info.version === version) {
|
|
834
|
+
if (override.tags) {
|
|
835
|
+
draft.tags = draft.tags || [];
|
|
836
|
+
draft.tags.push(...override.tags);
|
|
837
|
+
}
|
|
838
|
+
if (override.paths) {
|
|
839
|
+
draft.paths = { ...draft.paths, ...override.paths };
|
|
840
|
+
}
|
|
841
|
+
if (override.components) {
|
|
842
|
+
const keys = Object.keys(override.components);
|
|
843
|
+
keys.forEach((overrideKey) => {
|
|
844
|
+
draft.components = draft.components || {};
|
|
845
|
+
const overrideValue = override.components?.[overrideKey];
|
|
846
|
+
const originalValue = draft.components?.[overrideKey];
|
|
847
|
+
Object.assign(draft.components, {
|
|
848
|
+
[overrideKey]: {
|
|
849
|
+
...originalValue,
|
|
850
|
+
...overrideValue
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
const userMutatesDocumentation = config2["x-strapi-config"].mutateDocumentation;
|
|
860
|
+
const finalDocumentation = userMutatesDocumentation ? immer.produce(generatedDocumentation, userMutatesDocumentation) : generatedDocumentation;
|
|
861
|
+
const fullDocJsonPath = path__default.default.join(
|
|
862
|
+
this.getFullDocumentationPath(),
|
|
863
|
+
version,
|
|
864
|
+
"full_documentation.json"
|
|
865
|
+
);
|
|
866
|
+
await fs__default.default.ensureFile(fullDocJsonPath);
|
|
867
|
+
await fs__default.default.writeJson(fullDocJsonPath, finalDocumentation, { spaces: 2 });
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
};
|
|
871
|
+
const createService = ({ strapi: strapi2 }) => {
|
|
872
|
+
const registeredOverrides = [];
|
|
873
|
+
const excludedFromGeneration = [];
|
|
874
|
+
return {
|
|
875
|
+
registeredOverrides,
|
|
876
|
+
excludedFromGeneration,
|
|
877
|
+
/**
|
|
878
|
+
*
|
|
879
|
+
* @param {(string | string[])} api - The name of the api or and array of apis to exclude from generation
|
|
880
|
+
*/
|
|
881
|
+
excludeFromGeneration(api) {
|
|
882
|
+
if (Array.isArray(api)) {
|
|
883
|
+
excludedFromGeneration.push(...api);
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
excludedFromGeneration.push(api);
|
|
887
|
+
},
|
|
888
|
+
isEnabled(name) {
|
|
889
|
+
return excludedFromGeneration.includes(name);
|
|
890
|
+
},
|
|
891
|
+
registerOverride(override, opts) {
|
|
892
|
+
const { pluginOrigin, excludeFromGeneration = [] } = opts ?? {};
|
|
893
|
+
const pluginsThatNeedDocumentation = getPluginsThatNeedDocumentation(
|
|
894
|
+
strapi2.config.get("plugin::documentation")
|
|
895
|
+
);
|
|
896
|
+
if (pluginOrigin && !pluginsThatNeedDocumentation.includes(pluginOrigin))
|
|
897
|
+
return;
|
|
898
|
+
if (excludeFromGeneration.length) {
|
|
899
|
+
this.excludeFromGeneration(excludeFromGeneration);
|
|
900
|
+
}
|
|
901
|
+
let overrideToRegister = override;
|
|
902
|
+
if (typeof override === "string") {
|
|
903
|
+
overrideToRegister = require("yaml").parse(overrideToRegister);
|
|
904
|
+
}
|
|
905
|
+
registeredOverrides.push(overrideToRegister);
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
};
|
|
909
|
+
const services = {
|
|
910
|
+
documentation: createService$1,
|
|
911
|
+
override: createService
|
|
912
|
+
};
|
|
913
|
+
const restrictAccess = async (ctx, next) => {
|
|
914
|
+
const pluginStore = strapi.store({ type: "plugin", name: "documentation" });
|
|
915
|
+
const config2 = await pluginStore.get({ key: "config" });
|
|
916
|
+
if (!config2.restrictedAccess) {
|
|
917
|
+
return next();
|
|
918
|
+
}
|
|
919
|
+
if (!ctx.session || !ctx.session.documentation || !ctx.session.documentation.logged) {
|
|
920
|
+
const querystring = ctx.querystring ? `?${ctx.querystring}` : "";
|
|
921
|
+
return ctx.redirect(`${strapi.config.server.url}/documentation/login${querystring}`);
|
|
922
|
+
}
|
|
923
|
+
return next();
|
|
924
|
+
};
|
|
925
|
+
const routes = [
|
|
926
|
+
{
|
|
927
|
+
method: "GET",
|
|
928
|
+
path: "/",
|
|
929
|
+
handler: "documentation.index",
|
|
930
|
+
config: {
|
|
931
|
+
auth: false,
|
|
932
|
+
middlewares: [restrictAccess]
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
method: "GET",
|
|
937
|
+
path: "/v:major(\\d+).:minor(\\d+).:patch(\\d+)",
|
|
938
|
+
handler: "documentation.index",
|
|
939
|
+
config: {
|
|
940
|
+
auth: false,
|
|
941
|
+
middlewares: [restrictAccess]
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
method: "GET",
|
|
946
|
+
path: "/login",
|
|
947
|
+
handler: "documentation.loginView",
|
|
948
|
+
config: {
|
|
949
|
+
auth: false
|
|
950
|
+
}
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
method: "POST",
|
|
954
|
+
path: "/login",
|
|
955
|
+
handler: "documentation.login",
|
|
956
|
+
config: {
|
|
957
|
+
auth: false
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
method: "GET",
|
|
962
|
+
path: "/getInfos",
|
|
963
|
+
handler: "documentation.getInfos",
|
|
964
|
+
config: {
|
|
965
|
+
policies: [
|
|
966
|
+
{ name: "admin::hasPermissions", config: { actions: ["plugin::documentation.read"] } }
|
|
967
|
+
]
|
|
968
|
+
}
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
method: "POST",
|
|
972
|
+
path: "/regenerateDoc",
|
|
973
|
+
handler: "documentation.regenerateDoc",
|
|
974
|
+
config: {
|
|
975
|
+
policies: [
|
|
976
|
+
{
|
|
977
|
+
name: "admin::hasPermissions",
|
|
978
|
+
config: { actions: ["plugin::documentation.settings.regenerate"] }
|
|
979
|
+
}
|
|
980
|
+
]
|
|
981
|
+
}
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
method: "PUT",
|
|
985
|
+
path: "/updateSettings",
|
|
986
|
+
handler: "documentation.updateSettings",
|
|
987
|
+
config: {
|
|
988
|
+
policies: [
|
|
989
|
+
{
|
|
990
|
+
name: "admin::hasPermissions",
|
|
991
|
+
config: { actions: ["plugin::documentation.settings.update"] }
|
|
992
|
+
}
|
|
993
|
+
]
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
method: "DELETE",
|
|
998
|
+
path: "/deleteDoc/:version",
|
|
999
|
+
handler: "documentation.deleteDoc",
|
|
1000
|
+
config: {
|
|
1001
|
+
policies: []
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
];
|
|
1005
|
+
const validation = {
|
|
1006
|
+
validatSettings: utils.validateYupSchema(
|
|
1007
|
+
utils.yup.object().shape({
|
|
1008
|
+
restrictedAccess: utils.yup.boolean(),
|
|
1009
|
+
password: utils.yup.string().min(8).matches(/[a-z]/, "${path} must contain at least one lowercase character").matches(/[A-Z]/, "${path} must contain at least one uppercase character").matches(/\d/, "${path} must contain at least one number").when("restrictedAccess", (value, initSchema) => {
|
|
1010
|
+
return value ? initSchema.required("password is required") : initSchema;
|
|
1011
|
+
})
|
|
1012
|
+
})
|
|
1013
|
+
)
|
|
1014
|
+
};
|
|
1015
|
+
const documentation = {
|
|
1016
|
+
async getInfos(ctx) {
|
|
1017
|
+
try {
|
|
1018
|
+
const docService = getService("documentation");
|
|
1019
|
+
const docVersions = docService.getDocumentationVersions();
|
|
1020
|
+
const documentationAccess = await docService.getDocumentationAccess();
|
|
1021
|
+
ctx.send({
|
|
1022
|
+
docVersions,
|
|
1023
|
+
currentVersion: docService.getDocumentationVersion(),
|
|
1024
|
+
prefix: "/documentation",
|
|
1025
|
+
documentationAccess
|
|
1026
|
+
});
|
|
1027
|
+
} catch (err) {
|
|
1028
|
+
strapi.log.error(err);
|
|
1029
|
+
ctx.badRequest();
|
|
1030
|
+
}
|
|
1031
|
+
},
|
|
1032
|
+
async index(ctx, next) {
|
|
1033
|
+
try {
|
|
1034
|
+
const { major, minor, patch } = ctx.params;
|
|
1035
|
+
const version = major && minor && patch ? `${major}.${minor}.${patch}` : getService("documentation").getDocumentationVersion();
|
|
1036
|
+
const openAPISpecsPath = path__default.default.join(
|
|
1037
|
+
strapi.dirs.app.extensions,
|
|
1038
|
+
"documentation",
|
|
1039
|
+
"documentation",
|
|
1040
|
+
version,
|
|
1041
|
+
"full_documentation.json"
|
|
1042
|
+
);
|
|
1043
|
+
try {
|
|
1044
|
+
const documentation2 = fs__default.default.readFileSync(openAPISpecsPath, "utf8");
|
|
1045
|
+
const layout = (await Promise.resolve().then(() => require("../_chunks/index-WbbYm9_u.js"))).default;
|
|
1046
|
+
const filledLayout = ___default.default.template(layout)({
|
|
1047
|
+
backendUrl: strapi.config.server.url,
|
|
1048
|
+
spec: JSON.stringify(JSON.parse(documentation2))
|
|
1049
|
+
});
|
|
1050
|
+
try {
|
|
1051
|
+
const layoutPath = path__default.default.resolve(
|
|
1052
|
+
strapi.dirs.app.extensions,
|
|
1053
|
+
"documentation",
|
|
1054
|
+
"public",
|
|
1055
|
+
"index.html"
|
|
1056
|
+
);
|
|
1057
|
+
await fs__default.default.ensureFile(layoutPath);
|
|
1058
|
+
await fs__default.default.writeFile(layoutPath, filledLayout);
|
|
1059
|
+
ctx.url = path__default.default.basename(`${ctx.url}/index.html`);
|
|
1060
|
+
try {
|
|
1061
|
+
const staticFolder = path__default.default.resolve(
|
|
1062
|
+
strapi.dirs.app.extensions,
|
|
1063
|
+
"documentation",
|
|
1064
|
+
"public"
|
|
1065
|
+
);
|
|
1066
|
+
return koaStatic__default.default(staticFolder)(ctx, next);
|
|
1067
|
+
} catch (e) {
|
|
1068
|
+
strapi.log.error(e);
|
|
1069
|
+
}
|
|
1070
|
+
} catch (e) {
|
|
1071
|
+
strapi.log.error(e);
|
|
1072
|
+
}
|
|
1073
|
+
} catch (e) {
|
|
1074
|
+
strapi.log.error(e);
|
|
1075
|
+
}
|
|
1076
|
+
} catch (e) {
|
|
1077
|
+
strapi.log.error(e);
|
|
1078
|
+
}
|
|
1079
|
+
},
|
|
1080
|
+
async loginView(ctx, next) {
|
|
1081
|
+
const cheerio = require("cheerio");
|
|
1082
|
+
const { error } = ctx.query;
|
|
1083
|
+
try {
|
|
1084
|
+
const layout = (await Promise.resolve().then(() => require("../_chunks/login-HAajOKpu.js"))).default;
|
|
1085
|
+
const filledLayout = ___default.default.template(layout.toString())({
|
|
1086
|
+
actionUrl: `${strapi.config.server.url}/documentation/login`
|
|
1087
|
+
});
|
|
1088
|
+
const $ = cheerio.load(filledLayout);
|
|
1089
|
+
$(".error").text(___default.default.isEmpty(error) ? "" : "Wrong password...");
|
|
1090
|
+
try {
|
|
1091
|
+
const layoutPath = path__default.default.resolve(
|
|
1092
|
+
strapi.dirs.app.extensions,
|
|
1093
|
+
"documentation",
|
|
1094
|
+
"public",
|
|
1095
|
+
"login.html"
|
|
1096
|
+
);
|
|
1097
|
+
await fs__default.default.ensureFile(layoutPath);
|
|
1098
|
+
await fs__default.default.writeFile(layoutPath, $.html());
|
|
1099
|
+
ctx.url = path__default.default.basename(`${ctx.url}/login.html`);
|
|
1100
|
+
try {
|
|
1101
|
+
const staticFolder = path__default.default.resolve(strapi.dirs.app.extensions, "documentation", "public");
|
|
1102
|
+
return koaStatic__default.default(staticFolder)(ctx, next);
|
|
1103
|
+
} catch (e) {
|
|
1104
|
+
strapi.log.error(e);
|
|
1105
|
+
}
|
|
1106
|
+
} catch (e) {
|
|
1107
|
+
strapi.log.error(e);
|
|
1108
|
+
}
|
|
1109
|
+
} catch (e) {
|
|
1110
|
+
strapi.log.error(e);
|
|
1111
|
+
}
|
|
1112
|
+
},
|
|
1113
|
+
async login(ctx) {
|
|
1114
|
+
const {
|
|
1115
|
+
body: { password }
|
|
1116
|
+
} = ctx.request;
|
|
1117
|
+
const { password: hash } = await strapi.store({ type: "plugin", name: "documentation", key: "config" }).get();
|
|
1118
|
+
const isValid = await bcrypt__default.default.compare(password, hash);
|
|
1119
|
+
let querystring = "?error=password";
|
|
1120
|
+
if (isValid && ctx.session) {
|
|
1121
|
+
ctx.session.documentation = {
|
|
1122
|
+
logged: true
|
|
1123
|
+
};
|
|
1124
|
+
querystring = "";
|
|
1125
|
+
}
|
|
1126
|
+
ctx.redirect(`${strapi.config.server.url}/documentation${querystring}`);
|
|
1127
|
+
},
|
|
1128
|
+
async regenerateDoc(ctx) {
|
|
1129
|
+
const { version } = ctx.request.body;
|
|
1130
|
+
const service = getService("documentation");
|
|
1131
|
+
const documentationVersions = service.getDocumentationVersions().map((el) => el.version);
|
|
1132
|
+
if (___default.default.isEmpty(version)) {
|
|
1133
|
+
return ctx.badRequest("Please provide a version.");
|
|
1134
|
+
}
|
|
1135
|
+
if (!documentationVersions.includes(version)) {
|
|
1136
|
+
return ctx.badRequest("The version you are trying to generate does not exist.");
|
|
1137
|
+
}
|
|
1138
|
+
try {
|
|
1139
|
+
strapi.reload.isWatching = false;
|
|
1140
|
+
await service.generateFullDoc(version);
|
|
1141
|
+
ctx.send({ ok: true });
|
|
1142
|
+
} finally {
|
|
1143
|
+
strapi.reload.isWatching = true;
|
|
1144
|
+
}
|
|
1145
|
+
},
|
|
1146
|
+
async deleteDoc(ctx) {
|
|
1147
|
+
const { version } = ctx.params;
|
|
1148
|
+
const service = getService("documentation");
|
|
1149
|
+
const documentationVersions = service.getDocumentationVersions().map((el) => el.version);
|
|
1150
|
+
if (___default.default.isEmpty(version)) {
|
|
1151
|
+
return ctx.badRequest("Please provide a version.");
|
|
1152
|
+
}
|
|
1153
|
+
if (!documentationVersions.includes(version)) {
|
|
1154
|
+
return ctx.badRequest("The version you are trying to delete does not exist.");
|
|
1155
|
+
}
|
|
1156
|
+
try {
|
|
1157
|
+
strapi.reload.isWatching = false;
|
|
1158
|
+
await service.deleteDocumentation(version);
|
|
1159
|
+
ctx.send({ ok: true });
|
|
1160
|
+
} finally {
|
|
1161
|
+
strapi.reload.isWatching = true;
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
async updateSettings(ctx) {
|
|
1165
|
+
const pluginStore = strapi.store({ type: "plugin", name: "documentation" });
|
|
1166
|
+
const data = await validation.validatSettings(ctx.request.body);
|
|
1167
|
+
const config2 = {
|
|
1168
|
+
restrictedAccess: Boolean(data.restrictedAccess)
|
|
1169
|
+
};
|
|
1170
|
+
if (data.password) {
|
|
1171
|
+
config2.password = await bcrypt__default.default.hash(data.password, 10);
|
|
1172
|
+
}
|
|
1173
|
+
await pluginStore.set({ key: "config", value: config2 });
|
|
1174
|
+
return ctx.send({ ok: true });
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
const controllers = {
|
|
1178
|
+
documentation
|
|
1179
|
+
};
|
|
1180
|
+
const defaultConfig = {
|
|
1181
|
+
openapi: "3.0.0",
|
|
1182
|
+
info: {
|
|
1183
|
+
version: "1.0.0",
|
|
1184
|
+
title: "DOCUMENTATION",
|
|
1185
|
+
description: "",
|
|
1186
|
+
termsOfService: "YOUR_TERMS_OF_SERVICE_URL",
|
|
1187
|
+
contact: {
|
|
1188
|
+
name: "TEAM",
|
|
1189
|
+
email: "contact-email@something.io",
|
|
1190
|
+
url: "mywebsite.io"
|
|
1191
|
+
},
|
|
1192
|
+
license: {
|
|
1193
|
+
name: "Apache 2.0",
|
|
1194
|
+
url: "https://www.apache.org/licenses/LICENSE-2.0.html"
|
|
1195
|
+
}
|
|
1196
|
+
},
|
|
1197
|
+
"x-strapi-config": {
|
|
1198
|
+
plugins: null,
|
|
1199
|
+
mutateDocumentation: null
|
|
1200
|
+
},
|
|
1201
|
+
servers: [],
|
|
1202
|
+
externalDocs: {
|
|
1203
|
+
description: "Find out more",
|
|
1204
|
+
url: "https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html"
|
|
1205
|
+
},
|
|
1206
|
+
security: [
|
|
1207
|
+
{
|
|
1208
|
+
bearerAuth: []
|
|
1209
|
+
}
|
|
1210
|
+
],
|
|
1211
|
+
paths: {},
|
|
1212
|
+
components: {
|
|
1213
|
+
securitySchemes: {
|
|
1214
|
+
bearerAuth: {
|
|
1215
|
+
type: "http",
|
|
1216
|
+
scheme: "bearer",
|
|
1217
|
+
bearerFormat: "JWT"
|
|
1218
|
+
}
|
|
1219
|
+
},
|
|
1220
|
+
schemas: {
|
|
1221
|
+
Error: {
|
|
1222
|
+
type: "object",
|
|
1223
|
+
required: ["error"],
|
|
1224
|
+
properties: {
|
|
1225
|
+
data: {
|
|
1226
|
+
nullable: true,
|
|
1227
|
+
oneOf: [{ type: "object" }, { type: "array", items: { type: "object" } }]
|
|
1228
|
+
},
|
|
1229
|
+
error: {
|
|
1230
|
+
type: "object",
|
|
1231
|
+
properties: {
|
|
1232
|
+
status: {
|
|
1233
|
+
type: "integer"
|
|
1234
|
+
},
|
|
1235
|
+
name: {
|
|
1236
|
+
type: "string"
|
|
1237
|
+
},
|
|
1238
|
+
message: {
|
|
1239
|
+
type: "string"
|
|
1240
|
+
},
|
|
1241
|
+
details: {
|
|
1242
|
+
type: "object"
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
const config = {
|
|
1252
|
+
default: defaultConfig
|
|
1253
|
+
};
|
|
1254
|
+
const index = {
|
|
1255
|
+
bootstrap,
|
|
1256
|
+
config,
|
|
1257
|
+
routes,
|
|
1258
|
+
controllers,
|
|
1259
|
+
register,
|
|
1260
|
+
services
|
|
1261
|
+
};
|
|
1262
|
+
module.exports = index;
|
|
1263
|
+
//# sourceMappingURL=index.js.map
|