@tremho/mist-lift 1.1.4-pre-release.1 → 1.1.5

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 (59) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +70 -66
  3. package/build/QSTest/functions/IntegrationTest/src/main.js +1 -1
  4. package/build/src/commands/builtin/ApiDocMaker.js +0 -1
  5. package/build/src/commands/builtin/ApiDocMaker.js.map +1 -1
  6. package/build/src/commands/doctor.js +12 -1
  7. package/build/src/commands/doctor.js.map +1 -1
  8. package/build/src/lib/LiftVersion.js +1 -1
  9. package/build/src/lib/LiftVersion.js.map +1 -1
  10. package/package.json +79 -79
  11. package/src/commands/actions/initQuestions.ts +133 -133
  12. package/src/commands/actions/setupPackageJson.ts +32 -32
  13. package/src/commands/build.ts +173 -173
  14. package/src/commands/builtin/ApiDocMaker.ts +105 -106
  15. package/src/commands/builtin/BuiltInHandler.ts +47 -47
  16. package/src/commands/builtin/DeployBuiltInZip.ts +25 -25
  17. package/src/commands/builtin/StageWebrootZip.ts +36 -36
  18. package/src/commands/create.ts +52 -52
  19. package/src/commands/deploy.ts +161 -161
  20. package/src/commands/doctor.ts +118 -107
  21. package/src/commands/help.ts +178 -178
  22. package/src/commands/info.ts +42 -42
  23. package/src/commands/init.ts +61 -61
  24. package/src/commands/package.ts +234 -234
  25. package/src/commands/publish.ts +330 -330
  26. package/src/commands/settings.ts +73 -73
  27. package/src/commands/start.ts +43 -43
  28. package/src/commands/test.ts +37 -37
  29. package/src/commands/user.ts +20 -20
  30. package/src/expressRoutes/all.ts +99 -99
  31. package/src/expressRoutes/api.ts +22 -22
  32. package/src/expressRoutes/functionBinder.ts +155 -155
  33. package/src/integration-tests/quickstart-scenario.test.ts +76 -76
  34. package/src/lib/CaseUtils.ts +63 -63
  35. package/src/lib/DirectoryUtils.ts +34 -34
  36. package/src/lib/LiftConfig.ts +74 -74
  37. package/src/lib/LiftVersion.ts +87 -87
  38. package/src/lib/Tests/fileCompare.test.ts +35 -35
  39. package/src/lib/askQuestion.ts +17 -17
  40. package/src/lib/executeCommand.ts +45 -45
  41. package/src/lib/fileCompare.ts +55 -55
  42. package/src/lib/openAPI/ApiBuildCollector.ts +47 -47
  43. package/src/lib/openAPI/WebrootFileSupport.ts +19 -19
  44. package/src/lib/openAPI/openApiConstruction.ts +196 -196
  45. package/src/lib/pathResolve.ts +26 -26
  46. package/src/lib/utils.ts +43 -43
  47. package/src/lift.ts +87 -87
  48. package/templateData/function-definition-template +20 -20
  49. package/templateData/function-local-ts +16 -16
  50. package/templateData/function-main-ts +16 -16
  51. package/templateData/function-runmain-mjs +6 -6
  52. package/templateData/function-test-template +11 -11
  53. package/templateData/swagger-ui-bundle.js +2 -2
  54. package/templateData/swagger-ui-standalone-preset.js +2 -2
  55. package/templateData/swagger-ui.css +2 -2
  56. package/tsconfig.json +28 -28
  57. package/build/commands/builtin/prebuilt-zips/API.zip +0 -0
  58. package/build/commands/builtin/prebuilt-zips/FileServe.zip +0 -0
  59. package/build/commands/builtin/prebuilt-zips/Webroot.zip +0 -0
