@breautek/storm 7.1.2 → 8.1.0-beta.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 (170) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/docs/assets/highlight.css +16 -16
  3. package/docs/assets/main.js +2 -2
  4. package/docs/assets/navigation.js +1 -1
  5. package/docs/assets/style.css +3 -6
  6. package/docs/classes/Application.html +67 -67
  7. package/docs/classes/BackendAuthenticationMiddleware.html +3 -3
  8. package/docs/classes/CORSMiddleware.html +3 -3
  9. package/docs/classes/ConfigLoader.html +3 -3
  10. package/docs/classes/Database.html +2 -2
  11. package/docs/classes/DatabaseCastObject.html +2 -2
  12. package/docs/classes/DatabaseConnection.html +19 -19
  13. package/docs/classes/DatabaseQueryError.html +6 -6
  14. package/docs/classes/DeadLockError.html +6 -6
  15. package/docs/classes/DiskSpaceError.html +6 -6
  16. package/docs/classes/DropTemporaryTableQuery.html +6 -6
  17. package/docs/classes/DuplicateEntryError.html +6 -6
  18. package/docs/classes/EntityNotFoundError.html +6 -6
  19. package/docs/classes/ExpiredTokenError.html +6 -6
  20. package/docs/classes/Handler.html +2 -2
  21. package/docs/classes/InternalError.html +6 -6
  22. package/docs/classes/InvalidCredentialsError.html +6 -6
  23. package/docs/classes/InvalidValueError.html +6 -6
  24. package/docs/classes/LineString.html +2 -2
  25. package/docs/classes/LockWaitTimeoutError.html +6 -6
  26. package/docs/classes/ManagedDatabaseConnection.html +2 -2
  27. package/docs/classes/Middleware.html +2 -2
  28. package/docs/classes/MissingConfigError.html +6 -6
  29. package/docs/classes/MissingParameterError.html +6 -6
  30. package/docs/classes/MySQLConnection.html +19 -19
  31. package/docs/classes/MySQLDatabase.html +2 -2
  32. package/docs/classes/NotImplementedError.html +6 -6
  33. package/docs/classes/Point.html +2 -2
  34. package/docs/classes/Polygon.html +2 -2
  35. package/docs/classes/Query.html +6 -6
  36. package/docs/classes/RawError.html +6 -6
  37. package/docs/classes/RawQuery.html +6 -6
  38. package/docs/classes/Request.html +2 -2
  39. package/docs/classes/Response.html +2 -2
  40. package/docs/classes/ResponseData.html +2 -2
  41. package/docs/classes/ServiceProvider.html +2 -2
  42. package/docs/classes/ServiceResponse.html +2 -2
  43. package/docs/classes/SetSessionVariableQuery.html +6 -6
  44. package/docs/classes/StormError.html +6 -6
  45. package/docs/classes/TemporaryTableQuery.html +6 -6
  46. package/docs/classes/Token.html +2 -2
  47. package/docs/classes/TokenManager.html +2 -2
  48. package/docs/classes/Transaction.html +2 -2
  49. package/docs/classes/UnauthorizedAccessError.html +6 -6
  50. package/docs/enums/ErrorCode.html +2 -2
  51. package/docs/enums/ExitCode.html +2 -2
  52. package/docs/enums/HTTPMethod.html +2 -2
  53. package/docs/enums/IsolationLevel.html +2 -2
  54. package/docs/enums/JWTError.html +2 -2
  55. package/docs/enums/StatusCode.html +2 -2
  56. package/docs/functions/getInstance.html +1 -1
  57. package/docs/hierarchy.html +1 -1
  58. package/docs/index.html +3 -3
  59. package/docs/interfaces/IAdditionalErrorDetails.html +1 -1
  60. package/docs/interfaces/IAuthTokenData.html +1 -1
  61. package/docs/interfaces/ICloudwatchConfig.html +2 -2
  62. package/docs/interfaces/ICloudwatchCredentials.html +2 -2
  63. package/docs/interfaces/ICloudwatchStreamConfig.html +2 -2
  64. package/docs/interfaces/IConfig.html +2 -2
  65. package/docs/interfaces/IDatabaseConfig.html +2 -2
  66. package/docs/interfaces/IDatabaseConnection.html +2 -2
  67. package/docs/interfaces/IErrorResponse.html +2 -2
  68. package/docs/interfaces/IFormData.html +2 -2
  69. package/docs/interfaces/IHandler.html +2 -2
  70. package/docs/interfaces/IInsertQueryResult.html +2 -2
  71. package/docs/interfaces/IJWTVerifyOptions.html +2 -2
  72. package/docs/interfaces/IOKPacket.html +2 -2
  73. package/docs/interfaces/IParameterMap.html +1 -1
  74. package/docs/interfaces/IQueryable.html +2 -2
  75. package/docs/interfaces/IRequestResponse.html +2 -2
  76. package/docs/interfaces/IServiceHeaders.html +1 -1
  77. package/docs/interfaces/ISetSessionVariableQueryInput.html +2 -2
  78. package/docs/interfaces/IStormCLIArgs.html +2 -2
  79. package/docs/interfaces/ITemporaryTableQueryInput.html +2 -2
  80. package/docs/interfaces/IUpdateQueryResult.html +2 -2
  81. package/docs/modules/formidable.html +17 -17
  82. package/docs/types/IDeleteQueryResult.html +1 -1
  83. package/docs/types/IHandlerError.html +1 -1
  84. package/docs/types/IHandlerResponse.html +1 -1
  85. package/docs/types/IStoredProcedureResult.html +1 -1
  86. package/docs/types/TCoordinate.html +1 -1
  87. package/docs/variables/formidable-1.html +1 -0
  88. package/lib/Application.js +5 -3
  89. package/lib/Application.js.map +1 -1
  90. package/lib/ConfigLoader.js +8 -7
  91. package/lib/ConfigLoader.js.map +1 -1
  92. package/lib/Database.d.ts +3 -2
  93. package/lib/Database.js +4 -3
  94. package/lib/Database.js.map +1 -1
  95. package/lib/DatabaseCastObject.js +2 -1
  96. package/lib/DatabaseCastObject.js.map +1 -1
  97. package/lib/DatabaseConnection.d.ts +5 -0
  98. package/lib/DatabaseConnection.js.map +1 -1
  99. package/lib/IDatabaseConnection.d.ts +5 -0
  100. package/lib/IDatabasePosition.d.ts +7 -0
  101. package/lib/IDatabasePosition.js +18 -0
  102. package/lib/IDatabasePosition.js.map +1 -0
  103. package/lib/ManagedDatabaseConnection.d.ts +2 -0
  104. package/lib/ManagedDatabaseConnection.js +4 -0
  105. package/lib/ManagedDatabaseConnection.js.map +1 -1
  106. package/lib/MySQLConnection.d.ts +9 -0
  107. package/lib/MySQLConnection.js +25 -2
  108. package/lib/MySQLConnection.js.map +1 -1
  109. package/lib/MySQLDatabase.d.ts +3 -1
  110. package/lib/MySQLDatabase.js +28 -4
  111. package/lib/MySQLDatabase.js.map +1 -1
  112. package/lib/Request.js +4 -3
  113. package/lib/Request.js.map +1 -1
  114. package/lib/ServiceProvider.js +2 -1
  115. package/lib/ServiceProvider.js.map +1 -1
  116. package/lib/TimeoutError.d.ts +13 -0
  117. package/lib/TimeoutError.js +43 -0
  118. package/lib/TimeoutError.js.map +1 -0
  119. package/lib/TokenManager.js +2 -1
  120. package/lib/TokenManager.js.map +1 -1
  121. package/lib/api.d.ts +2 -0
  122. package/lib/api.js +6 -3
  123. package/lib/api.js.map +1 -1
  124. package/lib/private/ConnectionReplicationWaiter.d.ts +24 -0
  125. package/lib/private/ConnectionReplicationWaiter.js +92 -0
  126. package/lib/private/ConnectionReplicationWaiter.js.map +1 -0
  127. package/lib/private/GetBinLogPositionQuery.d.ts +12 -0
  128. package/lib/private/GetBinLogPositionQuery.js +49 -0
  129. package/lib/private/GetBinLogPositionQuery.js.map +1 -0
  130. package/lib/private/GetMasterPositionQuery.d.ts +11 -0
  131. package/lib/private/GetMasterPositionQuery.js +32 -0
  132. package/lib/private/GetMasterPositionQuery.js.map +1 -0
  133. package/lib/private/GetSlavePositionQuery.d.ts +11 -0
  134. package/lib/private/GetSlavePositionQuery.js +32 -0
  135. package/lib/private/GetSlavePositionQuery.js.map +1 -0
  136. package/package.json +17 -17
  137. package/src/Application.ts +4 -1
  138. package/src/ConfigLoader.ts +1 -1
  139. package/src/Database.ts +4 -3
  140. package/src/DatabaseConnection.ts +6 -0
  141. package/src/IDatabaseConnection.ts +6 -0
  142. package/src/IDatabasePosition.ts +23 -0
  143. package/src/ManagedDatabaseConnection.ts +6 -0
  144. package/src/MySQLConnection.ts +30 -1
  145. package/src/MySQLDatabase.ts +32 -4
  146. package/src/Request.ts +2 -2
  147. package/src/TimeoutError.ts +44 -0
  148. package/src/api.ts +2 -0
  149. package/src/private/ConnectionReplicationWaiter.ts +110 -0
  150. package/src/private/GetBinLogPositionQuery.ts +59 -0
  151. package/src/private/GetMasterPositionQuery.ts +37 -0
  152. package/src/private/GetSlavePositionQuery.ts +37 -0
  153. package/tsconfig.json +1 -0
  154. package/docs/functions/formidable-1.html +0 -1
  155. package/docs/interfaces/formidable.EmitData.html +0 -5
  156. package/docs/interfaces/formidable.EventData.html +0 -8
  157. package/docs/interfaces/formidable.Fields.html +0 -1
  158. package/docs/interfaces/formidable.File.html +0 -21
  159. package/docs/interfaces/formidable.FileJSON.html +0 -18
  160. package/docs/interfaces/formidable.Files.html +0 -1
  161. package/docs/interfaces/formidable.Options.html +0 -55
  162. package/docs/interfaces/formidable.Part.html +0 -136
  163. package/docs/types/formidable.BufferEncoding.html +0 -1
  164. package/docs/types/formidable.DefaultOptions.html +0 -1
  165. package/docs/types/formidable.EnabledPlugins.html +0 -1
  166. package/docs/types/formidable.EventNames.html +0 -1
  167. package/docs/types/formidable.MappedParsers.html +0 -1
  168. package/docs/types/formidable.Plugin.html +0 -1
  169. package/docs/types/formidable.PluginFunction.html +0 -1
  170. package/docs/types/formidable.Plugins.html +0 -1
