@ikonintegration/ikapi 4.0.1 → 5.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 (236) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.cjs +81 -0
  3. package/.github/workflows/npmpublish.yml +8 -19
  4. package/.github/workflows/prs.yml +12 -0
  5. package/README.md +89 -99
  6. package/dist/index.d.ts +16 -0
  7. package/dist/index.js +27 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/package-lock.json +11881 -0
  10. package/dist/package.json +81 -0
  11. package/dist/src/API/Request.d.ts +125 -0
  12. package/dist/src/API/Request.js +185 -0
  13. package/dist/src/API/Request.js.map +1 -0
  14. package/dist/src/API/Response.d.ts +188 -0
  15. package/dist/src/API/Response.js +270 -0
  16. package/dist/src/API/Response.js.map +1 -0
  17. package/dist/src/BaseEvent/DynamoTransaction.d.ts +70 -0
  18. package/dist/src/BaseEvent/DynamoTransaction.js +104 -0
  19. package/dist/src/BaseEvent/DynamoTransaction.js.map +1 -0
  20. package/dist/src/BaseEvent/EventProcessor.d.ts +58 -0
  21. package/dist/src/BaseEvent/EventProcessor.js +101 -0
  22. package/dist/src/BaseEvent/EventProcessor.js.map +1 -0
  23. package/dist/src/BaseEvent/Process.d.ts +50 -0
  24. package/dist/src/BaseEvent/Process.js +64 -0
  25. package/dist/src/BaseEvent/Process.js.map +1 -0
  26. package/dist/src/BaseEvent/StepTransaction.d.ts +23 -0
  27. package/dist/src/BaseEvent/StepTransaction.js +27 -0
  28. package/dist/src/BaseEvent/StepTransaction.js.map +1 -0
  29. package/dist/src/BaseEvent/Transaction.d.ts +149 -0
  30. package/dist/src/BaseEvent/Transaction.js +224 -0
  31. package/dist/src/BaseEvent/Transaction.js.map +1 -0
  32. package/dist/src/Cache/Redis.d.ts +29 -0
  33. package/dist/src/Cache/Redis.js +80 -0
  34. package/dist/src/Cache/Redis.js.map +1 -0
  35. package/dist/src/Cache/types.d.ts +31 -0
  36. package/dist/src/Cache/types.js +2 -0
  37. package/dist/src/Cache/types.js.map +1 -0
  38. package/dist/src/Config/Configuration.d.ts +123 -0
  39. package/dist/src/Config/Configuration.js +109 -0
  40. package/dist/src/Config/Configuration.js.map +1 -0
  41. package/dist/src/Config/EnvironmentVar.d.ts +74 -0
  42. package/dist/src/Config/EnvironmentVar.js +138 -0
  43. package/dist/src/Config/EnvironmentVar.js.map +1 -0
  44. package/dist/src/Crypto/Crypto.d.ts +45 -0
  45. package/dist/src/Crypto/Crypto.js +72 -0
  46. package/dist/src/Crypto/Crypto.js.map +1 -0
  47. package/dist/src/Database/Database.d.ts +21 -0
  48. package/dist/src/Database/Database.js +15 -0
  49. package/dist/src/Database/Database.js.map +1 -0
  50. package/dist/src/Database/DatabaseManager.d.ts +47 -0
  51. package/dist/src/Database/DatabaseManager.js +60 -0
  52. package/dist/src/Database/DatabaseManager.js.map +1 -0
  53. package/dist/src/Database/DatabaseTransaction.d.ts +101 -0
  54. package/dist/src/Database/DatabaseTransaction.js +126 -0
  55. package/dist/src/Database/DatabaseTransaction.js.map +1 -0
  56. package/dist/src/Database/index.d.ts +10 -0
  57. package/dist/src/Database/index.js +15 -0
  58. package/dist/src/Database/index.js.map +1 -0
  59. package/dist/src/Database/integrations/dynamo/DynamoDatabase.d.ts +35 -0
  60. package/dist/src/Database/integrations/dynamo/DynamoDatabase.js +59 -0
  61. package/dist/src/Database/integrations/dynamo/DynamoDatabase.js.map +1 -0
  62. package/dist/src/Database/integrations/kysely/KyselyDatabase.d.ts +66 -0
  63. package/dist/src/Database/integrations/kysely/KyselyDatabase.js +86 -0
  64. package/dist/src/Database/integrations/kysely/KyselyDatabase.js.map +1 -0
  65. package/dist/src/Database/integrations/kysely/KyselyTransaction.d.ts +70 -0
  66. package/dist/src/Database/integrations/kysely/KyselyTransaction.js +118 -0
  67. package/dist/src/Database/integrations/kysely/KyselyTransaction.js.map +1 -0
  68. package/dist/src/Database/integrations/pgsql/PostgresDatabase.d.ts +36 -0
  69. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js +54 -0
  70. package/dist/src/Database/integrations/pgsql/PostgresDatabase.js.map +1 -0
  71. package/dist/src/Database/integrations/pgsql/PostgresTransaction.d.ts +63 -0
  72. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js +61 -0
  73. package/dist/src/Database/integrations/pgsql/PostgresTransaction.js.map +1 -0
  74. package/dist/src/Database/types.d.ts +76 -0
  75. package/dist/src/Database/types.js +2 -0
  76. package/dist/src/Database/types.js.map +1 -0
  77. package/dist/src/Globals.d.ts +93 -0
  78. package/dist/src/Globals.js +99 -0
  79. package/dist/src/Globals.js.map +1 -0
  80. package/dist/src/Logger/Logger.d.ts +161 -0
  81. package/dist/src/Logger/Logger.js +299 -0
  82. package/dist/src/Logger/Logger.js.map +1 -0
  83. package/dist/src/Mailer/Mailer.d.ts +78 -0
  84. package/dist/src/Mailer/Mailer.js +182 -0
  85. package/dist/src/Mailer/Mailer.js.map +1 -0
  86. package/dist/src/Publisher/Publisher.d.ts +39 -0
  87. package/dist/src/Publisher/Publisher.js +77 -0
  88. package/dist/src/Publisher/Publisher.js.map +1 -0
  89. package/dist/src/Server/RouteResolver.d.ts +33 -0
  90. package/dist/src/Server/RouteResolver.js +100 -0
  91. package/dist/src/Server/RouteResolver.js.map +1 -0
  92. package/dist/src/Server/Router.d.ts +157 -0
  93. package/dist/src/Server/Router.js +32 -0
  94. package/dist/src/Server/Router.js.map +1 -0
  95. package/dist/src/Server/lib/ContainerServer.d.ts +42 -0
  96. package/dist/src/Server/lib/ContainerServer.js +66 -0
  97. package/dist/src/Server/lib/ContainerServer.js.map +1 -0
  98. package/dist/src/Server/lib/Server.d.ts +45 -0
  99. package/dist/src/Server/lib/Server.js +93 -0
  100. package/dist/src/Server/lib/Server.js.map +1 -0
  101. package/dist/src/Server/lib/container/GenericHandler.d.ts +9 -0
  102. package/dist/src/Server/lib/container/GenericHandler.js +82 -0
  103. package/dist/src/Server/lib/container/GenericHandler.js.map +1 -0
  104. package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +52 -0
  105. package/dist/src/Server/lib/container/GenericHandlerEvent.js +132 -0
  106. package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -0
  107. package/dist/src/Server/lib/container/HealthHandler.d.ts +9 -0
  108. package/dist/src/Server/lib/container/HealthHandler.js +19 -0
  109. package/dist/src/Server/lib/container/HealthHandler.js.map +1 -0
  110. package/dist/src/Server/lib/container/Proxy.d.ts +67 -0
  111. package/dist/src/Server/lib/container/Proxy.js +143 -0
  112. package/dist/src/Server/lib/container/Proxy.js.map +1 -0
  113. package/dist/src/Server/lib/container/Utils.d.ts +14 -0
  114. package/dist/src/Server/lib/container/Utils.js +37 -0
  115. package/dist/src/Server/lib/container/Utils.js.map +1 -0
  116. package/dist/src/Util/AsyncSingleton.d.ts +31 -0
  117. package/dist/src/Util/AsyncSingleton.js +83 -0
  118. package/dist/src/Util/AsyncSingleton.js.map +1 -0
  119. package/dist/src/Util/Utils.d.ts +61 -0
  120. package/dist/src/Util/Utils.js +147 -0
  121. package/dist/src/Util/Utils.js.map +1 -0
  122. package/dist/src/Validation/Validator.d.ts +17 -0
  123. package/dist/src/Validation/Validator.js +39 -0
  124. package/dist/src/Validation/Validator.js.map +1 -0
  125. package/dist/tsconfig.tsbuildinfo +1 -0
  126. package/index.ts +41 -0
  127. package/jest.config.ts +37 -0
  128. package/jest.smoke.config.ts +34 -0
  129. package/package.json +66 -22
  130. package/src/API/Request.ts +214 -0
  131. package/src/API/Response.ts +370 -0
  132. package/src/BaseEvent/DynamoTransaction.ts +175 -0
  133. package/src/BaseEvent/EventProcessor.ts +140 -0
  134. package/src/BaseEvent/Process.ts +78 -0
  135. package/src/BaseEvent/StepTransaction.ts +35 -0
  136. package/src/BaseEvent/Transaction.ts +323 -0
  137. package/src/Cache/Redis.ts +89 -0
  138. package/src/Cache/types.ts +33 -0
  139. package/src/Config/Configuration.ts +199 -0
  140. package/src/Config/EnvironmentVar.ts +142 -0
  141. package/src/Crypto/Crypto.ts +89 -0
  142. package/src/Database/Database.ts +22 -0
  143. package/src/Database/DatabaseManager.ts +67 -0
  144. package/src/Database/DatabaseTransaction.ts +170 -0
  145. package/src/Database/index.ts +27 -0
  146. package/src/Database/integrations/dynamo/DynamoDatabase.ts +58 -0
  147. package/src/Database/integrations/kysely/KyselyDatabase.ts +99 -0
  148. package/src/Database/integrations/kysely/KyselyTransaction.ts +172 -0
  149. package/src/Database/integrations/pgsql/PostgresDatabase.ts +56 -0
  150. package/src/Database/integrations/pgsql/PostgresTransaction.ts +87 -0
  151. package/src/Database/types.ts +85 -0
  152. package/src/Globals.ts +103 -0
  153. package/src/Logger/Logger.ts +363 -0
  154. package/src/Mailer/Mailer.ts +217 -0
  155. package/src/Publisher/Publisher.ts +96 -0
  156. package/src/Server/RouteResolver.ts +124 -0
  157. package/src/Server/Router.ts +200 -0
  158. package/src/Server/lib/ContainerServer.ts +65 -0
  159. package/src/Server/lib/Server.ts +109 -0
  160. package/src/Server/lib/container/GenericHandler.ts +76 -0
  161. package/src/Server/lib/container/GenericHandlerEvent.ts +154 -0
  162. package/src/Server/lib/container/HealthHandler.ts +11 -0
  163. package/src/Server/lib/container/Proxy.ts +172 -0
  164. package/src/Server/lib/container/Utils.ts +33 -0
  165. package/src/Util/AsyncSingleton.ts +86 -0
  166. package/src/Util/Utils.ts +131 -0
  167. package/src/Validation/Validator.ts +45 -0
  168. package/tests/API/Request.test.ts +273 -0
  169. package/tests/API/Response.test.ts +367 -0
  170. package/tests/BaseEvent/DynamoTransaction.test.ts +272 -0
  171. package/tests/BaseEvent/EventProcessor.test.ts +263 -0
  172. package/tests/BaseEvent/Process.test.ts +47 -0
  173. package/tests/BaseEvent/StepTransaction.test.ts +44 -0
  174. package/tests/BaseEvent/Transaction.test.ts +402 -0
  175. package/tests/Cache/Redis-client.test.ts +90 -0
  176. package/tests/Cache/Redis-cluster.test.ts +100 -0
  177. package/tests/Config/Config.test.ts +205 -0
  178. package/tests/Config/EnvironmentVar.test.ts +251 -0
  179. package/tests/Crypto/Crypto.test.ts +88 -0
  180. package/tests/Database/DatabaseManager.test.ts +79 -0
  181. package/tests/Database/integrations/dynamo/DynamoDatabase.test.ts +44 -0
  182. package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +113 -0
  183. package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +119 -0
  184. package/tests/Database/integrations/pg/PostgresDatabase.test.ts +76 -0
  185. package/tests/Database/integrations/pg/PostgresTransaction.test.ts +118 -0
  186. package/tests/Logger/Logger.test.ts +215 -0
  187. package/tests/Mailer/Mailer.test.ts +59 -0
  188. package/tests/Publisher/Publisher.test.ts +60 -0
  189. package/tests/Server/RouteResolver.test.ts +116 -0
  190. package/tests/Server/Router.test.ts +39 -0
  191. package/tests/Server/lib/ContainerServer.test.ts +531 -0
  192. package/tests/Server/lib/Server.test.ts +12 -0
  193. package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
  194. package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
  195. package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
  196. package/tests/Server/lib/container/Proxy.test.ts +268 -0
  197. package/tests/Server/lib/container/Utils.test.ts +47 -0
  198. package/tests/Test.utils.ts +78 -0
  199. package/tests/Utils/Utils.test.ts +229 -0
  200. package/tests/Validation/Validator.test.ts +82 -0
  201. package/tsconfig.json +26 -0
  202. package/tsconfig.smoke.json +26 -0
  203. package/index.js +0 -88
  204. package/src/API/IKRequest.js +0 -52
  205. package/src/API/IKResponse.js +0 -119
  206. package/src/API/IKUtils.js +0 -51
  207. package/src/BaseEvent/IKProcess.js +0 -77
  208. package/src/BaseEvent/IKTransaction.js +0 -139
  209. package/src/Cache/Prototype/IKCache.js +0 -17
  210. package/src/Cache/Redis/IKRedis.js +0 -148
  211. package/src/Database/DDB/IKDB.js +0 -56
  212. package/src/Database/DDB/IKDBBaseExpression.js +0 -130
  213. package/src/Database/DDB/IKDBBaseQuery.js +0 -151
  214. package/src/Database/DDB/IKDBQueryBatchGet.js +0 -37
  215. package/src/Database/DDB/IKDBQueryBatchWrite.js +0 -64
  216. package/src/Database/DDB/IKDBQueryDelete.js +0 -34
  217. package/src/Database/DDB/IKDBQueryGet.js +0 -48
  218. package/src/Database/DDB/IKDBQueryPut.js +0 -87
  219. package/src/Database/DDB/IKDBQueryScan.js +0 -45
  220. package/src/Database/DDB/IKDBQueryTransactionalWrite.js +0 -69
  221. package/src/Database/DDB/IKDBQueryUpdate.js +0 -221
  222. package/src/Database/DDB/_IKDBQueryTransactionalRead.js +0 -46
  223. package/src/Database/PSQL/IKDB.js +0 -41
  224. package/src/Database/PSQL/IKDBBaseQuery.js +0 -26
  225. package/src/Database/Prototype/IKDB.js +0 -21
  226. package/src/Database/Prototype/IKDBBaseQuery.js +0 -14
  227. package/src/IKDynamoStream.js +0 -42
  228. package/src/IKEventProcessor.js +0 -42
  229. package/src/IKGlobals.js +0 -24
  230. package/src/IKRouter.js +0 -47
  231. package/src/IKStepTransaction.js +0 -14
  232. package/src/Logger/IKLogger.js +0 -136
  233. package/src/Mailer/IKMailer.js +0 -69
  234. package/src/Publisher/IKPublisher.js +0 -44
  235. package/src/Tracker/IKExecutionTracker.js +0 -79
  236. package/src/Validation/IKValidation.js +0 -76
