@breautek/storm 8.6.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/docs/assets/hierarchy.js +1 -1
  3. package/docs/assets/navigation.js +1 -1
  4. package/docs/assets/search.js +1 -1
  5. package/docs/classes/Application.html +37 -38
  6. package/docs/classes/ConfigLoader.html +3 -3
  7. package/docs/classes/Database.html +2 -2
  8. package/docs/classes/DatabaseCastObject.html +2 -2
  9. package/docs/classes/DatabaseConnection.html +24 -21
  10. package/docs/classes/DatabaseQueryError.html +30 -9
  11. package/docs/classes/DeadLockError.html +30 -9
  12. package/docs/classes/DiskSpaceError.html +29 -8
  13. package/docs/classes/DropTemporaryTableQuery.html +7 -7
  14. package/docs/classes/DuplicateEntryError.html +29 -8
  15. package/docs/classes/EntityNotFoundError.html +29 -8
  16. package/docs/classes/ExpiredTokenError.html +29 -8
  17. package/docs/classes/Handler.html +4 -4
  18. package/docs/classes/InternalError.html +29 -8
  19. package/docs/classes/InvalidCredentialsError.html +29 -8
  20. package/docs/classes/InvalidValueError.html +29 -8
  21. package/docs/classes/LineString.html +2 -2
  22. package/docs/classes/LockWaitTimeoutError.html +30 -9
  23. package/docs/classes/ManagedDatabaseConnection.html +8 -5
  24. package/docs/classes/Middleware.html +5 -4
  25. package/docs/classes/MissingConfigError.html +29 -8
  26. package/docs/classes/MissingParameterError.html +29 -8
  27. package/docs/classes/MySQLConnection.html +27 -22
  28. package/docs/classes/MySQLDatabase.html +2 -2
  29. package/docs/classes/NotImplementedError.html +29 -8
  30. package/docs/classes/Point.html +2 -2
  31. package/docs/classes/Polygon.html +2 -2
  32. package/docs/classes/Query.html +7 -7
  33. package/docs/classes/RawError.html +29 -8
  34. package/docs/classes/RawQuery.html +7 -7
  35. package/docs/classes/Request.html +2 -2
  36. package/docs/classes/Response.html +2 -2
  37. package/docs/classes/ResponseData.html +2 -2
  38. package/docs/classes/ServiceProvider.html +2 -2
  39. package/docs/classes/ServiceResponse.html +2 -2
  40. package/docs/classes/SetSessionVariableQuery.html +7 -7
  41. package/docs/classes/StormError.html +29 -8
  42. package/docs/classes/TemporaryTableQuery.html +7 -7
  43. package/docs/classes/TimeoutError.html +29 -8
  44. package/docs/classes/Token.html +2 -2
  45. package/docs/classes/TokenManager.html +2 -2
  46. package/docs/classes/Transaction.html +2 -2
  47. package/docs/classes/UnauthorizedAccessError.html +29 -8
  48. package/docs/enums/ErrorCode.html +2 -2
  49. package/docs/enums/ExitCode.html +2 -2
  50. package/docs/enums/HTTPMethod.html +2 -2
  51. package/docs/enums/IsolationLevel.html +2 -2
  52. package/docs/enums/JWTError.html +2 -2
  53. package/docs/enums/StatusCode.html +2 -2
  54. package/docs/enums/TransactionAccessLevel.html +2 -2
  55. package/docs/functions/getInstance.html +1 -1
  56. package/docs/hierarchy.html +1 -1
  57. package/docs/index.html +1 -1
  58. package/docs/interfaces/IAdditionalErrorDetails.html +1 -1
  59. package/docs/interfaces/ICloudwatchConfig.html +2 -2
  60. package/docs/interfaces/ICloudwatchCredentials.html +2 -2
  61. package/docs/interfaces/ICloudwatchStreamConfig.html +2 -2
  62. package/docs/interfaces/IConfig.html +2 -2
  63. package/docs/interfaces/IDatabaseConfig.html +2 -2
  64. package/docs/interfaces/IDatabaseConnection.html +8 -5
  65. package/docs/interfaces/IDatabasePosition.html +2 -2
  66. package/docs/interfaces/IErrorResponse.html +2 -2
  67. package/docs/interfaces/IFormData.html +2 -2
  68. package/docs/interfaces/IInsertQueryResult.html +2 -2
  69. package/docs/interfaces/IJWTVerifyOptions.html +2 -2
  70. package/docs/interfaces/IOKPacket.html +2 -2
  71. package/docs/interfaces/IParameterMap.html +1 -1
  72. package/docs/interfaces/IQueryable.html +2 -2
  73. package/docs/interfaces/IRequestResponse.html +2 -2
  74. package/docs/interfaces/ISetSessionVariableQueryInput.html +2 -2
  75. package/docs/interfaces/IStormCLIArgs.html +2 -2
  76. package/docs/interfaces/ITemporaryTableQueryInput.html +2 -2
  77. package/docs/interfaces/IUpdateQueryResult.html +2 -2
  78. package/docs/interfaces/formidable.FileJSON.html +1 -1
  79. package/docs/interfaces/formidable.Part.html +16 -16
  80. package/docs/types/IDeleteQueryResult.html +1 -1
  81. package/docs/types/IStoredProcedureResult.html +1 -1
  82. package/docs/types/TCoordinate.html +1 -1
  83. package/lib/Application.d.ts +2 -3
  84. package/lib/Application.js +22 -9
  85. package/lib/Application.js.map +1 -1
  86. package/lib/DatabaseConnection.d.ts +3 -0
  87. package/lib/DatabaseConnection.js.map +1 -1
  88. package/lib/Handler.d.ts +25 -28
  89. package/lib/Handler.js +18 -4
  90. package/lib/Handler.js.map +1 -1
  91. package/lib/IDatabaseConnection.d.ts +3 -0
  92. package/lib/IRequestResponse.d.ts +2 -2
  93. package/lib/IRequestResponse.js +1 -1
  94. package/lib/ManagedDatabaseConnection.d.ts +3 -0
  95. package/lib/ManagedDatabaseConnection.js +9 -0
  96. package/lib/ManagedDatabaseConnection.js.map +1 -1
  97. package/lib/Middleware.d.ts +8 -2
  98. package/lib/Middleware.js +9 -1
  99. package/lib/Middleware.js.map +1 -1
  100. package/lib/MySQLConnection.d.ts +12 -0
  101. package/lib/MySQLConnection.js +30 -1
  102. package/lib/MySQLConnection.js.map +1 -1
  103. package/lib/MySQLDatabase.js +8 -10
  104. package/lib/MySQLDatabase.js.map +1 -1
  105. package/lib/Response.d.ts +8 -5
  106. package/lib/Response.js +4 -3
  107. package/lib/Response.js.map +1 -1
  108. package/lib/ServiceProvider.d.ts +6 -6
  109. package/lib/ServiceProvider.js +8 -5
  110. package/lib/ServiceProvider.js.map +1 -1
  111. package/lib/TokenManager.d.ts +2 -1
  112. package/lib/TokenManager.js.map +1 -1
  113. package/lib/api.d.ts +1 -5
  114. package/lib/api.js +2 -6
  115. package/lib/api.js.map +1 -1
  116. package/lib/private/ConnectionReplicationWaiter.js +1 -1
  117. package/lib/private/ConnectionReplicationWaiter.js.map +1 -1
  118. package/lib/private/GetProcessList.d.ts +15 -0
  119. package/lib/private/GetProcessList.js +11 -0
  120. package/lib/private/GetProcessList.js.map +1 -0
  121. package/package.json +10 -9
  122. package/src/Application.ts +23 -10
  123. package/src/DatabaseConnection.ts +6 -0
  124. package/src/Handler.ts +41 -46
  125. package/src/IDatabaseConnection.ts +3 -0
  126. package/src/IRequestResponse.ts +3 -3
  127. package/src/ManagedDatabaseConnection.ts +12 -0
  128. package/src/Middleware.ts +14 -2
  129. package/src/MySQLConnection.ts +34 -1
  130. package/src/MySQLDatabase.ts +8 -10
  131. package/src/Response.ts +20 -7
  132. package/src/ServiceProvider.ts +17 -13
  133. package/src/TokenManager.ts +2 -1
  134. package/src/api.ts +1 -5
  135. package/src/private/ConnectionReplicationWaiter.ts +1 -1
  136. package/src/private/GetProcessList.ts +20 -0
  137. package/docs/classes/BackendAuthenticationMiddleware.html +0 -8
  138. package/docs/classes/CORSMiddleware.html +0 -14
  139. package/docs/interfaces/IHandler.html +0 -2
  140. package/docs/interfaces/IServiceHeaders.html +0 -1
  141. package/docs/types/IHandlerError.html +0 -5
  142. package/docs/types/IHandlerResponse.html +0 -11
  143. package/lib/BackendAuthenticationMiddleware.d.ts +0 -18
  144. package/lib/BackendAuthenticationMiddleware.js +0 -67
  145. package/lib/BackendAuthenticationMiddleware.js.map +0 -1
  146. package/lib/CORSMiddleware.d.ts +0 -28
  147. package/lib/CORSMiddleware.js +0 -81
  148. package/lib/CORSMiddleware.js.map +0 -1
  149. package/lib/IHandler.d.ts +0 -5
  150. package/lib/IHandler.js +0 -18
  151. package/lib/IHandler.js.map +0 -1
  152. package/lib/IServiceHeaders.d.ts +0 -3
  153. package/lib/IServiceHeaders.js +0 -18
  154. package/lib/IServiceHeaders.js.map +0 -1
  155. package/src/BackendAuthenticationMiddleware.ts +0 -75
  156. package/src/CORSMiddleware.ts +0 -90
  157. package/src/IHandler.ts +0 -22
  158. package/src/IServiceHeaders.ts +0 -19
