├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── lib ├── background_validator.js ├── daemon.js ├── gateway.js ├── model_context_protocol.js ├── parser │ ├── function_parser.js │ ├── nodejs │ │ ├── comment_definition_parser.js │ │ ├── exported_function_parser.js │ │ └── validate_parameter_name.js │ └── static │ │ └── static_parser.js ├── test_engine │ ├── test_engine.js │ └── test_engine_tools.js ├── types.js └── well_knowns.js ├── package.json └── test ├── files ├── cases │ ├── arrowfunction_invalid_no_callback.js │ ├── arrowfunction_valid_empty.js │ ├── asyncfunction_invalid_callback.js │ ├── asyncfunction_invalid_esm_stream.mjs │ ├── asyncfunction_invalid_esm_with_2x_returns.mjs │ ├── asyncfunction_invalid_esm_with_const_methods_and_default.mjs │ ├── asyncfunction_invalid_esm_with_default_and_methods.mjs │ ├── asyncfunction_invalid_esm_with_nested_variable.mjs │ ├── asyncfunction_valid_context.js │ ├── asyncfunction_valid_esm.mjs │ ├── asyncfunction_valid_esm_private.mjs │ ├── asyncfunction_valid_esm_stream.mjs │ ├── asyncfunction_valid_esm_top_level_array.mjs │ ├── asyncfunction_valid_esm_with_comment.mjs │ ├── asyncfunction_valid_esm_with_const_methods.mjs │ ├── asyncfunction_valid_esm_with_left_sided_range.mjs │ ├── asyncfunction_valid_esm_with_left_sided_size.mjs │ ├── asyncfunction_valid_esm_with_methods.mjs │ ├── asyncfunction_valid_esm_with_nested_variable.mjs │ ├── asyncfunction_valid_esm_with_range_and_nullable.mjs │ ├── asyncfunction_valid_esm_with_right_sided_range.mjs │ ├── asyncfunction_valid_esm_with_right_sided_size.mjs │ ├── asyncfunction_valid_no_callback.js │ ├── asyncfunction_valid_no_default_parameters.js │ ├── function_invalid_array_schema.js │ ├── function_invalid_background.js │ ├── function_invalid_definition_order.js │ ├── function_invalid_definition_order_charge.js │ ├── function_invalid_enum_default.js │ ├── function_invalid_enum_dup.js │ ├── function_invalid_keyql_limit_default.js │ ├── function_invalid_keyql_limit_float.js │ ├── function_invalid_keyql_limit_mismatch.js │ ├── function_invalid_keyql_limit_oob.js │ ├── function_invalid_keyql_limit_oob_offset.js │ ├── function_invalid_keyql_limit_oob_user_lb.js │ ├── function_invalid_keyql_limit_oob_user_ub.js │ ├── function_invalid_keyql_options.js │ ├── function_invalid_keyql_order_options.js │ ├── function_invalid_multiple_schema.js │ ├── function_invalid_multiple_schema_empty.js │ ├── function_invalid_multiple_schema_empty_late.js │ ├── function_invalid_multiple_schema_nested.js │ ├── function_invalid_no_callback.js │ ├── function_invalid_optional_param.js │ ├── function_invalid_options.js │ ├── function_invalid_options_array.js │ ├── function_invalid_options_array_empty.js │ ├── function_invalid_options_default.js │ ├── function_invalid_options_default_1.js │ ├── function_invalid_options_default_2.js │ ├── function_invalid_options_keyql_array_default.js │ ├── function_invalid_options_keyql_default.js │ ├── function_invalid_options_type.js │ ├── function_invalid_origin.js │ ├── function_invalid_origin_asterisk.js │ ├── function_invalid_origin_bad_protocol.js │ ├── function_invalid_origin_env_invalid.js │ ├── function_invalid_origin_env_invalid_no_var.js │ ├── function_invalid_parameter_count_mismatch.js │ ├── function_invalid_parameter_mismatch.js │ ├── function_invalid_parameter_mismatch_integer.js │ ├── function_invalid_parameter_not.js │ ├── function_invalid_parameter_not_not.js │ ├── function_invalid_parameter_reserved_name.js │ ├── function_invalid_schema.js │ ├── function_invalid_stream_no_name.js │ ├── function_invalid_stream_nonfriendly_name.js │ ├── function_valid_array_keyql_order_options.js │ ├── function_valid_array_schema.js │ ├── function_valid_background.js │ ├── function_valid_background_mode.js │ ├── function_valid_blacklist.js │ ├── function_valid_charge.js │ ├── function_valid_commented_no_default_parameters.js │ ├── function_valid_default_float.js │ ├── function_valid_default_int_and_number_params.js │ ├── function_valid_default_parameters.js │ ├── function_valid_definition_order.js │ ├── function_valid_description_only.js │ ├── function_valid_empty.js │ ├── function_valid_empty_blacklist.js │ ├── function_valid_empty_whitelist.js │ ├── function_valid_enum.js │ ├── function_valid_enum_default.js │ ├── function_valid_has-hyphen.js │ ├── function_valid_inline.js │ ├── function_valid_inline_addition.js │ ├── function_valid_inline_await.js │ ├── function_valid_inline_context.js │ ├── function_valid_inline_empty.js │ ├── function_valid_keyql_limit.js │ ├── function_valid_keyql_options.js │ ├── function_valid_keyql_order_options.js │ ├── function_valid_multiline_param.js │ ├── function_valid_multiple_schema.js │ ├── function_valid_multiple_schema_nested.js │ ├── function_valid_multiple_schema_nested_returns.js │ ├── function_valid_named_return.js │ ├── function_valid_nested_enum_being_first_in_object_nested_in_arrays.js │ ├── function_valid_no_context.js │ ├── function_valid_no_default_parameters.js │ ├── function_valid_object_spread.js │ ├── function_valid_optional_param.js │ ├── function_valid_options.js │ ├── function_valid_options_array.js │ ├── function_valid_options_default.js │ ├── function_valid_options_keyql_array_default.js │ ├── function_valid_options_keyql_default.js │ ├── function_valid_origin.js │ ├── function_valid_origin_env_has_var.js │ ├── function_valid_origin_http_port_subdomain.js │ ├── function_valid_origin_https_port_subdomain.js │ ├── function_valid_origin_localhost.js │ ├── function_valid_origin_port.js │ ├── function_valid_origin_port_subdomain.js │ ├── function_valid_parameter_negative.js │ ├── function_valid_parameter_nullable.js │ ├── function_valid_parameter_positive.js │ ├── function_valid_parameter_reserved_name_nested.js │ ├── function_valid_special_parameter_names.js │ ├── function_valid_stream.js │ ├── function_valid_stream_with_name.js │ ├── function_valid_whitelist.js │ ├── function_valid_zero_charge.js │ ├── inline_valid_addition.js │ └── inline_valid_context.js ├── comprehensive │ ├── __main__.js │ ├── alternate_schemas.js │ ├── default.js │ ├── default_return.js │ ├── dir │ │ ├── 404.js │ │ ├── index.js │ │ ├── sub │ │ │ ├── __main__.js │ │ │ └── test.js │ │ └── test.js │ ├── enum.js │ ├── enum_nested.js │ ├── enum_nested_optional.js │ ├── enum_return.js │ ├── enum_schema.js │ ├── esdoc_support.mjs │ ├── esm_default.mjs │ ├── esm_named.mjs │ ├── inline.js │ ├── keyql_options.js │ ├── multiline_description.js │ ├── named_return.js │ ├── noname_return.js │ ├── nullable_return.js │ ├── options.js │ ├── returns.js │ ├── schema │ │ ├── array.js │ │ ├── basic.js │ │ ├── nested.js │ │ └── optional.js │ └── test.js └── ignore │ ├── .func.swp │ ├── __main__.js │ ├── dir │ └── ._test.js │ └── ignoreme.js ├── gateway ├── functions │ ├── a_standard_function.js │ ├── bg │ │ ├── __main__.js │ │ ├── empty.js │ │ ├── info.js │ │ ├── params.js │ │ ├── paramsSpecific1.js │ │ ├── paramsSpecific2.js │ │ └── paramsSpecific3.js │ ├── buffer_any_return.js │ ├── buffer_mocked_return.js │ ├── buffer_nested_any_return.js │ ├── buffer_nested_mocked_return.js │ ├── buffer_nested_return.js │ ├── buffer_reflect.js │ ├── buffer_return.js │ ├── buffer_return_content_type.js │ ├── buffer_within_array_param.js │ ├── buffer_within_object_param.js │ ├── context.js │ ├── context │ │ ├── basic.js │ │ └── keychain.js │ ├── empty │ │ └── __main__.js │ ├── enum.js │ ├── enum_context.js │ ├── enum_default.js │ ├── enum_null.js │ ├── enum_return.js │ ├── enum_schema.js │ ├── esm │ │ ├── alternate_types.mjs │ │ ├── any_options.mjs │ │ ├── boolean_or_custom_string.mjs │ │ ├── default.mjs │ │ ├── left_range.mjs │ │ ├── missing_method.mjs │ │ ├── named.mjs │ │ ├── nested.mjs │ │ ├── nested_top_level_array.mjs │ │ ├── right_range.mjs │ │ └── sizes.mjs │ ├── giphy.js │ ├── headers.js │ ├── http_body.js │ ├── index.mjs │ ├── inline │ │ ├── await.js │ │ ├── buffer.js │ │ ├── buffer_mock.js │ │ ├── context.js │ │ ├── extended_http_is_object.js │ │ ├── http.js │ │ ├── http_no_status.js │ │ ├── number.js │ │ └── require.js │ ├── keyql.js │ ├── keyql_limit.js │ ├── keyql_limit_range.js │ ├── keyql_options.js │ ├── keyql_options_array.js │ ├── keyql_order_options.js │ ├── keyql_order_options_array.js │ ├── mismatch_params_deep.js │ ├── mismatch_returns_anon.js │ ├── mismatch_returns_anon_array.js │ ├── mismatch_returns_deep.js │ ├── mismatch_returns_named.js │ ├── mismatch_returns_named_array.js │ ├── my_esm_function.mjs │ ├── my_esm_function_default.mjs │ ├── my_function.js │ ├── my_function_private.js │ ├── my_function_test_parsing.js │ ├── my_function_test_parsing_convert.js │ ├── nonstandard │ │ └── json.js │ ├── not_nullable_return.js │ ├── null_default_param.js │ ├── nullable_return.js │ ├── number_nullable.js │ ├── object_alternate_schema.js │ ├── object_parsing.js │ ├── object_tojson.js │ ├── optional_nested_schema_params.js │ ├── optional_param_not_null.js │ ├── optional_params.js │ ├── origin │ │ └── allow.js │ ├── range_integer.js │ ├── range_number.js │ ├── reflect.js │ ├── runtime │ │ ├── __main__.js │ │ ├── array.js │ │ ├── boolean.js │ │ ├── details.js │ │ ├── fatal.js │ │ ├── fatal_no_stack.js │ │ ├── largebuffer.js │ │ ├── number.js │ │ ├── object.js │ │ ├── promise_uncaught.js │ │ ├── promise_unhandled_rejection.js │ │ ├── string.js │ │ ├── thrown.js │ │ ├── thrown_status.js │ │ └── timeout.js │ ├── sanitize │ │ ├── http_object.js │ │ ├── http_object_base64.js │ │ ├── http_object_empty.js │ │ ├── http_object_header_case.js │ │ ├── http_object_invalid_header_names.js │ │ └── http_object_invalid_header_values.js │ ├── schema_optional_nested.js │ ├── schema_optional_params.js │ ├── schema_rejection.js │ ├── schema_rejection_array.js │ ├── schema_rejection_nested_array.js │ ├── schema_rejection_number_array.js │ ├── stream │ │ ├── basic.js │ │ ├── basic_buffer.js │ │ ├── basic_buffer_mocked.js │ │ ├── basic_buffer_nested.js │ │ ├── basic_buffer_nested_mocked.js │ │ ├── date.js │ │ ├── debug.js │ │ ├── debug_no_stream.js │ │ ├── invalid_stream_name.js │ │ ├── invalid_stream_param.js │ │ └── sleep.js │ ├── string_options.js │ ├── stripe.js │ ├── test │ │ ├── __notfound__.js │ │ └── status.js │ ├── type_rejection.js │ └── value_error │ │ ├── buffer_invalid.js │ │ ├── number_invalid.js │ │ └── object_alternate_schema_invalid.js └── www │ ├── compile │ ├── test-sass-error.scss │ └── test-sass.scss │ ├── error │ └── 404.html │ ├── fs-wordmark.png │ ├── page.html │ ├── page2.htm │ ├── static-test │ ├── htm │ │ └── index.htm │ └── index.html │ └── video.mp4 ├── helpers.mjs ├── output.mjs ├── run.mjs └── tests ├── _index.mjs ├── cases.mjs ├── comprehensive.mjs ├── gateway ├── gateway.mjs ├── gateway_esm.mjs └── gateway_mcp.mjs └── types.mjs /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules 3 | package-lock.json -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules 3 | package-lock.json 4 | /test 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: jammy 2 | language: node_js 3 | node_js: 4 | - "20.6.1" 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 Keith Horwood 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | FunctionParser: require('./lib/parser/function_parser.js'), 3 | Daemon: require('./lib/daemon.js'), 4 | Gateway: require('./lib/gateway.js'), 5 | EncryptionTools: require('@instant.dev/encrypt'), 6 | TestEngine: require('./lib/test_engine/test_engine.js'), 7 | types: require('./lib/types.js'), 8 | wellKnowns: require('./lib/well_knowns.js'), 9 | modelContextProtocol: require('./lib/model_context_protocol.js') 10 | }; -------------------------------------------------------------------------------- /lib/background_validator.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | modes: { 3 | 'info': (definition, params) => Buffer.from(`initiated "${definition.name}" ...`), 4 | 'empty': (definition, params) => Buffer.from([]), 5 | 'params': (definition, params) => { 6 | let specifiedBgParams = definition.background.value 7 | .split(/\s+/) 8 | .filter(param => !!param); 9 | return !specifiedBgParams.length 10 | ? params 11 | : Object.keys(params).reduce((bgParams, param) => { 12 | if (specifiedBgParams.includes(param)) { 13 | bgParams[param] = params[param]; 14 | } 15 | return bgParams; 16 | }, {}); 17 | } 18 | }, 19 | defaultMode: 'info' 20 | }; 21 | -------------------------------------------------------------------------------- /lib/daemon.js: -------------------------------------------------------------------------------- 1 | const cluster = require('cluster'); 2 | const os = require('os'); 3 | const http = require('http'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const colors = require('colors/safe'); 7 | 8 | const Gateway = require('./gateway.js'); 9 | 10 | const WATCH_FOR_CHANGES = ( 11 | !process.env.DISABLE_HOT_RELOAD && 12 | (process.env.NODE_ENV || 'development') === 'development' 13 | ); 14 | 15 | /** 16 | * Multi-process HTTP Daemon that resets when files changed (in development) 17 | * @class 18 | */ 19 | class Daemon { 20 | 21 | constructor (name, cpus) { 22 | 23 | this.name = name || 'HTTP'; 24 | 25 | this._watchers = null; 26 | 27 | this._error = null; 28 | this._server = null; 29 | this._port = null; 30 | 31 | this._paused = false; 32 | 33 | this.cpus = parseInt(cpus) || os.cpus().length; 34 | this.children = []; 35 | 36 | process.on('exit', (code) => { 37 | 38 | this.log(`Shutdown: Exited with code ${code}`); 39 | 40 | }); 41 | 42 | } 43 | 44 | log (message) { 45 | console.log(colors.grey(`[${colors.blue(`${this.name}.Daemon`)}] ${message}`)); 46 | } 47 | 48 | /** 49 | * Starts the Daemon. If all application services fail, will launch a 50 | * dummy error app on the port provided. 51 | * @param {Number} port 52 | */ 53 | start (port) { 54 | 55 | this._port = port || 3000; 56 | 57 | this.log(`Startup: Initializing`); 58 | 59 | if (WATCH_FOR_CHANGES) { 60 | 61 | this.watch('', (changes) => { 62 | changes.forEach(change => { 63 | this.log(`${change.event[0].toUpperCase()}${change.event.substr(1)}: ${change.path}`); 64 | }); 65 | this.children.forEach(child => child.send({invalidate: true})); 66 | this.children = []; 67 | !this.children.length && this.unwatch() && this.start(); 68 | }); 69 | 70 | } 71 | 72 | this._server && this._server.close(); 73 | this._server = null; 74 | 75 | for (var i = 0; i < this.cpus; i++) { 76 | 77 | let child = cluster.fork(); 78 | this.children.push(child); 79 | 80 | child.on('message', this.message.bind(this)); 81 | child.on('exit', this.exit.bind(this, child)); 82 | 83 | } 84 | 85 | this.log(`Startup: Spawning ${this.cpus} HTTP Worker${this.cpus > 1 ? `s` : ``}`); 86 | 87 | } 88 | 89 | /** 90 | * Daemon failed to load, set it in idle state (accept connections, give dummy response) 91 | */ 92 | idle () { 93 | 94 | let port = this._port || 3000; 95 | 96 | this._server = http 97 | .createServer((req, res) => { 98 | this.error(req, res, this._error); 99 | }) 100 | .listen(port); 101 | 102 | this.log(`Idle: Unable to spawn HTTP Workers, listening on port ${port}`); 103 | 104 | } 105 | 106 | error (req, res, error) { 107 | 108 | const env = process.env.NODE_ENV || 'development'; 109 | res.writeHead(500, {'Content-Type': 'text/plain'}); 110 | res.end( 111 | `Application Error: ` + 112 | ( 113 | error 114 | ? (env === 'development' ? error.stack : error.message) 115 | : 'Could not load application' 116 | ) 117 | ); 118 | 119 | } 120 | 121 | message (data) { 122 | 123 | if (data.error) { 124 | this.logError(data.error); 125 | } 126 | 127 | } 128 | 129 | /** 130 | * Shut down a child process given a specific exit code. (Reboot if clean shutdown.) 131 | * @param {child_process} child 132 | * @param {Number} code Exit status codes 133 | */ 134 | exit (child, code) { 135 | 136 | let index = this.children.indexOf(child); 137 | 138 | if (index === -1) { 139 | return; 140 | } 141 | 142 | this.children.splice(index, 1); 143 | 144 | if (code === 0) { 145 | child = cluster.fork(); 146 | this.children.push(child); 147 | child.on('message', this.message.bind(this)); 148 | child.on('exit', this.exit.bind(this, child)); 149 | } 150 | 151 | if (this.children.length === 0) { 152 | this.idle(); 153 | } 154 | 155 | } 156 | 157 | /** 158 | * Log an error on the Daemon 159 | * @param {Error} error 160 | */ 161 | logError (error) { 162 | 163 | this._error = error; 164 | this._server = null; 165 | console.error(`${error.name}: ${error.message}`); 166 | console.error(error.stack); 167 | 168 | } 169 | 170 | /** 171 | * Stops watching a directory tree for changes 172 | */ 173 | unwatch () { 174 | 175 | clearInterval(this._watchers.interval); 176 | this._watchers = null; 177 | return true; 178 | 179 | } 180 | 181 | /** 182 | * Watches a directory tree for changes 183 | * @param {string} root Directory tree to watch 184 | * @param {function} onChange Method to be executed when a change is detected 185 | */ 186 | watch (root, onChange) { 187 | 188 | let cwd = process.cwd(); 189 | 190 | function watchDir (dirname, watchers) { 191 | 192 | if (!watchers) { 193 | 194 | watchers = Object.create(null); 195 | watchers.directories = Object.create(null); 196 | watchers.interval = null; 197 | 198 | } 199 | 200 | let pathname = path.join(cwd, dirname); 201 | let files = fs.readdirSync(pathname); 202 | 203 | watchers.directories[dirname] = Object.create(null); 204 | 205 | files.forEach(function (name) { 206 | 207 | if ( 208 | name === 'node_modules' || 209 | name.indexOf('.') === 0 || 210 | name === 'dump.rdb' 211 | ) { 212 | return; 213 | } 214 | 215 | let filename = path.join(dirname, name); 216 | let fullPath = path.join(cwd, filename); 217 | 218 | let stat = fs.statSync(fullPath); 219 | 220 | if (stat.isDirectory()) { 221 | watchDir(filename, watchers); 222 | return; 223 | } 224 | 225 | watchers.directories[dirname][name] = stat; 226 | 227 | }); 228 | 229 | return watchers; 230 | 231 | } 232 | 233 | let watchers = watchDir(root || ''); 234 | let self = this; 235 | 236 | watchers.iterate = function (changes) { 237 | if (!fs.existsSync(path.join(process.cwd(), '.daemon.pause'))) { 238 | // Skip a cycle if just unpaused... 239 | if (!this._paused) { 240 | if (changes.length) { 241 | onChange.call(self, changes); 242 | } 243 | } else { 244 | this._paused = false; 245 | } 246 | } else { 247 | this._paused = true; 248 | } 249 | }; 250 | 251 | watchers.interval = setInterval(function() { 252 | 253 | let changes = []; 254 | 255 | Object.keys(watchers.directories).forEach(function (dirname) { 256 | 257 | let dir = watchers.directories[dirname]; 258 | let dirPath = path.join(cwd, dirname); 259 | 260 | if (!fs.existsSync(dirPath)) { 261 | 262 | delete watchers.directories[dirname]; 263 | changes.push({event: 'removed', path: dirPath}); 264 | 265 | } else { 266 | 267 | let files = fs.readdirSync(dirPath); 268 | let added = []; 269 | 270 | let contents = Object.create(null); 271 | 272 | files.forEach(function (filename) { 273 | 274 | if ( 275 | filename === 'node_modules' || 276 | filename.indexOf('.') === 0 || 277 | filename === 'dump.rdb' 278 | ) { 279 | return; 280 | } 281 | 282 | let fullPath = path.join(dirPath, filename); 283 | let stat = fs.statSync(fullPath); 284 | 285 | if (stat.isDirectory()) { 286 | let checkPath = path.join(dirname, filename); 287 | if (!watchers.directories[checkPath]) { 288 | watchDir(checkPath, watchers); 289 | } 290 | } else { 291 | if (!dir[filename]) { 292 | added.push([filename, stat]); 293 | changes.push({event: 'added', path: fullPath}); 294 | return; 295 | } 296 | 297 | if (stat.mtime.toString() !== dir[filename].mtime.toString()) { 298 | dir[filename] = stat; 299 | changes.push({event: 'modified', path: fullPath}); 300 | } 301 | 302 | contents[filename] = true; 303 | } 304 | 305 | }); 306 | 307 | Object.keys(dir).forEach(function (filename) { 308 | 309 | let fullPath = path.join(cwd, dirname, filename); 310 | 311 | if (!contents[filename]) { 312 | delete dir[filename]; 313 | changes.push({event: 'removed', path: fullPath}); 314 | } 315 | 316 | }); 317 | 318 | added.forEach(function (change) { 319 | let [filename, stat] = change; 320 | dir[filename] = stat; 321 | }); 322 | 323 | } 324 | 325 | }); 326 | 327 | watchers.iterate(changes); 328 | 329 | }, 1000); 330 | 331 | return this._watchers = watchers; 332 | 333 | } 334 | 335 | } 336 | 337 | class InstantDaemon extends Daemon { 338 | constructor (cpus, name = 'InstantAPI') { 339 | super(name, cpus); 340 | } 341 | } 342 | 343 | InstantDaemon.Gateway = class InstantDaemonGateway extends Gateway { 344 | 345 | constructor (cfg) { 346 | super(cfg); 347 | process.on('uncaughtException', e => { 348 | if (typeof process.send === 'function') { 349 | process.send({ 350 | error: { 351 | name: e.name, 352 | message: e.message, 353 | stack: e.stack 354 | } 355 | }); 356 | } 357 | process.exit(1); 358 | }); 359 | process.on('message', data => data.invalidate && process.exit(0)); 360 | process.on('exit', code => this.log(null, `Shutdown: Exited with code ${code}`)); 361 | } 362 | 363 | listen (port, callback, opts) { 364 | super.listen(port, callback, opts); 365 | if (typeof process.send === 'function') { 366 | process.send({message: 'ready'}); 367 | } 368 | return this.server; 369 | } 370 | 371 | } 372 | 373 | module.exports = InstantDaemon; 374 | -------------------------------------------------------------------------------- /lib/model_context_protocol.js: -------------------------------------------------------------------------------- 1 | const io = require('io'); 2 | const wellKnowns = require('./well_knowns.js'); 3 | 4 | const ERROR_CODES = { 5 | ParseError: -32700, 6 | InvalidRequest: -32600, 7 | MethodNotFound: -32601, 8 | InvalidParams: -32602, 9 | InternalError: -32603, 10 | ResourceNotFound: -32002 11 | }; 12 | 13 | const modelContextProtocol = { 14 | 15 | ERROR_CODES, 16 | 17 | endpoints: { 18 | 'server.mcp': { 19 | 'initialize': (definitions, mcpRequest, data, port, headers) => { 20 | return { 21 | jsonrpc: '2.0', 22 | id: mcpRequest.id ?? null, 23 | result: { 24 | protocolVersion: '2025-03-26', 25 | capabilities: { 26 | tools: {}, 27 | resources: {} 28 | }, 29 | serverInfo: { 30 | name: data.mcp_server_name || 'MyMCPServer', 31 | version: data.mcp_server_version || '1.0' 32 | } 33 | } 34 | }; 35 | }, 36 | 'ping': (definitions, mcpRequest) => { 37 | return { 38 | jsonrpc: '2.0', 39 | id: mcpRequest.id ?? null, 40 | result: {} 41 | }; 42 | }, 43 | 'tools/list': (definitions, mcpRequest) => { 44 | const tools = []; 45 | const JSONSchema = wellKnowns.generateJSONSchema(definitions); 46 | for (const endpoint of JSONSchema) { 47 | const description = endpoint.description || endpoint.name; 48 | const title = description.split(/\n|\./)[0].trim(); 49 | tools.push({ 50 | name: endpoint.name, 51 | description: endpoint.description, 52 | inputSchema: endpoint.parameters, 53 | annotations: { 54 | title: title, 55 | // readOnlyHint?: boolean; // If true, the tool does not modify its environment 56 | // destructiveHint?: boolean; // If true, the tool may perform destructive updates 57 | // idempotentHint?: boolean; // If true, repeated calls with same args have no additional effect 58 | // openWorldHint?: boolean; // If true, tool interacts with external entities 59 | } 60 | }); 61 | } 62 | return { 63 | jsonrpc: '2.0', 64 | id: mcpRequest.id ?? null, 65 | result: { 66 | tools, 67 | nextCursor: '' 68 | } 69 | }; 70 | }, 71 | 'tools/call': async (definitions, mcpRequest, data, port, headers) => { 72 | const { name, arguments } = mcpRequest.params; 73 | if (typeof name !== 'string') { 74 | return { 75 | jsonrpc: '2.0', 76 | id: mcpRequest.id ?? null, 77 | error: { code: ERROR_CODES.InvalidParams, message: `Invalid "name" parameter, must be a string` } 78 | }; 79 | } else if (typeof arguments !== 'object' || arguments === null || Array.isArray(arguments)) { 80 | return { 81 | jsonrpc: '2.0', 82 | id: mcpRequest.id ?? null, 83 | error: { code: ERROR_CODES.InvalidParams, message: `Invalid "arguments" parameter, must be an object` } 84 | }; 85 | } 86 | const JSONSchema = wellKnowns.generateJSONSchema(definitions); 87 | const endpoint = JSONSchema.find(endpoint => endpoint.name === name); 88 | if (!endpoint) { 89 | return { 90 | jsonrpc: '2.0', 91 | id: mcpRequest.id ?? null, 92 | error: { code: ERROR_CODES.MethodNotFound, message: `No such tool: "${name}"` } 93 | }; 94 | } 95 | const useHeaders = { 96 | 'content-type': 'application/json', 97 | 'host': headers['host'] 98 | }; 99 | if (data.mcp_authorization_header || headers['authorization']) { 100 | useHeaders['authorization'] = data.mcp_authorization_header || headers['authorization']; 101 | } 102 | const result = await io.request( 103 | endpoint.method, 104 | `http://localhost:${port}${endpoint.route}`, 105 | (endpoint.method === 'GET' || endpoint.method === 'DELETE') ? arguments : {}, 106 | useHeaders, 107 | (endpoint.method === 'POST' || endpoint.method === 'PUT') ? JSON.stringify(arguments) : null 108 | ); 109 | const contentType = result.headers['content-type'].split(';')[0]; 110 | const type = contentType.split('/')[0]; 111 | const content = []; 112 | if (type === 'text' || contentType === 'application/json') { 113 | content.push({ 114 | type: 'text', 115 | text: result.body.toString() 116 | }); 117 | } else if (type === 'image') { 118 | content.push({ 119 | type, 120 | data: result.body.toString('base64'), 121 | mimeType: contentType 122 | }); 123 | } else { 124 | content.push({ 125 | type: 'resource', 126 | resource: { 127 | uri: 'temporary://none', 128 | mimeType: contentType, 129 | blob: result.body.toString('base64') 130 | } 131 | }); 132 | } 133 | const isError = result.statusCode >= 400; 134 | return { 135 | jsonrpc: '2.0', 136 | id: mcpRequest.id ?? null, 137 | result: { 138 | content, 139 | isError 140 | } 141 | }; 142 | }, 143 | 'resources/list': (definitions, mcpRequest) => { 144 | const resources = []; 145 | const staticFiles = Object.keys(definitions) 146 | .map(key => definitions[key]) 147 | .filter(definition => definition.format.language === 'static'); 148 | for (const file of staticFiles) { 149 | const name = file.name.split('/').pop(); 150 | resources.push({ 151 | uri: `file://${file.name}`, 152 | name: name, 153 | description: name, 154 | mimeType: file.metadata.contentType 155 | }); 156 | } 157 | return { 158 | jsonrpc: '2.0', 159 | id: mcpRequest.id ?? null, 160 | result: { 161 | resources, 162 | nextCursor: '' 163 | } 164 | }; 165 | }, 166 | 'resources/templates/list': (definitions, mcpRequest) => { 167 | const resourceTemplates = [ 168 | { 169 | uriTemplate: "file://{path}", 170 | name: 'Package files', 171 | description: 'Files in this package', 172 | mimeType: "application/octet-stream" 173 | } 174 | ]; 175 | return { 176 | jsonrpc: '2.0', 177 | id: mcpRequest.id ?? null, 178 | result: { 179 | resourceTemplates, 180 | nextCursor: '' 181 | } 182 | }; 183 | }, 184 | 'resources/read': async (definitions, mcpRequest, data, port, headers) => { 185 | const { uri } = mcpRequest.params; 186 | if (typeof uri !== 'string') { 187 | return { 188 | jsonrpc: '2.0', 189 | id: mcpRequest.id ?? null, 190 | error: { code: ERROR_CODES.InvalidParams, message: `Invalid "uri" parameter, must be a string` } 191 | }; 192 | } else if (!uri.startsWith('file://')) { 193 | return { 194 | jsonrpc: '2.0', 195 | id: mcpRequest.id ?? null, 196 | error: { code: ERROR_CODES.InvalidParams, message: `Invalid "uri" parameter, must start with "file://"` } 197 | }; 198 | } 199 | const pathname = uri.slice('file://'.length); 200 | const file = definitions[pathname]; 201 | if (!file || file.format.language !== 'static') { 202 | return { 203 | jsonrpc: '2.0', 204 | id: mcpRequest.id ?? null, 205 | error: { code: ERROR_CODES.ResourceNotFound, message: `Resource not found: "${uri}"` } 206 | }; 207 | } 208 | const useHeaders = { 209 | 'host': headers['host'], 210 | }; 211 | if (data.mcp_authorization_header || headers['authorization']) { 212 | useHeaders['authorization'] = data.mcp_authorization_header || headers['authorization']; 213 | } 214 | const result = await io.request( 215 | 'GET', 216 | `http://localhost:${port}${pathname}`, 217 | {}, 218 | useHeaders, 219 | null 220 | ); 221 | const resource ={ 222 | uri: `file://${pathname}`, 223 | mimeType: file.metadata.contentType 224 | }; 225 | if (file.metadata.contentType.startsWith('text/') || file.metadata.contentType === 'application/json') { 226 | resource.text = result.body.toString(); 227 | } else { 228 | resource.blob = result.body.toString('base64'); 229 | } 230 | return { 231 | jsonrpc: '2.0', 232 | id: mcpRequest.id ?? null, 233 | result: { 234 | contents: [ 235 | resource 236 | ] 237 | } 238 | }; 239 | }, 240 | } 241 | } 242 | 243 | }; 244 | 245 | module.exports = modelContextProtocol; 246 | -------------------------------------------------------------------------------- /lib/parser/function_parser.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const minimatch = require('minimatch'); 5 | const mime = require('mime'); 6 | 7 | const backgroundValidator = require('../background_validator.js'); 8 | const types = require('../types.js'); 9 | const { isArray } = require('util'); 10 | 11 | const DEFAULT_IGNORE = [ 12 | '.*.swp', 13 | '._*', 14 | '.DS_Store', 15 | '.git', 16 | '.hg', 17 | '.npmrc', 18 | '.lock-wscript', 19 | '.svn', 20 | '.wafpickle-*', 21 | 'config.gypi', 22 | 'CVS', 23 | 'npm-debug.log' 24 | ]; 25 | 26 | class FunctionParser { 27 | 28 | constructor() { 29 | this._parsers = Object.keys(this.constructor.parsers).reduce((parsers, lang) => { 30 | parsers[lang] = new this.constructor.parsers[lang](); 31 | return parsers; 32 | }, {}); 33 | } 34 | 35 | getParser (ext) { 36 | ext = ext.toLowerCase(); 37 | let lang = this.constructor.extensions[ext]; 38 | if (!lang) { 39 | throw new Error(`No function parser available for extension "${ext}"`); 40 | } else if (!this._parsers[lang]) { 41 | throw new Error(`No function parser available for language "${lang}"`); 42 | } 43 | return this._parsers[lang]; 44 | } 45 | 46 | parseDefinition (pathname, buffer, functionsPath, isStatic, isPreload) { 47 | 48 | isStatic = !!isStatic; 49 | functionsPath = functionsPath || ''; 50 | functionsPath = (functionsPath && !functionsPath.endsWith('/')) ? `${functionsPath}/` : functionsPath; 51 | if (!pathname.startsWith(functionsPath)) { 52 | throw new Error(`Pathname does not start with "${functionsPath}"`); 53 | } 54 | let names = pathname.split('/'); 55 | let filename = names.pop(); 56 | let ext = filename.split('.').pop(); 57 | let name = filename.substr(0, filename.length - ext.length - 1); 58 | let definitionList = []; 59 | 60 | if (isStatic) { 61 | // Convert index.html -> mydomain.com/ 62 | // But also preserve mydomain.com/index.html 63 | // Special rules for html files named "index" or "404" 64 | // Which will create default routes 65 | let parser = this.getParser(''); 66 | let definitions; 67 | let shouldCreateFileEntry = true; 68 | if ( 69 | (name === 'index' || name === '404') && 70 | (ext === 'htm' || ext === 'html') 71 | ) { 72 | if (name === 'index') { 73 | name = names.join('/').substr(functionsPath.length); 74 | } else if (name === '404') { 75 | name = `${names.join('/').substr(functionsPath.length)}:notfound`; 76 | shouldCreateFileEntry = false; // 404 will trigger 404 anyway 77 | } 78 | try { 79 | definitions = parser.parse( 80 | name, 81 | buffer, 82 | pathname 83 | ); 84 | for (const definition of definitions) { 85 | definition.pathname = pathname; 86 | } 87 | } catch (e) { 88 | throw new Error(`Static file error (${pathname})\n${e.message}`); 89 | } 90 | for (const definition of definitions) { 91 | definitionList.push(definition); 92 | } 93 | } 94 | if (shouldCreateFileEntry) { 95 | try { 96 | definitions = parser.parse( 97 | names.concat(filename).join('/').substr(functionsPath.length), 98 | buffer, 99 | pathname 100 | ); 101 | for (const definition of definitions) { 102 | definition.pathname = pathname; 103 | } 104 | } catch (e) { 105 | throw new Error(`Static file error (${pathname})\n${e.message}`); 106 | } 107 | for (const definition of definitions) { 108 | definitionList.push(definition); 109 | } 110 | } 111 | } else { 112 | let parser; 113 | try { 114 | parser = this.getParser(`.${ext}`); 115 | } catch (e) { 116 | throw new Error(`Invalid endpoint file: (${pathname})\n${e.message}`); 117 | } 118 | let suffix; 119 | if (name === '__main__' || name === 'index') { 120 | name = names.join('/'); 121 | } else if (name === '__notfound__' || name === '404') { 122 | name = names.join('/'); 123 | suffix = 'notfound'; 124 | } else { 125 | name = names.concat(name).join('/'); 126 | } 127 | name = name.substr(functionsPath.length); 128 | if (name && !name.match(/^([A-Z][A-Z0-9\_\-]*\/)*[A-Z][A-Z0-9\_\-]*$/i)) { 129 | throw new Error( 130 | `Invalid endpoint file: "${name}" (${pathname})\n` + 131 | `File and directory names must be alphanumeric (or -, _) and start with a letter` 132 | ); 133 | } 134 | 135 | name = name + (suffix ? `:${suffix}` : ''); 136 | let definitions; 137 | 138 | try { 139 | definitions = parser.parse(name, buffer, pathname); 140 | for (const definition of definitions) { 141 | definition.pathname = pathname; 142 | } 143 | } catch (e) { 144 | e.message = `Endpoint definition error (${pathname})\n${e.message}`; 145 | throw e; 146 | } 147 | 148 | if (isPreload) { 149 | for (const definition of definitions) { 150 | definition.preload = true; 151 | } 152 | } 153 | 154 | for (const definition of definitions) { 155 | definitionList.push(definition); 156 | } 157 | 158 | } 159 | 160 | definitionList.forEach(definition => { 161 | let validations = this.constructor.definitionFields; 162 | Object.keys(validations).forEach(field => { 163 | let validate = validations[field]; 164 | let value = definition[field]; 165 | if (!validate(value)) { 166 | throw new Error( 167 | `Endpoint definition error (${pathname})\n`+ 168 | `Invalid field "${field}", unexpected value: ${JSON.stringify(value)}\n` + 169 | `\nThis is likely caused by a server misconfiguration.` 170 | ); 171 | } 172 | }); 173 | }); 174 | 175 | return definitionList; 176 | 177 | } 178 | 179 | readDefinitions (files, functionsPath, definitions, isStatic, isPreload) { 180 | functionsPath = (functionsPath && !functionsPath.endsWith('/')) ? `${functionsPath}/` : (functionsPath || ''); 181 | return Object.keys(files).reduce((definitions, pathname) => { 182 | if (functionsPath && !pathname.startsWith(functionsPath)) { 183 | return definitions; 184 | } 185 | let definitionList = this.parseDefinition(pathname, files[pathname], functionsPath, isStatic, isPreload); 186 | definitionList.forEach(definition => { 187 | if (definitions[definition.name]) { 188 | let existingDefinition = definitions[definition.name]; 189 | throw new Error( 190 | `Endpoint ${definition.name} (${definition.pathname}) was already defined in ${existingDefinition.pathname}\n` + 191 | ( 192 | existingDefinition.preload 193 | ? `This file was preloaded as part of a compilation step, it can not be overwritten.\n` 194 | : '' 195 | ) + 196 | ( 197 | isStatic 198 | ? (!existingDefinition.static && definition.static) 199 | ? [ 200 | `Endpoint functions and static files can not have the same name.`, 201 | `This can often be caused when a function is named "__main__" and a static file is name "index",`, 202 | `or when a function is named "__notfound__" and a static file is named "404".` 203 | ].join('\n') 204 | : `Only one static file per directory can have the name "index" or "404".` 205 | : `If declaring with [dir]/__main__.js, make sure [dir].js isn't a file in the parent directory.` 206 | ) 207 | ); 208 | } 209 | definitions[definition.name] = definition; 210 | }); 211 | return definitions; 212 | }, definitions || {}); 213 | } 214 | 215 | readFiles (rootPath, functionsPath, dirPath, files, ignore) { 216 | if (ignore && !Array.isArray(ignore)) { 217 | throw new Error(`Invalid ignore file, received ${typeof ignore} instead of Array`); 218 | } 219 | let ignoreList = (ignore || []).concat(DEFAULT_IGNORE); 220 | functionsPath = functionsPath || '.'; 221 | dirPath = dirPath || '.'; 222 | files = files || {}; 223 | if (!fs.existsSync(path.join(rootPath, functionsPath, dirPath))) { 224 | return files; 225 | } else { 226 | return fs.readdirSync(path.join(rootPath, functionsPath, dirPath)).reduce((files, filename) => { 227 | let pathname = path.join(rootPath, functionsPath, dirPath, filename); 228 | let fullPath = path.join(functionsPath, dirPath, filename); 229 | let filePath = path.join(dirPath, filename); 230 | let fullPathNormalized = fullPath.split(path.sep).join('/'); 231 | let isDirectory = fs.statSync(pathname).isDirectory(); 232 | for (let i = 0; i < ignoreList.length; i++) { 233 | if (minimatch(fullPathNormalized, ignoreList[i], {matchBase: true})) { 234 | return files; 235 | } 236 | } 237 | if (isDirectory) { 238 | files = this.readFiles(rootPath, functionsPath, filePath, files, ignore); 239 | } else { 240 | files[fullPathNormalized] = fs.readFileSync(pathname); 241 | } 242 | return files; 243 | }, files); 244 | } 245 | } 246 | 247 | load (rootPath, functionsPath, staticPath, ignore, preloadFiles) { 248 | let definitions = {}; 249 | if (preloadFiles && typeof preloadFiles === 'object') { 250 | definitions = this.readDefinitions(preloadFiles, functionsPath, definitions, false, true); 251 | definitions = this.readDefinitions(preloadFiles, staticPath, definitions, true, true); 252 | } 253 | let functionFiles = this.readFiles(rootPath, functionsPath, null, null, ignore); 254 | definitions = this.readDefinitions(functionFiles, functionsPath, definitions); 255 | if (staticPath) { 256 | let staticFiles = this.readFiles(rootPath, staticPath, null, null, ignore); 257 | definitions = this.readDefinitions(staticFiles, staticPath, definitions, true); 258 | } 259 | return definitions; 260 | } 261 | 262 | } 263 | 264 | FunctionParser.parsers = { 265 | 'static' : require('./static/static_parser.js'), 266 | 'nodejs': require('./nodejs/exported_function_parser.js') 267 | }; 268 | 269 | FunctionParser.commentParsers = { 270 | 'nodejs': require('./nodejs/comment_definition_parser.js') 271 | }; 272 | 273 | FunctionParser.extensions = { 274 | '': 'static', 275 | '.js': 'nodejs', 276 | '.mjs': 'nodejs', 277 | '.cjs': 'nodejs' 278 | }; 279 | 280 | FunctionParser.definitionFields = { 281 | 'name': name => typeof name === 'string', 282 | 'pathname': pathname => typeof pathname === 'string', 283 | 'format': format => { 284 | return format && 285 | typeof format === 'object' && 286 | typeof format.language === 'string' && 287 | typeof format.inline === 'boolean' 288 | }, 289 | 'description': description => typeof description === 'string', 290 | 'metadata': metadata => typeof metadata === 'object' && metadata !== null, 291 | 'private': isPrivate => isPrivate === void 0 || isPrivate === true || isPrivate === false, 292 | 'origins': origins => { 293 | return origins === null || origins === void 0 || Array.isArray(origins); 294 | }, 295 | 'background': background => { 296 | if (background) { 297 | return background && 298 | typeof background === 'object' && 299 | 'mode' in background && 300 | 'value' in background && 301 | typeof background.value === 'string' && 302 | background.mode in backgroundValidator.modes; 303 | } else { 304 | return background === null || background === void 0; 305 | } 306 | }, 307 | 'streams': streams => { 308 | return streams === null || 309 | FunctionParser.definitionFields['params'](streams); 310 | }, 311 | 'context': context => typeof context === 'object', 312 | 'params': (params, isArraySchema, ignoreName = false) => { 313 | return Array.isArray(params) && 314 | ( 315 | isArraySchema 316 | ? params.length === 1 317 | : true 318 | ) && 319 | params.filter(param => { 320 | return param && 321 | typeof param == 'object' && 322 | 'name' in param && 323 | (param.name || ignoreName) && // only require name if it's not an array schema 324 | 'description' in param && 325 | 'type' in param && 326 | ( 327 | 'defaultMetafield' in param 328 | ? typeof param.defaultMetafield === 'string' 329 | : true 330 | ) && 331 | ( 332 | 'options' in param 333 | ? param.options && (typeof param.options === 'object') 334 | : true 335 | ) && 336 | ( 337 | 'schema' in param 338 | ? ( 339 | (['object', 'array'].indexOf(param.type) !== -1) && 340 | FunctionParser.definitionFields['params'](param.schema, param.type === 'array', true) 341 | ) 342 | : true 343 | ) && 344 | ( 345 | 'alternateSchemas' in param 346 | ? ( 347 | (['object'].indexOf(param.type) !== -1) && 348 | Array.isArray(param.alternateSchemas) && 349 | param.alternateSchemas.filter(schema => { 350 | return FunctionParser.definitionFields['params'](schema); 351 | }).length === param.alternateSchemas.length 352 | ) 353 | : true 354 | ) && 355 | ( 356 | 'alternateTypes' in param 357 | ? ( 358 | Array.isArray(param.alternateTypes) && 359 | FunctionParser.definitionFields['params'](param.alternateTypes, false, true) 360 | ) 361 | : true 362 | ) && 363 | types.list.indexOf(param.type) > -1 364 | }).length === params.length; 365 | }, 366 | 'returns': returns => { 367 | return returns && 368 | typeof returns === 'object' && 369 | 'name' in returns && 370 | 'description' in returns && 371 | 'type' in returns; 372 | } 373 | }; 374 | 375 | module.exports = FunctionParser; 376 | -------------------------------------------------------------------------------- /lib/parser/nodejs/validate_parameter_name.js: -------------------------------------------------------------------------------- 1 | const babelParser = require('@babel/parser'); 2 | 3 | const RESERVED_NAMES = [ 4 | '_stream', 5 | '_debug', 6 | '_bg', 7 | 'context' 8 | ]; 9 | 10 | function validateParameterName(param) { 11 | try { 12 | let token = babelParser.parseExpression(param); 13 | if ( 14 | !token || token.type !== 'Identifier' || token.name === 'let' || 15 | RESERVED_NAMES.indexOf(token.name) !== -1 16 | ) { 17 | return false; 18 | } 19 | } catch (e) { 20 | return false; 21 | } 22 | return true; 23 | } 24 | 25 | module.exports = validateParameterName; 26 | -------------------------------------------------------------------------------- /lib/parser/static/static_parser.js: -------------------------------------------------------------------------------- 1 | const mime = require('mime'); 2 | 3 | class StaticParser { 4 | 5 | constructor() { 6 | this.language = 'static'; 7 | } 8 | 9 | parse (name, buffer, pathname) { 10 | 11 | let filename = pathname.split('/').pop(); 12 | 13 | return [ 14 | { 15 | name: `${name}`, 16 | method: null, 17 | pathname: pathname, 18 | format: { 19 | language: this.language, 20 | async: false, 21 | inline: false 22 | }, 23 | description: filename, 24 | metadata: { 25 | filename: filename, 26 | contentType: mime.getType(filename), 27 | contentLength: buffer.byteLength, 28 | }, 29 | origins: null, 30 | background: null, 31 | keys: [], 32 | charge: 0, 33 | streams: null, 34 | context: {}, 35 | params: [ 36 | { 37 | name: 'raw', 38 | description: 'turn off auto-formatting and return the raw file contents where applicable', 39 | type: 'boolean', 40 | defaultValue: false 41 | } 42 | ], 43 | returns: { 44 | name: 'file', 45 | description: 'Static File', 46 | type: 'object.http' 47 | } 48 | } 49 | ]; 50 | 51 | } 52 | 53 | } 54 | 55 | module.exports = StaticParser; 56 | -------------------------------------------------------------------------------- /lib/test_engine/test_engine.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const os = require('os'); 3 | const path = require('path'); 4 | const minimatch = require('minimatch'); 5 | 6 | const TestEngineTools = require('./test_engine_tools.js'); 7 | const formatPath = pathname => `/` + pathname.split(path.sep).slice(1).join('/'); 8 | 9 | const DEFAULT_IGNORE = [ 10 | '.DS_Store' 11 | ]; 12 | 13 | /** 14 | * Loads tests from a provided directory 15 | * Tests must export a default function or async function 16 | * Tests can optionally export a "name" to name the test 17 | */ 18 | class TestEngine { 19 | 20 | constructor (port) { 21 | if (!port) { 22 | throw new Error(`port is required for TestEngine instance`); 23 | } 24 | this.tests = []; 25 | this.testLookup = {}; 26 | this.tools = new TestEngineTools(port); 27 | this.setupResult = null; 28 | } 29 | 30 | /** 31 | * Loads tests from a specified directory 32 | * Tests will be loaded top-down, alphabetically, by file name 33 | * e.g. all tests in ./tests/ will be executed before ./tests/more_tests/ 34 | * You can not have non-test files in the directory specified; 35 | * use a higher-level directory for managing helper files 36 | * @param {string} dir Directory to load tests from 37 | * @returns {TestEngine} 38 | */ 39 | async initialize (dir) { 40 | const cwd = dir.replaceAll('~', os.homedir()); 41 | if (!fs.existsSync(cwd)) { 42 | throw new Error(`Can not initialize tests: "${dir}" does not exist`); 43 | } else if (!fs.statSync(cwd).isDirectory()) { 44 | throw new Error(`Can not initialize tests: "${dir}" is not a directory`); 45 | } 46 | this.tests = await this.__load__(cwd); 47 | for (const test of this.tests) { 48 | this.testLookup[test.filename] = test; 49 | } 50 | return this; 51 | } 52 | 53 | /** 54 | * Loads test files recursively 55 | * @private 56 | * @param {string} rootPath 57 | * @param {string} dirPath 58 | * @param {array} ignore Files to ignore 59 | * @returns {array} 60 | */ 61 | async __load__ (rootPath, dirPath = '.', ignore = null) { 62 | let tests = []; 63 | if (!rootPath || typeof rootPath !== 'string') { 64 | throw new Error(`rootPath must be a non-empty string`); 65 | } 66 | if (rootPath.startsWith('.')) { 67 | rootPath = path.join(process.cwd(), rootPath); 68 | } 69 | if (ignore && !Array.isArray(ignore)) { 70 | throw new Error(`Invalid ignore file, received ${typeof ignore} instead of Array`); 71 | } 72 | let ignoreList = (ignore || []).concat(DEFAULT_IGNORE); 73 | if (fs.existsSync(path.join(rootPath, dirPath))) { 74 | let filenames = fs.readdirSync(path.join(rootPath, dirPath)); 75 | let directories = []; 76 | let files = []; 77 | for (const filename of filenames) { 78 | let pathname = path.join(rootPath, dirPath, filename); 79 | let filePath = path.join(dirPath, filename); 80 | let fullPathNormalized = filePath.split(path.sep).join('/'); 81 | for (let i = 0; i < ignoreList.length; i++) { 82 | if (minimatch(fullPathNormalized, ignoreList[i], {matchBase: true})) { 83 | continue; 84 | } 85 | } 86 | const stat = fs.statSync(pathname); 87 | if (stat.isDirectory()) { 88 | directories.push({pathname, filePath}); 89 | } else { 90 | files.push({pathname, filePath}); 91 | } 92 | } 93 | directories.sort(); 94 | files.sort(); 95 | for (const file of files) { 96 | try { 97 | if (!file.pathname.endsWith('.mjs') && !file.pathname.endsWith('.js')) { 98 | throw new Error(`Must be a valid JavaScript .js or .mjs file`); 99 | } 100 | tests.push({ 101 | name: file.filePath.replace(/\.m?js$/gi, ''), 102 | filename: file.filePath, 103 | pathname: file.pathname 104 | }); 105 | } catch (e) { 106 | console.error(e); 107 | throw new Error(`Error loading test "${file.pathname}": ${e.message}`); 108 | } 109 | } 110 | for (const directory of directories) { 111 | tests = tests.concat(await this.__load__(rootPath, directory.filePath, ignore)); 112 | } 113 | } 114 | return tests; 115 | } 116 | 117 | /** 118 | * Sets up required test objects and infrastructure 119 | * @param {function} fn 120 | */ 121 | async setup (fn) { 122 | if (typeof fn !== 'function') { 123 | throw new Error(`.setup requires valid function`); 124 | } 125 | this.setupResult = await fn(); 126 | } 127 | 128 | /** 129 | * Finishes all tests, cleans up objects and infrastructure 130 | * @param {function} fn 131 | */ 132 | async finish (fn) { 133 | if (typeof fn !== 'function') { 134 | throw new Error(`.finish requires valid function`); 135 | } 136 | if (global.after) { 137 | global.after(async () => { 138 | await fn(this.setupResult); 139 | }); 140 | } else { 141 | await fn(this.setupResult); 142 | } 143 | } 144 | 145 | /** 146 | * Runs all tests 147 | * Arguments provided to this function will be passed to all tests when executed 148 | * @returns {TestEngine} 149 | */ 150 | async runAll () { 151 | for (const test of this.tests) { 152 | await this.run(test.filename); 153 | } 154 | return this; 155 | } 156 | 157 | /** 158 | * Runs a specific test by name 159 | * Arguments provided to this function after the test name will be passed to all tests when executed 160 | * @param {string} name 161 | * @returns {TestEngine} 162 | */ 163 | async run (name) { 164 | if (typeof name !== 'string') { 165 | throw new Error(`name must be a valid string`); 166 | } 167 | if (name.startsWith('/')) { 168 | name = name.slice(1); 169 | } 170 | name = name.replace(/\.m?js$/gi, ''); 171 | const test = this.testLookup[`${name}.js`] || this.testLookup[`${name}.mjs`]; 172 | if (!test) { 173 | throw new Error(`No test matching "${name}" found`); 174 | } 175 | let script = await this.importTest(test); 176 | if (global.describe) { 177 | global.describe(script.name, async () => { 178 | await script.run.apply(this.tools, [this.setupResult]); 179 | }); 180 | } else { 181 | await script.run.apply(this.tools, [this.setupResult]); 182 | } 183 | return this; 184 | } 185 | 186 | async importTest (test) { 187 | let name = test.name; 188 | let script; 189 | try { 190 | script = await import(formatPath(test.pathname)); 191 | if (!script.default) { 192 | throw new Error(`Missing default export`); 193 | } 194 | if (script.name) { 195 | if (typeof script.name !== 'string') { 196 | throw new Error(`Export "name" must be a string`); 197 | } else { 198 | name = `${script.name} (${test.name})`; 199 | } 200 | } 201 | if (typeof script.default !== 'function') { 202 | throw new Error(`Default export must be a function`); 203 | } 204 | } catch (e) { 205 | throw new Error(`Could not import "${test.name}": ${e.message}`); 206 | } 207 | return {name, run: script.default}; 208 | } 209 | 210 | } 211 | 212 | module.exports = TestEngine; -------------------------------------------------------------------------------- /lib/test_engine/test_engine_tools.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const zlib = require('zlib'); 3 | 4 | class TestEngineTools { 5 | 6 | constructor (port) { 7 | this.host = 'localhost'; 8 | this.port = port; 9 | } 10 | 11 | __parseServerSentEvents__ (buffer) { 12 | const events = {}; 13 | const entries = buffer.toString().split('\n\n'); 14 | entries 15 | .filter(entry => !!entry) 16 | .forEach(entry => { 17 | let event = ''; 18 | let data = null; 19 | entry.split('\n').forEach((line, i) => { 20 | let lineData = line.split(':'); 21 | let type = lineData[0]; 22 | let contents = lineData.slice(1).join(':'); 23 | if (contents.startsWith(' ')) { 24 | contents = contents.slice(1); 25 | } 26 | if (type === 'event' && data === null) { 27 | event = contents; 28 | } else if (type === 'data') { 29 | data = data || ''; 30 | data = data + contents; 31 | } 32 | }); 33 | events[event] = events[event] || []; 34 | events[event].push(data || ''); 35 | }); 36 | return events; 37 | }; 38 | 39 | __formatQueryParams__ (path, params) { 40 | let queryParams = ''; 41 | if (params) { 42 | if ( 43 | typeof params === 'object' && 44 | !Buffer.isBuffer(params) && 45 | Object.keys(params).length > 0 46 | ) { 47 | queryParams = Object.keys(params) 48 | .filter(key => params[key] !== null && params[key] !== void 0) 49 | .map(key => { 50 | let value = params[key]; 51 | if (Buffer.isBuffer(value)) { 52 | value = JSON.stringify({_base64: value.toString('base64')}); 53 | } else if (typeof value === 'object') { 54 | value = JSON.stringify(value); 55 | } 56 | return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; 57 | }) 58 | .join('&'); 59 | } else if ( 60 | (Buffer.isBuffer(params) && params.length > 0) || 61 | typeof params === 'string' 62 | ) { 63 | queryParams = params.toString(); 64 | } 65 | } 66 | path = path.replace(/[\?\&]+$/, ''); 67 | queryParams = queryParams.replace(/^[\?\&]+/, ''); 68 | return path.indexOf('?') > -1 69 | ? `${path}${queryParams ? `&${queryParams}` : ``}` 70 | : `${path}${queryParams ? `?${queryParams}` : ``}`; 71 | } 72 | 73 | async request (method, path, data, headers = {}) { 74 | method = method || 'GET'; 75 | path = path || ''; 76 | path = path.startsWith('/') ? path : `/${path}`; 77 | let queryParams = ''; 78 | if (data && typeof data === 'object' && !Buffer.isBuffer(data)) { 79 | data = JSON.stringify(data); 80 | headers['Content-Type'] = 'application/json'; 81 | } else if (typeof data === 'string') { 82 | let contentType = Object.keys(headers).find(k => k.toLowerCase() === 'content-type'); 83 | if (!contentType) { 84 | headers['Content-Type'] = 'application/x-www-form-urlencoded'; 85 | } 86 | } 87 | data = data || ''; 88 | return new Promise((resolve, reject) => { 89 | // return resolve({statusCode: 200, headers: {}, body: Buffer.from(''), text: '', json: {}, events: {}}); 90 | const pathname = `${path}${queryParams}`; 91 | const req = http.request( 92 | { 93 | host: this.host, 94 | port: this.port, 95 | path: pathname, 96 | method: method, 97 | headers: headers 98 | }, 99 | (res) => { 100 | let buffers = []; 101 | res.on('data', chunk => buffers.push(chunk)); 102 | res.on('error', err => reject(err)); 103 | res.on('end', () => { 104 | let body = Buffer.concat(buffers); 105 | if (res.headers['content-encoding'] === 'gzip') { 106 | body = zlib.gunzipSync(body); 107 | } else if (res.headers['content-encoding'] === 'deflate') { 108 | body = zlib.inflateSync(body); 109 | } 110 | let text = body.toString(); 111 | let json = null; 112 | let events = null; 113 | if ((res.headers['content-type'] || '').split(';')[0] === 'application/json') { 114 | json = JSON.parse(body.toString()); 115 | } else if ((res.headers['content-type'] || '').split(';')[0] === 'text/event-stream') { 116 | events = this.__parseServerSentEvents__(body); 117 | } 118 | if ( 119 | res.statusCode.toString().startsWith('4') || 120 | res.statusCode.toString().startsWith('5') 121 | ) { 122 | const error = json?.error?.message || (json?.error && JSON.stringify(json.error)) || text; 123 | console.error(`${method} ${pathname} ${res.statusCode}:\n${error}`); 124 | } 125 | resolve({statusCode: res.statusCode, headers: res.headers, body, text, json, events}); 126 | }); 127 | } 128 | ); 129 | req.on('error', err => reject(err)); 130 | req.useChunkedEncodingByDefault = true; 131 | req.end(data); 132 | }); 133 | } 134 | 135 | async get (path, params, headers) { 136 | return this.request('GET', this.__formatQueryParams__(path, params), null, headers); 137 | } 138 | 139 | async post (path, params, headers) { 140 | return this.request('POST', path, params, headers); 141 | } 142 | 143 | async put (path, params, headers) { 144 | return this.request('PUT', path, params, headers); 145 | } 146 | 147 | async del (path, params, headers) { 148 | return this.request('DELETE', this.__formatQueryParams__(path, params), null, headers); 149 | } 150 | 151 | } 152 | 153 | module.exports = TestEngineTools; -------------------------------------------------------------------------------- /lib/well_knowns.js: -------------------------------------------------------------------------------- 1 | const YAML = require('json-to-pretty-yaml'); 2 | 3 | const APIToJSONSchemaMapping = { 4 | 'boolean': (param) => { 5 | let json = {}; 6 | json.type = 'boolean'; 7 | return json; 8 | }, 9 | 'string': (param) => { 10 | let json = {}; 11 | json.type = 'string'; 12 | if (param.options && param.options.values) { 13 | json.enum = param.options.values; 14 | } 15 | return json; 16 | }, 17 | 'number': (param) => { 18 | let json = {}; 19 | json.type = 'number'; 20 | if (param.range) { 21 | if (param.range.min !== null) { 22 | json.minimum = param.range.min; 23 | } 24 | if (param.range.max !== null) { 25 | json.maximum = param.range.max; 26 | } 27 | } 28 | if (param.options && param.options.values) { 29 | json.enum = param.options.values; 30 | } 31 | return json; 32 | }, 33 | 'float': (param) => { 34 | let json = {}; 35 | json.type = 'number'; 36 | if (param.range) { 37 | if (param.range.min !== null) { 38 | json.minimum = param.range.min; 39 | } 40 | if (param.range.max !== null) { 41 | json.maximum = param.range.max; 42 | } 43 | } 44 | if (param.options && param.options.values) { 45 | json.enum = param.options.values; 46 | } 47 | return json; 48 | }, 49 | 'integer': (param) => { 50 | let json = {}; 51 | json.type = 'integer'; 52 | if (param.range) { 53 | if (param.range.min !== null) { 54 | json.minimum = param.range.min; 55 | } 56 | if (param.range.max !== null) { 57 | json.maximum = param.range.max; 58 | } 59 | } 60 | if (param.options) { 61 | json.enum = param.options; 62 | } 63 | return json; 64 | }, 65 | 'array': (param) => { 66 | let json = {}; 67 | json.type = 'array'; 68 | if (param.schema && param.schema.length) { 69 | json.items = convertParamToJSONSchema(param.schema[0]); 70 | } 71 | return json; 72 | }, 73 | 'object': (param) => { 74 | let schemas = [param.schema || []].concat(param.alternateSchemas || []); 75 | schemas = schemas.filter(schema => schema.length > 0); 76 | if (schemas.length > 1) { 77 | return { 78 | oneOf: schemas.map(schema => convertParametersArrayToJSONSchema(schema)) 79 | }; 80 | } else { 81 | return convertParametersArrayToJSONSchema(schemas[0] || []); 82 | } 83 | }, 84 | 'enum': (param) => { 85 | let json = {}; 86 | json.enum = param.members.map(member => member[0]); 87 | return json; 88 | }, 89 | 'buffer': (param) => { 90 | let json = {}; 91 | json.type = 'object'; 92 | json.properties = { 93 | '_base64': {type: 'string', contentEncoding: 'base64'}, 94 | }; 95 | return json; 96 | }, 97 | 'object.http': (param) => { 98 | let json = {}; 99 | json.type = 'object'; 100 | json.properties = { 101 | 'statusCode': {type: 'integer'}, 102 | 'headers': {type: 'object'}, 103 | 'body': {type: 'string'} 104 | }; 105 | return json; 106 | }, 107 | 'object.keyql.query': (param) => { 108 | let json = {}; 109 | json.type = 'object'; 110 | return json; 111 | }, 112 | 'object.keyql.limit': (param) => { 113 | let json = {}; 114 | json.type = 'object'; 115 | json.properties = { 116 | 'count': {type: 'integer', minimum: 0}, 117 | 'offset': {type: 'integer', minimum: 0} 118 | }; 119 | return json; 120 | }, 121 | 'object.keyql.order': (param) => { 122 | let json = {}; 123 | json.type = 'array'; 124 | json.items = { 125 | type: 'object', 126 | properties: { 127 | 'field': {type: 'string'}, 128 | 'sort': {enum: ['ASC', 'DESC']} 129 | } 130 | }; 131 | return json; 132 | }, 133 | 'any': (param) => { 134 | let json = {}; 135 | return json; 136 | } 137 | }; 138 | 139 | const convertParamToJSONSchema = (param) => { 140 | let convert = APIToJSONSchemaMapping[param.type]; 141 | if (typeof convert === 'function') { 142 | let json = convert(param); 143 | if (param.description) { 144 | json.description = param.description; 145 | } 146 | if (param.defaultValue !== null) { 147 | json.default = param.defaultValue; 148 | } 149 | return json; 150 | } else { 151 | throw new Error(`Invalid param type for JSON Schema: "${param.type}"`); 152 | } 153 | }; 154 | 155 | const convertParametersArrayToJSONSchema = (params) => { 156 | return params.reduce((obj, param) => { 157 | obj.properties[param.name] = convertParamToJSONSchema(param); 158 | if (!param.hasOwnProperty('defaultValue')) { 159 | obj.required = obj.required || []; 160 | obj.required.push(param.name); 161 | } 162 | return obj; 163 | }, { 164 | type: 'object', 165 | properties: {} 166 | }); 167 | }; 168 | 169 | const generateJSONSchema = (definitions, origin = 'localhost', opts = {}) => { 170 | opts = opts || {}; 171 | const includeFilenames = !!opts.includeFilenames; 172 | const schema = Object.keys(definitions) 173 | .filter(key => { 174 | let def = definitions[key]; 175 | return def.format.language !== 'static' && !def.private; 176 | }) 177 | .map(key => { 178 | let def = definitions[key]; 179 | let method = ''; 180 | if (key.match(/^(.*?)\#(.*)$/gi)) { 181 | key.replace(/^(.*?)\#(.*)$/gi, ($0, $1, $2) => { 182 | key = $1; 183 | method = $2; 184 | }); 185 | } 186 | let parts = key.split('/'); 187 | if (!parts[parts.length - 1]) { 188 | parts.pop(); 189 | } 190 | let name = parts.join('_').replace(/[^a-z0-9\-\_]+/gi, '-') || '_'; 191 | let route = `/${key}`; 192 | if (route.match(/:notfound$/)) { 193 | route = route.replace(/:notfound$/, '*/'); 194 | } else if (!route.endsWith('/')) { 195 | route = route + '/'; 196 | } 197 | const schema = { 198 | name: name + (!method ? `` : `_${method.toLowerCase()}`), 199 | description: def.description, 200 | route: route, 201 | url: `${origin}${route}`, 202 | method: method || 'POST', 203 | parameters: convertParametersArrayToJSONSchema(def.params), 204 | endpoint_name: def.name, 205 | }; 206 | if (def.returns && def.returns.type !== 'object.http') { 207 | schema.returns = convertParamToJSONSchema(def.returns); 208 | } 209 | if (includeFilenames) { 210 | schema.filename = def.pathname; 211 | } 212 | return schema; 213 | }); 214 | return schema; 215 | }; 216 | 217 | const generateOpenAPISpec = (definitions, plugin, server, origin, identifier) => { 218 | 219 | const paths = Object.keys(definitions) 220 | .filter(key => { 221 | let def = definitions[key]; 222 | return def.format.language !== 'static' && !def.private; 223 | }) 224 | .reduce((paths, key) => { 225 | let def = definitions[key]; 226 | let method = `POST`; 227 | if (key.match(/^(.*?)\#(.*)$/gi)) { 228 | key.replace(/^(.*?)\#(.*)$/gi, ($0, $1, $2) => { 229 | key = $1; 230 | method = $2; 231 | }); 232 | } 233 | let parts = key.split('/'); 234 | if (!parts[parts.length - 1]) { 235 | parts.pop(); 236 | } 237 | let name = parts.join('_').replace(/[^a-z0-9\-\_]+/gi, '-') || '_'; 238 | let route = `/${key}`; 239 | if (route.match(/:notfound$/)) { 240 | route = route.replace(/:notfound$/, '*/'); 241 | } else if (!route.endsWith('/')) { 242 | route = route + '/'; 243 | } 244 | let opIdentifier = identifier.replace(/\[(.*)\]/gi, ''); 245 | let operationId = `${opIdentifier}${parts.length ? ('.' + parts.join('.')) : ''}_${method.toLowerCase()}`; 246 | operationId = operationId.replace(/[^A-Z0-9_]+/gi, '_'); 247 | operationId = operationId.replace(/^_+/gi, ''); 248 | operationId = operationId.replace(/_+$/gi, ''); 249 | let pathData = { 250 | summary: def.description, 251 | description: def.description, 252 | operationId: operationId 253 | }; 254 | // If we have at least one parameter... 255 | if (def.params.length > 0) { 256 | const schema = {...convertParametersArrayToJSONSchema(def.params)}; 257 | if (method === 'GET' || method === 'DELETE') { 258 | pathData.parameters = def.params.map(param => { 259 | let p = { 260 | in: 'query', 261 | name: param.name, 262 | schema: schema.properties[param.name] 263 | }; 264 | if (param.hasOwnProperty('defaultValue')) { 265 | p.required = true; 266 | } 267 | if (param.description) { 268 | p.description = param.description; 269 | } 270 | return p; 271 | }); 272 | } else { 273 | pathData.requestBody = { 274 | 'content': { 275 | 'application/json': { 276 | 'schema': schema 277 | } 278 | } 279 | } 280 | } 281 | }; 282 | if (def.returns && def.returns.type !== 'object.http') { 283 | pathData.responses = { 284 | '200': { 285 | 'content': { 286 | 'application/json': { 287 | 'schema': { 288 | ...convertParamToJSONSchema(def.returns) 289 | } 290 | } 291 | } 292 | } 293 | }; 294 | } 295 | paths[route] = paths[route] || {}; 296 | paths[route][`${method.toLowerCase()}`] = pathData; 297 | return paths; 298 | }, {}); 299 | 300 | const spec = { 301 | openapi: '3.1.0', 302 | info: { 303 | version: plugin.version, 304 | title: plugin.name, 305 | description: plugin.description 306 | }, 307 | servers: [ 308 | { 309 | url: origin, 310 | description: server 311 | } 312 | ], 313 | paths: paths 314 | }; 315 | 316 | if (plugin.termsOfService) { 317 | spec.info.termsOfService = plugin.termsOfService; 318 | } 319 | 320 | if (plugin.contact) { 321 | const {name, url, email} = plugin.contact; 322 | if (name || url || email) { 323 | spec.info.contact = {}; 324 | } 325 | name && (spec.info.contact.name = name); 326 | url && (spec.info.contact.url = url); 327 | email && (spec.info.contact.email = email); 328 | } 329 | 330 | return spec; 331 | 332 | }; 333 | 334 | const wellKnowns = { 335 | 336 | generateJSONSchema: generateJSONSchema, 337 | 338 | validatePlugin: (rawPlugin, origin) => { 339 | 340 | const plugin = {}; 341 | 342 | if (rawPlugin && typeof rawPlugin !== 'object' || Array.isArray(rawPlugin)) { 343 | throw new Error(`"plugin" must be an object`); 344 | } 345 | 346 | plugin.name = rawPlugin.name || '(No name provided)'; 347 | plugin.description = rawPlugin.description || '(No description provided)'; 348 | plugin.version = rawPlugin.version || (process.env.NODE_ENV || 'development'); 349 | plugin.image_url = rawPlugin.image_url || null; 350 | if ( 351 | typeof plugin.image_url === 'string' && 352 | plugin.image_url.startsWith('/') 353 | ) { 354 | plugin.image_url = `${origin}${plugin.image_url}`; 355 | } 356 | 357 | plugin.forModel = rawPlugin.forModel || {}; 358 | plugin.forModel.name = plugin.forModel.name || plugin.name; 359 | plugin.forModel.description = plugin.forModel.description || plugin.description; 360 | 361 | plugin.termsOfService = rawPlugin.termsOfService || null; 362 | if ( 363 | typeof plugin.termsOfService === 'string' && 364 | plugin.termsOfService.startsWith('/') 365 | ) { 366 | plugin.termsOfService = `${origin}${plugin.termsOfService}`; 367 | } 368 | 369 | plugin.contact = rawPlugin.contact || {}; 370 | 371 | const checkPluginValue = (name, isRequired = false) => { 372 | let names = name.split('.'); 373 | let check = plugin; 374 | for (let i = 0; i < names.length; i++) { 375 | let n = names[i]; 376 | check = check[n]; 377 | } 378 | if (typeof check !== 'string') { 379 | if (check === null || check === void 0) { 380 | if (isRequired) { 381 | throw new Error(`plugin.${name} is required`); 382 | } 383 | } else { 384 | throw new Error(`plugin.${name} must be a string`); 385 | } 386 | } 387 | }; 388 | 389 | [ 390 | 'name', 391 | 'description', 392 | 'version', 393 | 'forModel.name', 394 | 'forModel.description' 395 | ].forEach(name => checkPluginValue(name, true)); 396 | 397 | [ 398 | 'image_url', 399 | 'termsOfService', 400 | 'contact.name', 401 | 'contact.url', 402 | 'contact.email' 403 | ].forEach(name => checkPluginValue(name)); 404 | 405 | return plugin; 406 | 407 | }, 408 | 409 | handlers: { 410 | 411 | '.well-known/plugin.json': (definitions, plugin, server, origin, identifier) => { 412 | 413 | const body = Buffer.from(JSON.stringify(plugin, null, 2)); 414 | return { 415 | headers: { 416 | 'Content-Type': 'application/json' 417 | }, 418 | body 419 | }; 420 | 421 | }, 422 | 423 | '.well-known/ai-plugin.json': (definitions, plugin, server, origin, identifier) => { 424 | 425 | const AIPlugin = {}; 426 | AIPlugin.schema_version = 'v1'; 427 | AIPlugin.name_for_human = plugin.name.slice(0, 20); 428 | AIPlugin.name_for_model = plugin.forModel.name.slice(0, 50); 429 | AIPlugin.name_for_model = AIPlugin.name_for_model.replace(/[^A-Z0-9_]+/gi, '_'); 430 | AIPlugin.name_for_model = AIPlugin.name_for_model.replace(/^_+/gi, ''); 431 | AIPlugin.name_for_model = AIPlugin.name_for_model.replace(/_+$/gi, ''); 432 | AIPlugin.description_for_human = plugin.description.slice(0, 100); 433 | AIPlugin.description_for_model = plugin.forModel.description.slice(0, 8000); 434 | AIPlugin.auth = { 435 | type: 'none' 436 | }; 437 | AIPlugin.api = { 438 | type: 'openapi', 439 | url: `${origin}/.well-known/openapi.yaml` 440 | }; 441 | AIPlugin.logo_url = `${origin}/logo.png`; 442 | AIPlugin.contact_email = `noreply@${origin.replace(/^https?\:\/\/(.*)(:\d+)/gi, '$1')}`; 443 | AIPlugin.legal_info_url = `${origin}/tos.txt`; 444 | if (plugin.image_url) { 445 | AIPlugin.logo_url = plugin.image_url; 446 | } 447 | if (plugin.contact && plugin.contact.email) { 448 | AIPlugin.contact_email = plugin.contact.email; 449 | } 450 | if (plugin.termsOfService) { 451 | AIPlugin.legal_info_url = plugin.termsOfService; 452 | } 453 | 454 | return { 455 | headers: { 456 | 'Content-Type': 'application/json' 457 | }, 458 | body: Buffer.from(JSON.stringify(AIPlugin, null, 2)) 459 | }; 460 | 461 | }, 462 | 463 | '.well-known/openapi.json': (definitions, plugin, server, origin, identifier) => { 464 | 465 | const spec = generateOpenAPISpec(definitions, plugin, server, origin, identifier); 466 | const body = Buffer.from(JSON.stringify(spec, null, 2)); 467 | return { 468 | headers: { 469 | 'Content-Type': 'application/json' 470 | }, 471 | body 472 | }; 473 | 474 | }, 475 | 476 | '.well-known/openapi.yaml': (definitions, plugin, server, origin, identifier) => { 477 | 478 | const spec = generateOpenAPISpec(definitions, plugin, server, origin, identifier); 479 | const body = Buffer.from(YAML.stringify(spec)); 480 | return { 481 | headers: { 482 | 'Content-Type': 'application/yaml' 483 | }, 484 | body 485 | }; 486 | 487 | }, 488 | 489 | '.well-known/schema.json': (definitions, plugin, server, origin, identifier) => { 490 | 491 | const schema = generateJSONSchema(definitions, origin); 492 | 493 | const response = { 494 | functions: schema 495 | }; 496 | 497 | const body = Buffer.from(JSON.stringify(response, null, 2)); 498 | 499 | return { 500 | headers: { 501 | 'Content-Type': 'application/json' 502 | }, 503 | body 504 | }; 505 | 506 | } 507 | } 508 | 509 | }; 510 | 511 | module.exports = wellKnowns; 512 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@instant.dev/api", 3 | "version": "0.2.4", 4 | "description": "An API gateway and framework for turning functions into web services", 5 | "author": "Keith Horwood ", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "mocha ./test/run.mjs", 9 | "output": "node ./test/output.mjs" 10 | }, 11 | "dependencies": { 12 | "@babel/parser": "^7.23.0", 13 | "@instant.dev/encrypt": "^0.0.7", 14 | "colors": "^1.4.0", 15 | "fast-deep-equal": "^3.1.3", 16 | "fast-xml-parser": "^4.3.2", 17 | "io": "^1.5.3", 18 | "json-to-pretty-yaml": "^1.2.2", 19 | "keyql": "^0.2.2", 20 | "mime": "^2.5.2", 21 | "minimatch": "^3.0.4", 22 | "uuid": "^9.0.1" 23 | }, 24 | "devDependencies": { 25 | "chai": "^3.5.0", 26 | "form-data": "^2.3.2", 27 | "mocha": "^10.2.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/files/cases/arrowfunction_invalid_no_callback.js: -------------------------------------------------------------------------------- 1 | module.exports = () => {}; 2 | // invalid, no callback 3 | -------------------------------------------------------------------------------- /test/files/cases/arrowfunction_valid_empty.js: -------------------------------------------------------------------------------- 1 | module.exports = callback => {}; 2 | // Valid, requires callback 3 | -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_invalid_callback.js: -------------------------------------------------------------------------------- 1 | module.exports = async function(callback) {}; 2 | // invalid, async shouldn't have callback 3 | -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_invalid_esm_stream.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Streams results for our lovable assistant 3 | * @param {string} query The question for our assistant 4 | * @stream {object} chunk 5 | * @stream {string} chunk.id 6 | * @stream {string} chunk.object 7 | * @stream {integer} chunk.created 8 | * @stream {string} chunk.model 9 | * @stream {object[]} chunk.choices 10 | * @stream {integer} chunk.choices.index 11 | * @stream {object} chunk.choices.delta 12 | * @stream {?string} chunk.choices.delta.role 13 | * @stream {?string} chunk.choices.delta.content 14 | * @returns {object} message 15 | * @returns {string} message.content 16 | */ 17 | export async function GET (query, context) { 18 | const completion = []; 19 | for await (const chunk of completion) { 20 | context.stream('chunk', chunk); 21 | message += chunk?.choices?.[0]?.delta?.content || ''; 22 | } 23 | return {message}; 24 | }; -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_invalid_esm_with_2x_returns.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid because can't provide two returns 3 | * @param {string} alpha 4 | * @returns {object} beta 5 | * @returns {object} beta2 6 | */ 7 | export default async (alpha) => { 8 | /* do nothing */ 9 | }; -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_invalid_esm_with_const_methods_and_default.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a 4 | * @param {number} b 5 | * @param {array} c 6 | */ 7 | export default async (a, b, c) => { 8 | /* do nothing */ 9 | } 10 | 11 | /** 12 | * My get function 13 | * @param {string} a 14 | * @param {number} b 15 | * @param {array} c 16 | */ 17 | export const GET = async (a, b, c) => { 18 | 19 | } 20 | 21 | /** 22 | * My put function 23 | * @param {string} a 24 | * @param {number} b 25 | * @param {array} c 26 | */ 27 | export const PUT = async (a, b, c) => { 28 | 29 | } 30 | 31 | /** 32 | * My post function 33 | * @param {string} a 34 | * @param {number} b 35 | * @param {array} c 36 | */ 37 | export const POST = async (a, b, c) => { 38 | 39 | } 40 | 41 | /** 42 | * My delete function 43 | * @param {string} a 44 | * @param {number} b 45 | * @param {array} c 46 | */ 47 | export const DELETE = async (a, b, c) => { 48 | 49 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_invalid_esm_with_default_and_methods.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a 4 | * @param {number} b 5 | * @param {array} c 6 | */ 7 | export default async (a, b, c) => { 8 | /* do nothing */ 9 | } 10 | 11 | /** 12 | * My get function 13 | * @param {string} a 14 | * @param {number} b 15 | * @param {array} c 16 | */ 17 | export async function GET (a, b, c) { 18 | 19 | } 20 | 21 | /** 22 | * My put function 23 | * @param {string} a 24 | * @param {number} b 25 | * @param {array} c 26 | */ 27 | export async function PUT (a, b, c) { 28 | 29 | } 30 | 31 | /** 32 | * My post function 33 | * @param {string} a 34 | * @param {number} b 35 | * @param {array} c 36 | */ 37 | export async function POST (a, b, c) { 38 | 39 | } 40 | 41 | /** 42 | * My delete function 43 | * @param {string} a 44 | * @param {number} b 45 | * @param {array} c 46 | */ 47 | export async function DELETE (a, b, c) { 48 | 49 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_invalid_esm_with_nested_variable.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid because can't provide schema to a number for beta.obj 3 | * @param {string} alpha 4 | * @param {object} beta 5 | * @param {number} beta.str 6 | * @param {number} beta.obj 7 | * @param {number} beta.obj.num 8 | * @param {string} beta.obj.str 9 | * @param {array} gamma 10 | */ 11 | export default async (alpha, beta, gamma) => { 12 | /* do nothing */ 13 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_context.js: -------------------------------------------------------------------------------- 1 | module.exports = async function(context) {}; 2 | // valid, context only 3 | -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm.mjs: -------------------------------------------------------------------------------- 1 | export default async (a, b, c) => { 2 | /* do nothing */ 3 | } 4 | -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_private.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @private 4 | * @param {string} a 5 | * @param {number} b 6 | * @param {array} c 7 | */ 8 | export default async (a, b, c) => { 9 | /* do nothing */ 10 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_stream.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Streams results for our lovable assistant 3 | * @param {string} query The question for our assistant 4 | * @stream {object} chunk 5 | * @stream {string} chunk.id 6 | * @stream {string} chunk.object 7 | * @stream {integer} chunk.created 8 | * @stream {string} chunk.model 9 | * @stream {object[]} chunk.choices 10 | * @stream {integer} chunk.choices[].index 11 | * @stream {object} chunk.choices[].delta 12 | * @stream {?string} chunk.choices[].delta.role 13 | * @stream {?string} chunk.choices[].delta.content 14 | * @returns {object} message 15 | * @returns {string} message.content 16 | */ 17 | export async function GET (query, context) { 18 | const completion = []; 19 | for await (const chunk of completion) { 20 | context.stream('chunk', chunk); 21 | message += chunk?.choices?.[0]?.delta?.content || ''; 22 | } 23 | return {message}; 24 | }; -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_top_level_array.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Sets params for an array object at the top level 3 | * @param {object[]} requests 4 | * @param {integer} requests[].index 5 | * @param {object} requests[].delta 6 | * @param {?string} requests[].delta.role 7 | * @param {?string} requests[].delta.content 8 | */ 9 | export async function GET (requests = []) { 10 | return true; 11 | }; -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_comment.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a 4 | * @param {number} b 5 | * @param {array} c 6 | */ 7 | export default async (a, b, c) => { 8 | /* do nothing */ 9 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_const_methods.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My get function 3 | * @param {string} a 4 | * @param {number} b 5 | * @param {array} c 6 | */ 7 | export const GET = async (a, b, c) => { 8 | 9 | } 10 | 11 | /** 12 | * My put function 13 | * @param {string} a 14 | * @param {number} b 15 | * @param {array} c 16 | */ 17 | export const PUT = async (a, b, c) => { 18 | 19 | } 20 | 21 | /** 22 | * My post function 23 | * @param {string} a 24 | * @param {number} b 25 | * @param {array} c 26 | */ 27 | export const POST = async (a, b, c) => { 28 | 29 | } 30 | 31 | /** 32 | * My delete function 33 | * @param {string} a 34 | * @param {number} b 35 | * @param {array} c 36 | */ 37 | export const DELETE = async (a, b, c) => { 38 | 39 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_left_sided_range.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {integer{1,}} alpha 4 | */ 5 | export default async (alpha) => { 6 | /* do nothing */ 7 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_left_sided_size.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string{10..}} alpha 4 | */ 5 | export default async (alpha) => { 6 | /* do nothing */ 7 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_methods.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My get function 3 | * @param {string} a 4 | * @param {number} b 5 | * @param {array} c 6 | */ 7 | export async function GET (a, b, c) { 8 | 9 | } 10 | 11 | /** 12 | * My put function 13 | * @param {string} a 14 | * @param {number} b 15 | * @param {array} c 16 | */ 17 | export async function PUT (a, b, c) { 18 | 19 | } 20 | 21 | /** 22 | * My post function 23 | * @param {string} a 24 | * @param {number} b 25 | * @param {array} c 26 | */ 27 | export async function POST (a, b, c) { 28 | 29 | } 30 | 31 | /** 32 | * My delete function 33 | * @param {string} a 34 | * @param {number} b 35 | * @param {array} c 36 | */ 37 | export async function DELETE (a, b, c) { 38 | 39 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_nested_variable.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} alpha 4 | * @param {object} beta 5 | * @param {number} beta.str 6 | * @param {object} beta.obj 7 | * @param {number} beta.obj.num 8 | * @param {string} beta.obj.str 9 | * @param {array} gamma 10 | */ 11 | export default async (alpha, beta, gamma) => { 12 | /* do nothing */ 13 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_range_and_nullable.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {integer{1,5}} alpha 4 | */ 5 | export default async (alpha = null) => { 6 | /* do nothing */ 7 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_right_sided_range.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {integer{,1}} alpha 4 | */ 5 | export default async (alpha) => { 6 | /* do nothing */ 7 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_esm_with_right_sided_size.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string{..10}} alpha 4 | */ 5 | export default async (alpha) => { 6 | /* do nothing */ 7 | } -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_no_callback.js: -------------------------------------------------------------------------------- 1 | module.exports = async function() {}; 2 | // Valid, async doesn't need callback 3 | -------------------------------------------------------------------------------- /test/files/cases/asyncfunction_valid_no_default_parameters.js: -------------------------------------------------------------------------------- 1 | module.exports = async function(a, b, c, d, e, f, context) {}; 2 | // Valid, first parameter can be "any" 3 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_array_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Test Array Schema 3 | * @param {array} arr 4 | * @ {string} name 5 | * @ {number} timestamp 6 | * @param {string} after 7 | * @returns {string} 8 | */ 9 | module.exports = async (arr, after) => { 10 | 11 | return 'hello'; 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_background.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an invalid background 3 | * @background hello 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'invalid acl entry'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_definition_order.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid function due to invalid function definition order 3 | * @param {string} test 4 | * @acl * 5 | * user_username faas_tester deny 6 | * user_username faas_tester2 deny 7 | * user_username faas_tester3 deny 8 | * @returns {string} 9 | */ 10 | module.exports = (test, callback) => { 11 | 12 | return callback(null, 'invalid function due to comment definition order'); 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_definition_order_charge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with invalid function definition order due to charge 3 | * @background empty 4 | * @acl * 5 | * user_username faas_tester deny 6 | * user_username faas_tester2 deny 7 | * user_username faas_tester3 deny 8 | * @param {string} test 9 | * @charge 10 10 | * @returns {string} 11 | */ 12 | module.exports = (test, callback) => { 13 | 14 | return callback(null, 'function with invalid definition order due to charge'); 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_enum_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Invalid Enum Default 3 | * @param {enum} basic some basic types 4 | * [num, 0] 5 | * [double, "1"] 6 | * [float, 1.2] 7 | * [numstr, "123"] 8 | * @returns {any} 9 | */ 10 | module.exports = async (basic = 'not one of those') => { 11 | return basic; 12 | }; 13 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_enum_dup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Enum Duplicate 3 | * @param {any} before 4 | * @param {enum} day 5 | * [sunday, 0] 6 | * [tuesday, 2] 7 | * [wednesday, 3] 8 | * [thursday, 4] 9 | * [friday, 5] 10 | * [saturday, 6] 11 | * [wednesday, 1] 12 | * @param {any} after 13 | * @returns {number} 14 | */ 15 | module.exports = async (before = null, day, after = null) => { 16 | return day; 17 | }; 18 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_limit_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit = {count: 0, fhg: 'wat'}) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_limit_float.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit = {count: 0.354, offset: 0}) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_limit_mismatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit {:} [5, 4] 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_limit_oob.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit = {count: -1, offset: 0}) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_limit_oob_offset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit = {count: 0, offset: -1}) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_limit_oob_user_lb.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit {:} [2, 20] 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit = {count: 1, offset: 0}) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_limit_oob_user_ub.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit {:} [2, 20] 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit = {count: 21, offset: 0}) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Query with Options 3 | * @param {object.keyql.query} query Query API based on these parameters {?} ["status", null, "goodbye"] 4 | * @returns {string} 5 | */ 6 | module.exports = async (query) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_keyql_order_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Query with Options 3 | * @param {object.keyql.order} order Order for keyql {?} ["status", null, "goodbye"] 4 | * @returns {string} 5 | */ 6 | module.exports = async (order) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_multiple_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Accepts multiple schemas for an object 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {number} size 6 | * @ OR 7 | * @ {string} name2 8 | * @ {number} size2 9 | * @returns {object} 10 | */ 11 | module.exports = async (fileOrFolder) => { 12 | return true; 13 | }; 14 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_multiple_schema_empty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Accepts multiple schemas for an object 3 | * @param {object} fileOrFolder 4 | * @ OR 5 | * @ {string} name 6 | * @ {number} size 7 | * @returns {object} 8 | */ 9 | module.exports = async (fileOrFolder) => { 10 | return true; 11 | }; 12 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_multiple_schema_empty_late.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Accepts multiple schemas for an object 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {number} size 6 | * @ OR 7 | * @returns {object} 8 | */ 9 | module.exports = async (fileOrFolder) => { 10 | return true; 11 | }; 12 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_multiple_schema_nested.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Accepts multiple schemas for an object 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {number} size 6 | * @ OR 7 | * @ {string} name2 8 | * @ {number} size2 9 | * @ {object} props 10 | * @ {string} label 11 | * @ OR 12 | * @ {number} size 13 | * @returns {object} 14 | */ 15 | module.exports = async (fileOrFolder) => { 16 | return true; 17 | }; 18 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_no_callback.js: -------------------------------------------------------------------------------- 1 | module.exports = function() {}; 2 | // Invalid, requires callback 3 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_optional_param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid function with an optional param 3 | * name should have a default value 4 | * @param {?string} name 5 | * @returns {string} 6 | */ 7 | module.exports = (name, callback) => { 8 | 9 | return callback(null, name || 'hello'); 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options 3 | * @param {string} database {?} db $[].name $[].id 4 | * @param {string} table {?} db.schema.databases.retrieve(databaseId=database) $[].name 5 | * @returns {boolean} 6 | */ 7 | module.exports = async (database = 'hello', table = 'wat') => { 8 | return true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Array 3 | * @param {string} keys {?} ["a", 1337, "c"] 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (keys) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_array_empty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Empty Array 3 | * @param {object} keys {?} [] 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (keys) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Default 3 | * @param {string} key {?} ["a", "b", "c"] 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (key = "d") => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_default_1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options 1 3 | * @param {string} database {!} ? {?} db.schema.databases.list $[].name $[].id 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (database = 'hello') => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_default_2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid Options 3 | * @param {string} database {?} db.schema.databases.list $[].name $[].id {!} databaseId 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (database = 'hello') => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_keyql_array_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Array 3 | * @param {array} query 4 | * @ {object.keyql.query} keyqlquery {?} ["name", "age"] 5 | * @returns {boolean} 6 | */ 7 | module.exports = async (query = [{"last_name__is": "john"}]) => { 8 | return true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_keyql_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Array 3 | * @param {object.keyql.query} query {?} ["name", "age"] 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (query = {"last_name__is": "john"}) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_options_type.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Type 3 | * @param {object} keys {?} [{}] 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (keys) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_origin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an invalid origin 3 | * @origin *.autocode.com 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_origin_asterisk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an invalid origin 3 | * @origin * 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_origin_bad_protocol.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an invalid origin 3 | * @origin file://www.autocode.com 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_origin_env_invalid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an invalid origin 3 | * @origin =CASE_ORIGIN_INVALID 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_origin_env_invalid_no_var.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an invalid origin 3 | * @origin =process.env.CASE_ORIGIN_INVALID 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_parameter_count_mismatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @returns {string} 5 | */ 6 | module.exports = function(a, b, context, callback) {}; 7 | // invalid, if one parameter commented, all parameters must exist 8 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_parameter_mismatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {number} b beta 5 | * @returns {string} 6 | */ 7 | module.exports = function(a = 'hi', b = 'hello', context, callback) {}; 8 | // invalid, default value mismatch 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_parameter_mismatch_integer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {integer} b beta 5 | * @returns {string} 6 | */ 7 | module.exports = function(a = 'hi', b = 47.2, context, callback) {}; 8 | // invalid, 47.2 not an integer 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_parameter_not.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {number} b beta 5 | * @returns {string} 6 | */ 7 | module.exports = async (a = 'hi', b = !7, context) => { 8 | // valid, negative number 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_parameter_not_not.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {number} b beta 5 | * @returns {string} 6 | */ 7 | module.exports = async (a = 'hi', b = !!7, context) => { 8 | // valid, negative number 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_parameter_reserved_name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid param - reserved name 3 | * @param {string} _stream 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (_stream, context) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Test Schema 3 | * @param {object} obj 4 | * @ {string} name 5 | * @ {object} data 6 | * @ {string} a 7 | * @ {string} WRONG 8 | * @ {number} timestamp 9 | * @param {string} after 10 | * @returns {string} 11 | */ 12 | module.exports = async (obj, after) => { 13 | 14 | return 'hello'; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_stream_no_name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid stream - no name 3 | * @stream {string} 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (context) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_invalid_stream_nonfriendly_name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid stream - nonfriendly name 3 | * @stream {string} ?stream 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (context) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_array_keyql_order_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid KeyQL Query with Options 3 | * @param {array} order 4 | * @ {object.keyql.order} orderEntry Order for keyql {?} ["status", "color", "goodbye"] 5 | * @returns {string} 6 | */ 7 | module.exports = async (order) => { 8 | return 'hello'; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_array_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid Test Array Schema 3 | * @param {array} arr 4 | * @ {string} name 5 | * @param {string} after 6 | * @returns {string} 7 | */ 8 | module.exports = async (arr, after) => { 9 | 10 | return 'hello'; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_background.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid background 3 | * @background 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'invalid acl entry'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_background_mode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid set background 3 | * @background params 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'invalid acl entry'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_blacklist.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a blacklist 3 | * @acl * 4 | * user_username faas_tester deny 5 | * user_username faas_tester2 deny 6 | * user_username faas_tester3 deny 7 | * @returns {string} 8 | */ 9 | module.exports = (callback) => { 10 | 11 | return callback(null, 'valid blacklist'); 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_charge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a charge 3 | * @charge 50 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'valid charge'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_commented_no_default_parameters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {number} b beta 5 | * @param {any} c gamma 6 | * @param {boolean} d delta 7 | * @param {object} e epsilon 8 | * @param {array} f zeta 9 | * @returns {string} 10 | */ 11 | module.exports = function(a, b, c, d, e, f, context, callback) {}; 12 | // valid, first parameter defined as string by comment 13 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_default_float.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {float} a alpha 4 | */ 5 | module.exports = function(a = 3.14, context, callback) {}; 6 | // valid 7 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_default_int_and_number_params.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {integer} a alpha 4 | * @param {number} b beta 5 | */ 6 | module.exports = function(a = 12, b = 342, context, callback) {}; 7 | // valid 8 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_default_parameters.js: -------------------------------------------------------------------------------- 1 | module.exports = function(a = 'string', b = 1, c = null, d = true, e = {}, f = [], context, callback) {}; 2 | // valid 3 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_definition_order.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with valid function definition order 3 | * @background empty 4 | * @charge 10 5 | * @acl * 6 | * user_username faas_tester deny 7 | * user_username faas_tester2 deny 8 | * user_username faas_tester3 deny 9 | * @param {string} test 10 | * @returns {string} 11 | */ 12 | module.exports = (test, callback) => { 13 | 14 | return callback(null, 'function with valid definition order'); 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_description_only.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function has a description 3 | */ 4 | module.exports = function(a = 'hi', b = null, context, callback) {}; 5 | // valid, parameters documented from default values 6 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_empty.js: -------------------------------------------------------------------------------- 1 | module.exports = function(context, callback) {}; 2 | // valid 3 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_empty_blacklist.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with an empty blacklist 3 | * @acl * 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'empty blacklist'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_empty_whitelist.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with an empty whitelist 3 | * @acl 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'empty whitelist'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_enum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid Enum 3 | * @param {any} before 4 | * @param {enum} day 5 | * ["sunday", 0] 6 | * ["monday", 0] 7 | * ["tuesday", 2] 8 | * ["wednesday", 3] 9 | * ["thursday", 4] 10 | * ["friday", 5] 11 | * ["saturday", 6] 12 | * @param {any} after 13 | * @returns {number} 14 | */ 15 | module.exports = async (before = null, day, after = null) => { 16 | return day; 17 | }; 18 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_enum_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Enum Default 3 | * @param {enum} basic some basic types 4 | * ["num", 0] 5 | * ["double", "1"] 6 | * ["float", 1.2] 7 | * ["numstr", "123"] 8 | * @returns {any} 9 | */ 10 | module.exports = async (basic = 'num') => { 11 | return basic; 12 | }; 13 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_has-hyphen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a hyphen 3 | * @returns {string} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, 'contains hyphen'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_inline.js: -------------------------------------------------------------------------------- 1 | return 'lol'; // valid 2 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_inline_addition.js: -------------------------------------------------------------------------------- 1 | // Valid inline function 2 | let a = 1; 3 | let b = 2; 4 | 5 | return a + b; 6 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_inline_await.js: -------------------------------------------------------------------------------- 1 | const sleep = t => new Promise(res => setTimeout(() => res(null), t)) 2 | await sleep(100); 3 | return `hello world`; 4 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_inline_context.js: -------------------------------------------------------------------------------- 1 | // Valid inline function 2 | console.log(context); 3 | 4 | return context.params; 5 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_inline_empty.js: -------------------------------------------------------------------------------- 1 | console.log('wat'); // valid 2 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_keyql_limit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid KeyQL Limit 3 | * @param {object.keyql.limit} limit Some limit {:} [2, 20] 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit = {count: 15, offset: 0}) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_keyql_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid KeyQL Query with Options 3 | * @param {object.keyql.query} query Query API based on these parameters {?} ["status", "hello", "goodbye"] 4 | * @returns {string} 5 | */ 6 | module.exports = async (query) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_keyql_order_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid KeyQL Query with Options 3 | * @param {object.keyql.order} order Order for keyql {?} ["status", "color", "goodbye"] 4 | * @returns {string} 5 | */ 6 | module.exports = async (order) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_multiline_param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a multiline param definition 3 | * @param {string} alpha Not the omega, 4 | * but the ____... 5 | * @returns {boolean} 6 | */ 7 | module.exports = async (alpha) => { 8 | 9 | return true; 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_multiple_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Accepts multiple schemas for an object 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {number} size 6 | * @ OR 7 | * @ {string} name2 8 | * @ {number} size2 9 | * @returns {object} 10 | */ 11 | module.exports = async (fileOrFolder) => { 12 | return true; 13 | }; 14 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_multiple_schema_nested.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Accepts multiple schemas for an object 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {number} size 6 | * @ OR 7 | * @ {string} name2 8 | * @ {number} size2 9 | * @ {object} props 10 | * @ {string} label 11 | * @ OR 12 | * @ {number} size 13 | * @returns {object} 14 | */ 15 | module.exports = async (fileOrFolder) => { 16 | return true; 17 | }; 18 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_multiple_schema_nested_returns.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Accepts multiple schemas for an object 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {number} size 6 | * @ OR 7 | * @ {string} name2 8 | * @ {number} size2 9 | * @ {object} props 10 | * @ {string} label 11 | * @ OR 12 | * @ {number} size 13 | * @returns {object} fileOrFolder 14 | * @ {string} name 15 | * @ {number} size 16 | * @ OR 17 | * @ {string} name2 18 | * @ {number} size2 19 | * @ {object} props 20 | * @ {string} label 21 | * @ OR 22 | * @ {number} size 23 | */ 24 | module.exports = async (fileOrFolder) => { 25 | return true; 26 | }; 27 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_named_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a named return value 3 | * @param {string} paramName And a param description 4 | * @returns {string} returnName And a return description 5 | */ 6 | module.exports = (paramName, callback) => { 7 | 8 | return callback(null, paramName); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_nested_enum_being_first_in_object_nested_in_arrays.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with nested enums being first fields inside objects nested in arrays 3 | * @param {?array} ruleSet The rules used to assign products to the collection. 4 | * @ {object} obj desc stuff 5 | * @ {enum} relation Specifies the relationship between the `column` and the condition. 6 | * ["CONTAINS", "CONTAINS"] 7 | * ["ENDS_WITH", "ENDS_WITH"] 8 | * ["EQUALS", "EQUALS"] 9 | * ["GREATER_THAN", "GREATER_THAN"] 10 | * ["IS_NOT_SET", "IS_NOT_SET"] 11 | * ["IS_SET", "IS_SET"] 12 | * ["LESS_THAN", "LESS_THAN"] 13 | * ["NOT_CONTAINS", "NOT_CONTAINS"] 14 | * ["NOT_EQUALS", "NOT_EQUALS"] 15 | * ["STARTS_WITH", "STARTS_WITH"] 16 | * @param {?array} ruleSet2 The rules used to assign products to the collection. 17 | * @ {object} obj desc stuff 18 | * @ {enum} relation Specifies the relationship between the `column` and the condition. 19 | * ["CONTAINS", "CONTAINS"] 20 | * ["ENDS_WITH", "ENDS_WITH"] 21 | * ["EQUALS", "EQUALS"] 22 | * ["GREATER_THAN", "GREATER_THAN"] 23 | * ["IS_NOT_SET", "IS_NOT_SET"] 24 | * ["IS_SET", "IS_SET"] 25 | * ["LESS_THAN", "LESS_THAN"] 26 | * ["NOT_CONTAINS", "NOT_CONTAINS"] 27 | * ["NOT_EQUALS", "NOT_EQUALS"] 28 | * ["STARTS_WITH", "STARTS_WITH"] 29 | * @ {boolean} appliedDisjunctively Whether products must match any 30 | * @param {?array} anotherArray The rules used to assign products to the collection. 31 | * @ {object} obj object desc 32 | * @ {array} arr arr desc 33 | * @ {object} obj2 obj2 desc 34 | * @ {enum} opts options 35 | * ["OPTION_ONE", "OPTION_ONE"] 36 | * ["OPTION_TWO", "OPTION_TWO"] 37 | * @ {object} obj3 obj3 desc 38 | * @ {any} id id desc 39 | * @ {array} arr2 Array description 40 | * @ {object} obj3 object desc 41 | * @ {enum} opt2 options2 42 | * ["OPTION_ONE", "OPTION_ONE"] 43 | * ["OPTION_TWO", "OPTION_TWO"] 44 | * @returns {any} result 45 | */ 46 | module.exports = async (ruleSet = null, ruleSet2 = null, anotherArray = null, context) => { 47 | 48 | return {}; 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_no_context.js: -------------------------------------------------------------------------------- 1 | module.exports = function(callback) {}; 2 | // valid, context not necessary 3 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_no_default_parameters.js: -------------------------------------------------------------------------------- 1 | module.exports = function(a, b, c, d, e, f, context, callback) {}; 2 | // Valid, first parameter can be "any" 3 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_object_spread.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with an empty blacklist 3 | * @returns {object} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | let obj = { 8 | akey: 'avalue' 9 | } 10 | 11 | let spreadObj = { 12 | ...obj, 13 | hey: 'o' 14 | }; 15 | 16 | return callback(null, spreadObj); 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_optional_param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with an optional param 3 | * @param {?string} name 4 | * @returns {string} 5 | */ 6 | module.exports = (name = null, callback) => { 7 | 8 | return callback(null, name || 'hello'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid Options 3 | * @param {string} database {?} db.schema.databases.list $[].name $[].id 4 | * @param {string} table {?} db.schema.databases.retrieve(databaseId=database) $[].name 5 | * @returns {boolean} 6 | */ 7 | module.exports = async (database = 'hello', table = 'wat') => { 8 | return true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_options_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid Options Array 3 | * @param {string} keys {?} ["a", "b", "c"] 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (keys) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_options_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid Options 3 | * @param {string} database {!} db.databaseId {?} db.schema.databases.list $[].name $[].id 4 | * @param {string} table {?} db.schema.databases.retrieve(databaseId=database) $[].name 5 | * @returns {boolean} 6 | */ 7 | module.exports = async (database = 'hello', table = 'wat') => { 8 | return true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_options_keyql_array_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Array 3 | * @param {array} query 4 | * @ {object.keyql.query} keyqlquery {?} ["name", "age"] 5 | * @returns {boolean} 6 | */ 7 | module.exports = async (query = [{"name__is": "john"}]) => { 8 | return true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_options_keyql_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Invalid Options Array 3 | * @param {object.keyql.query} query {?} ["name", "age"] 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (query = {"name__is": "john"}) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_origin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid origin 3 | * @origin autocode.com 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_origin_env_has_var.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an invalid origin 3 | * @origin =process.env.CASE_ORIGIN 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_origin_http_port_subdomain.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid origin 3 | * @origin http://x.y.z.localhost:8000 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_origin_https_port_subdomain.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid origin 3 | * @origin https://x.y.z.localhost:8000 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_origin_localhost.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid origin 3 | * @origin localhost 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_origin_port.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid origin 3 | * @origin localhost:8000 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_origin_port_subdomain.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function with an valid origin 3 | * @origin x.y.z.localhost:8000 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'origin'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_parameter_negative.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {number} b beta 5 | * @returns {string} 6 | */ 7 | module.exports = async (a = 'hi', b = -7, context) => { 8 | // valid, negative number 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_parameter_nullable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {number} b beta 5 | * @returns {string} 6 | */ 7 | module.exports = function(a = 'hi', b = null, context, callback) {}; 8 | // valid, all types are nullable 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_parameter_positive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} a alpha 4 | * @param {number} b beta 5 | * @returns {string} 6 | */ 7 | module.exports = async (a = 'hi', b = +7, context) => { 8 | // valid, negative number 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_parameter_reserved_name_nested.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid param - reserved name in subset 3 | * @param {object} myObject 4 | * @ {string} _stream 5 | * @returns {boolean} 6 | */ 7 | module.exports = async (myObject, context) => { 8 | return true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_special_parameter_names.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with parameters containing special characters 3 | * @returns {string} 4 | */ 5 | module.exports = ($good_param, good_param_, __good_param, ų̸͔̜̩͇͕̬͍̲̞̙͇͖͌̆̈͌̐̊̍n̴̨̨͇̗̬͕̠̱̫͌̃̉̇͝ͅì̴̢̨̨̱̬͎̖̼̻͌͆̄̉̋̇̉̐̿̚c̷̛͌̐͗̿͑͒̈́ͅo̸̧̘̘͕͖̮̙͂́͂̃͆͂̆͑͊̇̃͜͝d̸̢̻͔̹̦̰̼̤͇̣̘͎̒̌͐̏ͅe̵̡̢̦̥͖̯͂̽̽̅̎͋̑̓͋̐̅̕̚ͅ, callback) => { 6 | 7 | return callback(null, 'valid parameter name'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_stream.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid stream - has name 3 | * @stream {string} message 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (context) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_stream_with_name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid Streaming 3 | * @stream {string} hello Some description 4 | * @returns {boolean} 5 | */ 6 | module.exports = async (context) => { 7 | return true; 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_whitelist.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a whitelist 3 | * @acl 4 | * user_username faas_tester allow 5 | * user_username faas_tester2 allow 6 | * user_username faas_tester3 allow 7 | * @returns {string} 8 | */ 9 | module.exports = (callback) => { 10 | 11 | return callback(null, 'valid whitelist'); 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/files/cases/function_valid_zero_charge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a charge of 0 3 | * @charge 0 4 | * @returns {string} 5 | */ 6 | module.exports = (callback) => { 7 | 8 | return callback(null, 'valid charge'); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/cases/inline_valid_addition.js: -------------------------------------------------------------------------------- 1 | // Valid inline function 2 | let a = 1; 3 | let b = 2; 4 | 5 | return a + b; 6 | -------------------------------------------------------------------------------- /test/files/cases/inline_valid_context.js: -------------------------------------------------------------------------------- 1 | // Valid inline function 2 | console.log(context); 3 | 4 | return context.params; 5 | -------------------------------------------------------------------------------- /test/files/comprehensive/__main__.js: -------------------------------------------------------------------------------- 1 | module.exports = async function() {}; 2 | -------------------------------------------------------------------------------- /test/files/comprehensive/alternate_schemas.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides alternateSchemas 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {integer} size 6 | * @ OR 7 | * @ {string} name 8 | * @ {array} files 9 | * @ {object} options 10 | * @ {string} type 11 | * @ OR 12 | * @ {number} type 13 | * @returns {object} fileOrFolder 14 | * @ {string} name 15 | * @ {integer} size 16 | * @ OR 17 | * @ {string} name 18 | * @ {array} files 19 | * @ {object} options 20 | * @ {string} type 21 | * @ OR 22 | * @ {number} type 23 | */ 24 | module.exports = async (fileOrFolder) => { 25 | 26 | return {name: 'hello', size: 100}; 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /test/files/comprehensive/default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test default parameters 3 | * @param {string} name A name 4 | * @param {object} obj An object 5 | * @returns {string} 6 | */ 7 | module.exports = (name = 'hello', obj = {result: {"a-string-key": 1, 1: 'one'}}, context, callback) => { 8 | return callback(null, 'Hello world'); 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/comprehensive/default_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {?string} a 3 | * @returns {?string} 4 | */ 5 | module.exports = async (a = null) => { 6 | return a; 7 | }; 8 | -------------------------------------------------------------------------------- /test/files/comprehensive/dir/404.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 404 fn 3 | * @param {string} notfound 4 | */ 5 | module.exports = async (notfound) => { 6 | return 'wat'; 7 | }; -------------------------------------------------------------------------------- /test/files/comprehensive/dir/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * indexed fn 3 | * @param {string} indexed 4 | */ 5 | module.exports = async (indexed) => { 6 | return 'wat'; 7 | }; -------------------------------------------------------------------------------- /test/files/comprehensive/dir/sub/__main__.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test function 3 | * @keys TEST_KEY TEST_KEY2 4 | * @charge 19 5 | * @param {Boolean} a alpha 6 | * @param {String} b beta 7 | * @param {Number} c gamma 8 | * @param {Any} d delta 9 | * @param {Array} e epsilon 10 | * @param {Object} f zeta 11 | * @returns {Boolean} returnName A return description! 12 | */ 13 | module.exports = async function( 14 | a = true, 15 | b = 'false', 16 | c = 1, 17 | d = null, 18 | e = [1, 2, 3, {four: 'five'}], 19 | f = {one: 'two', three: [4, 5]} 20 | ) {}; 21 | -------------------------------------------------------------------------------- /test/files/comprehensive/dir/sub/test.js: -------------------------------------------------------------------------------- 1 | module.exports = function(context, callback) {}; 2 | -------------------------------------------------------------------------------- /test/files/comprehensive/dir/test.js: -------------------------------------------------------------------------------- 1 | module.exports = async function(a = true, b = 'false', c = 1, d = null, e = [], f = {}, context) {}; 2 | -------------------------------------------------------------------------------- /test/files/comprehensive/enum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Enum 3 | * @param {any} before 4 | * @param {enum} basic some basic types 5 | * ["num", 0] 6 | * ["double", "1"] 7 | * ["float", 1.2] 8 | * ["numstr", "123"] 9 | * @param {any} after 10 | * @returns {any} 11 | */ 12 | module.exports = async (before = null, basic, after = null) => { 13 | return basic; 14 | }; 15 | -------------------------------------------------------------------------------- /test/files/comprehensive/enum_nested.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Nested Enum 3 | * @param {object} obj 4 | * @ {string} selector The selector to query 5 | * @ {enum} operator Which data to retrieve: can be "text", "html" or "attr" 6 | * ["text", "text"] 7 | * ["html", "html"] 8 | * ["attr", "attr"] 9 | * @ {?string} attr If method is "attr", which attribute to retrieve 10 | * @param {array} arr 11 | * @ {object} obj 12 | * @ {string} selector The selector to query 13 | * @ {enum} operator Which data to retrieve: can be "text", "html" or "attr" 14 | * ["text", "text"] 15 | * ["html", "html"] 16 | * ["attr", "attr"] 17 | * @ {?string} attr If method is "attr", which attribute to retrieve 18 | * @param {object} obj2 19 | * @ {enum} operator Which data to retrieve: can be "text", "html" or "attr" 20 | * ["text", "text"] 21 | * ["html", "html"] 22 | * ["attr", "attr"] 23 | * @ {string} selector The selector to query 24 | * @ {?string} attr If method is "attr", which attribute to retrieve 25 | * @param {array} arr2 26 | * @ {object} obj 27 | * @ {enum} operator Which data to retrieve: can be "text", "html" or "attr" 28 | * ["text", "text"] 29 | * ["html", "html"] 30 | * ["attr", "attr"] 31 | * @ {string} selector The selector to query 32 | * @ {?string} attr If method is "attr", which attribute to retrieve 33 | * @returns {boolean} myBool A boolean value 34 | */ 35 | module.exports = async (obj, arr, obj2, arr2, context) => { 36 | return obj.operator; 37 | }; 38 | -------------------------------------------------------------------------------- /test/files/comprehensive/enum_nested_optional.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Optional Nested Enum 3 | * @param {?string} descriptionHtml The description of the product, complete with HTML formatting. 4 | * @param {?array} metafields The metafields to associate with this product. 5 | * @ {object} MetafieldInput Specifies the input fields for a metafield. 6 | * @ {?string} value The value of a metafield. 7 | * @ {?enum} valueType Metafield value types. 8 | * ["STRING", "STRING"] 9 | * ["INTEGER", "INTEGER"] 10 | * ["JSON_STRING", "JSON_STRING"] 11 | * @param {?array} privateMetafields The private metafields to associated with this product. 12 | * @ {object} PrivateMetafieldInput Specifies the input fields for a PrivateMetafield. 13 | * @ {?any} owner The owning resource. 14 | * @ {object} valueInput The value and value type of the metafield, wrapped in a ValueInput object. 15 | * @ {string} value The value of a private metafield. 16 | * @ {enum} valueType Private Metafield value types. 17 | * ["STRING", "STRING"] 18 | * ["INTEGER", "INTEGER"] 19 | * ["JSON_STRING", "JSON_STRING"] 20 | * @param {?array} variants A list of variants associated with the product. 21 | * @ {object} ProductVariantInput Specifies a product variant to create or update. 22 | * @ {?string} barcode The value of the barcode associated with the product. 23 | * @ {?enum} inventoryPolicy The inventory policy for a product variant controls whether customers can continue to buy the variant when it is out of stock. When the value is `continue`, customers are able to buy the variant when it's out of stock. When the value is `deny`, customers can't buy the variant when it's out of stock. 24 | * ["DENY", "DENY"] 25 | * ["CONTINUE", "CONTINUE"] 26 | * @ {?array} metafields Additional customizable information about the product variant. 27 | * @ {object} MetafieldInput Specifies the input fields for a metafield. 28 | * @ {?string} description The description of the metafield . 29 | * @ {?enum} valueType Metafield value types. 30 | * ["STRING", "STRING"] 31 | * ["INTEGER", "INTEGER"] 32 | * ["JSON_STRING", "JSON_STRING"] 33 | * @ {?array} privateMetafields The private metafields to associated with this product. 34 | * @ {object} PrivateMetafieldInput Specifies the input fields for a PrivateMetafield. 35 | * @ {?any} owner The owning resource. 36 | * @ {object} valueInput The value and value type of the metafield, wrapped in a ValueInput object. 37 | * @ {string} value The value of a private metafield. 38 | * @ {enum} valueType Private Metafield value types. 39 | * ["STRING", "STRING"] 40 | * ["INTEGER", "INTEGER"] 41 | * ["JSON_STRING", "JSON_STRING"] 42 | * @ {?string} taxCode The tax code associated with the variant. 43 | * @ {?enum} weightUnit Units of measurement for weight. 44 | * ["KILOGRAMS", "KILOGRAMS"] 45 | * ["GRAMS", "GRAMS"] 46 | * ["POUNDS", "POUNDS"] 47 | * ["OUNCES", "OUNCES"] 48 | * @param {?array} media List of new media to be added to the product. 49 | * @ {object} CreateMediaInput Specifies the input fields required to create a media object. 50 | * @ {string} originalSource The original source of the media object. May be an external URL or signed upload URL. 51 | * @ {enum} mediaContentType The possible content types for a media object. 52 | * ["VIDEO", "VIDEO"] 53 | * ["EXTERNAL_VIDEO", "EXTERNAL_VIDEO"] 54 | * ["MODEL_3D", "MODEL_3D"] 55 | * ["IMAGE", "IMAGE"] 56 | * @returns {boolean} myBool A boolean value 57 | */ 58 | module.exports = async (descriptionHtml = null, metafields = null, privateMetafields = null, variants = null, media = null, context) => { 59 | return obj.operator; 60 | }; 61 | -------------------------------------------------------------------------------- /test/files/comprehensive/enum_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Enum Returns 3 | * @param {?string} a 4 | * @param {?string} b 5 | * @returns {enum} either a or b 6 | * ["a", 0] 7 | * ["b", 1] 8 | */ 9 | module.exports = async (a = null, b = null, context) => { 10 | return a || b; 11 | }; 12 | -------------------------------------------------------------------------------- /test/files/comprehensive/enum_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} before a param 3 | * @param {object} valueRange The data to be inserted 4 | * @ {string} range 5 | * @ {enum} majorDimension 6 | * ["ROWS", "ROWS"] 7 | * ["COLUMNS", "COLUMNS"] 8 | * @ {array} values An array of arrays, the outer array representing all the data and each inner array representing a major dimension. Each item in the inner array corresponds with one cell 9 | * @param {string} after a param 10 | * @returns {any} 11 | */ 12 | module.exports = async (before, valueRange, after, context) => { 13 | return valueRange; 14 | }; 15 | -------------------------------------------------------------------------------- /test/files/comprehensive/esdoc_support.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} alpha 4 | * @param {object} beta 5 | * @param {number} beta.num 6 | * @param {object} beta.obj 7 | * @param {number{1,100}} beta.obj.num 8 | * @param {number{1.1,2.1}} beta.obj.float 9 | * @param {string{2..7}} beta.obj.str 10 | * @param {array>{1..3}} gamma 11 | * @param {boolean|string} boolstring 12 | * @param {array{5}|"jazzhands"|5.9|boolean} mystery 13 | * @param {number|"hello"|"goodbye"} hg 14 | * @param {string[]} a1 15 | * @param {buffer[5][2..7]} a2 16 | * @returns {object} response 17 | * @returns {number} response.a 18 | * @returns {object} response.b 19 | * @returns {string} response.b.c 20 | */ 21 | export default async (alpha, beta, gamma, boolstring, mystery, hg = 5.2, a1, a2) => { 22 | 23 | return { 24 | alpha, 25 | beta, 26 | gamma, 27 | boolstring, 28 | mystery, 29 | hg, 30 | a1, 31 | a2 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /test/files/comprehensive/esm_default.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Repeats a phrase 3 | * @param {string} str 4 | * @param {integer} repeat 5 | * @returns {string} 6 | */ 7 | export default async (str, repeat) => { 8 | 9 | return str.repeat(repeat); 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/files/comprehensive/esm_named.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Repeats a phrase 3 | * @param {string} str 4 | * @param {integer} repeat 5 | * @returns {string} 6 | */ 7 | export async function GET (str, repeat) { 8 | 9 | return str.repeat(repeat); 10 | 11 | }; 12 | 13 | /** 14 | * Repeats a phrase backwards 15 | * @param {string} str 16 | * @param {integer} repeat 17 | * @returns {string} 18 | */ 19 | export async function POST (str, repeat) { 20 | 21 | return str.split('').reverse().join('').repeat(repeat); 22 | 23 | }; 24 | 25 | /** 26 | * Outputs a phrase once 27 | * @param {string} str 28 | * @returns {string} 29 | */ 30 | export const PUT = async (str) => { 31 | 32 | return str; 33 | 34 | }; 35 | 36 | /** 37 | * Outputs a phrase once backwards 38 | * @param {string} str 39 | * @returns {string} 40 | */ 41 | export const DELETE = async (str) => { 42 | 43 | return str.split('').reverse().join(''); 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /test/files/comprehensive/inline.js: -------------------------------------------------------------------------------- 1 | return context.params; 2 | -------------------------------------------------------------------------------- /test/files/comprehensive/keyql_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid KeyQL Query with Options 3 | * @param {object.keyql.query} query Query API based on these parameters {?} ["status", "hello", "goodbye"] 4 | * @param {object.keyql.query} query2 Query API based on these parameters {?} db.schema.database.fields $.fields[].name $.fields[].id 5 | * @param {array} keyqlquery 6 | * @ {object.keyql.query} queryobj Query API based on these parameters {?} ["status", "hello", "goodbye"] 7 | * @returns {string} 8 | */ 9 | module.exports = async (query, query2, keyqlquery) => { 10 | return 'hello'; 11 | }; 12 | -------------------------------------------------------------------------------- /test/files/comprehensive/multiline_description.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test multi line descriptions 3 | * This is a second line 4 | * This is a third line 5 | * 6 | * This is a fourth line 7 | * 8 | * @param {number} alpha a number 9 | * @returns {any} 10 | */ 11 | module.exports = (alpha = null, callback) => { 12 | return callback(null, 'hello world'); 13 | }; 14 | -------------------------------------------------------------------------------- /test/files/comprehensive/named_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function with a named return value 3 | * @param {string} paramName And a param description 4 | * @returns {string} returnName And a return description 5 | */ 6 | module.exports = (paramName, callback) => { 7 | 8 | return callback(null, paramName); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/files/comprehensive/noname_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {buffer} 3 | */ 4 | module.exports = (a = 2, b = 4, c = 6, callback) => { 5 | 6 | return callback(null, Buffer.from('hello')); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/comprehensive/nullable_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {?string} a 3 | * @returns {?string} maybestring not sure 4 | */ 5 | module.exports = async (a = null) => { 6 | return a; 7 | }; 8 | -------------------------------------------------------------------------------- /test/files/comprehensive/options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Populate options properly 3 | * @param {string} database A database {!} db.databaseId {?} db.schema.databases.list $[].name $[].id 4 | * @param {string} table A table {?} db.schema.databases.retrieve(databaseId=database) $[].name 5 | * @returns {boolean} bool a Boolean? 6 | */ 7 | module.exports = async (database = 'hello', table = 'wat') => { 8 | return true; 9 | }; 10 | -------------------------------------------------------------------------------- /test/files/comprehensive/returns.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {number} name hello 3 | */ 4 | module.exports = (a = 2, b = 4, c = 6, callback) => { 5 | 6 | return callback(null, 1); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/files/comprehensive/schema/array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Array Schema Input 3 | * @param {array} arr1 4 | * @ {string} str 5 | * @param {array} arr2 6 | * @ {object} obj 7 | * @ {string} str 8 | * @ {object} obj 9 | * @ {string} str 10 | * @returns {string} 11 | */ 12 | module.exports = async (arr1, arr2) => { 13 | 14 | return 'hello'; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/files/comprehensive/schema/basic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Schema Input 3 | * @param {string} before 4 | * @param {object} obj 5 | * @ {string} name 6 | * @ {boolean} enabled 7 | * @ {object} data 8 | * @ {string} a 9 | * @ {string} b 10 | * @ {number} timestamp 11 | * @param {string} after 12 | * @returns {string} 13 | */ 14 | module.exports = async (before, obj, after) => { 15 | 16 | return 'hello'; 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /test/files/comprehensive/schema/nested.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Nested Schema Input 3 | * @param {string} before 4 | * @param {object} obj 5 | * @ {string} str 6 | * @ {boolean} bool 7 | * @ {object} obj 8 | * @ {string} str 9 | * @ {object} obj 10 | * @ {string} str 11 | * @ {number} num 12 | * @param {string} after 13 | * @returns {string} 14 | */ 15 | module.exports = async (before, obj, after) => { 16 | 17 | return 'hello'; 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /test/files/comprehensive/schema/optional.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Optional Schema Input 3 | * @param {?string} before 4 | * @param {object} obj 5 | * @ {?string} name 6 | * @ {?boolean} enabled 7 | * @ {object} data 8 | * @ {?string} a 9 | * @ {string} b 10 | * @ {number} timestamp 11 | * @param {string} after 12 | * @returns {string} 13 | */ 14 | module.exports = async (before = null, obj, after) => { 15 | 16 | return 'hello'; 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /test/files/comprehensive/test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test function 3 | * @charge 0 4 | * @param {Boolean} a alpha 5 | * @returns {Boolean} 6 | */ 7 | module.exports = async function(a, context) {}; 8 | -------------------------------------------------------------------------------- /test/files/ignore/.func.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instant-dev/api/a9efc6630afeea301a363d2102206f6735a77a93/test/files/ignore/.func.swp -------------------------------------------------------------------------------- /test/files/ignore/__main__.js: -------------------------------------------------------------------------------- 1 | module.exports = async function() {}; 2 | -------------------------------------------------------------------------------- /test/files/ignore/dir/._test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instant-dev/api/a9efc6630afeea301a363d2102206f6735a77a93/test/files/ignore/dir/._test.js -------------------------------------------------------------------------------- /test/files/ignore/ignoreme.js: -------------------------------------------------------------------------------- 1 | module.exports = async function() {}; 2 | -------------------------------------------------------------------------------- /test/gateway/functions/a_standard_function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Nothing special about this function 3 | */ 4 | module.exports = async () => { 5 | return true; 6 | }; 7 | -------------------------------------------------------------------------------- /test/gateway/functions/bg/__main__.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @background 3 | * @returns {string} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, 'hello world'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/bg/empty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @background empty 3 | * @returns {string} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, 'hello world'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/bg/info.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @background info 3 | * @returns {string} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, 'hello world'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/bg/params.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @background params 3 | * @returns {string} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, 'hello world'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/bg/paramsSpecific1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Comment for the function is here 3 | * @background params 4 | * data 5 | * @returns {string} 6 | */ 7 | module.exports = (callback) => { 8 | 9 | return callback(null, 'hello world'); 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/gateway/functions/bg/paramsSpecific2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @background params data otherdata 3 | * @returns {string} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, 'hello world'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/bg/paramsSpecific3.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @background params data 3 | * @returns {string} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, 'hello world'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_any_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} response 3 | */ 4 | module.exports = async () => { 5 | return {_base64: Buffer.from('lol').toString('base64')}; 6 | }; 7 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_mocked_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {buffer} response 3 | */ 4 | module.exports = async () => { 5 | return {_base64: Buffer.from('lol').toString('base64')}; 6 | }; 7 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_nested_any_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {object} response 3 | * @ {any} body 4 | * @ {object} test 5 | */ 6 | module.exports = async () => { 7 | return { 8 | body: { 9 | _base64: Buffer.from('lol').toString('base64') 10 | }, 11 | test: { 12 | deep: [ 13 | 0, 14 | { 15 | _base64: Buffer.from('wat').toString('base64') 16 | }, 17 | 2 18 | ] 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_nested_mocked_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {object} response 3 | * @ {buffer} body 4 | * @ {object} test 5 | */ 6 | module.exports = async () => { 7 | return { 8 | body: { 9 | _base64: Buffer.from('lol').toString('base64') 10 | }, 11 | test: { 12 | deep: [ 13 | 0, 14 | { 15 | _base64: Buffer.from('wat').toString('base64') 16 | }, 17 | 2 18 | ] 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_nested_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {object} response 3 | * @ {buffer} body 4 | * @ {object} test 5 | */ 6 | module.exports = async () => { 7 | return { 8 | body: Buffer.from('lol'), 9 | test: { 10 | deep: [ 11 | 0, 12 | Buffer.from('wat'), 13 | 2 14 | ] 15 | } 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_reflect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {buffer} bufferParam 3 | * @returns {buffer} mybuf 4 | */ 5 | module.exports = async (bufferParam) => { 6 | return bufferParam; 7 | }; 8 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {buffer} mybuf 3 | */ 4 | module.exports = async () => { 5 | return Buffer.from('lol'); 6 | }; 7 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_return_content_type.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @stream {string} hello 3 | * @returns {buffer} mybuf 4 | */ 5 | module.exports = async (context) => { 6 | let buffer = Buffer.from('lol'); 7 | context.stream('hello', 'world'); 8 | buffer.contentType = 'image/png'; 9 | return buffer; 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_within_array_param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {array} arrayParam 3 | * @ {buffer} bufferItem 4 | */ 5 | module.exports = async (arrayParam) => { 6 | if (!arrayParam.length) { 7 | throw new Error('No array items provided'); 8 | } 9 | if (!Buffer.isBuffer(arrayParam[0])) { 10 | throw new Error('The parsed value of the array parameter\'s item is not a buffer'); 11 | } 12 | return 'ok'; 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/buffer_within_object_param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {object} objectParam 3 | * @ {buffer} bufferVal 4 | */ 5 | module.exports = async (objectParam) => { 6 | if (!Buffer.isBuffer(objectParam.bufferVal)) { 7 | throw new Error('The parsed value of the object parameter\'s "bufferVal" key is not a buffer'); 8 | } 9 | return 'ok'; 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/context.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the context object 3 | * @returns {object} 4 | */ 5 | module.exports = async (context) => { 6 | 7 | return context; 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/context/basic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Error on platform keys 3 | */ 4 | module.exports = async (context) => { 5 | 6 | const value = context.platform.ui('hello').key('cool'); 7 | 8 | return { key: value }; 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/context/keychain.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Error on keychain keys 3 | */ 4 | module.exports = async (context) => { 5 | 6 | const value = context.keychain.key('hello'); 7 | 8 | return { key: value }; 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/empty/__main__.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {integer} intValue 3 | * @returns {string} 4 | */ 5 | module.exports = (intValue, callback) => { 6 | 7 | return callback(null, 'hello world'); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/enum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Enum 3 | * @param {enum} day the day of the week 4 | * ["sunday", 0] 5 | * ["monday", "0"] 6 | * ["tuesday", {"a": 1, "b": 2}] 7 | * ["wednesday", 3] 8 | * ["thursday", [1,2,3]] 9 | * ["friday", 5.4321] 10 | * ["saturday", 6] 11 | * @returns {any} 12 | */ 13 | module.exports = async day => { 14 | return day; 15 | }; 16 | -------------------------------------------------------------------------------- /test/gateway/functions/enum_context.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Enum 3 | * @param {enum} thingA 4 | * ["a", 0] 5 | * ["b", {"c": 1, "d": [1, 2, 3]}] 6 | * ["c", "4"] 7 | * ["d", 5.4321] 8 | * @returns {object} 9 | */ 10 | module.exports = async (thingA, context) => { 11 | return context.function.enums.thingA; 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/enum_default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Enum 3 | * @param {enum} thing 4 | * ["a", 0] 5 | * ["b", 1] 6 | * @returns {number} 7 | */ 8 | module.exports = async (thing = 'a') => { 9 | return thing; 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/enum_null.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Null Enum 3 | * @param {enum} thing 4 | * ["a", 0] 5 | * ["b", 1] 6 | * @returns {any} 7 | */ 8 | module.exports = async (thing = null) => { 9 | return thing; 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/enum_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Enum Returns 3 | * @param {?string} a 4 | * @param {?string} b 5 | * @returns {enum} either a or b 6 | * ["a", 0] 7 | * ["b", [1, 2, 3]] 8 | */ 9 | module.exports = async (a = null, b = null, context) => { 10 | if (a) { 11 | return a; 12 | } 13 | if (b) { 14 | return b; 15 | } 16 | return 'not correct'; 17 | }; 18 | -------------------------------------------------------------------------------- /test/gateway/functions/enum_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} before a param 3 | * @param {object} valueRange The data to be inserted 4 | * @ {string} range 5 | * @ {enum} majorDimension 6 | * ["ROWS", "ROWS"] 7 | * ["COLUMNS", "COLUMNS"] 8 | * @ {array} values An array of arrays, the outer array representing all the data and each inner array representing a major dimension. Each item in the inner array corresponds with one cell 9 | * @param {string} after a param 10 | * @returns {any} 11 | */ 12 | module.exports = async (before, valueRange, after, context) => { 13 | return valueRange; 14 | }; 15 | -------------------------------------------------------------------------------- /test/gateway/functions/esm/alternate_types.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Accept a boolean or a string 3 | * @param {boolean|string} value 4 | */ 5 | export default async (value) => { 6 | 7 | return {value}; 8 | 9 | } -------------------------------------------------------------------------------- /test/gateway/functions/esm/any_options.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Get any value from list of options 3 | * @param {any} value {?} [1, "two", ["three", "four"]] 4 | */ 5 | export default async (value) => { 6 | 7 | return value; 8 | 9 | } -------------------------------------------------------------------------------- /test/gateway/functions/esm/boolean_or_custom_string.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Accept a boolean or a specific string 3 | * @param {boolean|"hello"} value 4 | */ 5 | export default async (value) => { 6 | 7 | return {value}; 8 | 9 | } -------------------------------------------------------------------------------- /test/gateway/functions/esm/default.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Repeats a phrase 3 | * @param {string} str 4 | * @param {integer} repeat 5 | * @returns {string} 6 | */ 7 | export default async (str, repeat) => { 8 | 9 | return str.repeat(repeat); 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/gateway/functions/esm/left_range.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Restricts to a specific range 3 | * @param {integer{1,}} myval 4 | */ 5 | export default async (myval) => { 6 | 7 | return {myval}; 8 | 9 | } -------------------------------------------------------------------------------- /test/gateway/functions/esm/missing_method.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Repeats a phrase 3 | * @param {string} str 4 | * @param {integer} repeat 5 | * @returns {string} 6 | */ 7 | export async function GET (str, repeat) { 8 | 9 | return str.repeat(repeat); 10 | 11 | }; 12 | 13 | /** 14 | * Repeats a phrase backwards 15 | * @param {string} str 16 | * @param {integer} repeat 17 | * @returns {string} 18 | */ 19 | export async function POST (str, repeat) { 20 | 21 | return str.split('').reverse().join('').repeat(repeat); 22 | 23 | }; 24 | -------------------------------------------------------------------------------- /test/gateway/functions/esm/named.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Repeats a phrase 3 | * @param {string} str 4 | * @param {integer} repeat 5 | * @returns {string} 6 | */ 7 | export async function GET (str, repeat) { 8 | 9 | return str.repeat(repeat); 10 | 11 | }; 12 | 13 | /** 14 | * Repeats a phrase backwards 15 | * @param {string} str 16 | * @param {integer} repeat 17 | * @returns {string} 18 | */ 19 | export async function POST (str, repeat) { 20 | 21 | return str.split('').reverse().join('').repeat(repeat); 22 | 23 | }; 24 | 25 | /** 26 | * Outputs a phrase once 27 | * @param {string} str 28 | * @returns {string} 29 | */ 30 | export const PUT = async (str) => { 31 | 32 | return str; 33 | 34 | }; 35 | 36 | /** 37 | * Outputs a phrase once backwards 38 | * @param {string} str 39 | * @returns {string} 40 | */ 41 | export const DELETE = async (str) => { 42 | 43 | return str.split('').reverse().join(''); 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /test/gateway/functions/esm/nested.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @param {string} alpha 4 | * @param {object} beta 5 | * @param {number} beta.num 6 | * @param {object} beta.obj 7 | * @param {number} beta.obj.num 8 | * @param {string} beta.obj.str 9 | * @param {array} gamma 10 | */ 11 | export default async (alpha, beta, gamma) => { 12 | 13 | return { 14 | alpha, 15 | beta, 16 | gamma 17 | }; 18 | 19 | } -------------------------------------------------------------------------------- /test/gateway/functions/esm/nested_top_level_array.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Top level array handling 3 | * @param {object[]} arr 4 | * @param {number} arr[].num 5 | * @param {object} arr[].obj 6 | * @param {number} arr[].obj.num 7 | * @param {string} arr[].obj.str 8 | */ 9 | export default async (arr) => { 10 | 11 | return {arr}; 12 | 13 | } -------------------------------------------------------------------------------- /test/gateway/functions/esm/right_range.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Restricts to a specific range 3 | * @param {integer{,1}} myval 4 | */ 5 | export default async (myval) => { 6 | 7 | return {myval}; 8 | 9 | } -------------------------------------------------------------------------------- /test/gateway/functions/esm/sizes.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Restricts to a specific size 3 | * @param {string{2..5}} mystr 4 | */ 5 | export default async (mystr) => { 6 | 7 | return {mystr}; 8 | 9 | } -------------------------------------------------------------------------------- /test/gateway/functions/giphy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Search GIFs by a string and rating 3 | * @param {string} query Search query term or phrase 4 | * @param {string} rating limit results to those rated (y,g, pg, pg-13 or r) 5 | * @returns {array} gifs The array of GIF objects 6 | * @ {object} gif 7 | * @ {object} images 8 | * @ {?object} user 9 | * @ {string} url 10 | */ 11 | module.exports = async (query, rating = null, context) => { 12 | return [ 13 | { 14 | type: 'gif', 15 | id: 'F3gda5icxL73i', 16 | slug: 'steve-statements-bisciotti-F3gda5icxL73i', 17 | url: 'https://giphy.com/gifs/steve-statements-bisciotti-F3gda5icxL73i', 18 | bitly_gif_url: 'https://gph.is/1UmeYf3', 19 | bitly_url: 'https://gph.is/1UmeYf3', 20 | embed_url: 'https://giphy.com/embed/F3gda5icxL73i', 21 | source: 22 | 'https://www.eonline.com/news/581612/the-7-most-cringe-inducing-statements-from-baltimore-ravens-owner-steve-bisciotti', 23 | rating: 'g', 24 | content_url: null, 25 | tags: null, 26 | featured_tags: null, 27 | user: null, 28 | images: { 29 | media_id: 'F3gda5icxL73i', 30 | preview_gif: { 31 | media_id: 'F3gda5icxL73i', 32 | rendition_type: 'preview_gif', 33 | url: 'https://media0.giphy.com/media/F3gda5icxL73i/giphy-preview.gif', 34 | width: '190', 35 | height: '82', 36 | size: '49486', 37 | frames: null, 38 | mp4: null, 39 | mp4_size: null, 40 | webp: null, 41 | webp_size: null 42 | } 43 | }, 44 | source_tld: 'www.eonline.com', 45 | source_post_url: null, 46 | update_datetime: null, 47 | create_datetime: null, 48 | import_datetime: '2015-08-05T02:59:29.000Z', 49 | trending_datetime: null, 50 | title: 'steve GIF' 51 | } 52 | ]; 53 | }; 54 | -------------------------------------------------------------------------------- /test/gateway/functions/headers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {Buffer} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | return callback(null, Buffer.from('abcdef'), {'Content-Type': 'text/html'}); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/http_body.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (context, callback) => { 5 | 6 | return callback(null, context.http.body); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/index.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My index function 3 | * @param {string} name 4 | * @returns {string} 5 | */ 6 | export default async function (name) { 7 | return `hello ${name} - INDEX`; 8 | } 9 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/await.js: -------------------------------------------------------------------------------- 1 | const sleep = t => new Promise(res => setTimeout(() => res(null), t)) 2 | await sleep(10); 3 | return `hello world`; 4 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/buffer.js: -------------------------------------------------------------------------------- 1 | let buffer = Buffer.from('lol'); 2 | buffer.contentType = 'text/html'; 3 | return buffer; 4 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/buffer_mock.js: -------------------------------------------------------------------------------- 1 | return {_base64: Buffer.from('lol').toString('base64')}; 2 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/context.js: -------------------------------------------------------------------------------- 1 | return context; 2 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/extended_http_is_object.js: -------------------------------------------------------------------------------- 1 | return { 2 | statusCode: 429, 3 | headers: {'Content-Type': 'text/html'}, 4 | body: 'lol', 5 | extend: true 6 | }; 7 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/http.js: -------------------------------------------------------------------------------- 1 | return { 2 | statusCode: 429, 3 | headers: {'Content-Type': 'text/html'}, 4 | body: Buffer.from('lol') 5 | }; 6 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/http_no_status.js: -------------------------------------------------------------------------------- 1 | return { 2 | headers: {'Content-Type': 'text/html'}, 3 | body: Buffer.from('lol') 4 | }; 5 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/number.js: -------------------------------------------------------------------------------- 1 | return 1988; 2 | -------------------------------------------------------------------------------- /test/gateway/functions/inline/require.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | return 'hello'; 4 | -------------------------------------------------------------------------------- /test/gateway/functions/keyql.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Optional Params 3 | * @param {object.keyql.query} query 4 | * @param {object.keyql.limit} limit 5 | * @param {object.keyql.order} order 6 | * @returns {string} 7 | */ 8 | module.exports = async (query, limit, order) => { 9 | return 'hello'; 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/keyql_limit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Optional Params 3 | * @param {object.keyql.limit} limit 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/keyql_limit_range.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Optional Params 3 | * @param {object.keyql.limit} limit {:} [2, 20] 4 | * @returns {string} 5 | */ 6 | module.exports = async (limit) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/keyql_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * KeyQL with only a set of keys 3 | * @param {object.keyql.query} query {?} ["alpha", "beta"] 4 | * @returns {string} 5 | */ 6 | module.exports = async (query) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/keyql_options_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * KeyQL with only a set of keys 3 | * @param {array} query 4 | * @ {object.keyql.query} queryObj {?} ["alpha", "beta"] 5 | * @returns {string} 6 | */ 7 | module.exports = async (query) => { 8 | return 'hello'; 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/keyql_order_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * KeyQL with only a set of keys 3 | * @param {object.keyql.order} order {?} ["alpha", "beta"] 4 | * @returns {string} 5 | */ 6 | module.exports = async (order) => { 7 | return 'hello'; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/keyql_order_options_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * KeyQL with only a set of keys 3 | * @param {array} order 4 | * @ {object.keyql.order} orderObj {?} ["alpha", "beta"] 5 | * @returns {string} 6 | */ 7 | module.exports = async (order) => { 8 | return 'hello'; 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/mismatch_params_deep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test param mismatch 3 | * @param {object} userData 4 | * @ {object} user 5 | * @ {array} posts 6 | * @ {object} post 7 | * @ {string} title 8 | * @ {array} messages 9 | * @ {string} 10 | */ 11 | module.exports = async (userData) => { 12 | return userData; 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/mismatch_returns_anon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test mismatch 3 | * @returns {object} 4 | * @ {object} user 5 | * @ {string} name 6 | */ 7 | module.exports = async () => { 8 | return { 9 | user: { 10 | name: 5 11 | } 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/mismatch_returns_anon_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test mismatch 3 | * @returns {object} 4 | * @ {object} user 5 | * @ {array} names 6 | * @ {string} name 7 | */ 8 | module.exports = async () => { 9 | return { 10 | user: { 11 | names: ['keith', 2] 12 | } 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /test/gateway/functions/mismatch_returns_deep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test mismatch 3 | * @returns {object} 4 | * @ {object} user 5 | * @ {array} posts 6 | * @ {object} post 7 | * @ {string} title 8 | * @ {array} messages 9 | * @ {string} 10 | */ 11 | module.exports = async () => { 12 | return { 13 | user: { 14 | posts: [ 15 | { 16 | title: 'sup', 17 | messages: ['hey', 'there', 7] 18 | } 19 | ] 20 | } 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /test/gateway/functions/mismatch_returns_named.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test mismatch 3 | * @returns {object} myObject 4 | * @ {object} user 5 | * @ {string} name 6 | */ 7 | module.exports = async () => { 8 | return { 9 | user: { 10 | name: 5 11 | } 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/mismatch_returns_named_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test mismatch 3 | * @returns {object} myObject 4 | * @ {object} user 5 | * @ {array} names 6 | * @ {string} name 7 | */ 8 | module.exports = async () => { 9 | return { 10 | user: { 11 | names: ['keith', 2] 12 | } 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /test/gateway/functions/my_esm_function.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My ESM function (GET) 3 | * @param {string} name 4 | * @returns {string} 5 | */ 6 | export async function GET (name) { 7 | return `hello ${name} - GET`; 8 | } 9 | 10 | /** 11 | * My ESM function (POST) 12 | * @param {string} name 13 | * @returns {string} 14 | */ 15 | export async function POST (name) { 16 | return `hello ${name} - POST`; 17 | } 18 | 19 | /** 20 | * My ESM function (PUT) 21 | * @param {string} name 22 | * @returns {string} 23 | */ 24 | export async function PUT (name) { 25 | return `hello ${name} - PUT`; 26 | } 27 | 28 | /** 29 | * My ESM function (DELETE) 30 | * @param {string} name 31 | * @returns {string} 32 | */ 33 | export async function DELETE (name) { 34 | return `hello ${name} - DELETE`; 35 | } 36 | -------------------------------------------------------------------------------- /test/gateway/functions/my_esm_function_default.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * My ESM function (DEFAULT) 3 | * @param {string} name 4 | * @returns {string} 5 | */ 6 | export default async function (name) { 7 | return `hello ${name} - DEFAULT`; 8 | } 9 | -------------------------------------------------------------------------------- /test/gateway/functions/my_function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function 3 | * @returns {number} 4 | */ 5 | module.exports = (a = 1, b = 2, c = 3, callback) => { 6 | 7 | if (c === 100) { 8 | return callback(null, 'hello value'); 9 | } 10 | 11 | return callback(null, a + b + c); 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/my_function_private.js: -------------------------------------------------------------------------------- 1 | /** 2 | * My function (private) 3 | * @private 4 | * @returns {number} 5 | */ 6 | module.exports = (a = 1, b = 2, c = 3, callback) => { 7 | 8 | if (c === 100) { 9 | return callback(null, 'hello value'); 10 | } 11 | 12 | return callback(null, a + b + c); 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /test/gateway/functions/my_function_test_parsing.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {object} 3 | */ 4 | module.exports = async (a = [], b = {}) => { 5 | 6 | return { 7 | a: a, 8 | b: b 9 | }; 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/gateway/functions/my_function_test_parsing_convert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {array} a 3 | * @ {?number} someNumber 4 | * @param {object} b 5 | * @ {?number} lol 6 | * @ {?string} wat 7 | * @returns {object} 8 | */ 9 | module.exports = async (a = [], b = {}) => { 10 | 11 | return { 12 | a: a, 13 | b: b 14 | }; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/gateway/functions/nonstandard/json.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test nonstandard JSON submissions 3 | * @returns {object} 4 | */ 5 | module.exports = async (a = 1, b = 2, c = 3, context) => { 6 | 7 | return context; 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/not_nullable_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {?string} a 3 | * @returns {string} 4 | */ 5 | module.exports = async (a = null) => { 6 | return a; 7 | }; 8 | -------------------------------------------------------------------------------- /test/gateway/functions/null_default_param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Optional Params 3 | * @param {string} name 4 | * @returns {string} 5 | */ 6 | module.exports = async (name = 'default') => { 7 | return name; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/nullable_return.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {?string} a 3 | * @returns {?string} 4 | */ 5 | module.exports = async (a = null) => { 6 | return a; 7 | }; 8 | -------------------------------------------------------------------------------- /test/gateway/functions/number_nullable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test nullability with numbers 3 | * @param {number} alpha a number 4 | * @param {number} beta a number 5 | * @returns {array} 6 | */ 7 | module.exports = (alpha = null, beta = null, callback) => { 8 | return callback(null, [alpha, beta]); 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/object_alternate_schema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides alternateSchemas 3 | * @param {object} fileOrFolder 4 | * @ {string} name 5 | * @ {integer} size 6 | * @ OR 7 | * @ {string} name 8 | * @ {array} files 9 | * @ {object} options 10 | * @ {string} type 11 | * @ OR 12 | * @ {number} type 13 | */ 14 | module.exports = async (fileOrFolder) => { 15 | return {}; 16 | }; 17 | -------------------------------------------------------------------------------- /test/gateway/functions/object_parsing.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} value a string value 3 | * @param {object} obj Should be an object 4 | * @returns {any} 5 | */ 6 | module.exports = (value = '', obj = null, callback) => { 7 | 8 | return callback(null, obj); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/object_tojson.js: -------------------------------------------------------------------------------- 1 | class MyClass { 2 | 3 | constructor (name = '?') { 4 | this.name = name; 5 | } 6 | 7 | toJSON () { 8 | return { 9 | name: this.name, 10 | description: this.constructor.name 11 | }; 12 | } 13 | 14 | } 15 | 16 | /** 17 | * @returns {any} 18 | */ 19 | module.exports = async () => { 20 | 21 | let obj = new MyClass('hello world'); 22 | 23 | return obj; 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /test/gateway/functions/optional_nested_schema_params.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Schema Input 3 | * @param {object} obj 4 | * @ {string} name 5 | * @ {?object} options 6 | * @ {?number} threads 7 | * @ {boolean} istest 8 | * @returns {any} 9 | */ 10 | module.exports = async (obj = null) => { 11 | 12 | return obj; 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /test/gateway/functions/optional_param_not_null.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Non-Null Optional Params 3 | * @param {?string} name 4 | * @returns {string} 5 | */ 6 | module.exports = async (name = 'default') => { 7 | 8 | return name; 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/optional_params.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Optional Params 3 | * @param {?string} name 4 | * @returns {string} 5 | */ 6 | module.exports = async (name = null) => { 7 | 8 | return name || 'hello'; 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/origin/allow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for origins 3 | * @origin autocode.com 4 | * @origin localhost:8000 5 | * @origin test.some-url.com:9999 6 | * @origin https://hello.com 7 | * @origin =process.env.ALLOWED_ORIGIN 8 | * @background 9 | * @param {string} alpha Some value 10 | * @stream {boolean} hello Some value 11 | */ 12 | module.exports = async (alpha, context) => { 13 | 14 | return true; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/gateway/functions/range_integer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test range 3 | * @param {integer} ranged {:} [1, 200] 4 | * @returns {any} 5 | */ 6 | module.exports = async (ranged) => { 7 | return ranged; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/range_number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test range 3 | * @param {number} ranged {:} [1.01, 199.9] 4 | * @returns {any} 5 | */ 6 | module.exports = async (ranged) => { 7 | return ranged; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/reflect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (context, callback) => { 5 | 6 | return callback(null, context.params); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/__main__.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback(new Error('error')); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback([1, 2, 3]); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/boolean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback(true); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/details.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | let error = new Error('error'); 7 | error.details = {objects: 'supported'}; 8 | callback(error); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/fatal.js: -------------------------------------------------------------------------------- 1 | // Cause a fatal error 2 | let x = {}; 3 | x.doAThing(); 4 | 5 | /** 6 | * @returns {any} 7 | */ 8 | module.exports = (callback) => { 9 | 10 | callback(null, 'fatal error should occur due to code above'); 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/fatal_no_stack.js: -------------------------------------------------------------------------------- 1 | // Cause a fatal error 2 | let error = new Error('stack removed'); 3 | delete error.stack; 4 | throw error; 5 | 6 | /** 7 | * @returns {any} 8 | */ 9 | module.exports = (callback) => { 10 | 11 | callback(null, 'fatal error should occur due to code above'); 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/largebuffer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {buffer} file 3 | * @returns {any} 4 | */ 5 | module.exports = (file, callback) => { 6 | 7 | callback(null, file.length); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback(1); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/object.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback({hey: 'you'}); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/promise_uncaught.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | new Promise((resolve, reject) => { 7 | reject(new Error('crap')); 8 | }).then(result => { 9 | return callback(null, result); 10 | }); 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/promise_unhandled_rejection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | Promise.resolve(null).then(() => { 7 | throw 'crap x2'; 8 | }); 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback('hello'); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/thrown.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | throw new Error('crap'); 7 | callback(new Error('error')); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/thrown_status.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | throw new Error('401: crap'); 7 | callback(new Error('error')); 8 | 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/runtime/timeout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {any} 3 | */ 4 | module.exports = async () => { 5 | return new Promise((resolve, reject) => { 6 | // Empty promise that never resolves 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/sanitize/http_object.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test httpObject return 3 | * @param {string} body Body value 4 | * @param {number} statusCode Status code 5 | * @param {any} headers Headers object 6 | * @returns {object.http} 7 | */ 8 | module.exports = (body = null, statusCode = null, headers = null, callback) => { 9 | 10 | let returnValue = {body: body}; 11 | if (statusCode !== null) { 12 | returnValue.statusCode = statusCode; 13 | } 14 | if (headers !== null) { 15 | returnValue.headers = headers; 16 | } 17 | 18 | return callback(null, returnValue); 19 | 20 | }; 21 | -------------------------------------------------------------------------------- /test/gateway/functions/sanitize/http_object_base64.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test httpObject return 3 | * @returns {object.http} 4 | */ 5 | module.exports = (callback) => { 6 | 7 | return callback(null, { 8 | body: {_base64: 'Zml4IGZvciBzdGV2ZW4='} 9 | }); 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/gateway/functions/sanitize/http_object_empty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test httpObject return 3 | * @returns {object.http} 4 | */ 5 | module.exports = (callback) => { 6 | return callback(null, {}); 7 | }; 8 | -------------------------------------------------------------------------------- /test/gateway/functions/sanitize/http_object_header_case.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test httpObject return 3 | * @param {string} contentType A content type 4 | * @returns {object.http} 5 | */ 6 | module.exports = (contentType = 'text/html', callback) => { 7 | 8 | return callback(null, { 9 | body: 'hello', 10 | headers: { 11 | 'Content-Type': contentType 12 | } 13 | }); 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /test/gateway/functions/sanitize/http_object_invalid_header_names.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test rejection of invalid header names 3 | * @param {string} contentType A content type 4 | * @returns {object.http} 5 | */ 6 | module.exports = (contentType = 'text/html', callback) => { 7 | 8 | return callback(null, { 9 | body: 'hello', 10 | headers: { 11 | 'Content-Type ': contentType, 12 | 'X Authorization Key': 'somevalue', 13 | ' AnotherHeader': 'somevalue', 14 | 'WeirdName!@#$%^&*()œ∑´®†¥¨ˆøπåß∂ƒ©˙∆˚¬≈ç√∫˜µ≤:|\{}🔥🔥🔥': 'test', 15 | 'MultilineName\n': 'test', 16 | 'Good-Header-Name': 'good value' 17 | } 18 | }); 19 | 20 | }; 21 | -------------------------------------------------------------------------------- /test/gateway/functions/sanitize/http_object_invalid_header_values.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test rejection of invalid header values 3 | * @param {string} contentType A content type 4 | * @returns {object.http} 5 | */ 6 | module.exports = (contentType = 'text/html', callback) => { 7 | 8 | return callback(null, { 9 | body: 'hello', 10 | headers: { 11 | 'Null-Value': null, 12 | 'Undefined-Value': undefined, 13 | 'Object-Value': { 14 | 'a': 'b' 15 | }, 16 | 'Number-Value': 0xdeadbeef, 17 | 'Boolean-Value': false, 18 | 'Empty-String-Value': '' 19 | } 20 | }); 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /test/gateway/functions/schema_optional_nested.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {object} enrichment The Enrichment data 3 | * @ {?object} person 4 | * @ {?string} id 5 | * @ {?object} name 6 | * @ {?string} givenName 7 | * @ {?string} familyName 8 | * @ {?string} fullName 9 | * @ {?string} location 10 | * @ {?string} timeZone 11 | * @ {?number} utcOffset 12 | * @ {?object} geo 13 | * @ {?string} city 14 | * @ {?string} state 15 | * @ {?string} country 16 | * @ {?float} lng 17 | * @ {?float} lat 18 | * @ {?string} bio 19 | * @ {?string} site 20 | * @ {?string} avatar 21 | * @ {?object} employment 22 | * @ {?string} name 23 | * @ {?string} title 24 | * @ {?string} role 25 | * @ {?string} subRole 26 | * @ {?string} seniority 27 | * @ {?string} domain 28 | * @ {?object} facebook 29 | * @ {?string} handle 30 | * @ {?object} github 31 | * @ {?number} id 32 | * @ {?string} handle 33 | * @ {?string} avatar 34 | * @ {?string} company 35 | * @ {?string} blog 36 | * @ {?string} followers 37 | * @ {?string} following 38 | * @ {?object} twitter 39 | * @ {?number} id 40 | * @ {?string} handle 41 | * @ {?string} location 42 | * @ {?number} followers 43 | * @ {?number} followers 44 | * @ {?string} site 45 | * @ {?string} statuses 46 | * @ {?string} favorites 47 | * @ {?string} avatar 48 | * @ {?object} linkedin 49 | * @ {?string} handle 50 | * @ {?object} googleplus 51 | * @ {?string} handle 52 | * @ {?object} gravatar 53 | * @ {?string} handle 54 | * @ {?array} urls 55 | * @ {?string} avatar 56 | * @ {?array} avatars 57 | * @ {?boolean} fuzzy 58 | * @ {?string} indexAt 59 | * @ {?object} company 60 | * @ {?string} id 61 | * @ {?string} name 62 | * @ {?string} legalName 63 | * @ {?string} domain 64 | * @ {?array} domainAliases 65 | * @ {?object} site 66 | * @ {?array} phoneNumbers 67 | * @ {?array} emailAddresses 68 | * @ {?array} tags 69 | * @ {?object} category 70 | * @ {?string} sector 71 | * @ {?string} industryGroup 72 | * @ {?string} industry 73 | * @ {?string} subIndustry 74 | * @ {?string} sicCode 75 | * @ {?string} naicsCode 76 | * @ {?string} description 77 | * @ {?number} foundedYear 78 | * @ {?string} location 79 | * @ {?string} timeZone 80 | * @ {?number} utcOffset 81 | * @ {?object} geo 82 | * @ {?string} streetNumber 83 | * @ {?string} streetName 84 | * @ {?string} subPremise 85 | * @ {?string} city 86 | * @ {?string} state 87 | * @ {?string} stateCode 88 | * @ {?string} postalCode 89 | * @ {?string} country 90 | * @ {?string} countryCode 91 | * @ {?number} lat 92 | * @ {?number} lng 93 | * @ {?object} identifiers 94 | * @ {?string} usEIN 95 | * @ {?object} metrics 96 | * @ {?number} rasied 97 | * @ {?number} alexaUsRank 98 | * @ {?number} alexaGlobalRank 99 | * @ {?number} employees 100 | * @ {?string} employeesRange 101 | * @ {?number} marketCap 102 | * @ {?number} annualRevenue 103 | * @ {?string} estimatedAnnualRevenue 104 | * @ {?number} fiscalYearEnd 105 | * @ {?object} facebook 106 | * @ {?string} handle 107 | * @ {?object} twitter 108 | * @ {?string} id 109 | * @ {?string} handle 110 | * @ {?string} location 111 | * @ {?number} followers 112 | * @ {?number} following 113 | * @ {?string} site 114 | * @ {?string} statuses 115 | * @ {?string} favorites 116 | * @ {?string} avatar 117 | * @ {?object} linkedin 118 | * @ {?string} handle 119 | * @ {?object} crunchbase 120 | * @ {?string} handle 121 | * @ {?string} logo 122 | * @ {?string} type 123 | * @ {?string} phone 124 | * @ {?array} tech 125 | * @ {?object} parent 126 | */ 127 | module.exports = async () => { 128 | return { 129 | person: { 130 | id: '30b42ed8-0bde-4b89-8ef3-d0d3d08af89f', 131 | name: { 132 | fullName: 'Steve Meyer', 133 | givenName: 'Steve', 134 | familyName: 'Meyer' 135 | }, 136 | email: 'steve@stdlib.com', 137 | location: null, 138 | timeZone: null, 139 | utcOffset: null, 140 | geo: { 141 | city: null, 142 | state: null, 143 | stateCode: null, 144 | country: null, 145 | countryCode: null, 146 | lat: null, 147 | lng: null 148 | }, 149 | bio: null, 150 | site: null, 151 | avatar: null, 152 | employment: { 153 | domain: 'stdlib.com', 154 | name: 'StdLib', 155 | title: null, 156 | role: null, 157 | subRole: null, 158 | seniority: null 159 | }, 160 | facebook: { handle: null }, 161 | github: { 162 | handle: null, 163 | id: null, 164 | avatar: null, 165 | company: null, 166 | blog: null, 167 | followers: null, 168 | following: null 169 | }, 170 | twitter: { 171 | handle: null, 172 | id: null, 173 | bio: null, 174 | followers: null, 175 | following: null, 176 | statuses: null, 177 | favorites: null, 178 | location: null, 179 | site: null, 180 | avatar: null 181 | }, 182 | linkedin: { handle: null }, 183 | googleplus: { handle: null }, 184 | gravatar: { handle: null, urls: null, avatar: null, avatars: [] }, 185 | fuzzy: false, 186 | emailProvider: false, 187 | indexedAt: '2019-02-27T10:43:02.308Z' 188 | }, 189 | company: { 190 | id: 'e7687ca2-ecd4-491f-8d64-5e304026906c', 191 | name: 'StdLib', 192 | legalName: null, 193 | domain: 'stdlib.com', 194 | domainAliases: ['code.xyz', 'standardlibrary.com'], 195 | site: { 196 | phoneNumbers: ['+1 415-650-1337', '+1 800-778-7879', '+1 800-952-5210'], 197 | emailAddresses: [] 198 | }, 199 | category: { 200 | sector: 'Information Technology', 201 | industryGroup: 'Software & Services', 202 | industry: 'Internet Software & Services', 203 | subIndustry: 'Internet Software & Services', 204 | sicCode: '73', 205 | naicsCode: '54' 206 | }, 207 | tags: ['Technology', 'Information Technology & Services', 'SAAS', 'B2B'], 208 | description: 209 | 'Build the business-critical integrations and APIs you want in minutes instead of days. Intelligent enough for you, powerful enough for your engineering team. Join tens of thousands building on Standard Library today.', 210 | foundedYear: null, 211 | location: '2390 30th Ave, San Francisco, CA 94116, USA', 212 | timeZone: 'America/Los_Angeles', 213 | utcOffset: -7, 214 | geo: { 215 | streetNumber: '2390', 216 | streetName: '30th Avenue', 217 | subPremise: null, 218 | city: 'San Francisco', 219 | postalCode: '94116', 220 | state: 'California', 221 | stateCode: 'CA', 222 | country: 'United States', 223 | countryCode: 'US', 224 | lat: 37.7427673, 225 | lng: -122.4873437 226 | }, 227 | logo: 'https://logo.clearbit.com/stdlib.com', 228 | facebook: { handle: null, likes: null }, 229 | linkedin: { handle: 'company/stdlib' }, 230 | twitter: { 231 | handle: 'StdLibHQ', 232 | id: '722579682298880000', 233 | bio: 234 | 'A Standard Library for the Web. https://t.co/hmBfCldjVS. Join in.', 235 | followers: 1736, 236 | following: 55, 237 | location: 'San Francisco, CA', 238 | site: 'https://t.co/vMOOVQrzsh', 239 | avatar: 240 | 'https://pbs.twimg.com/profile_images/1019974946963972096/dMff2KGl_normal.jpg' 241 | }, 242 | crunchbase: { handle: 'organization/stdlib' }, 243 | emailProvider: false, 244 | type: 'private', 245 | ticker: null, 246 | identifiers: { usEIN: null }, 247 | phone: null, 248 | metrics: { 249 | alexaUsRank: 140760, 250 | alexaGlobalRank: 306578, 251 | employees: null, 252 | employeesRange: null, 253 | marketCap: null, 254 | raised: 4000000, 255 | annualRevenue: null, 256 | estimatedAnnualRevenue: null, 257 | fiscalYearEnd: null 258 | }, 259 | indexedAt: '2019-02-24T07:37:43.337Z', 260 | tech: [ 261 | 'google_apps', 262 | 'cloud_flare', 263 | 'stripe', 264 | 'twitter_advertiser', 265 | 'amazon_s3', 266 | 'facebook_advertiser', 267 | 'google_analytics', 268 | 'heroku', 269 | 'facebook_connect', 270 | 'twitter_button', 271 | 'youtube' 272 | ], 273 | parent: { domain: null } 274 | } 275 | }; 276 | }; 277 | -------------------------------------------------------------------------------- /test/gateway/functions/schema_optional_params.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Schema Input 3 | * @param {?object} obj 4 | * @ {string} name 5 | * @ {?boolean} enabled 6 | * @returns {any} 7 | */ 8 | module.exports = async (obj = null) => { 9 | 10 | return obj; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/schema_rejection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Schema Input 3 | * @param {object} obj 4 | * @ {string} name 5 | * @ {boolean} enabled 6 | * @ {object} data 7 | * @ {string} a 8 | * @ {string} b 9 | * @ {number} timestamp 10 | * @returns {string} 11 | */ 12 | module.exports = async (obj) => { 13 | 14 | return 'hello'; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/gateway/functions/schema_rejection_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Schema Input - Array 3 | * @param {array} users 4 | * @ {object} user 5 | * @ {string} username 6 | * @ {number} age 7 | * @returns {string} 8 | */ 9 | module.exports = async (users) => { 10 | 11 | return 'hello'; 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/schema_rejection_nested_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Schema Input - Array 3 | * @param {array} users 4 | * @ {object} user a user 5 | * @ {string} username 6 | * @ {array} posts 7 | * @ {object} post 8 | * @ {string} title 9 | * @ {string} body 10 | * @returns {array} 11 | */ 12 | module.exports = async (users) => { 13 | 14 | return users; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /test/gateway/functions/schema_rejection_number_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test Schema Input - Array 3 | * @param {array} userIds 4 | * @ {number} 5 | * @returns {string} 6 | */ 7 | module.exports = async (userIds) => { 8 | 9 | return 'hello'; 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/basic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {boolean} hello Some value 5 | */ 6 | module.exports = async (alpha, context) => { 7 | 8 | context.stream('hello', true); 9 | 10 | return true; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/basic_buffer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {buffer} hello Some value 5 | */ 6 | module.exports = async (alpha, context) => { 7 | 8 | context.stream('hello', Buffer.from('123')); 9 | 10 | return true; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/basic_buffer_mocked.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {buffer} hello Some value 5 | */ 6 | module.exports = async (alpha, context) => { 7 | 8 | context.stream('hello', {_base64: Buffer.from('123').toString('base64')}); 9 | 10 | return true; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/basic_buffer_nested.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {any} hello 5 | */ 6 | module.exports = async (alpha, context) => { 7 | 8 | context.stream('hello', {mybuff: Buffer.from('123')}); 9 | 10 | return true; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/basic_buffer_nested_mocked.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {object} hello 5 | * @ {buffer} mybuff 6 | */ 7 | module.exports = async (alpha, context) => { 8 | 9 | context.stream('hello', {mybuff: {_base64: Buffer.from('123').toString('base64')}}); 10 | 11 | return true; 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/date.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {object} hello Some object 5 | */ 6 | module.exports = async (alpha, context) => { 7 | 8 | context.stream('hello', { date: new Date() }); 9 | context.stream('hello', { deep: { date: new Date() } }); 10 | 11 | return true; 12 | 13 | }; 14 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/debug.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {string} hello Hello message 5 | * @stream {string} goodbye Goodbye message 6 | */ 7 | module.exports = async (alpha, context) => { 8 | 9 | context.stream('hello', 'Hello?'); 10 | context.stream('hello', 'How are you?'); 11 | context.log('what?', 'who?'); 12 | 13 | await new Promise(resolve => setTimeout(() => resolve(), 20)); 14 | 15 | context.stream('hello', 'Is it me you\'re looking for?'); 16 | context.error('oh no'); 17 | 18 | await new Promise(resolve => setTimeout(() => resolve(), 20)); 19 | 20 | context.stream('goodbye', 'Nice to see ya'); 21 | context.log('finally'); 22 | 23 | return true; 24 | 25 | }; 26 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/debug_no_stream.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Not a streaming function, can debug with streaming 3 | * @param {string} alpha Some value 4 | */ 5 | module.exports = async (alpha, context) => { 6 | 7 | context.log('what?', 'who?'); 8 | 9 | await new Promise(resolve => setTimeout(() => resolve(), 20)); 10 | 11 | context.error('oh no'); 12 | 13 | await new Promise(resolve => setTimeout(() => resolve(), 20)); 14 | 15 | context.log('finally'); 16 | 17 | return true; 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/invalid_stream_name.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {boolean} hello Some value 5 | */ 6 | module.exports = async (alpha, context) => { 7 | 8 | context.stream('hello2', 'what'); 9 | 10 | return true; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/invalid_stream_param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {boolean} hello Some value 5 | */ 6 | module.exports = async (alpha, context) => { 7 | 8 | context.stream('hello', 'what'); 9 | 10 | return true; 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /test/gateway/functions/stream/sleep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Valid function for streaming 3 | * @param {string} alpha Some value 4 | * @stream {string} hello Hello message 5 | * @stream {string} goodbye Goodbye message 6 | */ 7 | module.exports = async (alpha, context) => { 8 | 9 | context.stream('hello', 'Hello?'); 10 | context.stream('hello', 'How are you?'); 11 | 12 | await new Promise(resolve => setTimeout(() => resolve(), 20)); 13 | 14 | context.stream('hello', 'Is it me you\'re looking for?'); 15 | 16 | await new Promise(resolve => setTimeout(() => resolve(), 20)); 17 | 18 | context.stream('goodbye', 'Nice to see ya'); 19 | 20 | return true; 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /test/gateway/functions/string_options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test options with string 3 | * @param {string} value {?} ["one", "two", "three"] 4 | * @returns {any} 5 | */ 6 | module.exports = async (value) => { 7 | return value; 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/stripe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Retrieves Customer details by id 3 | * @param {string} id 4 | * @returns {object} customer The Customer data 5 | * @ {string} id 6 | * @ {string} object 7 | * @ {number} account_balance 8 | * @ {number} created 9 | * @ {boolean} delinquent 10 | * @ {string} email 11 | * @ {string} invoice_prefix 12 | * @ {boolean} livemode 13 | * @ {object} sources 14 | * @ {string} object 15 | * @ {array} data 16 | * @ {boolean} has_more 17 | * @ {number} total_count 18 | * @ {string} url 19 | * @ {object} subscriptions 20 | * @ {string} object 21 | * @ {array} data 22 | * @ {boolean} has_more 23 | * @ {number} total_count 24 | * @ {string} url 25 | */ 26 | module.exports = async (id, context) => { 27 | return { 28 | id: 'cus_EEFPdddddCjZ1dM', 29 | object: 'customer', 30 | account_balance: 0, 31 | created: 1545871187, 32 | currency: null, 33 | default_source: null, 34 | delinquent: false, 35 | description: 'test', 36 | discount: null, 37 | email: 'an@email.com', 38 | invoice_prefix: '535D7D1', 39 | livemode: false, 40 | metadata: {}, 41 | shipping: null, 42 | sources: { 43 | object: 'list', 44 | data: [], 45 | has_more: false, 46 | total_count: 0, 47 | url: '/v1/customers/cus_EEFPmasaaasdfd1dM/sources' 48 | }, 49 | subscriptions: { 50 | object: 'list', 51 | data: [], 52 | has_more: false, 53 | total_count: 0, 54 | url: '/v1/customers/cus_EEFPmsdfsdfFCjZ1dM/subscriptions' 55 | }, 56 | tax_info: null, 57 | tax_info_verification: null 58 | }; 59 | }; 60 | -------------------------------------------------------------------------------- /test/gateway/functions/test/__notfound__.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {String} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback(null, 'not found?'); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/test/status.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {Buffer} 3 | */ 4 | module.exports = (callback) => { 5 | 6 | callback(null, Buffer.from('not found'), {status: 404}); 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/type_rejection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test type rejection 3 | * @param {integer} alpha An Integer 4 | * @returns {integer} 5 | */ 6 | module.exports = (alpha = 100, context, callback) => { 7 | return callback(null, alpha); 8 | }; 9 | -------------------------------------------------------------------------------- /test/gateway/functions/value_error/buffer_invalid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {object} response 3 | * @ {buffer} body 4 | */ 5 | module.exports = async () => { 6 | return { 7 | body: {} 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /test/gateway/functions/value_error/number_invalid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @returns {number} myNum 3 | */ 4 | module.exports = async () => { 5 | return 'hello'; 6 | }; 7 | -------------------------------------------------------------------------------- /test/gateway/functions/value_error/object_alternate_schema_invalid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Provides alternateSchemas 3 | * @returns {object} fileOrFolder 4 | * @ {string} name 5 | * @ {integer} size 6 | * @ OR 7 | * @ {string} name 8 | * @ {array} files 9 | * @ {object} options 10 | * @ {string} type 11 | * @ OR 12 | * @ {number} type 13 | */ 14 | module.exports = async () => { 15 | 16 | return {name: 'keith', files: []}; 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /test/gateway/www/compile/test-sass-error.scss: -------------------------------------------------------------------------------- 1 | body { 2 | div { 3 | font-family: 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/gateway/www/compile/test-sass.scss: -------------------------------------------------------------------------------- 1 | body { 2 | div { 3 | font-family: Arial; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/gateway/www/error/404.html: -------------------------------------------------------------------------------- 1 | error 404 2 | -------------------------------------------------------------------------------- /test/gateway/www/fs-wordmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instant-dev/api/a9efc6630afeea301a363d2102206f6735a77a93/test/gateway/www/fs-wordmark.png -------------------------------------------------------------------------------- /test/gateway/www/page.html: -------------------------------------------------------------------------------- 1 | this is an html file 2 | -------------------------------------------------------------------------------- /test/gateway/www/page2.htm: -------------------------------------------------------------------------------- 1 | this is an htm file 2 | -------------------------------------------------------------------------------- /test/gateway/www/static-test/htm/index.htm: -------------------------------------------------------------------------------- 1 | this is an index.htm file 2 | -------------------------------------------------------------------------------- /test/gateway/www/static-test/index.html: -------------------------------------------------------------------------------- 1 | this is an index.html file 2 | -------------------------------------------------------------------------------- /test/gateway/www/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instant-dev/api/a9efc6630afeea301a363d2102206f6735a77a93/test/gateway/www/video.mp4 -------------------------------------------------------------------------------- /test/helpers.mjs: -------------------------------------------------------------------------------- 1 | import InstantAPI_import from '../index.js'; 2 | 3 | export const HOST = 'localhost'; 4 | export const PORT = 7357; 5 | export const ROOT = './test/gateway'; 6 | export const InstantAPI = InstantAPI_import; -------------------------------------------------------------------------------- /test/output.mjs: -------------------------------------------------------------------------------- 1 | const FunctionParser = require('../index.js').FunctionParser; 2 | let definition = new FunctionParser().load('./test/files', 'comprehensive'); 3 | console.log(JSON.stringify(definition, null, 2)); 4 | -------------------------------------------------------------------------------- /test/run.mjs: -------------------------------------------------------------------------------- 1 | import { PORT, InstantAPI } from './helpers.mjs'; 2 | const TestEngine = InstantAPI.TestEngine; 3 | 4 | const testEngine = new TestEngine(PORT); 5 | await testEngine.initialize('./test/tests'); 6 | 7 | testEngine.setup(async () => { 8 | let startTime = new Date().valueOf(); 9 | return { startTime }; 10 | }); 11 | 12 | const args = process.argv.slice(3); 13 | if (args[0]) { 14 | await testEngine.run(args[0]); 15 | } else { 16 | await testEngine.runAll(); 17 | } 18 | 19 | testEngine.finish(async ({ startTime }) => { 20 | let time = new Date().valueOf() - startTime; 21 | console.log(`Tests finished in ${time} ms`); 22 | }); -------------------------------------------------------------------------------- /test/tests/_index.mjs: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | const expect = chai.expect; 3 | 4 | import { InstantAPI } from '../helpers.mjs'; 5 | 6 | const EncryptionTools = InstantAPI.EncryptionTools; 7 | 8 | export const name = 'Main tests'; 9 | export default async function (setupResult) { 10 | 11 | it('should load EncryptionTools', () => { 12 | 13 | expect(EncryptionTools).to.exist; 14 | 15 | }); 16 | 17 | }; 18 | -------------------------------------------------------------------------------- /test/tests/cases.mjs: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | const expect = chai.expect; 3 | 4 | import fs from 'fs'; 5 | import path from 'path'; 6 | 7 | import { InstantAPI } from '../helpers.mjs'; 8 | 9 | const CASE_PATH = './test/files/cases'; 10 | const cases = fs.readdirSync(CASE_PATH).map(filename => { 11 | if (!filename.match(/\.[cm]?js$/)) { 12 | throw new Error(`Invalid case ${filename} in "./test/files/cases", file must be (.js|.mjs|.cjs)`); 13 | } 14 | let name = filename.replace(/\.[cm]?js$/, ''); 15 | let names = name.split('_').map(n => n[0].toUpperCase() + n.substr(1)); 16 | return { 17 | name: [names[0], `(${names[1]})`].concat(names.slice(2)).join(' '), 18 | valid: names[1] === 'Valid', 19 | pathname: filename, 20 | buffer: fs.readFileSync(path.join(CASE_PATH, filename)) 21 | } 22 | }); 23 | 24 | const FunctionParser = InstantAPI.FunctionParser; 25 | const parser = new FunctionParser(); 26 | 27 | process.env.CASE_ORIGIN = 'hello.com'; 28 | 29 | export const name = 'Function export validation'; 30 | export default async function (setupResult) { 31 | 32 | cases.forEach(functionCase => { 33 | 34 | it(`Should check ${functionCase.name}`, () => { 35 | 36 | let err; 37 | 38 | try { 39 | parser.parseDefinition(functionCase.pathname, functionCase.buffer); 40 | } catch (e) { 41 | if (functionCase.valid) { 42 | console.error(e); 43 | } 44 | err = e; 45 | } 46 | 47 | functionCase.valid ? 48 | expect(err).to.not.exist : 49 | expect(err).to.exist; 50 | 51 | }); 52 | 53 | }); 54 | 55 | }; 56 | --------------------------------------------------------------------------------