@@ -0,0 +1,199 @@
1
+ import MemCache from 'node-cache'
2
+ import DurationParser from 'parse-duration'
3
+
4
+ import EnvironmentVar, { EnvironmentType } from './EnvironmentVar.js'
5
+
6
+ // Hold cached values at nodeVM level
7
+ // eslint-disable-next-line no-var
8
+ /**
9
+ * Creates a new instance of a memory cache store.
10
+ * @returns {MemCache} A new instance of a memory cache store.
11
+ */
12
+ let cacheStore = new MemCache()
13
+
14
+ /**
15
+ * Represents the schema for the configuration object.
16
+ * @typedef {Object} ConfigurationSchema
17
+ * @property {Object} [name] - The name of the configuration property.
18
+ * @property {boolean} [name.isLocal] - Indicates if the property is for local use.
19
+ * @property {boolean} [name.isRemote] - Indicates if the property is for remote use.
20
+ * @property {boolean} [name.required] - Indicates if the property is required.
21
+ * @property {string} [name.cachingPolicy] - The caching policy for the property.
22
+ * @property {string} [name.nameOverride] - The optional name override if the key differs
23
+ */
24
+ export type ConfigurationSchema = {
25
+ [name: string]: {
26
+ isLocal?: boolean
27
+ isRemote?: boolean
28
+ isSecure?: boolean
29
+ required?: boolean
30
+ noPrefix?: boolean
31
+ cachingPolicy?: string
32
+ nameOverride?: string
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Extracts the properties from a given type that have the `isRemote` property set to `true`.
38
+ * @param {Type} - The type to extract properties from.
39
+ * @returns An object type with the extracted properties.
40
+ */
41
+ // runtime type infer to ConfigurationSchema keys, which type is remote
42
+ type ExtractRemote<Type> = {
43
+ [Property in keyof Type]-?: Type[Property] extends {
44
+ isRemote: true
45
+ }
46
+ ? Property
47
+ : null
48
+ }
49
+ /**
50
+ * Extracts the properties from a given type that have the `isLocal` property set to `true`.
51
+ * @typeparam Type - The type to extract properties from.
52
+ * @returns An object type with the extracted properties as keys and their corresponding types.
53
+ */
54
+ // runtime type infer to ConfigurationSchema keys, which type is local
55
+ type ExtractLocal<Type> = {
56
+ [Property in keyof Type]-?: Type[Property] extends {
57
+ isLocal: true
58
+ }
59
+ ? Property
60
+ : null
61
+ }
62
+
63
+ /**
64
+ * Creates a new type by omitting keys from type T whose values are of type U.
65
+ * @param {T} - The original type
66
+ * @param {U} - The type to omit from T
67
+ * @returns A new type with the omitted keys
68
+ */
69
+ // Helpers to filter null keys
70
+ type OmitKeysByValueType<T, U> = {
71
+ [P in keyof T]: T[P] extends U ? never : P
72
+ }[keyof T]
73
+ /**
74
+ * Omit properties from an object type by their value type.
75
+ * @template T - The object type to omit properties from.
76
+ * @template V - The value type of properties to omit.
77
+ * @typedef OmitByValueType
78
+ * @property {T} T - The object type to omit properties from.
79
+ * @property {V} V - The value type of properties to omit.
80
+ * @returns {OmitKeysByValueType<T, V>} - The resulting object type after omitting properties.
81
+ */
82
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, prettier/prettier
83
+ type OmitByValueType<T, V> = T extends infer _
84
+ ? {
85
+ [key in OmitKeysByValueType<T, V>]: T[key]
86
+ }
87
+ : never
88
+
89
+ /**
90
+ * Represents a configuration object with a specified schema and remote prefix.
91
+ * @template T - The type of the configuration schema.
92
+ */
93
+ export default class Configuration<T extends ConfigurationSchema> {
94
+ /**
95
+ * The schema for the private readonly property.
96
+ * @type {T}
97
+ */
98
+ private readonly schema: T
99
+ /**
100
+ * The prefix used for remote resources.
101
+ * @type {string}
102
+ */
103
+ private readonly remotePrefix: string
104
+ /**
105
+ * Indicates if config is local and should attempt to override
106
+ * remote values from local.
107
+ * @type {string}
108
+ */
109
+ private static readonly isLocal: boolean = process.env.NODE_ENV == 'local'
110
+
111
+ /**
112
+ * Constructs a new instance of the class.
113
+ * @param {T} schema - The schema object.
114
+ * @param {string} remotePrefix - The remote prefix string.
115
+ * @returns None
116
+ */
117
+ constructor(schema: T, remotePrefix: string) {
118
+ this.schema = schema
119
+ this.remotePrefix = remotePrefix
120
+ }
121
+
122
+ /**
123
+ * Retrieves the value of a property from the environment variables or cache.
124
+ * @param {keyof OmitByValueType<ExtractLocal<T>, null>} propName - The name of the property to retrieve.
125
+ * @returns The value of the property.
126
+ */
127
+ public get(propName: keyof OmitByValueType<ExtractLocal<T>, null>): any {
128
+ const propString = propName as string
129
+ const propSchema = this.schema[propString]
130
+ let v = this.getCachedValue(propString)
131
+ v =
132
+ v ||
133
+ new EnvironmentVar<string>(
134
+ propSchema.nameOverride || propString,
135
+ EnvironmentType.Local,
136
+ !propSchema.required,
137
+ !propSchema.noPrefix ? this.remotePrefix : ''
138
+ ).syncResolve()
139
+ this.cacheValue(propString, v, propSchema.cachingPolicy)
140
+ return v
141
+ }
142
+
143
+ /**
144
+ * Asynchronously retrieves the value of a property from the remote environment.
145
+ * @param {keyof OmitByValueType<ExtractRemote<T>, null>} propName - The name of the property to retrieve.
146
+ * @returns {Promise<any>} - A promise that resolves to the value of the property.
147
+ */
148
+ public async asyncGet(propName: keyof OmitByValueType<ExtractRemote<T>, null>): Promise<any> {
149
+ const propString = propName as string
150
+ const propSchema = this.schema[propString]
151
+ // check cache
152
+ let v = this.getCachedValue(propString)
153
+ if (v !== undefined) return v
154
+ // check for local override
155
+ if (Configuration.isLocal && process.env[propString] !== undefined) {
156
+ console.log(`Overriding remote variable ${propString} with local value!`)
157
+ const v = process.env[propString]
158
+ this.cacheValue(propString, v, propSchema.cachingPolicy)
159
+ return v
160
+ }
161
+ // remote
162
+ v = await new EnvironmentVar<string>(
163
+ propSchema.nameOverride || propString,
164
+ propSchema.isSecure ? EnvironmentType.SecureRemote : EnvironmentType.PlainRemote,
165
+ !propSchema.required,
166
+ !propSchema.noPrefix ? this.remotePrefix : ''
167
+ ).resolve()
168
+ this.cacheValue(propString, v, propSchema.cachingPolicy)
169
+ return v
170
+ }
171
+
172
+ /**
173
+ * Retrieves the cached value associated with the given key from the cache store.
174
+ * @param {string} valueKey - The key of the value to retrieve from the cache.
175
+ * @returns The cached value associated with the given key, or undefined if the key does not exist in the cache.
176
+ */
177
+ private getCachedValue(valueKey: string): any {
178
+ return cacheStore.get(valueKey)
179
+ }
180
+
181
+ /**
182
+ * Caches a value with the specified key and expiration policy.
183
+ * @param {string} valueKey - The key to associate with the cached value.
184
+ * @param {any} value - The value to be cached.
185
+ * @param {string} [policy='1d'] - The expiration policy for the cached value. Defaults to '1d' (1 day).
186
+ * @returns None
187
+ */
188
+ private cacheValue(valueKey: string, value: any, policy: string = '1d'): void {
189
+ cacheStore.set(valueKey, value, DurationParser(policy, 's') || '')
190
+ }
191
+
192
+ /**
193
+ * Resets the cache by creating a new instance of the MemCache class and assigning it to the cacheStore variable.
194
+ * @returns None
195
+ */
196
+ private resetCache() {
197
+ cacheStore = new MemCache()
198
+ }
199
+ }
@@ -0,0 +1,142 @@
1
+ import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
2
+ import { SSMClient, GetParameterCommand } from '@aws-sdk/client-ssm'
3
+
4
+ // Explicity setting VM level variables in order to persist
5
+ // client across different important and instances.
6
+ // eslint-disable-next-line no-var
7
+ /**
8
+ * Variables to hold instances of SSMClient and SecretsManagerClient, initialized as null.
9
+ * @type {SSMClient | null} ssmClient - Instance of SSMClient or null if not initialized.
10
+ * @type {SecretsManagerClient | null} secretsClient - Instance of SecretsManagerClient or null if not initialized.
11
+ */
12
+ let ssmClient: SSMClient | null = null,
13
+ secretsClient: SecretsManagerClient | null = null
14
+
15
+ /**
16
+ * An enumeration representing different types of environments.
17
+ * @enum {number}
18
+ * @readonly
19
+ * @property {number} PlainRemote - Represents a plain remote environment.
20
+ * @property {number} SecureRemote - Represents a secure remote environment.
21
+ * @property {number} Local - Represents a local environment.
22
+ */
23
+ export enum EnvironmentType {
24
+ PlainRemote,
25
+ SecureRemote,
26
+ Local,
27
+ }
28
+ /**
29
+ * Represents an environment variable with methods to resolve its value based on the environment type.
30
+ * @template T - The type of the environment variable value.
31
+ */
32
+ export default class EnvironmentVar<T> {
33
+ /**
34
+ * The name of the parameter.
35
+ */
36
+ private readonly paramName: string
37
+ /**
38
+ * The type of environment.
39
+ * @readonly
40
+ */
41
+ private readonly type: EnvironmentType
42
+ /**
43
+ * A boolean flag indicating whether the field is optional or not.
44
+ */
45
+ private readonly optional: boolean
46
+ /**
47
+ * The prefix used for parameters in the class.
48
+ * @type {string}
49
+ */
50
+ private readonly paramPrefix: string
51
+
52
+ /**
53
+ * Constructs a new instance of the EnvironmentVar class.
54
+ * @param {string} paramName - The name of the environment variable.
55
+ * @param {EnvironmentType} type - The type of the environment.
56
+ * @param {boolean} [optional] - Indicates whether the environment variable is optional.
57
+ * @param {string} [paramPrefix] - The prefix to be added to the environment variable name.
58
+ */
59
+ constructor(paramName: string, type: EnvironmentType, optional = true, paramPrefix: string) {
60
+ this.paramName = paramName
61
+ this.type = type
62
+ this.optional = !!optional
63
+ this.paramPrefix = paramPrefix
64
+ }
65
+
66
+ /**
67
+ * Resolves the value of the environment variable synchronously.
68
+ * @returns {T} - The resolved value of the environment variable.
69
+ * @throws {Error} - If the environment type is not 'Local'.
70
+ */
71
+ public syncResolve(): T {
72
+ if (this.type == EnvironmentType.Local) return this.getLocalValue()
73
+ else {
74
+ throw new Error(
75
+ "EnvironmentVar syncResolve method can only be called for environments of type 'Local'"
76
+ )
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Resolves the value based on the environment type.
82
+ * @returns {Promise<any>} - The resolved value.
83
+ */
84
+ public async resolve() {
85
+ if (this.type == EnvironmentType.Local) return this.getLocalValue()
86
+ else if (this.type == EnvironmentType.SecureRemote) return this.getSecureValue()
87
+ else return this.getPlainValue()
88
+ }
89
+
90
+ /**
91
+ * Retrieves the value of a local environment variable.
92
+ * @returns {T} - The value of the local environment variable.
93
+ * @throws {Error} - If the local environment variable is not defined and is not optional.
94
+ */
95
+ private getLocalValue(): T {
96
+ const value = process.env[this.paramName]
97
+ if (!value && !this.optional) {
98
+ throw new Error(
99
+ `Local environment ${this.paramName} is not defined, please reconfigure the application and redeploy!`
100
+ )
101
+ }
102
+ return value as T
103
+ }
104
+
105
+ /**
106
+ * Retrieves the plain value of a remote environment parameter.
107
+ * @returns {Promise<T>} - A promise that resolves to the plain value of the parameter.
108
+ * @throws {Error} - If the parameter cannot be retrieved and is not optional.
109
+ */
110
+ private async getPlainValue(): Promise<T | undefined> {
111
+ if (!ssmClient) ssmClient = new SSMClient()
112
+ const pName = `${this.paramPrefix}${this.paramName}`
113
+ try {
114
+ const data = await ssmClient.send(new GetParameterCommand({ Name: pName }))
115
+ if (data.Parameter && data.Parameter.Value) return data.Parameter.Value as T
116
+ } catch (error) {
117
+ console.error(error)
118
+ }
119
+ if (!this.optional) {
120
+ throw new Error(`Unable to retrieve plain remote env value: ${pName}`)
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Retrieves a secure value from the secrets manager.
126
+ * @returns {Promise<T>} - A promise that resolves to the secure value.
127
+ * @throws {Error} - Throws an error if the secure value cannot be retrieved and is not optional.
128
+ */
129
+ private async getSecureValue(): Promise<T | undefined> {
130
+ if (!secretsClient) secretsClient = new SecretsManagerClient()
131
+ const pName = `${this.paramPrefix}${this.paramName}`
132
+ try {
133
+ const data = await secretsClient.send(new GetSecretValueCommand({ SecretId: pName }))
134
+ if (data.SecretString) return data.SecretString as T
135
+ } catch (error) {
136
+ console.error(error)
137
+ }
138
+ if (!this.optional) {
139
+ throw new Error(`Unable to retrieve secure remote env: ${pName}`)
140
+ }
141
+ }
142
+ }
@@ -0,0 +1,89 @@
1
+ import {
2
+ KMSClient,
3
+ EncryptCommand,
4
+ DecryptCommand,
5
+ EncryptionAlgorithmSpec,
6
+ } from '@aws-sdk/client-kms'
7
+
8
+ /**
9
+ * Represents a Crypto class that provides encryption and decryption functionality using AWS KMS.
10
+ */
11
+ export default class Crypto {
12
+ /**
13
+ * The KMSClient instance used for making requests to the Key Management Service (KMS).
14
+ */
15
+ private readonly client: KMSClient
16
+ /**
17
+ * The AWS region of the object. This property is readonly and cannot be modified once set.
18
+ */
19
+ private readonly region: string
20
+ /**
21
+ * The unique identifier for the KMS.
22
+ * @readonly
23
+ * @type {string}
24
+ */
25
+ private readonly keyId: string
26
+ /**
27
+ * Specifies the encryption algorithm used for encryption.
28
+ */
29
+ private readonly encryptionAlgorithm: EncryptionAlgorithmSpec
30
+
31
+ /**
32
+ * Constructs a new instance of a KeyManager with the provided region, keyId, and optional encryption algorithm.
33
+ * @param {string} region - The region where the key is stored.
34
+ * @param {string} keyId - The ID of the key.
35
+ * @param {EncryptionAlgorithmSpec} [optEncryptionAlgorithm='RSAES_OAEP_SHA_256'] - The encryption algorithm to use (default is RSAES_OAEP_SHA_256).
36
+ * @returns None
37
+ */
38
+ constructor(region: string, keyId: string, optEncryptionAlgorithm?: EncryptionAlgorithmSpec) {
39
+ this.region = region
40
+ this.keyId = keyId
41
+ this.encryptionAlgorithm = optEncryptionAlgorithm || 'RSAES_OAEP_SHA_256'
42
+ this.client = new KMSClient({ region: this.region })
43
+ }
44
+
45
+ /**
46
+ * Encrypts the given data using RSAES_OAEP_SHA_256 encryption algorithm.
47
+ * @param {string | any} data - The data to be encrypted.
48
+ * @returns {Promise<string | null>} - A promise that resolves to the encrypted data as a hexadecimal string.
49
+ */
50
+ public async encryptData(data: string | any): Promise<string | null> {
51
+ try {
52
+ const resp = await this.client.send(
53
+ new EncryptCommand({
54
+ KeyId: this.keyId,
55
+ EncryptionAlgorithm: this.encryptionAlgorithm,
56
+ Plaintext: new TextEncoder().encode(
57
+ typeof data === 'string' ? data : JSON.stringify(data)
58
+ ),
59
+ })
60
+ )
61
+ return Buffer.from(resp.CiphertextBlob as any, 'utf8').toString('hex')
62
+ } catch (e) {
63
+ console.error('Encryption failure', e)
64
+ return null
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Decrypts the given data using the RSAES_OAEP_SHA_256 encryption algorithm.
70
+ * @param {string} data - The encrypted data to decrypt.
71
+ * @returns {Promise<string | null>} - A promise that resolves to the decrypted plaintext string.
72
+ * If decryption fails, null is returned.
73
+ */
74
+ public async decryptData(data: string): Promise<string | null> {
75
+ try {
76
+ const resp = await this.client.send(
77
+ new DecryptCommand({
78
+ KeyId: this.keyId,
79
+ CiphertextBlob: Buffer.from(data, 'hex'),
80
+ EncryptionAlgorithm: this.encryptionAlgorithm,
81
+ })
82
+ )
83
+ return new TextDecoder().decode(resp.Plaintext)
84
+ } catch (e) {
85
+ console.error('Decryption failure', e)
86
+ return null
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,22 @@
1
+ import { DatabaseTransaction } from './DatabaseTransaction.js'
2
+ import { DbConfig } from './types.js'
3
+
4
+ /**
5
+ * Abstract class representing a Database with a generic type extending DatabaseTransaction.
6
+ * @template T - The type of DatabaseTransaction to be used.
7
+ */
8
+ export abstract class Database<T extends DatabaseTransaction> {
9
+ /**
10
+ * Constructor for a class that takes in a database configuration object.
11
+ * @param {DbConfig<any>} config - The database configuration object.
12
+ * @returns None
13
+ */
14
+ protected constructor(public readonly config: DbConfig<any>) {}
15
+
16
+ /**
17
+ * Represents an abstract method for a transaction that returns a Promise of type T.
18
+ * This method needs to be implemented by subclasses.
19
+ * @returns A Promise that resolves to a value of type T.
20
+ */
21
+ public abstract transaction(): Promise<T>
22
+ }
@@ -0,0 +1,67 @@
1
+ import hash from 'object-hash'
2
+
3
+ import { DynamoDatabase } from './integrations/dynamo/DynamoDatabase.js'
4
+ import { KyselyDatabase } from './integrations/kysely/KyselyDatabase.js'
5
+ import { PostgresDatabase } from './integrations/pgsql/PostgresDatabase.js'
6
+ import type { DatabaseImplType, DatabaseType, DbConfig } from './types.js'
7
+
8
+ /**
9
+ * Object containing different database implementations.
10
+ * @type {Object}
11
+ * @property {PostgresDatabase} pg - Postgres database implementation
12
+ * @property {KyselyDatabase<any>} kysely - Kysely database implementation
13
+ */
14
+ export const DATABASES = {
15
+ pg: PostgresDatabase,
16
+ kysely: KyselyDatabase,
17
+ dynamo: DynamoDatabase,
18
+ }
19
+
20
+ /**
21
+ * Manages the creation and storage of database instances.
22
+ */
23
+ export class DatabaseManager {
24
+ /**
25
+ * Singleton instance of the DatabaseManager class.
26
+ * This instance is used to interact with the database.
27
+ */
28
+ public static readonly INSTANCE = new DatabaseManager()
29
+ /**
30
+ * A private property that holds a reference to the DATABASES constant.
31
+ * @type {typeof DATABASES}
32
+ */
33
+ private databases: typeof DATABASES = DATABASES
34
+ /**
35
+ * An object that stores instances of DatabaseImplType objects with keys of type string.
36
+ * @type {Object.<string, DatabaseImplType<any, any>>}
37
+ */
38
+ private instances: { [k: string]: DatabaseImplType<any, any> } = {}
39
+
40
+ /**
41
+ * Creates a database instance based on the provided configuration.
42
+ * @param {DbConfig<S>} config - The configuration object for the database.
43
+ * @returns {DatabaseImplType<S, DBSchema>} An instance of the database based on the configuration.
44
+ */
45
+ public create<S extends DatabaseType, DBSchema>(
46
+ config: DbConfig<S>
47
+ ): DatabaseImplType<S, DBSchema> {
48
+ const configHash = hash(config)
49
+ if (this.instances[configHash]) {
50
+ return this.instances[configHash] as any
51
+ }
52
+ const instance = this.instantiateDb<S, DBSchema>(config as any)
53
+ this.instances[configHash] = instance
54
+ return instance
55
+ }
56
+
57
+ /**
58
+ * Instantiates a database connection based on the provided configuration.
59
+ * @param {DbConfig<'pg'> | DbConfig<'kysely'>} config - The configuration object specifying the type of database.
60
+ * @returns {DatabaseImplType<S, DBSchema>} An instance of the specified database connection.
61
+ */
62
+ private instantiateDb<S extends DatabaseType, DBSchema>(
63
+ config: DbConfig<'pg'> | DbConfig<'kysely'> | DbConfig<'dynamo'>
64
+ ): DatabaseImplType<S, DBSchema> {
65
+ return new this.databases[config.type](config as any) as any
66
+ }
67
+ }
@@ -0,0 +1,170 @@
1
+ import { Database } from './Database.js'
2
+
3
+ /**
4
+ * Abstract class representing a database transaction.
5
+ * Warning: These need to be arrow functions!
6
+ * @class DatabaseTransaction
7
+ */
8
+ export abstract class DatabaseTransaction extends Function {
9
+ /**
10
+ * A boolean flag indicating whether a certain feature is open or closed.
11
+ * @type {boolean}
12
+ */
13
+ protected _isOpen: boolean
14
+ /**
15
+ * A property representing a writer object.
16
+ * @type {any}
17
+ */
18
+ public readonly writer: any
19
+ /**
20
+ * A property representing a reader object.
21
+ * @type {any}
22
+ */
23
+ public readonly reader: any
24
+ /**
25
+ * A protected property representing a transaction.
26
+ * @type {any}
27
+ */
28
+ protected transaction: any
29
+ /**
30
+ * A protected property representing a database of type Database<any>.
31
+ * This property is accessible within the class and its subclasses.
32
+ */
33
+ protected database: Database<any>
34
+
35
+ /**
36
+ * Constructor for a class that interacts with a database using a writer and reader.
37
+ * @param {any} writer - The object responsible for writing to the database.
38
+ * @param {Database<any>} database - The database to interact with.
39
+ * @param {any} [reader] - The object responsible for reading from the database (optional).
40
+ * @returns None
41
+ */
42
+ protected constructor(writer: any, database: Database<any>, reader?: any) {
43
+ super('...args', 'return this.transaction(...args)')
44
+ this.writer = writer
45
+ this.database = database
46
+ this.reader = reader
47
+ }
48
+
49
+ /**
50
+ * Creates a proxy instance for the given subclass of DatabaseTransaction.
51
+ * The proxy handles method binding and transaction execution based on the subclass state.
52
+ * @param {T} subclass - The subclass of DatabaseTransaction to proxy.
53
+ * @returns A proxied instance of the subclass with method binding and transaction execution logic.
54
+ */
55
+ protected static proxyInstance<T extends DatabaseTransaction>(subclass: T): T {
56
+ const bind = (target: any, key: string | symbol) =>
57
+ typeof target[key] === 'function' ? target[key].bind(target) : target[key]
58
+
59
+ return new Proxy<T>(subclass, {
60
+ get(target: T, p: string | symbol): any {
61
+ if (target[p] !== undefined) {
62
+ return bind(target, p)
63
+ } else if (target._isOpen) {
64
+ return bind(target.transaction, p)
65
+ }
66
+ return undefined
67
+ },
68
+ apply(target: T, thisArg: any, argArray: any[]): any {
69
+ if (target._isOpen) {
70
+ return target.transaction(...argArray)
71
+ }
72
+ throw new Error('Transaction is closed!')
73
+ },
74
+ })
75
+ }
76
+
77
+ /**
78
+ * Check if the object is open.
79
+ * @returns {boolean} - true if the object is open, false otherwise.
80
+ */
81
+ public isOpen = (): boolean => {
82
+ return this._isOpen
83
+ }
84
+
85
+ /**
86
+ * Begins a transaction asynchronously.
87
+ * @returns {Promise<void>} A Promise that resolves when the transaction has begun.
88
+ * @throws {Error} If the transaction is already open.
89
+ */
90
+ public begin = async (): Promise<void> => {
91
+ if (this._isOpen) {
92
+ throw new Error('Cannot begin, transaction is already opened!')
93
+ }
94
+ await this.doBegin()
95
+ this._isOpen = true
96
+ }
97
+
98
+ /**
99
+ * Asynchronously commits the transaction.
100
+ * If the transaction is already closed, an error is thrown.
101
+ * @returns Promise<void>
102
+ * @throws Error if the transaction is already closed
103
+ */
104
+ public commit = async (): Promise<void> => {
105
+ if (!this._isOpen) {
106
+ throw new Error('Cannot commit, transaction is already closed!')
107
+ }
108
+ await this.doCommit()
109
+ this._isOpen = false
110
+ }
111
+
112
+ /**
113
+ * Rollback the transaction by reverting any changes made within the transaction.
114
+ * If the transaction is already closed, an error is thrown.
115
+ * @returns Promise<void>
116
+ * @throws Error if the transaction is already closed.
117
+ */
118
+ public rollback = async (): Promise<void> => {
119
+ if (!this._isOpen) {
120
+ throw new Error('Cannot rollback, transaction is already closed!')
121
+ }
122
+ await this.doRollback()
123
+ this._isOpen = false
124
+ }
125
+
126
+ /**
127
+ * Closes the success modal, committing or rolling back changes based on the autoCommit setting.
128
+ * If the modal is open and autoCommit is enabled, it will commit the changes.
129
+ * If autoCommit is disabled, it will rollback the changes.
130
+ * @returns {Promise<void>} A promise that resolves once the commit or rollback operation is completed.
131
+ */
132
+ public closeSuccess = async () => {
133
+ if (this._isOpen) {
134
+ if (this.database.config['autoCommit']) {
135
+ await this.doCommit()
136
+ } else {
137
+ await this.doRollback()
138
+ }
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Closes the failure by performing a rollback if the failure is currently open.
144
+ * @returns {Promise<void>} A promise that resolves once the rollback is completed.
145
+ */
146
+ public closeFailure = async () => {
147
+ if (this._isOpen) {
148
+ await this.doRollback()
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Abstract method that should be implemented by subclasses to perform a commit operation.
154
+ * @returns A Promise that resolves when the commit operation is completed.
155
+ */
156
+ protected abstract doCommit: () => Promise<any>
157
+
158
+ /**
159
+ * An abstract method that defines the rollback functionality.
160
+ * This method should be implemented by subclasses to perform the actual rollback operation.
161
+ * @returns A Promise that resolves when the rollback operation is completed.
162
+ */
163
+ protected abstract doRollback: () => Promise<any>
164
+
165
+ /**
166
+ * Abstract method that defines the beginning of an asynchronous operation.
167
+ * @returns A Promise that resolves when the operation begins.
168
+ */
169
+ protected abstract doBegin: () => Promise<any>
170
+ }