package/src/Handler.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2017-2021 Norman Breau
2
+ Copyright 2017-2025 Norman Breau
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -15,9 +15,8 @@
15
15
  */
16
16
 
17
17
  import {Application} from './Application';
18
- import {getInstance} from './instance';
19
18
  import {Request} from './Request';
20
- import {Response} from './Response';
19
+ import {Response, SendableData} from './Response';
21
20
  import {Middleware} from './Middleware';
22
21
  import {StormError} from './StormError';
23
22
  import {IConfig} from './IConfig';
@@ -25,47 +24,28 @@ import { InternalError } from './InternalError';
25
24
  import { IRequestResponse } from './IRequestResponse';
26
25
  import { BaseLogger } from '@arashi/logger';
27
26
  import { ResponseData } from './ResponseData';
28
- import { ReadStream } from 'fs';
29
27
  import { NotImplementedError } from './NotImplementedError';
30
28
  import { HTTPMethod } from './HTTPMethod';
31
29
 
32
30
  const TAG: string = 'Handler';
33
31
 
34
- /**
35
- * IHandlerResponse can actually accept any arbitrary object, however it may do
36
- * certain things depending on the type of object it receives.
37
- *
38
- * - If the response object is a stream, it will pipe the stream to stream the HTTP response.
39
- * - If the response is ResponseData, the status code and response data will be passed as the HTTP response.
40
- * - Passing nothing/undefined will return a status code of 204 with no body content
41
- * - Primitive data types will be passed as is
42
- * - Buffers will be passed through
43
- * - Any other object will be passed through JSON.stringify
44
- */
45
- export type IHandlerResponse = ResponseData | ReadableStream | ReadStream | any | void;
46
-
47
- /**
48
- * Like IHandlerResponse, an IHandlerError can be any arbitrary type of object,
49
- * however it's recommended that the type be of a StormError.
50
- *
51
- * If the type is not a StormError, the error will be wrapped in an InternalError object.
52
- * This is to avoid accidental leakage of privilege data (e.g. snippets of database queries with sensitive information)
53
- */
54
- export type IHandlerError = StormError | Error | any;
55
-
56
32
  export class Handler<
