Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
dade010
refactor: introducing swagger
meenahoda Nov 4, 2021
7259828
feat: add swagger details about statebox-api
meenahoda Nov 4, 2021
2de2962
feat: file downloading swagger schema
meenahoda Nov 4, 2021
118760d
Merge remote-tracking branch 'origin/master' into swagger
meenahoda Nov 5, 2021
5706568
feat: add tags to swagger docs
meenahoda Nov 5, 2021
61746a1
refactor: route schemas
meenahoda Nov 5, 2021
ffcf2a8
feat: extract common schema out and authorize
meenahoda Nov 5, 2021
bc46d97
Merge remote-tracking branch 'origin/master' into swagger
meenahoda Nov 11, 2021
c260b15
feat: extend start execution schema and comment out some swagger options
meenahoda Nov 11, 2021
5587c9d
feat: integrate swagger with helmet
meenahoda Nov 11, 2021
05bb0e4
fix: try staticCSP as well
meenahoda Nov 11, 2021
e6fbfc1
fix: uncomment schemes
meenahoda Nov 11, 2021
f701a8a
fix: standard style and revert some changes to swagger config
meenahoda Nov 11, 2021
4a88811
fix: swagger api can be called on listen
meenahoda Nov 11, 2021
a7c6425
fix: try adding port
meenahoda Nov 11, 2021
b4b1c01
fix: remove host
meenahoda Nov 11, 2021
e0fcba4
fix: force http scheme for dev
meenahoda Nov 11, 2021
e7d3213
fix: remove schemes
meenahoda Nov 11, 2021
c27969a
Merge remote-tracking branch 'origin/master' into swagger
meenahoda Nov 15, 2021
67804d8
fix: disable swagger ui validator
meenahoda Nov 15, 2021
61975fe
fix(swagger): disable `try it out`
meenahoda Nov 15, 2021
38e494d
fix(swagger): disable security definitions, as `try it out` is disabled
meenahoda Nov 15, 2021
772df90
style: standard fix
meenahoda Nov 15, 2021
5922a83
feat: merge from master
reecebrend Feb 25, 2026
1fb3e49
fix: remove ref to redundant debug
reecebrend Feb 25, 2026
d82cb3d
feat: update refactored fastify imports
reecebrend Feb 25, 2026
80188fc
fix: update fastify swagger
reecebrend Feb 25, 2026
db84176
fix: update swagger/fastify
reecebrend Feb 25, 2026
9e313c9
feat: update all swagger parts to new impl ensure tests pass
reecebrend Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion lib/components/services/file-downloading/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,21 @@ class FileDownloadingService {

const { app } = server
const router = async app => {
app.get('/:downloadKey', (request, reply) => this.serveFile(request, reply))
const opts = {
schema: {
description: 'Download a file',
params: {
type: 'object',
properties: {
downloadKey: {
type: 'string',
description: 'Download key'
}
}
}
}
}
app.get('/:downloadKey', opts, (request, reply) => this.serveFile(request, reply))
}

app.register(router, { prefix: downloadPrefix })
Expand Down
7 changes: 6 additions & 1 deletion lib/components/services/file-uploading/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ class FileUploadingService {
)

const router = async app => {
const opts = { preValidation: [app.jwtCheck] }
const opts = {
preValidation: [app.jwtCheck],
schema: {
description: 'Upload a file'
}
}

app.post('/', opts, (request, reply) => this.upload(request, reply))
}
Expand Down
43 changes: 39 additions & 4 deletions lib/components/services/server/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const fastify = require('fastify')
const helmet = require('@fastify/helmet')
const cors = require('@fastify/cors')
const swagger = require('@fastify/swagger')
const swaggerUi = require('@fastify/swagger-ui')
const swaggerOpts = require('./swagger')
const helmet = require('@fastify/helmet')

const addStaticDir = require('./add-static-dir')

Expand All @@ -19,8 +22,31 @@ class FastifyServerService {
loggerInstance: this.logger
})