@@ -22,6 +22,7 @@ import {IDatabaseConnection} from './IDatabaseConnection';
22
22
  import {IQueryable} from './IQueryable';
23
23
  import { IConfig } from './IConfig';
24
24
  import { IsolationLevel } from './IsolationLevel';
25
+ import { IDatabasePosition } from './IDatabasePosition';
25
26
 
26
27
  export const LINGER_WARNING: number = 10000;
27
28
  export const DEFAULT_QUERY_TIMEOUT: number = 3600000;
@@ -260,4 +261,9 @@ export abstract class DatabaseConnection<TAPI> implements IDatabaseConnection {
260
261
  */
261
262
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
262
263
  protected abstract _stream(query: string, params?: any, streamOptions?: any): Readable;
264
+
265
+ /**
266
+ * @since 8.1.0
267
+ */
268
+ public abstract getCurrentDatabasePosition(): Promise<IDatabasePosition>;
263
269
  }
@@ -17,6 +17,7 @@
17
17
  import { Readable } from 'stream';
18
18
  import { IQueryable } from './IQueryable';
19
19
  import { IsolationLevel } from './IsolationLevel';
20
+ import { IDatabasePosition } from './IDatabasePosition';
20
21
 
21
22
  export interface IDatabaseConnection {
22
23
  setInstantiationStack(stack: string): void;
@@ -33,4 +34,9 @@ export interface IDatabaseConnection {
33
34
  isTransaction(): boolean;
34
35
  commit(): Promise<void>;
35
36
  rollback(): Promise<void>;
37
+
38
+ /**
39
+ * @since 8.1.0
40
+ */
41
+ getCurrentDatabasePosition(): Promise<IDatabasePosition>;
36
42
  }
@@ -0,0 +1,23 @@
1
+ /*
2
+ Copyright 2017-2024 Norman Breau
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * @since 8.1.0
19
+ */
20
+ export interface IDatabasePosition {
21
+ page: number;
22
+ position: number;
23
+ }
@@ -19,6 +19,7 @@ import {getInstance} from './instance';
19
19
  import {Readable} from 'stream';
20
20
  import { Query } from './Query';
21
21
  import { IsolationLevel } from './IsolationLevel';
22
+ import { IDatabasePosition } from './IDatabasePosition';
22
23
 
23
24
  const TAG: string = 'ManagedDatabaseConnection';
24
25
 
@@ -81,6 +82,11 @@ export class ManagedDatabaseConnection implements IDatabaseConnection {
81
82
  }
82
83
  }
