@prauga/flexdoc-backend 2.1.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 (53) hide show
  1. package/README.md +227 -0
  2. package/dist/flexdoc.module.d.ts +14 -0
  3. package/dist/flexdoc.module.js +77 -0
  4. package/dist/flexdoc.module.js.map +1 -0
  5. package/dist/flexdoc.module.test.d.ts +1 -0
  6. package/dist/flexdoc.module.test.js +72 -0
  7. package/dist/flexdoc.module.test.js.map +1 -0
  8. package/dist/flexdoc.service.d.ts +5 -0
  9. package/dist/flexdoc.service.js +24 -0
  10. package/dist/flexdoc.service.js.map +1 -0
  11. package/dist/framework-adapters.d.ts +25 -0
  12. package/dist/framework-adapters.js +163 -0
  13. package/dist/framework-adapters.js.map +1 -0
  14. package/dist/framework-adapters.test.d.ts +1 -0
  15. package/dist/framework-adapters.test.js +37 -0
  16. package/dist/framework-adapters.test.js.map +1 -0
  17. package/dist/index.d.ts +6 -0
  18. package/dist/index.js +14 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/interfaces.d.ts +169 -0
  21. package/dist/interfaces.js +3 -0
  22. package/dist/interfaces.js.map +1 -0
  23. package/dist/renderer/flexdoc.standalone.css +1 -0
  24. package/dist/renderer/flexdoc.standalone.js +200 -0
  25. package/dist/renderer-assets.d.ts +5 -0
  26. package/dist/renderer-assets.js +60 -0
  27. package/dist/renderer-assets.js.map +1 -0
  28. package/dist/scripts/generate-auth.d.ts +2 -0
  29. package/dist/scripts/generate-auth.js +107 -0
  30. package/dist/scripts/generate-auth.js.map +1 -0
  31. package/dist/setup.d.ts +6 -0
  32. package/dist/setup.js +220 -0
  33. package/dist/setup.js.map +1 -0
  34. package/dist/setup.test.d.ts +1 -0
  35. package/dist/setup.test.js +89 -0
  36. package/dist/setup.test.js.map +1 -0
  37. package/dist/template.d.ts +15 -0
  38. package/dist/template.js +64 -0
  39. package/dist/template.js.map +1 -0
  40. package/dist/template.test.d.ts +1 -0
  41. package/dist/template.test.js +38 -0
  42. package/dist/template.test.js.map +1 -0
  43. package/dist/templates/code-examples.njk +106 -0
  44. package/dist/templates/content.njk +272 -0
  45. package/dist/templates/footer.njk +38 -0
  46. package/dist/templates/header.njk +57 -0
  47. package/dist/templates/layout.njk +647 -0
  48. package/dist/templates/parameters.njk +64 -0
  49. package/dist/templates/request-body.njk +63 -0
  50. package/dist/templates/responses.njk +78 -0
  51. package/dist/templates/sidebar.njk +117 -0
  52. package/dist/tsconfig.tsbuildinfo +1 -0
  53. package/package.json +34 -0