57
33
  TApplication extends Application = Application,
58
- TGetRequest = any,
59
- TGetResponse = IHandlerResponse,
60
- TPostRequest = any,
61
- TPostResponse = IHandlerResponse,
62
- TPutRequest = any,
63
- TPutResponse = IHandlerResponse,
64
- TDeleteRequest = any,
65
- TDeleteResponse = IHandlerResponse,
34
+ TGetRequest extends SendableData = void | SendableData,
35
+ TGetResponse extends SendableData = void | SendableData,
36
+ TPostRequest extends SendableData = void | SendableData,
37
+ TPostResponse extends SendableData = void | SendableData,
38
+ TPutRequest extends SendableData = void | SendableData,
39
+ TPutResponse extends SendableData = void | SendableData,
40
+ TDeleteRequest extends SendableData = void | SendableData,
41
+ TDeleteResponse extends SendableData = void | SendableData
66
42
  > {
67
43
 
68
44
  private $app: TApplication;
45
+
46
+ /**
47
+ * @deprecated
48
+ */
69
49
  private $middlewares: Middleware[];
70
50
 
71
51
  constructor(app: TApplication) {
@@ -77,23 +57,32 @@ export class Handler<
77
57
  return this.$app;
78
58
  }
79
59
 
60
+ /**
61
+ * @deprecated
62
+ */
80
63
  protected _initMiddlewares(): Middleware[] {
81
64
  return [];
82
65
  }
83
66
 
84
- public getAccessToken(request: Request): string {
85
- let config: IConfig = getInstance().getConfig();
67
+ public getAccessToken(request: Request<unknown>): string {
68
+ let config: IConfig = this.$app.getConfig();
86
69
  let authHeader: string = config.authentication_header;
87
70
  return request.getHeader(authHeader);
88
71
  }
89
72
 
73
+ /**
74
+ * @deprecated
75
+ * @param request
76
+ * @param response
77
+ * @returns
78
+ */
90
79
  private async $executeMiddlewares(request: Request, response: Response): Promise<IRequestResponse> {
91
80
  let result: IRequestResponse = {
92
81
  request,
93
82
  response
94
83
  };
95
84
 
96
- let logger: BaseLogger = getInstance().getLogger();
85
+ let logger: BaseLogger = this.$app.getLogger();
97
86
 
98
87
  try {
99
88
  for (let i: number = 0; i < this.$middlewares.length; i++) {
@@ -133,13 +122,19 @@ export class Handler<
133
122
  return Promise.resolve(result);
134
123
  }
135
124
 
125
+ /**
126
+ * @deprecated
127
+ * @param request
128
+ * @param response
129
+ * @param error
130
+ */
136
131
  protected _onMiddlewareReject(request: Request, response: Response, error: StormError): void {}
137
132
 
138
- private $handleResponse<TResponse>(response: Response<TResponse>, data: any): void {
133
+ private $handleResponse<TResponse extends SendableData>(response: Response<TResponse>, data: TResponse | ResponseData<TResponse>): void {
139
134
  response.send(data);
140
135
  }
141
136
 
142
- private $handleResponseError<TResponse>(response: Response<TResponse>, error: any): void {
137
+ private $handleResponseError<TResponse extends SendableData>(response: Response<TResponse>, error: any): void {
143
138
  response.error(error);
144
139
  }
145
140
 
@@ -148,7 +143,7 @@ export class Handler<
148
143
 
149
144
  try {
150
145
  let result: IRequestResponse<TGetRequest, TGetResponse> = await this.$executeMiddlewares(request, response);
151
- let req: any = await this._get(result.request);
146
+ let req: TGetResponse | ResponseData<TGetResponse> = await this._get(result.request);
152
147
  this.$handleResponse(response, req);
153
148
  }
154
149
  catch (ex) {
@@ -161,7 +156,7 @@ export class Handler<
161
156
 
162
157
  try {
163
158
  let result: IRequestResponse<TPutRequest, TPutResponse> = await this.$executeMiddlewares(request, response);
164
- let req: any = await this._put(result.request);
159
+ let req: TPutResponse | ResponseData<TPutResponse> = await this._put(result.request);
165
160
  this.$handleResponse(response, req);
166
161
  }
167
162
  catch (ex) {
@@ -187,7 +182,7 @@ export class Handler<
187
182
 
188
183
  try {
189
184
  let result: IRequestResponse<TDeleteRequest, TDeleteResponse> = await this.$executeMiddlewares(request, response);
190
- let req: any = await this._delete(result.request);
185
+ let req: ResponseData<TDeleteResponse> | TDeleteResponse = await this._delete(result.request);
191
186
  this.$handleResponse(response, req);
192
187
  }
193
188
  catch (ex) {
@@ -195,19 +190,19 @@ export class Handler<
195
190
  }
196
191
  }
197
192
 
198
- protected async _get(request: Request<TGetRequest>): Promise<TGetResponse> {
193
+ protected async _get(request: Request<TGetRequest>): Promise<TGetResponse | ResponseData<TGetResponse>> {
199
194
  throw new NotImplementedError(HTTPMethod.GET);
200
195
  }
201
196
 
202
- protected async _post(request: Request<TPostRequest>): Promise<TPostResponse> {
197
+ protected async _post(request: Request<TPostRequest>): Promise<TPostResponse | ResponseData<TPostResponse>> {
203
198
  throw new NotImplementedError(HTTPMethod.POST);
204
199
  }
205
200
 
206
- protected async _put(request: Request<TPutRequest>): Promise<TPutResponse> {
201
+ protected async _put(request: Request<TPutRequest>): Promise<TPutResponse | ResponseData<TPutResponse>> {
207
202
  throw new NotImplementedError(HTTPMethod.PUT);
208
203
  }
209
204
 
210
- protected async _delete(request: Request<TDeleteRequest>): Promise<TDeleteResponse> {
205
+ protected async _delete(request: Request<TDeleteRequest>): Promise<TDeleteResponse | ResponseData<TDeleteResponse>> {
211
206
  throw new NotImplementedError(HTTPMethod.DELETE);
212
207
  }
213
208
  }
@@ -25,6 +25,9 @@ export interface IDatabaseConnection {
25
25
  getInstantiationStack(): string;
26
26
  getAPI(): any;
27
27
  isReadOnly(): boolean;
28
+ isMaster(): boolean;
29
+ isReplication(): boolean;
30
+ hasReplicationEnabled(): boolean;
28
31
  setTimeout(timeout: number): void;
29
32
  getTimeout(): number;
30
33
  query(query: IQueryable<any>, params?: any): Promise<any>;
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright 2017-2021 Norman Breau
2
+ Copyright 2017-2025 Norman Breau
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
@@ -15,9 +15,9 @@
15
15
  */
16
16
 
17
17
  import {Request} from './Request';
18
- import {Response} from './Response';
18
+ import {Response, SendableData} from './Response';
19
19
 
20
- export interface IRequestResponse<TRequest = any, TResponse = any> {
20
+ export interface IRequestResponse<TRequest = any, TResponse extends SendableData = SendableData> {
21
21
  request: Request<TRequest>;
22
22
  response: Response<TResponse>;
23
23
  }
@@ -44,6 +44,18 @@ export class ManagedDatabaseConnection implements IDatabaseConnection {
44
44
  this.$instantionStack = new Error().stack;
45
45
  }
46
46
 
47
+ public isMaster(): boolean {
48
+ throw new Error('Method not implemented.');
49
+ }
50
+
51
+ public isReplication(): boolean {
52
+ throw new Error('Method not implemented.');
53
+ }
54
+
55
+ public hasReplicationEnabled(): boolean {
56
+ throw new Error('Method not implemented.');
57
+ }
58
+
47
59
  public formatQuery(query: IQueryable<any>): string {
48
60
  throw new Error('Unsupported API call');
49
61
  }
package/src/Middleware.ts CHANGED
@@ -17,9 +17,21 @@
17
17
  import {Request} from './Request';
18
18
  import {Response} from './Response';
19
19
  import {IRequestResponse} from './IRequestResponse';
20
+ import { Application } from './Application';
20
21
 
21
- export abstract class Middleware {
22
- public constructor() {}
22
+ /**
23
+ * @deprecated
24
+ */
25
+ export abstract class Middleware<TApplication extends Application = Application> {
26
+ private $app: TApplication;
27
+
28
+ public constructor(app: TApplication) {
29
+ this.$app = app;
30
+ }
31
+
32
+ public getApplication(): TApplication {
33
+ return this.$app;
34
+ }
23
35
 
24
36
  protected abstract _execute(request: Request, response: Response): Promise<IRequestResponse>;
25
37
 
@@ -37,6 +37,7 @@ import { GetMasterPositionQuery } from './private/GetMasterPositionQuery';
37
37
  import { IQueryable } from './IQueryable';
38
38
  import { queryFormatter } from './mysql/queryFormatter';
39
39
  import { TransactionAccessLevel } from './TransactionAccessLevel';
40
+ import { GetProcessList, IGetProcessListOutput } from './private/GetProcessList';
40
41
 
41
42
  const DEFAULT_HIGH_WATERMARK: number = 512; // in number of result objects
42
43
  const TAG: string = 'MySQLConnection';
@@ -62,11 +63,13 @@ let rollbackQuery: RollbackQuery = new RollbackQuery();
62
63
  export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
63
64
  private $transaction: boolean;
64
65
  private $opened: boolean;
66
+ private $hasReplicationEnabled: boolean;
65
67
  private $isMasterConnection: boolean;
66
68
 
67
69
  public constructor(connection: MySQL.PoolConnection, instantiationStack: string, isReadOnly: boolean = true) {
68
70
  super(connection, isReadOnly, instantiationStack);
69
71
 
72
+ this.$hasReplicationEnabled = false;
70
73
  this.$opened = true;
71
74
  this.$transaction = false;
72
75
  this.$isMasterConnection = null;
@@ -91,17 +94,47 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
91
94
  */
92
95
  public async __internal_init(): Promise<void> {
93
96
  let result = await new GetSlavePositionQuery().execute(this);
94
- this.$isMasterConnection = result === null;
97
+ if (result !== null) {
98
+ this.$hasReplicationEnabled = true;
99
+ this.$isMasterConnection = false;
100
+ }
101
+ else {
102
+ this.$isMasterConnection = true;
103
+ let processList: IGetProcessListOutput[] = await new GetProcessList().execute(this);
104
+
105
+ for (let i: number = 0; i < processList.length; i++) {
106
+ let p: IGetProcessListOutput = processList[i];
107
+
108
+ if (p.Command === 'Binlog Dump') {
109
+ this.$hasReplicationEnabled = true;
110
+ break;
111
+ }
112
+ }
113
+ }
95
114
  }
96
115
 
97
116
  public override formatQuery(query: IQueryable<any>): string {
98
117
  return this.getAPI().config.queryFormat(query.getQuery(this), query.getParametersForQuery());
99
118
  }
100
119
 
120
+ /**
121
+ * Returns true if this server is the source.
122
+ * Will also return true if there is no replication detected.
123
+ */
101
124
  public isMaster(): boolean {
102
125
  return this.$isMasterConnection;
103
126
  }
104
127
 
128
+ /**
129
+ * Returns true if this server is part of a replication cluster.
130
+ */
131
+ public hasReplicationEnabled(): boolean {
132
+ return this.$hasReplicationEnabled;
133
+ }
134
+
135
+ /**
136
+ * Returns true if this server is a replication server.
137
+ */
105
138
  public isReplication(): boolean {
106
139
  return !this.isMaster();
107
140
  }
@@ -89,21 +89,19 @@ export class MySQLDatabase extends Database<MySQL.PoolConfig, MySQL.PoolConnecti
89
89
  let conn: MySQLConnection = await this.$getConnectionFromPool(query, requireWriteAccess, instantationStack);
90
90
  await conn.__internal_init();
91
91
 
92
- if (conn.isReplication()) {
92
+ if (conn.hasReplicationEnabled() && conn.isReplication() && position && position.page && position.position) {
93
93
  // master connections will not wait on database positions
94
94
  // they are guarenteed to be at the tip.
95
95
  // readonly, or otherwise known as replication connections
96
96
  // may have replication lag. If we have a desired position target,
97
97
  // then await for the connection to catch up to that target.
98
- if (position && position.page && position.position) {
99
- let waiter: ConnectionReplicationWaiter = new ConnectionReplicationWaiter(conn);
100
- try {
101
- await waiter.wait(position);
102
- }
103
- catch (ex) {
104
- conn.close(true);
105
- throw ex;
106
- }
98
+ let waiter: ConnectionReplicationWaiter = new ConnectionReplicationWaiter(conn);
99
+ try {
100
+ await waiter.wait(position);
101
+ }
102
+ catch (ex) {
103
+ conn.close(true);
104
+ throw ex;
107
105
  }
108
106
  }
109
107
 
package/src/Response.ts CHANGED
@@ -19,23 +19,35 @@ import {ResponseData} from './ResponseData';
19
19
  import {StormError, IErrorResponse} from './StormError';
20
20
  import * as express from 'express';
21
21
  import { InternalError } from './InternalError';
22
- import { getInstance } from './instance';
23
22
  import { Stream } from 'stream';
23
+ import { Application } from './Application';
24
24
 
25
25
  const TAG: string = 'Response';
26
26
 
27
- export type SendableData = ResponseData | Error | IErrorResponse | Buffer | any;
27
+ export type SendableData =
28
+ ResponseData<SendableData> |
29
+ Error |
30
+ IErrorResponse |
31
+ Buffer |
32
+ string |
33
+ number |
34
+ void |
35
+ ReadableStream |
36
+ Stream.Readable
37
+ ;
28
38
 
29
39
  export interface IHeaderKeyValuePair {
30
40
  [key: string]: string;
31
41
  }
32
42
 
33
- export class Response<TResponse = SendableData, TErrorResponse = Error | IErrorResponse | string> {
43
+ export class Response<TResponse extends SendableData = SendableData, TErrorResponse extends SendableData = SendableData> {
44
+ private $app: Application;
34
45
  private $response: express.Response;
35
46
  private $created: Date;
36
47
  private $requestURL: string;
37
48
 
38
- public constructor(response: express.Response, requestURL: string) {
49
+ public constructor(app: Application, response: express.Response, requestURL: string) {
50
+ this.$app = app;
39
51
  this.$response = response;
40
52
  this.$created = new Date();
41
53
  this.$requestURL = requestURL;
@@ -54,7 +66,7 @@ export class Response<TResponse = SendableData, TErrorResponse = Error | IErrorR
54
66
  this.$response.redirect(url);
55
67
  }
56
68
 
57
- private $send(data?: TResponse | TErrorResponse | StormError | IErrorResponse | Buffer, statusOverride?: StatusCode): void {
69
+ private $send(data?: SendableData, statusOverride?: StatusCode): void {
58
70
  if (data === null || data === undefined) {
59
71
  this.setStatus(statusOverride || StatusCode.OK_NO_CONTENT);
60
72
  this.$response.send()
@@ -92,9 +104,10 @@ export class Response<TResponse = SendableData, TErrorResponse = Error | IErrorR
92
104
  }
93
105
  }
94
106
 
95
- public send(data?: TResponse | TErrorResponse | StormError | IErrorResponse | Buffer): void {
107
+ // public send(data?: TResponse | TErrorResponse | StormError | IErrorResponse | Buffer): void {
108
+ public send(data?: SendableData): void {
96
109
  this.$send(data);
97
- getInstance().getLogger().info(TAG, `API ${this.$requestURL} (${this.getStatus()}) responded in ${new Date().getTime() - this.$created.getTime()}ms`);
110
+ this.$app.getLogger().info(TAG, `API ${this.$requestURL} (${this.getStatus()}) responded in ${new Date().getTime() - this.$created.getTime()}ms`);
98
111
  }
99
112
 
100
113
  public pipe(stream: NodeJS.ReadableStream): void {
@@ -15,10 +15,10 @@
15
15
  */
16
16
 
17
17
  import {Application} from './Application';
18
- import {IServiceHeaders} from './IServiceHeaders';
19
18
  import {HTTPMethod} from './HTTPMethod';
20
19
  import {ServiceResponse} from './ServiceResponse';
21
20
  import * as http from 'http';
21
+ import { OutgoingHttpHeaders } from 'http2';
22
22
 
23
23
  const TAG: string = 'ServiceProvider';
24
24
  const NO_DATA: string = `|${0x0}|`;
@@ -78,8 +78,19 @@ export abstract class ServiceProvider {
78
78
  return `/api/${this._getBase()}/${this.getVersion()}/${url}${this.urlSuffix()}${queryString}`;
79
79
  }
80
80
 
81
- public request(method: HTTPMethod, url: string, accessToken: string, data: any, headers?: IServiceHeaders, additionalOptions?: any): Promise<ServiceResponse> {
81
+ public request(method: HTTPMethod, url: string, accessToken: string, data: any, headers?: OutgoingHttpHeaders, additionalOptions?: any): Promise<ServiceResponse> {
82
82
  return new Promise<ServiceResponse>((resolve, reject) => {
83
+ if (!headers) {
84
+ headers = {};
85
+ }
86
+
87
+ headers[this.$app.getConfig().authentication_header] = accessToken;
88
+ headers[this.$app.getConfig().backend_authentication_header] = this.$getSecret();
89
+
90
+ if (!headers['content-type']) {
91
+ headers['content-type'] = 'application/json';
92
+ }
93
+
83
94
  let httpOpts: http.RequestOptions = {
84
95
  port: this._getPort(),
85
96
  hostname: `${this._getDomain()}`,
@@ -88,13 +99,6 @@ export abstract class ServiceProvider {
88
99
  headers: headers || {}
89
100
  };
90
101
 
91
- httpOpts.headers[this.$app.getConfig().authentication_header] = accessToken;
92
- httpOpts.headers[this.$app.getConfig().backend_authentication_header] = this.$getSecret();
93
-
94
- if (!httpOpts.headers['Content-Type']) {
95
- httpOpts.headers['Content-Type'] = 'application/json';
96
- }
97
-
98
102
  this.$app.getLogger().trace(TAG, `ServiceProvider Request`);
99
103
  this.$app.getLogger().trace(TAG, `METHOD: ${httpOpts.method}`);
100
104
  this.$app.getLogger().trace(TAG, `HOSTNAME: ${httpOpts.hostname}`);
@@ -137,19 +141,19 @@ export abstract class ServiceProvider {
137
141
  request.end();
138
142
  }
139
143
 
140
- public get(url: string, accessToken: string, data?: any, headers?: IServiceHeaders, additionalOptions?: any): Promise<ServiceResponse> {
144
+ public get(url: string, accessToken: string, data?: any, headers?: OutgoingHttpHeaders, additionalOptions?: any): Promise<ServiceResponse> {
141
145
  return this.request(HTTPMethod.GET, this._createURL(url, data), accessToken, NO_DATA, headers, additionalOptions);
142
146
  }
143
147
 
144
- public post(url: string, accessToken: string, data?: any, headers?: IServiceHeaders, additionalOptions?: any): Promise<ServiceResponse> {
148
+ public post(url: string, accessToken: string, data?: any, headers?: OutgoingHttpHeaders, additionalOptions?: any): Promise<ServiceResponse> {
145
149
  return this.request(HTTPMethod.POST, this._createURL(url), accessToken, data, headers, additionalOptions);
146
150
  }
147
151
 
148
- public put(url: string, accessToken: string, data?: any, headers?: IServiceHeaders, additionalOptions?: any): Promise<ServiceResponse> {
152
+ public put(url: string, accessToken: string, data?: any, headers?: OutgoingHttpHeaders, additionalOptions?: any): Promise<ServiceResponse> {
149
153
  return this.request(HTTPMethod.PUT, this._createURL(url), accessToken, data, headers, additionalOptions);
150
154
  }
151
155
 
152
- public delete(url: string, accessToken: string, data?: any, headers?: IServiceHeaders, additionalOptions?: any): Promise<ServiceResponse> {
156
+ public delete(url: string, accessToken: string, data?: any, headers?: OutgoingHttpHeaders, additionalOptions?: any): Promise<ServiceResponse> {
153
157
  return this.request(HTTPMethod.DELETE, this._createURL(url), accessToken, data, headers, additionalOptions);
154
158
  }
155
159
  }
@@ -20,6 +20,7 @@ import {IJWTVerifyOptions} from './IJWTVerifyOptions';
20
20
  import {JWTVerifyOptionsParser} from './JWTVerifyOptionsParser';
21
21
  import {randomBytes} from 'crypto';
22
22
  import { IAuthTokenData } from './IAuthTokenData';
23
+ import { StringValue } from 'ms';
23
24
 
24
25
  // const TAG: string = 'TokenManager';
25
26
 
@@ -30,7 +31,7 @@ export class TokenManager<TAuthToken extends IAuthTokenData = IAuthTokenData> {
30
31
  this.$secret = secret;
31
32
  }
32
33
 
33
- public sign(payload: {[key: string]: any}, expiresIn: string | number): Promise<Token> {
34
+ public sign(payload: {[key: string]: any}, expiresIn: StringValue | number): Promise<Token> {
34
35
  return new Promise<Token>((resolve, reject) => {
35
36
  randomBytes(64, (err: Error, buffer: Buffer) => {
36
37
  if (err) {
package/src/api.ts CHANGED
@@ -75,17 +75,14 @@ export {Middleware} from './Middleware';
75
75
  export {Request, IParameterMap} from './Request';
76
76
  export {Response} from './Response';
77
77
  export {ResponseData} from './ResponseData';
78
- export {Handler, IHandlerError, IHandlerResponse} from './Handler';
79
- export {CORSMiddleware} from './CORSMiddleware';
78
+ export {Handler} from './Handler';
80
79
  export {ServiceProvider} from './ServiceProvider';
81
80
  export {HTTPMethod} from './HTTPMethod';
82
81
  export {ServiceResponse} from './ServiceResponse';
83
- export {BackendAuthenticationMiddleware} from './BackendAuthenticationMiddleware';
84
82
 
85
83
  // Interfaces
86
84
  export {IDatabaseConfig} from './IDatabaseConfig';
87
85
  export {IJWTVerifyOptions} from './IJWTVerifyOptions';
88
- export {IHandler} from './IHandler';
89
86
  export {IRequestResponse} from './IRequestResponse';
90
87
  export {
91
88
  IConfig,
@@ -95,7 +92,6 @@ export {
95
92
  } from './IConfig';
96
93
  export {IFormData} from './IFormData';
97
94
  export {IDatabaseConnection} from './IDatabaseConnection';
98
- export {IServiceHeaders} from './IServiceHeaders';
99
95
  export {IAuthTokenData} from './IAuthTokenData';
100
96
  export {IQueryable} from './IQueryable';
101
97
  export {IDatabasePosition} from './IDatabasePosition';
@@ -55,7 +55,7 @@ export class ConnectionReplicationWaiter {
55
55
  }
56
56
 
57
57
  public async wait(target: IDatabasePosition, timeout: number = ConnectionReplicationWaiter.DEFAULT_TIMEOUT): Promise<void> {
58
- if (!this.$conn.isReadOnly()) {
58
+ if (this.$conn.isMaster()) {
59
59
  return;
60
60
  }
61
61
 
@@ -0,0 +1,20 @@
1
+
2
+ import { IDatabaseConnection } from '../IDatabaseConnection';
3
+ import {Query} from '../Query';
4
+
5
+ export interface IGetProcessListOutput {
6
+ Id: number;
7
+ User: string;
8
+ Host: string;
9
+ db: string;
10
+ Command: string;
11
+ Time: number;
12
+ State: string;
13
+ Info: string;
14
+ }
15
+
16
+ export class GetProcessList extends Query<void, IGetProcessListOutput[]> {
17
+ protected override _getQuery(connection: IDatabaseConnection): string {
18
+ return 'SHOW PROCESSLIST';
19
+ }
20
+ }
@@ -1,8 +0,0 @@
1
- <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>BackendAuthenticationMiddleware | @breautek/storm</title><meta name="description" content="Documentation for @breautek/storm"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@breautek/storm</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">BackendAuthenticationMiddleware</a></li></ul><h1>Class BackendAuthenticationMiddleware</h1></div><section class="tsd-panel tsd-comment"><div class="tsd-comment tsd-typography"><p>A base authentication strategy that handles 90% of the authentication process.
2
- This will verify that the token hasn't been manipulated or tainted.
3
- The authenticate API must be implemented by subclasses to further validate the token data
4
- for their specific use cases.</p>
5
- </div><div class="tsd-comment tsd-typography"></div></section><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/breautek/storm/blob/aee41fe79c42b214a44357bedb97b86fde2c357f/src/BackendAuthenticationMiddleware.ts#L32">src/BackendAuthenticationMiddleware.ts:32</a></li></ul></aside><section class="tsd-panel-group tsd-index-group"><section class="tsd-panel tsd-index-panel"><details class="tsd-index-content tsd-accordion" open><summary class="tsd-accordion-summary tsd-index-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h5 class="tsd-index-heading uppercase">Index</h5></summary><div class="tsd-accordion-details"><section class="tsd-index-section"><h3 class="tsd-index-heading">Constructors</h3><div class="tsd-index-list"><a href="#constructor" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Constructor"><use href="../assets/icons.svg#icon-512"></use></svg><span>constructor</span></a>
6
- </div></section><section class="tsd-index-section"><h3 class="tsd-index-heading">Methods</h3><div class="tsd-index-list"><a href="#execute" class="tsd-index-link"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Method"><use href="../assets/icons.svg#icon-2048"></use></svg><span>execute</span></a>
7
- </div></section></div></details></section></section><details class="tsd-panel-group tsd-member-group tsd-accordion" open><summary class="tsd-accordion-summary" data-key="section-Constructors"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h2>Constructors</h2></summary><section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="constructor"><span>constructor</span><a href="#constructor" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><ul class="tsd-signatures"><li class=""><div class="tsd-signature tsd-anchor-link" id="constructorbackendauthenticationmiddleware"><span class="tsd-signature-keyword">new</span> <span class="tsd-kind-constructor-signature">BackendAuthenticationMiddleware</span><span class="tsd-signature-symbol">()</span><span class="tsd-signature-symbol">:</span> <a href="" class="tsd-signature-type tsd-kind-class">BackendAuthenticationMiddleware</a><a href="#constructorbackendauthenticationmiddleware" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></div><div class="tsd-description"><h4 class="tsd-returns-title">Returns <a href="" class="tsd-signature-type tsd-kind-class">BackendAuthenticationMiddleware</a></h4><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/breautek/storm/blob/aee41fe79c42b214a44357bedb97b86fde2c357f/src/BackendAuthenticationMiddleware.ts#L35">src/BackendAuthenticationMiddleware.ts:35</a></li></ul></aside></div></li></ul></section></section></details><details class="tsd-panel-group tsd-member-group tsd-accordion" open><summary class="tsd-accordion-summary" data-key="section-Methods"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h2>Methods</h2></summary><section><section class="tsd-panel tsd-member"><h3 class="tsd-anchor-link" id="execute"><span>execute</span><a href="#execute" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><ul class="tsd-signatures"><li class=""><div class="tsd-signature tsd-anchor-link" id="execute-1"><span class="tsd-kind-call-signature">execute</span><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">request</span><span class="tsd-signature-symbol">:</span> <a href="Request.html" class="tsd-signature-type tsd-kind-class">Request</a><span class="tsd-signature-symbol">,</span> <span class="tsd-kind-parameter">options</span><span class="tsd-signature-symbol">?:</span> <span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">&gt;</span><a href="#execute-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></div><div class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">request</span>: <a href="Request.html" class="tsd-signature-type tsd-kind-class">Request</a></span><div class="tsd-comment tsd-typography"></div></li><li><span><code class="tsd-tag">Optional</code><span class="tsd-kind-parameter">options</span>: <span class="tsd-signature-type">any</span></span><div class="tsd-comment tsd-typography"><p>Arbituary object containing any relevant information used for authentication.</p>
8
- </div><div class="tsd-comment tsd-typography"></div></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">&gt;</span></h4><div class="tsd-comment tsd-typography"></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/breautek/storm/blob/aee41fe79c42b214a44357bedb97b86fde2c357f/src/BackendAuthenticationMiddleware.ts#L45">src/BackendAuthenticationMiddleware.ts:45</a></li></ul></aside></div></li></ul></section></section></details></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><details open class="tsd-accordion tsd-page-navigation-section"><summary class="tsd-accordion-summary" data-key="section-Constructors"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Constructors</summary><div><a href="#constructor"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Constructor"><use href="../assets/icons.svg#icon-512"></use></svg><span>constructor</span></a></div></details><details open class="tsd-accordion tsd-page-navigation-section"><summary class="tsd-accordion-summary" data-key="section-Methods"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Methods</summary><div><a href="#execute"><svg class="tsd-kind-icon" viewBox="0 0 24 24" aria-label="Method"><use href="../assets/icons.svg#icon-2048"></use></svg><span>execute</span></a></div></details></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../index.html">@breautek/storm</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>