83
84
 
85
+ public async getCurrentDatabasePosition(): Promise<IDatabasePosition> {
86
+ let conn: IDatabaseConnection = await this.$getConnection();
87
+ return await conn.getCurrentDatabasePosition();
88
+ }
89
+
84
90
  public isWriteRequired(): boolean {
85
91
  return this.$requiresWrite;
86
92
  }
@@ -31,6 +31,10 @@ import { DeadLockError } from './DeadLockError';
31
31
  import { IsolationLevel } from './IsolationLevel';
32
32
  import {SetIsolationLevelQuery} from './private/SetIsolationLevelQuery';
33
33
  import { LockWaitTimeoutError } from './LockWaitTimeoutError';
34
+ import { IDatabasePosition } from './IDatabasePosition';
35
+ import { GetBinLogPositionQuery } from './private/GetBinLogPositionQuery';
36
+ import { GetSlavePositionQuery } from './private/GetSlavePositionQuery';
37
+ import { GetMasterPositionQuery } from './private/GetMasterPositionQuery';
34
38
 
35
39
  const DEFAULT_HIGH_WATERMARK: number = 512; // in number of result objects
36
40
  const TAG: string = 'MySQLConnection';
@@ -45,7 +49,9 @@ const SQL_FORMATTING_OPTIONS: SQLFormatter.FormatOptions = {
45
49
  linesBetweenQueries: 1,
46
50
  denseOperators: false,
47
51
  newlineBeforeSemicolon: false,
48
- expressionWidth: 4
52
+ expressionWidth: 4,
53
+ dataTypeCase: 'upper',
54
+ functionCase: 'upper'
49
55
  };