app.register(helmet, {
crossOriginResourcePolicy: { policy: 'cross-origin' }
app.register(swagger, swaggerOpts)
app.register(swaggerUi, {
routePrefix: '/documentation',
uiConfig: {
validatorUrl: null,
supportedSubmitMethods: []
}
})
app.after(() => {
app.register(helmet, instance => {
return {
contentSecurityPolicy: {
directives: {
...helmet.contentSecurityPolicy.getDefaultDirectives(),
'form-action': ['\'self\''],
'img-src': ['\'self\'', 'data:', 'validator.swagger.io'],
'script-src': ['\'self\''].concat(instance.swaggerCSP.script),
'style-src': ['\'self\'', 'https:'].concat(
instance.swaggerCSP.style
)
}
},
crossOriginResourcePolicy: { policy: 'cross-origin' }
}
})
})

app.addContentTypeParser(
Expand Down Expand Up @@ -75,7 +101,16 @@ class FastifyServerService {
)
*/
listen (port, host, callback) {
this.app.listen({ port, host }, callback)
return new Promise((resolve, reject) => {
this.app.listen({ port, host }, (err) => {
if (err) {
if (callback) callback(err)
return reject(err)
}
if (callback) callback(null)
resolve()
})
})
}

/**
Expand Down
33 changes: 33 additions & 0 deletions lib/components/services/server/swagger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module.exports = {
swagger: {
info: {
title: 'Tymly API',
description: 'Provides a CORS-enabled Fastify server'
},
// host: '0.0.0.0',
// schemes: ['http', 'https'],
// schemes: ['http'],
consumes: ['application/json'],
produces: ['application/json']
// securityDefinitions: {
// Bearer: {
// type: 'apiKey',
// name: 'Authorization',
// in: 'header'
// }
// },
// security: [
// {
// Bearer: []
// }
// ]
// security: [{ bearerAuth: [] }],
// securityDefinitions: {
// bearerAuth: {
// type: "http",
// scheme: "bearer",
// bearerFormat: "JWT"
// }
// }
}
}
8 changes: 4 additions & 4 deletions lib/components/services/statebox-api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ class StateboxApiService {
const router = async app => {
const opts = { preValidation: [app.jwtCheck] }

app.post('/', opts, routes.startExecution)
app.get('/:executionName', opts, routes.describeExecution)
app.put('/:executionName', opts, routes.executionAction)
app.delete('/:executionName', opts, routes.stopExecution)
app.post('/', { ...opts, schema: routes.startExecution.schema }, routes.startExecution)
app.get('/:executionName', { ...opts, schema: routes.describeExecution.schema }, routes.describeExecution)
app.put('/:executionName', { ...opts, schema: routes.executionAction.schema }, routes.executionAction)
app.delete('/:executionName', { ...opts, schema: routes.stopExecution.schema }, routes.stopExecution)
}

app.register(router, { prefix: '/executions' })
Expand Down
10 changes: 10 additions & 0 deletions lib/components/services/statebox-api/routes/common-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const schema = {
tags: ['executions']
// security: [
// {
// Bearer: []
// }
// ]
}

module.exports = schema
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
const respond = require('../../../../util/respond')
const schema = {
...require('./common-schema'),
description: 'Describe an existing Statebox execution',
params: {
type: 'object',
properties: {
executionName: {
type: 'string',
description: 'Execution name'
}
}
}
}

module.exports = function describeExecution (request, reply) {
function describeExecution (request, reply) {
const jwtAuthService = this.services.jwtAuth
const statebox = this.services.statebox

Expand Down Expand Up @@ -31,3 +44,6 @@ module.exports = function describeExecution (request, reply) {
}
)
}

module.exports = describeExecution
module.exports.schema = schema
33 changes: 32 additions & 1 deletion lib/components/services/statebox-api/routes/execution-action.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,36 @@
const { cloneDeep } = require('lodash')
const boom = require('@hapi/boom')
const actions = require('../actions/index')
const schema = {
...require('./common-schema'),
description: 'Perform an action on an existing Statebox execution',
params: {
type: 'object',
properties: {
executionName: {
type: 'string',
description: 'Execution name'
}
}
},
body: {
type: 'object',
properties: {
action: {
type: 'string',
description: 'Action to perform on Statebox execution',
enum: [
'SendTaskSuccess',
'SendTaskHeartbeat',
'SendTaskRevivification',
'WaitUntilStoppedRunning'
]
}
}
}
}

module.exports = function (request, reply) {
function executionAction (request, reply) {
const jwtAuthService = this.services.jwtAuth
const statebox = this.services.statebox

Expand All @@ -28,3 +56,6 @@ module.exports = function (request, reply) {
)
}
}

module.exports = executionAction
module.exports.schema = schema
43 changes: 39 additions & 4 deletions lib/components/services/statebox-api/routes/start-execution.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
const { cloneDeep } = require('lodash')
const respond = require('../../../../util/respond')
const cloneOrDefault = obj => obj ? cloneDeep(obj) : {}

module.exports = function startExecution (request, reply) {
const schema = {
...require('./common-schema'),
description: 'Start a new Statebox execution',
body: {
type: 'object',
properties: {
stateMachineName: {
type: 'string'
},
input: {
type: 'object'
},
options: {
type: 'object',
properties: {
instigatingClient: {
type: 'object',
properties: {
appName: {
type: 'string'
},
domain: {
type: 'string'
}
}
},
sendResponse: {
type: 'string'
}
}
}
}
}
}

function startExecution (request, reply) {
const jwtAuthService = this.services.jwtAuth
const statebox = this.services.statebox

Expand Down Expand Up @@ -30,6 +66,5 @@ module.exports = function startExecution (request, reply) {
)
}

function cloneOrDefault (obj) {
return obj ? cloneDeep(obj) : {}
}
module.exports = startExecution
module.exports.schema = schema
18 changes: 17 additions & 1 deletion lib/components/services/statebox-api/routes/stop-execution.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
const respond = require('../../../../util/respond')
const schema = {
...require('./common-schema'),
description: 'Stop an existing Statebox execution',
params: {
type: 'object',
properties: {
executionName: {
type: 'string',
description: 'Execution name'
}
}
}
}

module.exports = function cancelTymlyRoute (request, reply) {
function stopExecution (request, reply) {
const jwtAuthService = this.services.jwtAuth
const statebox = this.services.statebox

Expand All @@ -25,3 +38,6 @@ module.exports = function cancelTymlyRoute (request, reply) {
}
)
}

module.exports = stopExecution
module.exports.schema = schema
20 changes: 11 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,32 @@
},
"main": "./lib/index.js",
"dependencies": {
"axios": "1.11.0",
"@hapi/boom": "10.0.1",
"cpr": "3.0.1",
"debug": "4.4.1",
"dottie": "2.0.6",
"fastify": "5.4.0",
"@fastify/cors": "11.0.1",
"@fastify/helmet": "13.0.1",
"@fastify/jwt": "9.1.0",
"@fastify/multipart": "9.0.3",
"@fastify/static": "8.2.0",
"@fastify/swagger": "9.0.0",
"@fastify/swagger-ui": "^5.2.5",
"@hapi/boom": "10.0.1",
"axios": "1.11.0",
"cpr": "3.0.1",
"debug": "4.4.1",
"dottie": "2.0.6",
"fastify": "5.4.0",
"jsonwebtoken": "9.0.2",
"lodash": "4.17.21",
"uuid": "11.1.0"
},
"devDependencies": {
"@semantic-release/changelog": "6.0.3",
"@semantic-release/release-notes-generator": "14.1.0",
"@semantic-release/git": "10.0.1",
"@semantic-release/exec": "7.1.0",
"@semantic-release/git": "10.0.1",
"@semantic-release/release-notes-generator": "14.1.0",
"@wmfs/tymly": "1.315.0",
"@wmfs/tymly-cardscript-plugin": "1.51.0",
"@wmfs/tymly-rbac-plugin": "1.32.0",
"@wmfs/tymly-rest-client-plugin": "1.34.0",
"@wmfs/tymly-cardscript-plugin": "1.51.0",
"chai": "4.5.0",
"chai-string": "1.6.0",
"codecov": "3.8.3",
Expand Down
6 changes: 2 additions & 4 deletions test/download-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ describe('Download tests', function () {
downloadService = tymlyServices.fileDownloading
statebox = tymlyServices.statebox
const server = tymlyServices.server
server.listen(PORT, HOST, (err) => {
expect(err).to.eql(null)
console.log(`Listening on ${PORT}`)
})
await server.listen(PORT, HOST)
console.log(`Listening on ${PORT}`)
})

describe('service tests', () => {
Expand Down