@@ -1,73 +1,73 @@
1
- import path from 'path'
2
- import fs from 'fs'
3
- import { LiftConfig, RuntimeType } from '../lib/LiftConfig'
4
- import { homedir } from 'os'
5
- import { ask } from '../lib/askQuestion'
6
- import * as ac from 'ansi-colors'
7
-
8
- export async function doSettings (): Promise<number> {
9
- try {
10
- const mistLiftPath = path.join(homedir(), '.mistlift')
11
- let settings: LiftConfig = { cloudHost: 'AWS' }
12
- if (fs.existsSync(mistLiftPath)) {
13
- settings = JSON.parse(fs.readFileSync(mistLiftPath).toString())
14
- }
15
-
16
- let ok = false
17
- while (!ok) {
18
- settings.cloudHost = ask('Type of cloud host (AWS)',
19
- 'cloud host',
20
- settings.cloudHost
21
- )
22
- ok = settings.cloudHost === 'AWS' // all we support now
23
- }
24
- ok = false
25
-
26
- if (settings.cloudHost === 'AWS') {
27
- ok = false
28
- console.log('Choose from a configured AWS profile, or leave empty to use a custom credentials config file')
29
- while (!ok) {
30
- settings.awsIniProfile = ask('Name of AWS profile to use',
31
- 'AWS Profile',
32
- settings.awsIniProfile ?? 'default'
33
- )
34
- ok = settings.awsIniProfile !== ''
35
- }
36
- ok = false
37
- let runtime: string = settings.awsNodeRuntime as string
38
- while (!ok) {
39
- runtime = ask('AWS Node Runtime Version',
40
- 'NodeJS Runtime',
41
- 'Nodejs20.x'
42
- )
43
- ok = runtime !== ''
44
- }
45
- settings.awsNodeRuntime = runtime.toLowerCase() as RuntimeType
46
-
47
- ok = false
48
- while (!ok) {
49
- settings.awsPreferredRegion = ask('Preferred AWS region',
50
- 'preferred AWS region',
51
- settings.awsPreferredRegion ?? 'us-east-1'
52
- )
53
- ok = (settings.awsPreferredRegion ?? '') !== ''
54
- }
55
- ok = false
56
- console.log('Supply the ARN for the service role you have created in your AWS IAM account for Lambda and Cloudwatch access')
57
- while (!ok) {
58
- settings.awsServiceRoleARN = ask('AWS service role ARN',
59
- 'serviceRole ARN',
60
- settings.awsServiceRoleARN ?? 'arn:aws.iam::xxxxxxxxxxxx:role/service-role-name'
61
- )
62
- ok = settings.awsServiceRoleARN !== 'arn:aws.iam::xxxxxxxxxxxx:role/service-role-name' &&
63
- settings.awsServiceRoleARN !== ''
64
- }
65
- }
66
- fs.writeFileSync(mistLiftPath, JSON.stringify(settings))
67
-
68
- return 0
69
- } catch (e: any) {
70
- console.error(ac.bold.red('Error with settings:'), e)
71
- return -1
72
- }
73
- }
1
+ import path from 'path'
2
+ import fs from 'fs'
3
+ import { LiftConfig, RuntimeType } from '../lib/LiftConfig'
4
+ import { homedir } from 'os'
5
+ import { ask } from '../lib/askQuestion'
6
+ import * as ac from 'ansi-colors'
7
+
8
+ export async function doSettings (): Promise<number> {
9
+ try {
10
+ const mistLiftPath = path.join(homedir(), '.mistlift')
11
+ let settings: LiftConfig = { cloudHost: 'AWS' }
12
+ if (fs.existsSync(mistLiftPath)) {
13
+ settings = JSON.parse(fs.readFileSync(mistLiftPath).toString())
14
+ }
15
+
16
+ let ok = false
17
+ while (!ok) {
18
+ settings.cloudHost = ask('Type of cloud host (AWS)',
19
+ 'cloud host',
20
+ settings.cloudHost
21
+ )
22
+ ok = settings.cloudHost === 'AWS' // all we support now
23
+ }
24
+ ok = false
25
+
26
+ if (settings.cloudHost === 'AWS') {
27
+ ok = false
28
+ console.log('Choose from a configured AWS profile, or leave empty to use a custom credentials config file')
29
+ while (!ok) {
30
+ settings.awsIniProfile = ask('Name of AWS profile to use',
31
+ 'AWS Profile',
32
+ settings.awsIniProfile ?? 'default'
33
+ )
34
+ ok = settings.awsIniProfile !== ''
35
+ }
36
+ ok = false
37
+ let runtime: string = settings.awsNodeRuntime as string
38
+ while (!ok) {
39
+ runtime = ask('AWS Node Runtime Version',
40
+ 'NodeJS Runtime',
41
+ 'Nodejs20.x'
42
+ )
43
+ ok = runtime !== ''
44
+ }
45
+ settings.awsNodeRuntime = runtime.toLowerCase() as RuntimeType
46
+
47
+ ok = false
48
+ while (!ok) {
49
+ settings.awsPreferredRegion = ask('Preferred AWS region',
50
+ 'preferred AWS region',
51
+ settings.awsPreferredRegion ?? 'us-east-1'
52
+ )
53
+ ok = (settings.awsPreferredRegion ?? '') !== ''
54
+ }
55
+ ok = false
56
+ console.log('Supply the ARN for the service role you have created in your AWS IAM account for Lambda and Cloudwatch access')
57
+ while (!ok) {
58
+ settings.awsServiceRoleARN = ask('AWS service role ARN',
59
+ 'serviceRole ARN',
60
+ settings.awsServiceRoleARN ?? 'arn:aws.iam::xxxxxxxxxxxx:role/service-role-name'
61
+ )
62
+ ok = settings.awsServiceRoleARN !== 'arn:aws.iam::xxxxxxxxxxxx:role/service-role-name' &&
63
+ settings.awsServiceRoleARN !== ''
64
+ }
65
+ }
66
+ fs.writeFileSync(mistLiftPath, JSON.stringify(settings))
67
+
68
+ return 0
69
+ } catch (e: any) {
70
+ console.error(ac.bold.red('Error with settings:'), e)
71
+ return -1
72
+ }
73
+ }
@@ -1,43 +1,43 @@
1
- /** Run Express Server */
2
- import express from 'express'
3
-
4
- import functionRouter, { functionBinder } from '../expressRoutes/functionBinder'
5
-
6
- import apiRouter from '../expressRoutes/api'
7
- import allRouter, { allBinder } from '../expressRoutes/all'
8
- import { resolvePaths } from '../lib/pathResolve'
9
- import { doBuildAsync } from './build'
10
-
11
- import * as ac from 'ansi-colors'
12
-
13
- export async function startLocalServer (): Promise<void> {
14
- const projectPaths = resolvePaths()
15
- if (!projectPaths.verified) {
16
- console.log(ac.bold.red('Cannot start local server'))
17
- console.log(ac.blue.italic('Not in a valid MistLift project directory'))
18
- console.log('')
19
- return
20
- }
21
- await doBuildAsync([])
22
- const port = 8081
23
- allBinder()
24
- functionBinder()
25
- const app = express()
26
- // for JSON posts
27
- // app.use(bodyParser.json({limit: '50mb'}))
28
- app.use(express.json())
29
- // for form posts
30
- app.use(express.urlencoded({ extended: true }))
31
-
32
- app.use('/', functionRouter)
33
- app.use('/api', apiRouter)
34
- app.use('*', allRouter)
35
-
36
- // =========================================
37
- // Start server
38
- // http only
39
- app.listen(port, function () {
40
- console.log(`http listening on port ${port}`)
41
- })
42
- // ================================================
43
- }
1
+ /** Run Express Server */
2
+ import express from 'express'
3
+
4
+ import functionRouter, { functionBinder } from '../expressRoutes/functionBinder'
5
+
6
+ import apiRouter from '../expressRoutes/api'
7
+ import allRouter, { allBinder } from '../expressRoutes/all'
8
+ import { resolvePaths } from '../lib/pathResolve'
9
+ import { doBuildAsync } from './build'
10
+
11
+ import * as ac from 'ansi-colors'
12
+
13
+ export async function startLocalServer (): Promise<void> {
14
+ const projectPaths = resolvePaths()
15
+ if (!projectPaths.verified) {
16
+ console.log(ac.bold.red('Cannot start local server'))
17
+ console.log(ac.blue.italic('Not in a valid MistLift project directory'))
18
+ console.log('')
19
+ return
20
+ }
21
+ await doBuildAsync([])
22
+ const port = 8081
23
+ allBinder()
24
+ functionBinder()
25
+ const app = express()
26
+ // for JSON posts
27
+ // app.use(bodyParser.json({limit: '50mb'}))
28
+ app.use(express.json())
29
+ // for form posts
30
+ app.use(express.urlencoded({ extended: true }))
31
+
32
+ app.use('/', functionRouter)
33
+ app.use('/api', apiRouter)
34
+ app.use('*', allRouter)
35
+
36
+ // =========================================
37
+ // Start server
38
+ // http only
39
+ app.listen(port, function () {
40
+ console.log(`http listening on port ${port}`)
41
+ })
42
+ // ================================================
43
+ }
@@ -1,37 +1,37 @@
1
- import { executeCommand } from '../lib/executeCommand'
2
- import { doBuildAsync } from './build'
3
-
4
- export async function doTestAsync (args: string[]): Promise<number> {
5
- if (await doBuildAsync(args) !== 0) return 1 // don't test if build fails
6
- if (args.length === 0) args = ['*']
7
- let ret = 0
8
- for (const funcName of args) {
9
- const result = await executeCommand('tap', [
10
- `build/functions/${funcName}/*-tests/*.js`,
11
- /*
12
- - base -- looks a lot like terse
13
- - terse -- pass/fail counts
14
- - min -- errors only
15
- - dot -- like min, but a dot per assert
16
- - silent
17
- - json
18
- - jsonstream
19
- - markdown
20
- - junit
21
- - tap
22
- */
23
- '--reporter=base',
24
- '--color',
25
- '--passes',
26
- '--allow-empty-coverage',
27
- '--allow-incomplete-coverage'
28
-
29
- ], '', true)
30
-
31
- if (result.retcode !== 0) {
32
- ret = result.retcode
33
- break
34
- }
35
- }
36
- return ret
37
- }
1
+ import { executeCommand } from '../lib/executeCommand'
2
+ import { doBuildAsync } from './build'
3
+
4
+ export async function doTestAsync (args: string[]): Promise<number> {
5
+ if (await doBuildAsync(args) !== 0) return 1 // don't test if build fails
6
+ if (args.length === 0) args = ['*']
7
+ let ret = 0
8
+ for (const funcName of args) {
9
+ const result = await executeCommand('tap', [
10
+ `build/functions/${funcName}/*-tests/*.js`,
11
+ /*
12
+ - base -- looks a lot like terse
13
+ - terse -- pass/fail counts
14
+ - min -- errors only
15
+ - dot -- like min, but a dot per assert
16
+ - silent
17
+ - json
18
+ - jsonstream
19
+ - markdown
20
+ - junit
21
+ - tap
22
+ */
23
+ '--reporter=base',
24
+ '--color',
25
+ '--passes',
26
+ '--allow-empty-coverage',
27
+ '--allow-incomplete-coverage'
28
+
29
+ ], '', true)
30
+
31
+ if (result.retcode !== 0) {
32
+ ret = result.retcode
33
+ break
34
+ }
35
+ }
36
+ return ret
37
+ }
@@ -1,20 +1,20 @@
1
- /** Handles the set of user management commands
2
- *
3
- * Default and prime user is the default of the AWS profile set
4
- * In configuration, this can be changed to a different profile
5
- * The user command module is meant to
6
- */
7
-
8
- // TODO:
9
-
10
- /*
11
- - lift user create <name>
12
- - lift user destroy <name>
13
- - lift user grant <name> <privilege>
14
- - lift user revoke <name> <privilege>
15
- - lift user show <name>
16
- - lift user list
17
-
18
- */
19
- // }
20
- // }
1
+ /** Handles the set of user management commands
2
+ *
3
+ * Default and prime user is the default of the AWS profile set
4
+ * In configuration, this can be changed to a different profile
5
+ * The user command module is meant to
6
+ */
7
+
8
+ // TODO:
9
+
10
+ /*
11
+ - lift user create <name>
12
+ - lift user destroy <name>
13
+ - lift user grant <name> <privilege>
14
+ - lift user revoke <name> <privilege>
15
+ - lift user show <name>
16
+ - lift user list
17
+
18
+ */
19
+ // }
20
+ // }
@@ -1,99 +1,99 @@
1
- import path from 'path'
2
- import fs from 'fs'
3
-
4
- import * as ac from 'ansi-colors'
5
- import { resolvePaths } from '../lib/pathResolve'
6
- import { gatherFunctionDefinitions } from '../lib/openAPI/ApiBuildCollector'
7
-
8
- import express from 'express'
9
- const router = express.Router()
10
-
11
- export function allBinder (): void {
12
- const projectPaths = resolvePaths()
13
- const defs = gatherFunctionDefinitions()
14
-
15
- /**
16
- * @name /all
17
- * @description
18
- * Catch-all handler for URLs
19
- * Provides some simple spam blocking and checks for file pass through at file root.
20
- *
21
- * ##### Filtering:
22
- * - all .php extension references
23
- *
24
- * ##### File root:
25
- * - file root is at service root + 'Public'
26
- * - no path or path ending in / is appended with '/index.html' for folder root default behavior
27
- * - File contents passed through using `sendFile` (will handle its own 404 if not found)
28
- *
29
- */
30
- router.all('*', (req, res, next) => {
31
- // any PHP requests should be ignored
32
- // ClogTrace('incoming: '+req.originalUrl)
33
- if (req.originalUrl.includes('.php')) {
34
- return res.send('')
35
- }
36
- if (req.originalUrl.includes('.env')) {
37
- return res.send('')
38
- }
39
-
40
- let filepath = req.originalUrl ?? '/'
41
- // match cloud behavior for docs because /api doesn't change cwd there
42
- if (filepath.substring(0, 10) === '/api/docs/') {
43
- filepath = filepath.replace('/api', '')
44
- }
45
- let funcFound = filepath === '/api' // reserved "function"
46
- if (!funcFound) {
47
- if (filepath.charAt(0) === '/') {
48
- let n = filepath.indexOf('/', 1)
49
- if (n === -1) n = filepath.length
50
- let rootEntity = filepath.substring(0, n)
51
- n = rootEntity.indexOf('?')
52
- if (n === -1) n = rootEntity.length
53
- rootEntity = rootEntity.substring(0, n)
54
- for (const entry of defs) {
55
- let entryRoot = entry.pathMap
56
- const n = entryRoot.indexOf('/{')
57
- if (n !== -1) entryRoot = entryRoot.substring(0, n)
58
- if (rootEntity === entryRoot) {
59
- funcFound = true
60
- break
61
- }
62
- }
63
- }
64
- }
65
-
66
- if (!funcFound) {
67
- // check for '/' in path beyond the first one
68
- if (filepath.includes('/', 1)) {
69
- // console.log(ac.magenta.italic("Warning: / path delimiters will not be honored in a cloud deployment, use + instead ")+filepath)
70
- }
71
- // convert any incoming + to / to match cloud behavior
72
- while (filepath.includes('+')) filepath = filepath.replace('+', '/')
73
-
74
- // Put any other filtering here
75
- if (filepath.includes('?')) {
76
- filepath = filepath.substring(0, filepath.indexOf('?'))
77
- }
78
- if (filepath.substring(filepath.length - 1) === '/') filepath += 'index.html'
79
- if (filepath.substring(0, 10) === '/api/docs/') {
80
- filepath = filepath.replace('/api', '')
81
- }
82
- if (filepath.includes('/docs')) {
83
- if (filepath.includes('.map')) {
84
- return res.sendStatus(200)
85
- }
86
- }
87
- filepath = path.resolve(path.join(projectPaths.basePath, 'webroot', filepath)) // .. out of build
88
- if (fs.existsSync(filepath)) {
89
- return res.sendFile(filepath)
90
- } else {
91
- console.log(ac.red.bold("can't find " + filepath))
92
- return res.sendStatus(404)
93
- }
94
- }
95
- // if none of the above, tickle enumerator so we can process other paths
96
- next()
97
- })
98
- }
99
- export default router
1
+ import path from 'path'
2
+ import fs from 'fs'
3
+
4
+ import * as ac from 'ansi-colors'
5
+ import { resolvePaths } from '../lib/pathResolve'
6
+ import { gatherFunctionDefinitions } from '../lib/openAPI/ApiBuildCollector'
7
+
8
+ import express from 'express'
9
+ const router = express.Router()
10
+
11
+ export function allBinder (): void {
12
+ const projectPaths = resolvePaths()
13
+ const defs = gatherFunctionDefinitions()
14
+
15
+ /**
16
+ * @name /all
17
+ * @description
18
+ * Catch-all handler for URLs
19
+ * Provides some simple spam blocking and checks for file pass through at file root.
20
+ *
21
+ * ##### Filtering:
22
+ * - all .php extension references
23
+ *
24
+ * ##### File root:
25
+ * - file root is at service root + 'Public'
26
+ * - no path or path ending in / is appended with '/index.html' for folder root default behavior
27
+ * - File contents passed through using `sendFile` (will handle its own 404 if not found)
28
+ *
29
+ */
30
+ router.all('*', (req, res, next) => {
31
+ // any PHP requests should be ignored
32
+ // ClogTrace('incoming: '+req.originalUrl)
33
+ if (req.originalUrl.includes('.php')) {
34
+ return res.send('')
35
+ }
36
+ if (req.originalUrl.includes('.env')) {
37
+ return res.send('')
38
+ }
39
+
40
+ let filepath = req.originalUrl ?? '/'
41
+ // match cloud behavior for docs because /api doesn't change cwd there
42
+ if (filepath.substring(0, 10) === '/api/docs/') {
43
+ filepath = filepath.replace('/api', '')
44
+ }
45
+ let funcFound = filepath === '/api' // reserved "function"
46
+ if (!funcFound) {
47
+ if (filepath.charAt(0) === '/') {
48
+ let n = filepath.indexOf('/', 1)
49
+ if (n === -1) n = filepath.length
50
+ let rootEntity = filepath.substring(0, n)
51
+ n = rootEntity.indexOf('?')
52
+ if (n === -1) n = rootEntity.length
53
+ rootEntity = rootEntity.substring(0, n)
54
+ for (const entry of defs) {
55
+ let entryRoot = entry.pathMap
56
+ const n = entryRoot.indexOf('/{')
57
+ if (n !== -1) entryRoot = entryRoot.substring(0, n)
58
+ if (rootEntity === entryRoot) {
59
+ funcFound = true
60
+ break
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ if (!funcFound) {
67
+ // check for '/' in path beyond the first one
68
+ if (filepath.includes('/', 1)) {
69
+ // console.log(ac.magenta.italic("Warning: / path delimiters will not be honored in a cloud deployment, use + instead ")+filepath)
70
+ }
71
+ // convert any incoming + to / to match cloud behavior
72
+ while (filepath.includes('+')) filepath = filepath.replace('+', '/')
73
+
74
+ // Put any other filtering here
75
+ if (filepath.includes('?')) {
76
+ filepath = filepath.substring(0, filepath.indexOf('?'))
77
+ }
78
+ if (filepath.substring(filepath.length - 1) === '/') filepath += 'index.html'
79
+ if (filepath.substring(0, 10) === '/api/docs/') {
80
+ filepath = filepath.replace('/api', '')
81
+ }
82
+ if (filepath.includes('/docs')) {
83
+ if (filepath.includes('.map')) {
84
+ return res.sendStatus(200)
85
+ }
86
+ }
87
+ filepath = path.resolve(path.join(projectPaths.basePath, 'webroot', filepath)) // .. out of build
88
+ if (fs.existsSync(filepath)) {
89
+ return res.sendFile(filepath)
90
+ } else {
91
+ console.log(ac.red.bold("can't find " + filepath))
92
+ return res.sendStatus(404)
93
+ }
94
+ }
95
+ // if none of the above, tickle enumerator so we can process other paths
96
+ next()
97
+ })
98
+ }
99
+ export default router
@@ -1,22 +1,22 @@
1
- /* eslint @typescript-eslint/no-var-requires: "off" */
2
- import express from 'express'
3
-
4
- import { getProjectName, getProjectVersion } from '../lib/LiftVersion'
5
-
6
- const openApiUi = require('openapi-ui')
7
- const router = express.Router()
8
-
9
- router.get('/', function (req, res, next) {
10
- res.send(generateApiDoc())
11
- })
12
-
13
- export default router
14
-
15
- function generateApiDoc (): void {
16
- console.log('---- Serving up api')
17
- return openApiUi.generateIndex({
18
- baseUrl: 'docs',
19
- title: `${getProjectName() ?? ''} ${getProjectVersion()?.toString() ?? ''}`,
20
- url: 'docs/apidoc.yaml'
21
- })
22
- }
1
+ /* eslint @typescript-eslint/no-var-requires: "off" */
2
+ import express from 'express'
3
+
4
+ import { getProjectName, getProjectVersion } from '../lib/LiftVersion'
5
+
6
+ const openApiUi = require('openapi-ui')
7
+ const router = express.Router()
8
+
9
+ router.get('/', function (req, res, next) {
10
+ res.send(generateApiDoc())
11
+ })
12
+
13
+ export default router
14
+
15
+ function generateApiDoc (): void {
16
+ console.log('---- Serving up api')
17
+ return openApiUi.generateIndex({
18
+ baseUrl: 'docs',
19
+ title: `${getProjectName() ?? ''} ${getProjectVersion()?.toString() ?? ''}`,
20
+ url: 'docs/apidoc.yaml'
21
+ })
22
+ }