50
56
 
51
57
  let startTransactionQuery: Query = new StartTransactionQuery();
@@ -55,12 +61,14 @@ let rollbackQuery: Query = new RollbackQuery();
55
61
  export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
56
62
  private $transaction: boolean;
57
63
  private $opened: boolean;
64
+ private $isMasterConnection: boolean;
58
65
 
59
66
  public constructor(connection: MySQL.PoolConnection, instantiationStack: string, isReadOnly: boolean = true) {
60
67
  super(connection, isReadOnly, instantiationStack);
61
68
 
62
69
  this.$opened = true;
63
70
  this.$transaction = false;
71
+ this.$isMasterConnection = null;
64
72
 
65
73
  connection.config.queryFormat = function(query: string, values: any) {
66
74
  if (!values) return query;
@@ -75,6 +83,22 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
75
83
  };
76
84
  }
77
85
 
86
+ /**
87
+ * @internal - Do not use in application code
88
+ */
89
+ public async __internal_init(): Promise<void> {
90
+ let result = await new GetSlavePositionQuery().execute(this);
91
+ this.$isMasterConnection = result === null;
92
+ }
93
+
94
+ public isMaster(): boolean {
95
+ return this.$isMasterConnection;
96
+ }
97
+
98
+ public isReplication(): boolean {
99
+ return !this.isMaster();
100
+ }
101
+
78
102
  public isTransaction(): boolean {
79
103
  return this.$transaction;
80
104
  }
@@ -83,6 +107,11 @@ export class MySQLConnection extends DatabaseConnection<MySQL.PoolConnection> {
83
107
  return this.$opened;
84
108
  }
85
109
 
110
+ public override async getCurrentDatabasePosition(): Promise<IDatabasePosition> {
111
+ let statusQuery: GetBinLogPositionQuery = this.isReplication() ? new GetSlavePositionQuery() : new GetMasterPositionQuery();
112
+ return await statusQuery.execute(this);
113
+ }
114
+
86
115
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
87
116
  protected _query(query: string, params?: any): Promise<any> {
88
117
  let logger: BaseLogger = getInstance().getLogger();
@@ -18,6 +18,8 @@ import {Database} from './Database';
18
18
  import {MySQLConnection} from './MySQLConnection';
19
19
  import * as MySQL from 'mysql';
20
20
  import {getInstance} from './instance';
21
+ import { IDatabasePosition } from './IDatabasePosition';
22
+ import { ConnectionReplicationWaiter } from './private/ConnectionReplicationWaiter';
21
23
 
22
24
  const TAG: string = 'MySQLDatabase';
23
25
 
@@ -69,18 +71,44 @@ export class MySQLDatabase extends Database<MySQL.PoolConfig, MySQL.PoolConnecti
69
71
  });
70
72
  }
71
73
 
