velocious 1.0.97 → 1.0.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/eslint.config.js +1 -0
  2. package/package.json +2 -1
  3. package/spec/database/connection/drivers/mysql/query-parser-spec.js +4 -4
  4. package/spec/http-server/post-spec.js +2 -0
  5. package/src/application.js +27 -9
  6. package/src/configuration-resolver.js +29 -10
  7. package/src/configuration-types.js +44 -0
  8. package/src/configuration.js +63 -33
  9. package/src/database/drivers/base-column.js +6 -1
  10. package/src/database/drivers/base-columns-index.js +11 -1
  11. package/src/database/drivers/base-foreign-key.js +45 -0
  12. package/src/database/drivers/base-table.js +24 -2
  13. package/src/database/drivers/base.js +211 -39
  14. package/src/database/drivers/mssql/index.js +1 -3
  15. package/src/database/drivers/sqlite/sql/alter-table.js +4 -2
  16. package/src/database/handler.js +5 -0
  17. package/src/database/migration/index.js +79 -20
  18. package/src/database/migrator/files-finder.js +21 -22
  19. package/src/database/migrator/types.js +29 -0
  20. package/src/database/migrator.js +98 -59
  21. package/src/database/pool/async-tracked-multi-connection.js +42 -7
  22. package/src/database/pool/base-methods-forward.js +37 -0
  23. package/src/database/pool/base.js +79 -46
  24. package/src/database/pool/single-multi-use.js +18 -3
  25. package/src/database/query/alter-table-base.js +4 -4
  26. package/src/database/query/base.js +9 -2
  27. package/src/database/query/create-database-base.js +8 -0
  28. package/src/database/query/create-index-base.js +20 -5
  29. package/src/database/query/create-table-base.js +28 -9
  30. package/src/database/query/from-base.js +17 -0
  31. package/src/database/query/from-plain.js +8 -3
  32. package/src/database/query/from-table.js +8 -3
  33. package/src/database/query/index.js +43 -32
  34. package/src/database/query/join-base.js +28 -1
  35. package/src/database/query/join-object.js +67 -0
  36. package/src/database/query/join-plain.js +6 -1
  37. package/src/database/query/order-base.js +18 -0
  38. package/src/database/query/order-plain.js +8 -2
  39. package/src/database/query/select-base.js +15 -0
  40. package/src/database/query/select-plain.js +6 -1
  41. package/src/database/query/select-table-and-column.js +8 -2
  42. package/src/database/query/where-base.js +23 -1
  43. package/src/database/query/where-hash.js +15 -0
  44. package/src/database/query/where-plain.js +6 -0
  45. package/src/database/query-parser/base-query-parser.js +8 -2
  46. package/src/database/query-parser/from-parser.js +2 -0
  47. package/src/database/query-parser/joins-parser.js +10 -45
  48. package/src/database/query-parser/select-parser.js +2 -0
  49. package/src/database/record/index.js +1 -1
  50. package/src/database/table-data/index.js +39 -121
  51. package/src/database/table-data/table-column.js +54 -25
  52. package/src/database/table-data/table-foreign-key.js +5 -3
  53. package/src/database/table-data/table-index.js +12 -6
  54. package/src/database/table-data/table-reference.js +2 -0
  55. package/src/database/use-database.js +4 -2
  56. package/src/environment-handlers/base.js +41 -8
  57. package/src/environment-handlers/node/cli/commands/destroy/migration.js +3 -0
  58. package/src/environment-handlers/node/cli/commands/generate/migration.js +3 -0
  59. package/src/environment-handlers/node/cli/commands/generate/model.js +3 -0
  60. package/src/environment-handlers/node/cli/commands/init.js +3 -0
  61. package/src/environment-handlers/node.js +59 -28
  62. package/src/http-client/header.js +6 -0
  63. package/src/http-client/request.js +31 -5
  64. package/src/http-client/response.js +31 -7
  65. package/src/http-server/client/index.js +24 -4
  66. package/src/http-server/client/request-buffer/form-data-part.js +11 -0
  67. package/src/http-server/client/request-buffer/header.js +6 -0
  68. package/src/http-server/client/request-buffer/index.js +91 -13
  69. package/src/http-server/client/request-parser.js +26 -0
  70. package/src/http-server/client/request-runner.js +15 -3
  71. package/src/http-server/client/request.js +17 -0
  72. package/src/http-server/client/response.js +41 -1
  73. package/src/http-server/index.js +32 -4
  74. package/src/http-server/server-client.js +33 -2
  75. package/src/http-server/worker-handler/index.js +42 -9
  76. package/src/http-server/worker-handler/worker-script.js +2 -0
  77. package/src/http-server/worker-handler/worker-thread.js +34 -6
  78. package/src/logger.js +21 -15
  79. package/src/routes/app-routes.js +1 -1
  80. package/src/testing/test-files-finder.js +8 -4
  81. package/src/testing/test-runner.js +76 -24
  82. package/src/utils/backtrace-cleaner.js +6 -4
  83. package/src/utils/ensure-error.js +13 -0
  84. package/src/utils/file-exists.js +3 -1
  85. package/src/utils/rest-args-error.js +2 -0