@@ -0,0 +1,5 @@
1
+ export interface RendererAssets {
2
+ javascript: string;
3
+ css: string;
4
+ }
5
+ export declare function getRendererAssets(): RendererAssets;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getRendererAssets = getRendererAssets;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ function findAsset(relativePath) {
40
+ const candidates = [
41
+ path.join(__dirname, 'renderer', relativePath),
42
+ path.resolve(__dirname, '../../client/dist/standalone', relativePath),
43
+ ];
44
+ for (const candidate of candidates) {
45
+ if (fs.existsSync(candidate))
46
+ return candidate;
47
+ }
48
+ throw new Error(`FlexDoc renderer asset not found: ${relativePath}. Build @prauga/flexdoc-client before @prauga/flexdoc-backend.`);
49
+ }
50
+ let cachedAssets = null;
51
+ function getRendererAssets() {
52
+ if (cachedAssets)
53
+ return cachedAssets;
54
+ cachedAssets = {
55
+ javascript: fs.readFileSync(findAsset('flexdoc.standalone.js'), 'utf8'),
56
+ css: fs.readFileSync(findAsset('flexdoc.standalone.css'), 'utf8'),
57
+ };
58
+ return cachedAssets;
59
+ }
60
+ //# sourceMappingURL=renderer-assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer-assets.js","sourceRoot":"","sources":["../src/renderer-assets.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,8CASC;AAlCD,uCAAyB;AACzB,2CAA6B;AAO7B,SAAS,SAAS,CAAC,YAAoB;IACrC,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,8BAA8B,EAAE,YAAY,CAAC;KACtE,CAAC;IAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IACjD,CAAC;IAED,MAAM,IAAI,KAAK,CACb,qCAAqC,YAAY,gEAAgE,CAClH,CAAC;AACJ,CAAC;AAED,IAAI,YAAY,GAA0B,IAAI,CAAC;AAE/C,SAAgB,iBAAiB;IAC/B,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IAEtC,YAAY,GAAG;QACb,UAAU,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACvE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;KAClE,CAAC;IAEF,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const crypto = __importStar(require("crypto"));
41
+ const jwt = __importStar(require("jsonwebtoken"));
42
+ const yargs_1 = __importDefault(require("yargs"));
43
+ const helpers_1 = require("yargs/helpers");
44
+ function generatePassword(username, secret) {
45
+ const hmac = crypto.createHmac('sha256', secret);
46
+ hmac.update(username);
47
+ const hash = hmac.digest('base64');
48
+ const basePassword = hash.substring(0, 12);
49
+ let password = basePassword;
50
+ if (!/[A-Z]/.test(password))
51
+ password += 'A';
52
+ if (!/[a-z]/.test(password))
53
+ password += 'a';
54
+ if (!/[0-9]/.test(password))
55
+ password += '1';
56
+ if (!/[^A-Za-z0-9]/.test(password))
57
+ password += '!';
58
+ return password;
59
+ }
60
+ function generateToken(expiry, secret) {
61
+ const payload = {
62
+ iss: 'flexdoc',
63
+ iat: Math.floor(Date.now() / 1000),
64
+ exp: Math.floor(Date.now() / 1000) + expiry * 24 * 60 * 60,
65
+ };
66
+ return jwt.sign(payload, secret);
67
+ }
68
+ (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
69
+ .command('basic', 'Generate a password for basic authentication', {
70
+ username: {
71
+ description: 'Username to generate password for',
72
+ demandOption: true,
73
+ type: 'string',
74
+ },
75
+ secret: {
76
+ description: 'Secret key used for generation',
77
+ demandOption: true,
78
+ type: 'string',
79
+ },
80
+ }, (argv) => {
81
+ const password = generatePassword(argv.username, argv.secret);
82
+ console.log(`\nCredentials for user "${argv.username}":`);
83
+ console.log(`Username: ${argv.username}`);
84
+ console.log(`Password: ${password}\n`);
85
+ console.log(`These credentials can be used with Basic Authentication.\n`);
86
+ })
87
+ .command('bearer', 'Generate a JWT token for bearer authentication', {
88
+ expiry: {
89
+ description: 'Token expiry in days',
90
+ default: 30,
91
+ type: 'number',
92
+ },
93
+ secret: {
94
+ description: 'Secret key used for signing',
95
+ demandOption: true,
96
+ type: 'string',
97
+ },
98
+ }, (argv) => {
99
+ const token = generateToken(argv.expiry, argv.secret);
100
+ console.log(`\nBearer token (valid for ${argv.expiry} days):`);
101
+ console.log(token);
102
+ console.log(`\nUse this token with Bearer Authentication.\n`);
103
+ })
104
+ .demandCommand(1, 'You must specify a command: basic or bearer')
105
+ .help()
106
+ .parse();
107
+ //# sourceMappingURL=generate-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-auth.js","sourceRoot":"","sources":["../../src/scripts/generate-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { FlexDocModuleOptions } from './interfaces';
2
+ interface AppWithUse {
3
+ use: (path: string, handler: (req: any, res: any, next?: any) => void | Promise<void>) => void;
4
+ }
5
+ export declare function setupFlexDoc(app: AppWithUse, path: string, options: Omit<FlexDocModuleOptions, 'path'>): void;
6
+ export {};
package/dist/setup.js ADDED
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.setupFlexDoc = setupFlexDoc;
37
+ const template_1 = require("./template");
38
+ const renderer_assets_1 = require("./renderer-assets");
39
+ const crypto = __importStar(require("crypto"));
40
+ const jwt = __importStar(require("jsonwebtoken"));
41
+ const http = __importStar(require("http"));
42
+ const https = __importStar(require("https"));
43
+ function generatePassword(username, secret) {
44
+ const hmac = crypto.createHmac('sha256', secret);
45
+ hmac.update(username);
46
+ const hash = hmac.digest('base64');
47
+ const basePassword = hash.substring(0, 12);
48
+ let password = basePassword;
49
+ if (!/[A-Z]/.test(password))
50
+ password += 'A';
51
+ if (!/[a-z]/.test(password))
52
+ password += 'a';
53
+ if (!/[0-9]/.test(password))
54
+ password += '1';
55
+ if (!/[^A-Za-z0-9]/.test(password))
56
+ password += '!';
57
+ return password;
58
+ }
59
+ function createAuthMiddleware(authOptions) {
60
+ return (req, res, next) => {
61
+ const { type, secretKey } = authOptions;
62
+ const authHeader = req.headers.authorization;
63
+ if (type === 'basic') {
64
+ if (!authHeader || !authHeader.startsWith('Basic ')) {
65
+ res.statusCode = 401;
66
+ res.setHeader('WWW-Authenticate', 'Basic');
67
+ return res.end('Authentication required');
68
+ }
69
+ const credentials = Buffer.from(authHeader.split(' ')[1], 'base64').toString('ascii');
70
+ const separatorIndex = credentials.indexOf(':');
71
+ const username = separatorIndex === -1 ? credentials : credentials.slice(0, separatorIndex);
72
+ const password = separatorIndex === -1 ? '' : credentials.slice(separatorIndex + 1);
73
+ if (password !== generatePassword(username, secretKey)) {
74
+ res.statusCode = 401;
75
+ res.setHeader('WWW-Authenticate', 'Basic');
76
+ return res.end('Invalid credentials');
77
+ }
78
+ return next();
79
+ }
80
+ if (type === 'bearer') {
81
+ let token;
82
+ if (authHeader?.startsWith('Bearer ')) {
83
+ token = authHeader.split(' ')[1];
84
+ }
85
+ else if (authHeader?.startsWith('Basic ')) {
86
+ const credentials = Buffer.from(authHeader.split(' ')[1], 'base64').toString('ascii');
87
+ const separatorIndex = credentials.indexOf(':');
88
+ token = separatorIndex === -1 ? undefined : credentials.slice(separatorIndex + 1);
89
+ }
90
+ if (token) {
91
+ try {
92
+ jwt.verify(token, secretKey);
93
+ return next();
94
+ }
95
+ catch {
96
+ res.statusCode = 401;
97
+ res.setHeader('WWW-Authenticate', 'Basic realm="Enter token as password"');
98
+ return res.end('Invalid or expired token');
99
+ }
100
+ }
101
+ res.statusCode = 401;
102
+ res.setHeader('WWW-Authenticate', 'Basic realm="Enter token as password"');
103
+ return res.end('Authentication required');
104
+ }
105
+ return next();
106
+ };
107
+ }
108
+ function fetchJson(urlString, redirectsRemaining = 3) {
109
+ return new Promise((resolve, reject) => {
110
+ let url;
111
+ try {
112
+ url = new URL(urlString);
113
+ }
114
+ catch {
115
+ reject(new Error(`Invalid OpenAPI spec URL: ${urlString}`));
116
+ return;
117
+ }
118
+ const client = url.protocol === 'https:' ? https : url.protocol === 'http:' ? http : null;
119
+ if (!client) {
120
+ reject(new Error(`Unsupported OpenAPI spec URL protocol: ${url.protocol}`));
121
+ return;
122
+ }
123
+ const request = client.get(url, (response) => {
124
+ const statusCode = response.statusCode || 0;
125
+ const location = response.headers.location;
126
+ if (statusCode >= 300 && statusCode < 400 && location) {
127
+ response.resume();
128
+ if (redirectsRemaining <= 0) {
129
+ reject(new Error('Too many redirects while loading OpenAPI spec'));
130
+ return;
131
+ }
132
+ fetchJson(new URL(location, url).toString(), redirectsRemaining - 1).then(resolve, reject);
133
+ return;
134
+ }
135
+ if (statusCode < 200 || statusCode >= 300) {
136
+ response.resume();
137
+ reject(new Error(`Failed to load OpenAPI spec: HTTP ${statusCode || 'unknown'}`));
138
+ return;
139
+ }
140
+ const chunks = [];
141
+ response.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
142
+ response.on('end', () => {
143
+ try {
144
+ resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')));
145
+ }
146
+ catch {
147
+ reject(new Error('OpenAPI spec URL did not return valid JSON'));
148
+ }
149
+ });
150
+ response.on('error', reject);
151
+ });
152
+ request.on('error', reject);
153
+ request.setTimeout(10000, () => {
154
+ request.destroy(new Error('Timed out while loading OpenAPI spec'));
155
+ });
156
+ });
157
+ }
158
+ function setupFlexDoc(app, path, options) {
159
+ const { spec, specUrl, options: flexDocOptions } = options;
160
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
161
+ const rendererBasePath = `${normalizedPath}/__flexdoc`;
162
+ if (flexDocOptions?.auth) {
163
+ app.use(normalizedPath, createAuthMiddleware(flexDocOptions.auth));
164
+ }
165
+ app.use(`${rendererBasePath}/renderer.js`, (_req, res) => {
166
+ try {
167
+ res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
168
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
169
+ res.send((0, renderer_assets_1.getRendererAssets)().javascript);
170
+ }
171
+ catch (error) {
172
+ res.statusCode = 500;
173
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
174
+ res.end(error instanceof Error ? error.message : 'Renderer asset unavailable');
175
+ }
176
+ });
177
+ app.use(`${rendererBasePath}/renderer.css`, (_req, res) => {
178
+ try {
179
+ res.setHeader('Content-Type', 'text/css; charset=utf-8');
180
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
181
+ res.send((0, renderer_assets_1.getRendererAssets)().css);
182
+ }
183
+ catch (error) {
184
+ res.statusCode = 500;
185
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
186
+ res.end(error instanceof Error ? error.message : 'Renderer asset unavailable');
187
+ }
188
+ });
189
+ let remoteSpecPromise = null;
190
+ const getSpec = async () => {
191
+ if (spec)
192
+ return spec;
193
+ if (!specUrl)
194
+ return null;
195
+ if (!remoteSpecPromise) {
196
+ remoteSpecPromise = fetchJson(specUrl).catch((error) => {
197
+ remoteSpecPromise = null;
198
+ throw error;
199
+ });
200
+ }
201
+ return remoteSpecPromise;
202
+ };
203
+ app.use(normalizedPath, async (_req, res) => {
204
+ try {
205
+ const resolvedSpec = await getSpec();
206
+ const html = (0, template_1.generateFlexDocHTML)(resolvedSpec, {
207
+ ...(flexDocOptions || {}),
208
+ rendererBasePath,
209
+ });
210
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
211
+ res.send(html);
212
+ }
213
+ catch (error) {
214
+ res.statusCode = 502;
215
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
216
+ res.end(`Unable to load OpenAPI specification: ${error instanceof Error ? error.message : 'Unknown error'}`);
217
+ }
218
+ });
219
+ }
220
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const setup_1 = require("./setup");
4
+ const template_1 = require("./template");
5
+ const renderer_assets_1 = require("./renderer-assets");
6
+ jest.mock('./template', () => ({
7
+ generateFlexDocHTML: jest.fn().mockReturnValue('<html>Mocked HTML</html>'),
8
+ }));
9
+ jest.mock('./renderer-assets', () => ({
10
+ getRendererAssets: jest.fn().mockReturnValue({
11
+ javascript: 'window.renderer = true;',
12
+ css: '.renderer { display: block; }',
13
+ }),
14
+ }));
15
+ describe('setupFlexDoc', () => {
16
+ let mockApp;
17
+ let mockReq;
18
+ let mockRes;
19
+ let handlers;
20
+ beforeEach(() => {
21
+ jest.clearAllMocks();
22
+ handlers = new Map();
23
+ mockApp = {
24
+ use: jest.fn().mockImplementation((path, middleware) => {
25
+ handlers.set(path, middleware);
26
+ }),
27
+ };
28
+ mockReq = { headers: {} };
29
+ mockRes = {
30
+ setHeader: jest.fn(),
31
+ send: jest.fn(),
32
+ end: jest.fn(),
33
+ statusCode: 200,
34
+ };
35
+ });
36
+ it('registers the page and canonical renderer asset routes', () => {
37
+ (0, setup_1.setupFlexDoc)(mockApp, '/docs', { spec: { openapi: '3.0.0' } });
38
+ expect(handlers.has('/docs')).toBe(true);
39
+ expect(handlers.has('/docs/__flexdoc/renderer.js')).toBe(true);
40
+ expect(handlers.has('/docs/__flexdoc/renderer.css')).toBe(true);
41
+ });
42
+ it('normalizes path to include a leading slash', () => {
43
+ (0, setup_1.setupFlexDoc)(mockApp, 'docs', { spec: { openapi: '3.0.0' } });
44
+ expect(handlers.has('/docs')).toBe(true);
45
+ });
46
+ it('serves the shared renderer bundle locally', async () => {
47
+ (0, setup_1.setupFlexDoc)(mockApp, '/docs', { spec: { openapi: '3.0.0' } });
48
+ await handlers.get('/docs/__flexdoc/renderer.js')(mockReq, mockRes);
49
+ expect(renderer_assets_1.getRendererAssets).toHaveBeenCalled();
50
+ expect(mockRes.setHeader).toHaveBeenCalledWith('Content-Type', 'application/javascript; charset=utf-8');
51
+ expect(mockRes.send).toHaveBeenCalledWith('window.renderer = true;');
52
+ });
53
+ it('generates HTML with the spec and renderer base path', async () => {
54
+ const spec = {
55
+ openapi: '3.0.0',
56
+ info: { title: 'Test API', version: '1.0.0' },
57
+ };
58
+ (0, setup_1.setupFlexDoc)(mockApp, '/docs', { spec });
59
+ await handlers.get('/docs')(mockReq, mockRes);
60
+ expect(template_1.generateFlexDocHTML).toHaveBeenCalledWith(spec, expect.objectContaining({ rendererBasePath: '/docs/__flexdoc' }));
61
+ expect(mockRes.setHeader).toHaveBeenCalledWith('Content-Type', 'text/html; charset=utf-8');
62
+ expect(mockRes.send).toHaveBeenCalledWith('<html>Mocked HTML</html>');
63
+ });
64
+ it('returns a gateway error when specUrl cannot be loaded', async () => {
65
+ (0, setup_1.setupFlexDoc)(mockApp, '/docs', {
66
+ specUrl: 'file:///tmp/openapi.json',
67
+ });
68
+ await handlers.get('/docs')(mockReq, mockRes);
69
+ expect(template_1.generateFlexDocHTML).not.toHaveBeenCalled();
70
+ expect(mockRes.statusCode).toBe(502);
71
+ expect(mockRes.setHeader).toHaveBeenCalledWith('Content-Type', 'text/plain; charset=utf-8');
72
+ expect(mockRes.end).toHaveBeenCalledWith(expect.stringContaining('Unsupported OpenAPI spec URL protocol'));
73
+ });
74
+ it('passes FlexDoc options to the shared renderer host page', async () => {
75
+ const flexDocOptions = {
76
+ theme: 'dark',
77
+ };
78
+ (0, setup_1.setupFlexDoc)(mockApp, '/docs', {
79
+ spec: { openapi: '3.0.0' },
80
+ options: flexDocOptions,
81
+ });
82
+ await handlers.get('/docs')(mockReq, mockRes);
83
+ expect(template_1.generateFlexDocHTML).toHaveBeenCalledWith(expect.any(Object), expect.objectContaining({
84
+ ...flexDocOptions,
85
+ rendererBasePath: '/docs/__flexdoc',
86
+ }));
87
+ });
88
+ });
89
+ //# sourceMappingURL=setup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.test.js","sourceRoot":"","sources":["../src/setup.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { FlexDocOptions } from './interfaces';
2
+ interface OpenAPISpec {
3
+ info?: {
4
+ title?: string;
5
+ description?: string;
6
+ version?: string;
7
+ };
8
+ [key: string]: unknown;
9
+ }
10
+ interface RenderOptions extends FlexDocOptions {
11
+ specUrl?: string;
12
+ rendererBasePath?: string;
13
+ }
14
+ export declare function generateFlexDocHTML(spec: OpenAPISpec | null, options?: RenderOptions): string;
15
+ export {};
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateFlexDocHTML = generateFlexDocHTML;
4
+ function escapeHtml(value) {
5
+ return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
6
+ }
7
+ function serializeForScript(value) {
8
+ return JSON.stringify(value).replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/&/g, '\\u0026').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
9
+ }
10
+ function generateFlexDocHTML(spec, options = {}) {
11
+ const { title, description, version, customCss = '', customJs = '', favicon = '', specUrl, rendererBasePath = './__flexdoc', auth: _serverOnlyAuth, ...rendererOptions } = options;
12
+ const documentTitle = title || spec?.info?.title || 'API Documentation';
13
+ const publicOptions = {
14
+ contractVersion: '1',
15
+ ...rendererOptions,
16
+ ...(title ? { title } : {}),
17
+ ...(description ? { description } : {}),
18
+ ...(version ? { version } : {}),
19
+ };
20
+ return `<!DOCTYPE html>
21
+ <html lang="en">
22
+ <head>
23
+ <meta charset="UTF-8" />
24
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
25
+ <meta name="color-scheme" content="light dark" />
26
+ <title>${escapeHtml(documentTitle)}</title>
27
+ ${favicon ? `<link rel="icon" href="${escapeHtml(favicon)}" />` : ''}
28
+ <link rel="stylesheet" href="${escapeHtml(rendererBasePath)}/renderer.css" />
29
+ ${customCss ? `<style>${customCss}</style>` : ''}
30
+ </head>
31
+ <body>
32
+ <div id="flexdoc-root"></div>
33
+ <script>
34
+ window.__FLEXDOC_SPEC__ = ${serializeForScript(spec)};
35
+ window.__FLEXDOC_SPEC_URL__ = ${serializeForScript(specUrl || null)};
36
+ window.__FLEXDOC_OPTIONS__ = ${serializeForScript(publicOptions)};
37
+ </script>
38
+ <script src="${escapeHtml(rendererBasePath)}/renderer.js"></script>
39
+ <script>
40
+ (async function bootstrapFlexDoc() {
41
+ const root = document.getElementById('flexdoc-root');
42
+ try {
43
+ let spec = window.__FLEXDOC_SPEC__;
44
+ if (!spec && window.__FLEXDOC_SPEC_URL__) {
45
+ const response = await fetch(window.__FLEXDOC_SPEC_URL__);
46
+ if (!response.ok) throw new Error('Unable to load OpenAPI specification: HTTP ' + response.status);
47
+ spec = await response.json();
48
+ }
49
+ if (!spec) throw new Error('No OpenAPI specification was provided');
50
+ if (!window.FlexDocStandalone?.mount) throw new Error('FlexDoc renderer failed to load');
51
+ const config = { spec, options: window.__FLEXDOC_OPTIONS__ || {}, baseUri: window.__FLEXDOC_SPEC_URL__ || undefined };
52
+ if (window.FlexDocStandalone.mountAsync && config.baseUri) await window.FlexDocStandalone.mountAsync(root, config);
53
+ else window.FlexDocStandalone.mount(root, config);
54
+ } catch (error) {
55
+ root.innerHTML = '<pre style="padding:24px;color:#b91c1c;white-space:pre-wrap"></pre>';
56
+ root.firstChild.textContent = error instanceof Error ? error.message : String(error);
57
+ }
58
+ })();
59
+ </script>
60
+ ${customJs ? `<script>${customJs}</script>` : ''}
61
+ </body>
62
+ </html>`;
63
+ }
64
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":";;AAkBA,kDAkEC;AA3ED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAClI,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACtK,CAAC;AAGD,SAAgB,mBAAmB,CAAC,IAAwB,EAAE,UAAyB,EAAE;IACvF,MAAM,EACJ,KAAK,EACL,WAAW,EACX,OAAO,EACP,SAAS,GAAG,EAAE,EACd,QAAQ,GAAG,EAAE,EACb,OAAO,GAAG,EAAE,EACZ,OAAO,EACP,gBAAgB,GAAG,aAAa,EAChC,IAAI,EAAE,eAAe,EACrB,GAAG,eAAe,EACnB,GAAG,OAAO,CAAC;IAEZ,MAAM,aAAa,GAAG,KAAK,IAAI,IAAI,EAAE,IAAI,EAAE,KAAK,IAAI,mBAAmB,CAAC;IACxE,MAAM,aAAa,GAAG;QACpB,eAAe,EAAE,GAAG;QACpB,GAAG,eAAe;QAClB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChC,CAAC;IAEF,OAAO;;;;;;WAME,UAAU,CAAC,aAAa,CAAC;IAChC,OAAO,CAAC,CAAC,CAAC,0BAA0B,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;iCACrC,UAAU,CAAC,gBAAgB,CAAC;IACzD,SAAS,CAAC,CAAC,CAAC,UAAU,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE;;;;;gCAKlB,kBAAkB,CAAC,IAAI,CAAC;oCACpB,kBAAkB,CAAC,OAAO,IAAI,IAAI,CAAC;mCACpC,kBAAkB,CAAC,aAAa,CAAC;;iBAEnD,UAAU,CAAC,gBAAgB,CAAC;;;;;;;;;;;;;;;;;;;;;;IAsBzC,QAAQ,CAAC,CAAC,CAAC,WAAW,QAAQ,WAAW,CAAC,CAAC,CAAC,EAAE;;QAE1C,CAAC;AACT,CAAC"}
@@ -0,0 +1 @@
1
+ export {};