72
- protected _getConnection(query: string, requireWriteAccess: boolean): Promise<MySQLConnection> {
73
- getInstance().getLogger().trace(TAG, `Querying connection pool for "${query}".`);
74
+ private $getConnectionFromPool(query: string, requireWriteAccess: boolean, instantationStack: string): Promise<MySQLConnection> {
74
75
  return new Promise<MySQLConnection>((resolve, reject) => {
75
- let instantationStack: string = new Error().stack;
76
76
  this.$cluster.getConnection(query, (error: MySQL.MysqlError, connection: MySQL.PoolConnection) => {
77
77
  if (error) {
78
78
  reject(error);
79
79
  return;
80
80
  }
81
-
81
+
82
82
  resolve(new MySQLConnection(connection, instantationStack, !requireWriteAccess));
83
83
  });
84
84
  });
85
85
  }
86
+
87
+ protected override async _getConnection(query: string, requireWriteAccess: boolean, position?: IDatabasePosition): Promise<MySQLConnection> {
88
+ getInstance().getLogger().trace(TAG, `Querying connection pool for "${query}".`);
89
+ let instantationStack: string = new Error().stack;
90
+
91
+ let conn: MySQLConnection = await this.$getConnectionFromPool(query, requireWriteAccess, instantationStack);
92
+ await conn.__internal_init();
93
+
94
+ if (conn.isReplication()) {
95
+ // master connections will not wait on database positions
96
+ // they are guarenteed to be at the tip.
97
+ // readonly, or otherwise known as replication connections
98
+ // may have replication lag. If we have a desired position target,
99
+ // then await for the connection to catch up to that target.
100
+ if (position && position.page && position.position) {
101
+ let waiter: ConnectionReplicationWaiter = new ConnectionReplicationWaiter(conn);
102
+ try {
103
+ await waiter.wait(position);
104
+ }
105
+ catch (ex) {
106
+ conn.close(true);
107
+ throw ex;
108
+ }
109
+ }
110
+ }
111
+
112
+ return conn;
113
+ }
86
114
  }
package/src/Request.ts CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  Fields,
22
22
  Files
23
23
  } from 'formidable';
24
- import formidable = require('formidable');
24
+ import formidable from 'formidable';
25
25
  import {IFormData} from './IFormData';
26
26
  import { IAuthTokenData } from './IAuthTokenData';
27
27
  import { getInstance } from './instance';