@@ -1,11 +1,17 @@
1
+ // @ts-check
2
+
1
3
  import restArgsError from "../../utils/rest-args-error.js"
2
4
 
5
+ /**
6
+ * @typedef {object} TableIndexArgsType
7
+ * @property {string} name
8
+ * @property {boolean} unique
9
+ */
10
+
3
11
  export default class TableIndex {
4
12
  /**
5
- * @param {Array<string>} columns
6
- * @param {object} args
7
- * @param {string} args.name
8
- * @param {boolean} args.unique
13
+ * @param {Array<string | import("./table-column.js").default>} columns
14
+ * @param {TableIndexArgsType} [args]
9
15
  */
10
16
  constructor(columns, args) {
11
17
  if (args) {
@@ -19,12 +25,12 @@ export default class TableIndex {
19
25
  }
20
26
 
21
27
  /**
22
- * @returns {Array<string>}
28
+ * @returns {Array<string | import("./table-column.js").default>}
23
29
  */
24
30
  getColumns() { return this.columns }
25
31
 
26
32
  /**
27
- * @returns {string}
33
+ * @returns {string | undefined}
28
34
  */
29
35
  getName() { return this.args?.name }
30
36
 
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  export default class TableReference {
2
4
  /**
3
5
  * @param {string} name
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  import React from "react"
2
4
  import useEnvSense from "env-sense/src/use-env-sense.js"
3
5
 
@@ -7,8 +9,8 @@ import restArgsError from "../utils/rest-args-error.js"
7
9
 
8
10
  /**
9
11
  * @param {object} args
10
- * @param {object} args.migrationsRequireContextCallback
11
- * @returns {Promise<{loaded: boolean}>}
12
+ * @param {() => Promise<import("./migrator/types.js").RequireMigrationContextType>} args.migrationsRequireContextCallback
13
+ * @returns {{loaded: boolean}}
12
14
  */
13
15
  export default function loadMigrations({migrationsRequireContextCallback, ...restArgs}) {
14
16
  const instance = React.useMemo(() => ({running: false}), [])
@@ -1,3 +1,19 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @typedef {object} CommandFileObjectType
5
+ * @property {string} name
6
+ * @property {string} file
7
+ */
8
+
9
+ /**
10
+ * @typedef {object} MigrationObjectType
11
+ * @property {number} date
12
+ * @property {string} [fullPath]
13
+ * @property {string} migrationClassName
14
+ * @property {string} file
15
+ */
16
+
1
17
  export default class VelociousEnvironmentHandlerBase {
2
18
  /**
3
19
  * @param {import("../cli/base-command.js").default} _command
@@ -8,10 +24,10 @@ export default class VelociousEnvironmentHandlerBase {
8
24
  }
9
25
 
10
26
  /**
11
- * @param {import("../cli/base-command.js").default} _command
27
+ * @param {import("../cli/base-command.js").default} command
12
28
  * @returns {Promise<void>}
13
29
  */
14
- async cliCommandsInit(_command) { // eslint-disable-line no-unused-vars
30
+ async cliCommandsInit(command) { // eslint-disable-line no-unused-vars
15
31
  throw new Error("cliCommandsInit not implemented")
16
32
  }
17
33
 
@@ -57,19 +73,20 @@ export default class VelociousEnvironmentHandlerBase {
57
73
 
58
74
  /**
59
75
  * @interface
76
+ * @returns {Promise<CommandFileObjectType[]>}
60
77
  */
61
78
  async findCommands() { throw new Error("findCommands not implemented") }
62
79
 
63
80
  /**
64
81
  * @interface
82
+ * @returns {Promise<Array<MigrationObjectType>>}
65
83
  */
66
84
  async findMigrations() { throw new Error("findMigrations not implemneted") }
67
85
 
68
86
  /**
69
- * @template T extends import("../cli/base-command.js").default
70
- * @param {T} command
71
- * @param {typeof T} CommandClass
72
- * @returns {any}
87
+ * @param {import("../cli/base-command.js").default} command
88
+ * @param {typeof import("../cli/base-command.js").default} CommandClass
89
+ * @returns {Promise<any>}
73
90
  */
74
91
  async forwardCommand(command, CommandClass) {
75
92
  const newCommand = new CommandClass({
@@ -81,20 +98,36 @@ export default class VelociousEnvironmentHandlerBase {
81
98
 
82
99
  /**
83
100
  * @interface
101
+ * @returns {Promise<string>}
84
102
  */
85
- async getVelociousPath() { throw new Error("getVelociousPath not implemented") }
103
+ getVelociousPath() { throw new Error("getVelociousPath not implemented") }
86
104
 
87
105
  /**
88
106
  * @interface
107
+ * @returns {Promise<import("../routes/index.js").default>}
89
108
  */
90
109
  async importApplicationRoutes() { throw new Error("importApplicationRoutes not implemented") }
91
110
 
111
+ /**
112
+ * @interface
113
+ * @param {string[]} _testFiles
114
+ * @returns {Promise<void>}
115
+ */
116
+ importTestFiles(_testFiles) { throw new Error("'importTestFiles' not implemented") } // eslint-disable-line no-unused-vars
117
+
118
+ /**
119
+ * @interface
120
+ * @returns {Promise<void>}
121
+ */
122
+ importTestingConfigPath() { throw new Error(`'importTestingConfigPath' not implemented`) }
123
+
92
124
  /**
93
125
  * @param {object} args
94
126
  * @param {string[]} args.commandParts
127
+ * @returns {Promise<import ("../cli/base-command.js").default>}
95
128
  * @interface
96
129
  */
97
- async requireCommand({commandParts}) { throw new Error("requireCommand not implemented") } // eslint-disable-line no-unused-vars
130
+ async requireCommand({commandParts}) { throw new Error("'requireCommand' not implemented") } // eslint-disable-line no-unused-vars
98
131
 
99
132
  /**
100
133
  * @param {object} newArgs
@@ -2,6 +2,9 @@ import BaseCommand from "../../../../../cli/base-command.js"
2
2
  import fs from "fs/promises"
3
3
 
4
4
  export default class DbDestroyMigration extends BaseCommand {
5
+ /**
6
+ * @returns {Promise<void>}
7
+ */
5
8
  async execute() {
6
9
  const migrationName = this.processArgs[1]
7
10
  const migrationDir = `${this.getConfiguration().getDirectory()}/src/database/migrations`
@@ -5,6 +5,9 @@ import * as inflection from "inflection"
5
5
  import strftime from "strftime"
6
6
 
7
7
  export default class DbGenerateMigration extends BaseCommand {
8
+ /**
9
+ * @returns {Promise<void>}
10
+ */
8
11
  async execute() {
9
12
  const migrationName = this.processArgs[1]
10
13
  const migrationNameCamelized = inflection.camelize(migrationName.replaceAll("-", "_"))
@@ -4,6 +4,9 @@ import fs from "fs/promises"
4
4
  import * as inflection from "inflection"
5
5
 
6
6
  export default class DbGenerateModel extends BaseCommand {
7
+ /**
8
+ * @returns {Promise<void>}
9
+ */
7
10
  async execute() {
8
11
  const modelName = this.processArgs[1]
9
12
  const modelNameCamelized = inflection.camelize(modelName.replaceAll("-", "_"))
@@ -3,6 +3,9 @@ import fileExists from "../../../../utils/file-exists.js"
3
3
  import fs from "fs/promises"
4
4
 
5
5
  export default class VelociousCliCommandsInit extends BaseCommand {
6
+ /**
7
+ * @returns {Promise<void>}
8
+ */
6
9
  async execute() {
7
10
  const velociousPath = await this.getEnvironmentHandler().getVelociousPath()
8
11
  const projectPath = this.getConfiguration()?.getDirectory() || process.cwd()
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  import Base from "./base.js"
2
4
  import CliCommandsDestroyMigration from "./node/cli/commands/destroy/migration.js"
3
5
  import CliCommandsInit from "./node/cli/commands/init.js"
@@ -13,11 +15,16 @@ import * as inflection from "inflection"
13
15
  import path from "path"
14
16
 
15
17
  export default class VelociousEnvironmentHandlerNode extends Base{
18
+ /** @type {import("./base.js").CommandFileObjectType[] | undefined} */
19
+ _findCommandsResult = undefined
20
+
16
21
  /**
17
- * @returns {Promise<Array<{name: string, file: string}>>}
22
+ * @returns {Promise<Array<import("./base.js").CommandFileObjectType>>}
18
23
  */
19
24
  async findCommands() {
20
- this._findCommandsResult ||= this._actualFindCommands()
25
+ this._findCommandsResult ||= await this._actualFindCommands()
26
+
27
+ if (!this._findCommandsResult) throw new Error("Could not get commands")
21
28
 
22
29
  return this._findCommandsResult
23
30
  }
@@ -49,38 +56,66 @@ export default class VelociousEnvironmentHandlerNode extends Base{
49
56
  return commands
50
57
  }
51
58
 
59
+ /**
60
+ * @param {import("../cli/base-command.js").default} command
61
+ * @returns {Promise<void>}
62
+ */
52
63
  async cliCommandsInit(command) {
53
64
  return await this.forwardCommand(command, CliCommandsInit)
54
65
  }
55
66
 
67
+ /**
68
+ * @param {import("../cli/base-command.js").default} command
69
+ * @returns {Promise<any>}
70
+ */
56
71
  async cliCommandsMigrationGenerate(command) {
57
72
  return await this.forwardCommand(command, CliCommandsGenerateMigration)
58
73
  }
59
74
 
75
+ /**
76
+ * @param {import("../cli/base-command.js").default} command
77
+ * @returns {Promise<any>}
78
+ */
60
79
  async cliCommandsMigrationDestroy(command) {
61
80
  return await this.forwardCommand(command, CliCommandsDestroyMigration)
62
81
  }
63
82
 
83
+ /**
84
+ * @param {import("../cli/base-command.js").default} command
85
+ * @returns {Promise<any>}
86
+ */
64
87
  async cliCommandsGenerateBaseModels(command) {
65
88
  return await this.forwardCommand(command, CliCommandsGenerateBaseModels)
66
89
  }
67
90
 
91
+ /**
92
+ * @param {import("../cli/base-command.js").default} command
93
+ * @returns {Promise<any>}
94
+ */
68
95
  async cliCommandsGenerateModel(command) {
69
96
  return await this.forwardCommand(command, CliCommandsGenerateModel)
70
97
  }
71
98
 
99
+ /**
100
+ * @param {import("../cli/base-command.js").default} command
101
+ * @returns {Promise<any>}
102
+ */
72
103
  async cliCommandsServer(command) {
73
104
  return await this.forwardCommand(command, CliCommandsServer)
74
105
  }
75
106
 
107
+ /**
108
+ * @param {import("../cli/base-command.js").default} command
109
+ * @returns {Promise<any>}
110
+ */
76
111
  async cliCommandsTest(command) {
77
112
  return await this.forwardCommand(command, CliCommandsTest)
78
113
  }
79
114
 
80
115
  /**
81
- * @param {Array<string>} commandParts
82
- * @template T extends import ("./base-command.js").default
83
- * @returns {Promise<T>}
116
+ * @param {object} args
117
+ * @param {string[]} args.commandParts
118
+ * @returns {Promise<import ("../cli/base-command.js").default>}
84
119
  */
85
120
  async requireCommand({commandParts}) {
86
121
  const commands = await this.findCommands()
@@ -89,7 +124,7 @@ export default class VelociousEnvironmentHandlerNode extends Base{
89
124
  if (!command) {
90
125
  const possibleCommands = commands.map(aCommand => aCommand.name)
91
126
 
92
- throw new Error(`Unknown command: ${this.args.processArgs[0]} which should have been one of: ${possibleCommands.sort().join(", ")}`)
127
+ throw new Error(`Unknown command: ${commandParts.join(":")} which should have been one of: ${possibleCommands.sort().join(", ")}`)
93
128
  }
94
129
 
95
130
  const commandClassImport = await import(command.file)
@@ -99,40 +134,35 @@ export default class VelociousEnvironmentHandlerNode extends Base{
99
134
  }
100
135
 
101
136
  /**
102
- * @returns {Promise<Array<{name: string, file: string}>>}
137
+ * @returns {Promise<Array<import("./base.js").MigrationObjectType>>}
103
138
  */
104
139
  async findMigrations() {
105
140
  const migrationsPath = `${this.getConfiguration().getDirectory()}/src/database/migrations`
106
141
  const glob = await fs.glob(`${migrationsPath}/**/*.js`)
107
- const files = []
142
+ let files = []
108
143
 
109
144
  for await (const fullPath of glob) {
110
145
  const file = await path.basename(fullPath)
111
146
 
112
- files.push(file)
113
- }
114
-
115
- const migrationFiles = files
116
- .map((file) => {
117
- const match = file.match(/^(\d{14})-(.+)\.js$/)
147
+ const match = file.match(/^(\d{14})-(.+)\.js$/)
118
148
 
119
- if (!match) return null
149
+ if (!match) continue
120
150
 
121
- const date = parseInt(match[1])
122
- const migrationName = match[2]
123
- const migrationClassName = inflection.camelize(migrationName.replaceAll("-", "_"))
151
+ const date = parseInt(match[1])
152
+ const migrationName = match[2]
153
+ const migrationClassName = inflection.camelize(migrationName.replaceAll("-", "_"))
124
154
 
125
- return {
126
- file,
127
- fullPath: `${migrationsPath}/${file}`,
128
- date,
129
- migrationClassName
130
- }
155
+ files.push({
156
+ file,
157
+ fullPath: `${migrationsPath}/${file}`,
158
+ date,
159
+ migrationClassName
131
160
  })
132
- .filter((migration) => Boolean(migration))
133
- .sort((migration1, migration2) => migration1.date - migration2.date)
161
+ }
162
+
163
+ files = files.sort((migration1, migration2) => migration1.date - migration2.date)
134
164
 
135
- return migrationFiles
165
+ return files
136
166
  }
137
167
 
138
168
  /**
@@ -145,7 +175,7 @@ export default class VelociousEnvironmentHandlerNode extends Base{
145
175
  }
146
176
 
147
177
  /**
148
- * @returns {string}
178
+ * @returns {Promise<string>}
149
179
  */
150
180
  async getVelociousPath() {
151
181
  if (!this._velociousPath) {
@@ -159,6 +189,7 @@ export default class VelociousEnvironmentHandlerNode extends Base{
159
189
  }
160
190
 
161
191
  /**
192
+ * @param {string[]} testFiles
162
193
  * @returns {Promise<void>}
163
194
  */
164
195
  async importTestFiles(testFiles) {
@@ -1,4 +1,10 @@
1
+ // @ts-check
2
+
1
3
  export default class Header {
4
+ /**
5
+ * @param {string} name
6
+ * @param {string | number} value
7
+ */
2
8
  constructor(name, value) {
3
9
  this.name = name
4
10
  this.value = value
@@ -1,4 +1,16 @@
1
+ // @ts-check
2
+
3
+ import Header from "./header.js"
4
+
1
5
  export default class Request {
6
+ /**
7
+ * @param {object} args
8
+ * @param {string} args.body
9
+ * @param {string} args.method
10
+ * @param {Header[]} args.headers
11
+ * @param {string} args.path
12
+ * @param {string} args.version
13
+ */
2
14
  constructor({body, method = "GET", headers = [], path, version = "1.1"}) {
3
15
  this.body = body
4
16
  this.headers = headers
@@ -17,26 +29,40 @@ export default class Request {
17
29
  return requestString
18
30
  }
19
31
 
20
- getHeader(key) {
21
- const compareName = key.toLowerCase().trim()
32
+ /**
33
+ * @param {string} name
34
+ */
35
+ getHeader(name) {
36
+ const compareName = name.toLowerCase().trim()
22
37
 
23
38
  for (const header of this.headers) {
24
- const headerCompareName = header.key.toLowerCase().trim()
39
+ const headerCompareName = header.getName().toLowerCase().trim()
25
40
 
26
41
  if (compareName == headerCompareName) {
27
42
  return header
28
43
  }
29
44
  }
30
45
 
31
- throw new Error(`Header ${key} not found`)
46
+ throw new Error(`Header ${name} not found`)
47
+ }
48
+
49
+ /**
50
+ * @param {string} name
51
+ * @param {string | number} value
52
+ */
53
+ addHeader(name, value) {
54
+ this.headers.push(new Header(name, value))
32
55
  }
33
56
 
34
57
  prepare() {
35
58
  if (this.body) {
36
- this.addHeader("Content-Length", this.body.byteLength)
59
+ this.addHeader("Content-Length", Buffer.from(this.body).byteLength)
37
60
  }
38
61
  }
39
62
 
63
+ /**
64
+ * @param {function(string) : void} callback
65
+ */
40
66
  stream(callback) {
41
67
  this.prepare()
42
68
 
@@ -1,23 +1,37 @@
1
+ // @ts-check
2
+
1
3
  import Header from "./header.js"
2
4
 
3
5
  export default class Response {
6
+ /**
7
+ * @param {object} args
8
+ * @param {string} args.method
9
+ * @param {function() : void} args.onComplete
10
+ */
4
11
  constructor({method = "GET", onComplete}) {
5
12
  if (!method) throw new Error(`Invalid method given: ${method}`)
6
13
 
14
+ /** @type {Header[]} */
7
15
  this.headers = []
16
+
8
17
  this.method = method.toUpperCase().trim()
9
18
  this.onComplete = onComplete
10
19
  this.state = "status-line"
11
20
 
12
- this.arrayBuffer = new ArrayBuffer()
13
- this.response = new Uint8Array(this.arrayBuffer)
21
+ /** @type {Buffer} */
22
+ this.response = Buffer.alloc(0);
14
23
  }
15
24
 
25
+ /** @param {Buffer} data */
16
26
  feed(data) {
17
- this.response += data
27
+ this.response = Buffer.concat([this.response, data])
18
28
  this.tryToParse()
19
29
  }
20
30
 
31
+ /**
32
+ * @param {string} name
33
+ * @returns {Header}
34
+ */
21
35
  getHeader(name) {
22
36
  const compareName = name.toLowerCase().trim()
23
37
 
@@ -33,9 +47,11 @@ export default class Response {
33
47
  }
34
48
 
35
49
  json() {
36
- const contentTypeHeader = this.getHeader("Content-Type")?.getValue()?.toLowerCase()?.trim()
50
+ const contentTypeHeader = this.getHeader("Content-Type")?.getValue()
51
+
52
+ if (typeof contentTypeHeader != "string") throw new Error(`Content-Type wasn't a string: ${contentTypeHeader}`)
37
53
 
38
- if (!contentTypeHeader.startsWith("application/json")) {
54
+ if (!contentTypeHeader.toLowerCase().trim().startsWith("application/json")) {
39
55
  throw new Error(`Content-Type is not JSON: ${contentTypeHeader}`)
40
56
  }
41
57
 
@@ -48,13 +64,21 @@ export default class Response {
48
64
  tryToParse() {
49
65
  while (true) {
50
66
  if (this.state == "body") {
51
- const contentLengthValue = this.getHeader("Content-Length")?.value
67
+ const contentLengthValue = this.getHeader("Content-Length")?.getValue()
52
68
 
53
69
  if (contentLengthValue === undefined) {
54
70
  throw new Error("No content length given")
55
71
  }
56
72
 
57
- const contentLengthNumber = parseInt(contentLengthValue)
73
+ let contentLengthNumber
74
+
75
+ if (typeof contentLengthValue == "number") {
76
+ contentLengthNumber = contentLengthValue
77
+ } else if (contentLengthValue == "string") {
78
+ contentLengthNumber = parseInt(contentLengthValue)
79
+ } else {
80
+ throw new Error(`Content-Length is not a number: ${contentLengthValue}`)
81
+ }
58
82
 
59
83
  if (this.response.byteLength >= contentLengthNumber) {
60
84
  this.completeResponse()
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+
1
3
  import {digg} from "diggerize"
2
4
  import {EventEmitter} from "events"
3
5
  import {Logger} from "../../logger.js"
@@ -8,26 +10,33 @@ export default class VeoliciousHttpServerClient {
8
10
  events = new EventEmitter()
9
11
  state = "initial"
10
12
 
11
- constructor({clientCount, configuration, onExecuteRequest}) {
13
+ /**
14
+ * @param {object} args
15
+ * @param {number} args.clientCount
16
+ * @param {import("../../configuration.js").default} args.configuration
17
+ */
18
+ constructor({clientCount, configuration}) {
12
19
  if (!configuration) throw new Error("No configuration given")
13
20
 
14
21
  this.logger = new Logger(this)
15
22
  this.clientCount = clientCount
16
23
  this.configuration = configuration
17
- this.onExecuteRequest = onExecuteRequest
24
+
25
+ /** @type {RequestRunner[]} */
18
26
  this.requestRunners = []
19
27
  }
20
28
 
21
29
  executeCurrentRequest = () => {
22
30
  this.logger.debug("executeCurrentRequest")
23
31
 
32
+ if (!this.currentRequest) throw new Error("No current request")
33
+
24
34
  // We are done parsing the given request and can theoretically start parsing a new one, before the current request is done - so reset the state.
25
35
  this.state = "initial"
26
36
 
27
37
  const requestRunner = new RequestRunner({
28
38
  configuration: this.configuration,
29
- request: this.currentRequest,
30
- routes: this.routes
39
+ request: this.currentRequest
31
40
  })
32
41
 
33
42
  this.requestRunners.push(requestRunner)
@@ -36,6 +45,9 @@ export default class VeoliciousHttpServerClient {
36
45
  requestRunner.run()
37
46
  }
38
47
 
48
+ /**
49
+ * @param {string} data
50
+ */
39
51
  onWrite(data) {
40
52
  if (this.state == "initial") {
41
53
  this.currentRequest = new Request({client: this, configuration: this.configuration})
@@ -43,6 +55,8 @@ export default class VeoliciousHttpServerClient {
43
55
  this.currentRequest.feed(data)
44
56
  this.state = "requestStarted"
45
57
  } else if (this.state == "requestStarted") {
58
+ if (!this.currentRequest) throw new Error("No current request")
59
+
46
60
  this.currentRequest.feed(data)
47
61
  } else {
48
62
  throw new Error(`Unknown state for client: ${this.state}`)
@@ -76,7 +90,13 @@ export default class VeoliciousHttpServerClient {
76
90
  }
77
91
  }
78
92
 
93
+ /**
94
+ * @param {RequestRunner} requestRunner
95
+ * @returns {void}
96
+ */
79
97
  sendResponse(requestRunner) {
98
+ if (!this.currentRequest) throw new Error("No current request")
99
+
80
100
  const response = digg(requestRunner, "response")
81
101
  const request = requestRunner.getRequest()
82
102
  const body = response.getBody()
@@ -1,7 +1,15 @@
1
+ // @ts-check
2
+
1
3
  export default class FormDataPart {
4
+ /** @type {Record<string, import("./header.js").default>} */
2
5
  headers = {}
6
+
7
+ /** @type {number[]} */
3
8
  body = []
4
9
 
10
+ /**
11
+ * @param {import("./header.js").default} header
12
+ */
5
13
  addHeader(header) {
6
14
  const name = header.formattedName
7
15
 
@@ -36,6 +44,9 @@ export default class FormDataPart {
36
44
  return this.value
37
45
  }
38
46
 
47
+ /**
48
+ * @param {string} text
49
+ */
39
50
  removeFromBody(text) {
40
51
  this.body = this.body.slice(0, this.body.length - text.length)
41
52
  }
@@ -1,4 +1,10 @@
1
+ // @ts-check
2
+
1
3
  export default class Header {
4
+ /**
5
+ * @param {string} name
6
+ * @param {string} value
7
+ */
2
8
  constructor(name, value) {
3
9
  this.formattedName = name.toLowerCase().trim()
4
10
  this.name = name