@@ -51,7 +51,7 @@ export class Request<TBody = any, TAuthToken extends IAuthTokenData = IAuthToken
51
51
  return new Promise<IFormData>((resolve, reject) => {
52
52
  let r: express.Request = this.getRequestSource();
53
53
  let form: IncomingForm = formidable({
54
- hash: 'md5'
54
+ hashAlgorithm: 'md5'
55
55
  });
56
56
 
57
57
  form.parse(r, (error: any, fields: Fields, files: Files): any => {
@@ -0,0 +1,44 @@
1
+ /*
2
+ Copyright 2017-2024 Norman Breau
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import {StormError} from './StormError';
18
+ import {ErrorCode} from './ErrorCode';
19
+ import {StatusCode} from './StatusCode';
20
+
21
+ /**
22
+ * @since 8.1.0
23
+ */
24
+ export class TimeoutError extends StormError {
25
+ public constructor() {
26
+ super();
27
+ }
28
+
29
+ public getMessage(): string {
30
+ return `The requested resource could not be reached in time.`;
31
+ }
32
+
33
+ public getCode(): ErrorCode {
34
+ return ErrorCode.INTERNAL;
35
+ }
36
+
37
+ public getHTTPCode(): StatusCode {
38
+ return StatusCode.ERR_REQUEST_TIMEOUT;
39
+ }
40
+
41
+ public override getLocaleCode(): string {
42
+ return '@breautek/storm/TimeoutError/message';
43
+ }
44
+ }
package/src/api.ts CHANGED
@@ -51,6 +51,7 @@ export {
51
51
  IErrorResponse,
52
52
  IAdditionalErrorDetails
53
53
  } from './StormError';
54
+ export {TimeoutError} from './TimeoutError';
54
55
  export {JWTError} from './JWTError';
55
56
  export {MissingParameterError} from './MissingParameterError';
56
57
  export {InvalidCredentialsError} from './InvalidCredentialsError';
@@ -96,6 +97,7 @@ export {IDatabaseConnection} from './IDatabaseConnection';
96
97
  export {IServiceHeaders} from './IServiceHeaders';
97
98
  export {IAuthTokenData} from './IAuthTokenData';
98
99
  export {IQueryable} from './IQueryable';
100
+ export {IDatabasePosition} from './IDatabasePosition';
99
101
 
100
102
  // Token
101
103
  export {Token} from './Token';
@@ -0,0 +1,110 @@
1
+
2
+ /*
3
+ Copyright 2017-2024 Norman Breau
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ import { IDatabaseConnection } from '../IDatabaseConnection';
19
+ import { IDatabasePosition } from '../IDatabasePosition';
20
+ import { InternalError } from '../InternalError';
21
+ import { TimeoutError } from '../TimeoutError';
22
+
23
+ export class ConnectionReplicationWaiter {
24
+ /**
25
+ * The default retry delay in milliseconds.
26
+ * Defaults to 1 second.
27
+ *
28
+ * This is the value used in between status query iterations.
29
+ */
30
+ public static readonly DEFAULT_RETRY_DELAY: number = 1000;
31
+
32
+ /**
33
+ * The default timeout delay. Defaults to 120 seconds.
34
+ * If the connection could not reach the target position in time,
35
+ * then the wait will timeout
36
+ *
37
+ * Using `Infinity` will disable the timeout
38
+ */
39
+ public static readonly DEFAULT_TIMEOUT = 120 * 1000; // 120 seconds in ms
40
+
41
+ private $conn: IDatabaseConnection;
42
+ private $retryDelay: number;
43
+
44
+ public constructor(conn: IDatabaseConnection, retryDelay: number = ConnectionReplicationWaiter.DEFAULT_RETRY_DELAY) {
45
+ this.$conn = conn;
46
+ this.$retryDelay = retryDelay;
47
+ }
48
+
49
+ private $sleep(timeout: number): Promise<void> {
50
+ return new Promise((resolve, reject) => {
51
+ setTimeout(() => {
52
+ resolve();
53
+ }, timeout);
54
+ });
55
+ }
56
+
57
+ public async wait(target: IDatabasePosition, timeout: number = ConnectionReplicationWaiter.DEFAULT_TIMEOUT): Promise<void> {
58
+ if (!this.$conn.isReadOnly()) {
59
+ return;
60
+ }
61
+
62
+ let shouldTimeout: boolean = false;
63
+ let didTimeout: boolean = false;
64
+
65
+ let timeoutTimer = setTimeout(() => {
66
+ shouldTimeout = true;
67
+ }, timeout);
68
+
69
+ // eslint-disable-next-line no-constant-condition
70
+ while (true) {
71
+ if (shouldTimeout) {
72
+ didTimeout = true;
73
+ break;
74
+ }
75
+
76
+ let currentPos: IDatabasePosition = await this.$conn.getCurrentDatabasePosition();
77
+
78
+ if (currentPos === null || (currentPos && !currentPos.page === null) || (currentPos && !currentPos.position === null)) {
79
+ throw new InternalError('Database Position not supported');
80
+ }
81
+
82
+ // If the current page is greater than the target page,
83
+ // then the position doesn't matter, we are ahead of the
84
+ // desired target position.
85
+ if (currentPos.page > target.page) {
86
+ break;
87
+ }
88
+
89
+ // If the pages are equal, we need to check the position
90
+ // and ensure we are at or greater than the target.
91
+ if (currentPos.page === target.page && currentPos.position >= target.position) {
92
+ break;
93
+ }
94
+
95
+ // If we made it here, it means the position state checks failed
96
+ // so wait a short while and then re-iterate
97
+ await this.$sleep(this.$retryDelay);
98
+ }
99
+
100
+ if (didTimeout) {
101
+ // If the while loop exited due to the timeout,
102
+ // then throw a timeout error
103
+ throw new TimeoutError();
104
+ }
105
+
106
+ // Otherwise we are good to go!
107
+ clearTimeout(timeoutTimer);
108
+ }
109
+ }
110
+
@@ -0,0 +1,59 @@
1
+ /*
2
+ Copyright 2017-2024 Norman Breau
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import {Query} from '../Query';
18
+ import {IDatabasePosition} from '../IDatabasePosition';
19
+ import { IDatabaseConnection } from '../IDatabaseConnection';
20
+
21
+ /**
22
+ * @since 8.1.0
23
+ */
24
+ export abstract class GetBinLogPositionQuery<TStatusRow = unknown> extends Query<void, TStatusRow[], IDatabasePosition> {
25
+ protected abstract _getQuery(): string;
26
+
27
+ protected abstract _getFile(row: TStatusRow): string;
28
+ protected abstract _getPosition(row: TStatusRow): string;
29
+
30
+ public async onPostProcess(connection: IDatabaseConnection, resultSet: TStatusRow[]): Promise<IDatabasePosition> {
31
+ let row: TStatusRow = null;
32
+ if (resultSet.length > 0) {
33
+ row = resultSet[0];
34
+ }
35
+
36
+ if (!row) {
37
+ return null;
38
+ }
39
+
40
+ let pageParts: string[] = this._getFile(row).split('.');
41
+ let strPage: string = pageParts[pageParts.length - 1];
42
+
43
+ let page: number = parseInt(strPage);
44
+
45
+ if (isNaN(page)) {
46
+ return null;
47
+ }
48
+
49
+ let position: number = parseInt(this._getPosition(row));
50
+ if (isNaN(position)) {
51
+ return null;
52
+ }
53
+
54
+ return {
55
+ page: page,
56
+ position: position
57
+ };
58
+ }
59
+ }
@@ -0,0 +1,37 @@
1
+ /*
2
+ Copyright 2017-2024 Norman Breau
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import { GetBinLogPositionQuery } from './GetBinLogPositionQuery';
18
+
19
+ interface IStatus {
20
+ File: string;
21
+ Position: string;
22
+ }
23
+
24
+ export class GetMasterPositionQuery extends GetBinLogPositionQuery<IStatus> {
25
+
26
+ protected override _getQuery(): string {
27
+ return 'SHOW MASTER STATUS';
28
+ }
29
+
30
+ protected override _getFile(row: IStatus): string {
31
+ return row.File;
32
+ }
33
+
34
+ protected override _getPosition(row: IStatus): string {
35
+ return row.Position;
36
+ }
37
+ }
@@ -0,0 +1,37 @@
1
+ /*
2
+ Copyright 2017-2024 Norman Breau
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import { GetBinLogPositionQuery } from './GetBinLogPositionQuery';
18
+
19
+ interface IStatus {
20
+ Master_Log_File: string;
21
+ Read_Master_Log_Pos: string;
22
+ }
23
+
24
+ export class GetSlavePositionQuery extends GetBinLogPositionQuery<IStatus> {
25
+
26
+ protected override _getQuery(): string {
27
+ return 'SHOW SLAVE STATUS';
28
+ }
29
+
30
+ protected override _getFile(row: IStatus): string {
31
+ return row.Master_Log_File;
32
+ }
33
+
34
+ protected override _getPosition(row: IStatus): string {
35
+ return row.Read_Master_Log_Pos;
36
+ }
37
+ }
package/tsconfig.json CHANGED
@@ -10,6 +10,7 @@
10
10
  "noImplicitThis": true,
11
11
  "alwaysStrict": true,
12
12
  "noImplicitReturns": true,
13
+ "esModuleInterop": true,
13
14
  "moduleResolution": "node"
14
15
  },
15
16
  "exclude": [
@@ -1 +0,0 @@
1
- <!DOCTYPE html><html class="default" lang="en"><head><meta charSet="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>formidable | @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></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search" data-base=".."><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">@breautek/storm</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb"><li><a href="../index.html">@breautek/storm</a></li><li><a href="formidable-1.html">formidable</a></li></ul><h1>Function formidable</h1></div><section class="tsd-panel"><ul class="tsd-signatures tsd-is-external"><li class="tsd-signature tsd-anchor-link"><a id="formidable" class="tsd-anchor"></a><span class="tsd-kind-call-signature">formidable</span><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">options</span><span class="tsd-signature-symbol">?</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">IncomingForm</span><a href="#formidable" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><code class="tsd-tag ts-flagOptional">Optional</code> <span class="tsd-kind-parameter">options</span>: <a href="../interfaces/formidable.Options.html" class="tsd-signature-type tsd-kind-interface">Options</a></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">IncomingForm</span></h4><aside class="tsd-sources"><ul><li>Defined in node_modules/@types/formidable/index.d.ts:282</li></ul></aside></li></ul></section></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-index-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><h4 class="uppercase">Member Visibility</h4><form><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></form></div><div class="tsd-theme-toggle"><h4 class="uppercase">Theme</h4><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../index.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1"></use></svg><span>@breautek/storm</span></a><ul class="tsd-small-nested-navigation" id="tsd-nav-container" data-base=".."><li>Loading...</li></ul></nav></div></div></div><div class="tsd-generator"><p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></div><div class="overlay"></div></body></html>
@@ -1,5 +0,0 @@
1
- <!DOCTYPE html><html class="default" lang="en"><head><meta charSet="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>EmitData | @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></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search" data-base=".."><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">@breautek/storm</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb"><li><a href="../index.html">@breautek/storm</a></li><li><a href="../modules/formidable.html">formidable</a></li><li><a href="formidable.EmitData.html">EmitData</a></li></ul><h1>Interface EmitData</h1></div><div class="tsd-signature"><span class="tsd-signature-keyword">interface </span><span class="tsd-kind-interface">EmitData</span> <span class="tsd-signature-symbol">{ </span><br/><span>    </span><a class="tsd-kind-property" href="formidable.EmitData.html#formname">formname</a><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">any</span><span class="tsd-signature-symbol">; </span><br/><span>    </span><a class="tsd-kind-property" href="formidable.EmitData.html#key">key</a><span class="tsd-signature-symbol">?: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">number</span><span class="tsd-signature-symbol">; </span><br/><span>    </span><a class="tsd-kind-property" href="formidable.EmitData.html#name">name</a><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">&quot;file&quot;</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">&quot;fileBegin&quot;</span><span class="tsd-signature-symbol">; </span><br/><span>    </span><a class="tsd-kind-property" href="formidable.EmitData.html#value">value</a><span class="tsd-signature-symbol">: </span><span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> | </span><a href="formidable.File.html" class="tsd-signature-type tsd-kind-interface">File</a><span class="tsd-signature-symbol">; </span><br/><span class="tsd-signature-symbol">}</span></div><aside class="tsd-sources"><ul><li>Defined in node_modules/@types/formidable/index.d.ts:245</li></ul></aside><section class="tsd-panel-group tsd-index-group"><section class="tsd-panel tsd-index-panel"><details class="tsd-index-content tsd-index-accordion" open><summary class="tsd-accordion-summary tsd-index-summary"><h5 class="tsd-index-heading uppercase" role="button" aria-expanded="false" tabIndex="0"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-chevronSmall"></use></svg> Index</h5></summary><div class="tsd-accordion-details"><section class="tsd-index-section"><h3 class="tsd-index-heading">Properties</h3><div class="tsd-index-list"><a href="formidable.EmitData.html#formname" class="tsd-index-link tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>formname</span></a>
2
- <a href="formidable.EmitData.html#key" class="tsd-index-link tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>key?</span></a>
3
- <a href="formidable.EmitData.html#name" class="tsd-index-link tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>name</span></a>
4
- <a href="formidable.EmitData.html#value" class="tsd-index-link tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>value</span></a>
5
- </div></section></div></details></section></section><section class="tsd-panel-group tsd-member-group"><h2>Properties</h2><section class="tsd-panel tsd-member tsd-is-external"><a id="formname" class="tsd-anchor"></a><h3 class="tsd-anchor-link"><span>formname</span><a href="#formname" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-property">formname</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">any</span></div><aside class="tsd-sources"><ul><li>Defined in node_modules/@types/formidable/index.d.ts:246</li></ul></aside></section><section class="tsd-panel tsd-member tsd-is-external"><a id="key" class="tsd-anchor"></a><h3 class="tsd-anchor-link"><code class="tsd-tag ts-flagOptional">Optional</code> <span>key</span><a href="#key" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-property">key</span><span class="tsd-signature-symbol">?:</span> <span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">number</span></div><aside class="tsd-sources"><ul><li>Defined in node_modules/@types/formidable/index.d.ts:247</li></ul></aside></section><section class="tsd-panel tsd-member tsd-is-external"><a id="name" class="tsd-anchor"></a><h3 class="tsd-anchor-link"><span>name</span><a href="#name" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-property">name</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">&quot;file&quot;</span><span class="tsd-signature-symbol"> | </span><span class="tsd-signature-type">&quot;fileBegin&quot;</span></div><aside class="tsd-sources"><ul><li>Defined in node_modules/@types/formidable/index.d.ts:248</li></ul></aside></section><section class="tsd-panel tsd-member tsd-is-external"><a id="value" class="tsd-anchor"></a><h3 class="tsd-anchor-link"><span>value</span><a href="#value" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><div class="tsd-signature"><span class="tsd-kind-property">value</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">string</span><span class="tsd-signature-symbol"> | </span><a href="formidable.File.html" class="tsd-signature-type tsd-kind-interface">File</a></div><aside class="tsd-sources"><ul><li>Defined in node_modules/@types/formidable/index.d.ts:249</li></ul></aside></section></section></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-index-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><h4 class="uppercase">Member Visibility</h4><form><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></form></div><div class="tsd-theme-toggle"><h4 class="uppercase">Theme</h4><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-index-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#formname" class="tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>formname</span></a><a href="#key" class="tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>key</span></a><a href="#name" class="tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>name</span></a><a href="#value" class="tsd-is-external"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1024"></use></svg><span>value</span></a></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../index.html"><svg class="tsd-kind-icon" viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-1"></use></svg><span>@breautek/storm</span></a><ul class="tsd-small-nested-navigation" id="tsd-nav-container" data-base=".."><li>Loading...</li></ul></nav></div></div></div><div class="tsd-generator"><p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></div><div class="overlay"></div></body></html>