@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.
- package/.eslintignore +3 -0
- package/.eslintrc.cjs +81 -0
- package/.github/workflows/npmpublish.yml +8 -19
- package/.github/workflows/prs.yml +12 -0
- package/README.md +89 -99
- package/dist/index.d.ts +16 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/package-lock.json +11881 -0
- package/dist/package.json +81 -0
- package/dist/src/API/Request.d.ts +125 -0
- package/dist/src/API/Request.js +185 -0
- package/dist/src/API/Request.js.map +1 -0
- package/dist/src/API/Response.d.ts +188 -0
- package/dist/src/API/Response.js +270 -0
- package/dist/src/API/Response.js.map +1 -0
- package/dist/src/BaseEvent/DynamoTransaction.d.ts +70 -0
- package/dist/src/BaseEvent/DynamoTransaction.js +104 -0
- package/dist/src/BaseEvent/DynamoTransaction.js.map +1 -0
- package/dist/src/BaseEvent/EventProcessor.d.ts +58 -0
- package/dist/src/BaseEvent/EventProcessor.js +101 -0
- package/dist/src/BaseEvent/EventProcessor.js.map +1 -0
- package/dist/src/BaseEvent/Process.d.ts +50 -0
- package/dist/src/BaseEvent/Process.js +64 -0
- package/dist/src/BaseEvent/Process.js.map +1 -0
- package/dist/src/BaseEvent/StepTransaction.d.ts +23 -0
- package/dist/src/BaseEvent/StepTransaction.js +27 -0
- package/dist/src/BaseEvent/StepTransaction.js.map +1 -0
- package/dist/src/BaseEvent/Transaction.d.ts +149 -0
- package/dist/src/BaseEvent/Transaction.js +224 -0
- package/dist/src/BaseEvent/Transaction.js.map +1 -0
- package/dist/src/Cache/Redis.d.ts +29 -0
- package/dist/src/Cache/Redis.js +80 -0
- package/dist/src/Cache/Redis.js.map +1 -0
- package/dist/src/Cache/types.d.ts +31 -0
- package/dist/src/Cache/types.js +2 -0
- package/dist/src/Cache/types.js.map +1 -0
- package/dist/src/Config/Configuration.d.ts +123 -0
- package/dist/src/Config/Configuration.js +109 -0
- package/dist/src/Config/Configuration.js.map +1 -0
- package/dist/src/Config/EnvironmentVar.d.ts +74 -0
- package/dist/src/Config/EnvironmentVar.js +138 -0
- package/dist/src/Config/EnvironmentVar.js.map +1 -0
- package/dist/src/Crypto/Crypto.d.ts +45 -0
- package/dist/src/Crypto/Crypto.js +72 -0
- package/dist/src/Crypto/Crypto.js.map +1 -0
- package/dist/src/Database/Database.d.ts +21 -0
- package/dist/src/Database/Database.js +15 -0
- package/dist/src/Database/Database.js.map +1 -0
- package/dist/src/Database/DatabaseManager.d.ts +47 -0
- package/dist/src/Database/DatabaseManager.js +60 -0
- package/dist/src/Database/DatabaseManager.js.map +1 -0
- package/dist/src/Database/DatabaseTransaction.d.ts +101 -0
- package/dist/src/Database/DatabaseTransaction.js +126 -0
- package/dist/src/Database/DatabaseTransaction.js.map +1 -0
- package/dist/src/Database/index.d.ts +10 -0
- package/dist/src/Database/index.js +15 -0
- package/dist/src/Database/index.js.map +1 -0
- package/dist/src/Database/integrations/dynamo/DynamoDatabase.d.ts +35 -0
- package/dist/src/Database/integrations/dynamo/DynamoDatabase.js +59 -0
- package/dist/src/Database/integrations/dynamo/DynamoDatabase.js.map +1 -0
- package/dist/src/Database/integrations/kysely/KyselyDatabase.d.ts +66 -0
- package/dist/src/Database/integrations/kysely/KyselyDatabase.js +86 -0
- package/dist/src/Database/integrations/kysely/KyselyDatabase.js.map +1 -0
- package/dist/src/Database/integrations/kysely/KyselyTransaction.d.ts +70 -0
- package/dist/src/Database/integrations/kysely/KyselyTransaction.js +118 -0
- package/dist/src/Database/integrations/kysely/KyselyTransaction.js.map +1 -0
- package/dist/src/Database/integrations/pgsql/PostgresDatabase.d.ts +36 -0
- package/dist/src/Database/integrations/pgsql/PostgresDatabase.js +54 -0
- package/dist/src/Database/integrations/pgsql/PostgresDatabase.js.map +1 -0
- package/dist/src/Database/integrations/pgsql/PostgresTransaction.d.ts +63 -0
- package/dist/src/Database/integrations/pgsql/PostgresTransaction.js +61 -0
- package/dist/src/Database/integrations/pgsql/PostgresTransaction.js.map +1 -0
- package/dist/src/Database/types.d.ts +76 -0
- package/dist/src/Database/types.js +2 -0
- package/dist/src/Database/types.js.map +1 -0
- package/dist/src/Globals.d.ts +93 -0
- package/dist/src/Globals.js +99 -0
- package/dist/src/Globals.js.map +1 -0
- package/dist/src/Logger/Logger.d.ts +161 -0
- package/dist/src/Logger/Logger.js +299 -0
- package/dist/src/Logger/Logger.js.map +1 -0
- package/dist/src/Mailer/Mailer.d.ts +78 -0
- package/dist/src/Mailer/Mailer.js +182 -0
- package/dist/src/Mailer/Mailer.js.map +1 -0
- package/dist/src/Publisher/Publisher.d.ts +39 -0
- package/dist/src/Publisher/Publisher.js +77 -0
- package/dist/src/Publisher/Publisher.js.map +1 -0
- package/dist/src/Server/RouteResolver.d.ts +33 -0
- package/dist/src/Server/RouteResolver.js +100 -0
- package/dist/src/Server/RouteResolver.js.map +1 -0
- package/dist/src/Server/Router.d.ts +157 -0
- package/dist/src/Server/Router.js +32 -0
- package/dist/src/Server/Router.js.map +1 -0
- package/dist/src/Server/lib/ContainerServer.d.ts +42 -0
- package/dist/src/Server/lib/ContainerServer.js +66 -0
- package/dist/src/Server/lib/ContainerServer.js.map +1 -0
- package/dist/src/Server/lib/Server.d.ts +45 -0
- package/dist/src/Server/lib/Server.js +93 -0
- package/dist/src/Server/lib/Server.js.map +1 -0
- package/dist/src/Server/lib/container/GenericHandler.d.ts +9 -0
- package/dist/src/Server/lib/container/GenericHandler.js +82 -0
- package/dist/src/Server/lib/container/GenericHandler.js.map +1 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +52 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.js +132 -0
- package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +1 -0
- package/dist/src/Server/lib/container/HealthHandler.d.ts +9 -0
- package/dist/src/Server/lib/container/HealthHandler.js +19 -0
- package/dist/src/Server/lib/container/HealthHandler.js.map +1 -0
- package/dist/src/Server/lib/container/Proxy.d.ts +67 -0
- package/dist/src/Server/lib/container/Proxy.js +143 -0
- package/dist/src/Server/lib/container/Proxy.js.map +1 -0
- package/dist/src/Server/lib/container/Utils.d.ts +14 -0
- package/dist/src/Server/lib/container/Utils.js +37 -0
- package/dist/src/Server/lib/container/Utils.js.map +1 -0
- package/dist/src/Util/AsyncSingleton.d.ts +31 -0
- package/dist/src/Util/AsyncSingleton.js +83 -0
- package/dist/src/Util/AsyncSingleton.js.map +1 -0
- package/dist/src/Util/Utils.d.ts +61 -0
- package/dist/src/Util/Utils.js +147 -0
- package/dist/src/Util/Utils.js.map +1 -0
- package/dist/src/Validation/Validator.d.ts +17 -0
- package/dist/src/Validation/Validator.js +39 -0
- package/dist/src/Validation/Validator.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/index.ts +41 -0
- package/jest.config.ts +37 -0
- package/jest.smoke.config.ts +34 -0
- package/package.json +66 -22
- package/src/API/Request.ts +214 -0
- package/src/API/Response.ts +370 -0
- package/src/BaseEvent/DynamoTransaction.ts +175 -0
- package/src/BaseEvent/EventProcessor.ts +140 -0
- package/src/BaseEvent/Process.ts +78 -0
- package/src/BaseEvent/StepTransaction.ts +35 -0
- package/src/BaseEvent/Transaction.ts +323 -0
- package/src/Cache/Redis.ts +89 -0
- package/src/Cache/types.ts +33 -0
- package/src/Config/Configuration.ts +199 -0
- package/src/Config/EnvironmentVar.ts +142 -0
- package/src/Crypto/Crypto.ts +89 -0
- package/src/Database/Database.ts +22 -0
- package/src/Database/DatabaseManager.ts +67 -0
- package/src/Database/DatabaseTransaction.ts +170 -0
- package/src/Database/index.ts +27 -0
- package/src/Database/integrations/dynamo/DynamoDatabase.ts +58 -0
- package/src/Database/integrations/kysely/KyselyDatabase.ts +99 -0
- package/src/Database/integrations/kysely/KyselyTransaction.ts +172 -0
- package/src/Database/integrations/pgsql/PostgresDatabase.ts +56 -0
- package/src/Database/integrations/pgsql/PostgresTransaction.ts +87 -0
- package/src/Database/types.ts +85 -0
- package/src/Globals.ts +103 -0
- package/src/Logger/Logger.ts +363 -0
- package/src/Mailer/Mailer.ts +217 -0
- package/src/Publisher/Publisher.ts +96 -0
- package/src/Server/RouteResolver.ts +124 -0
- package/src/Server/Router.ts +200 -0
- package/src/Server/lib/ContainerServer.ts +65 -0
- package/src/Server/lib/Server.ts +109 -0
- package/src/Server/lib/container/GenericHandler.ts +76 -0
- package/src/Server/lib/container/GenericHandlerEvent.ts +154 -0
- package/src/Server/lib/container/HealthHandler.ts +11 -0
- package/src/Server/lib/container/Proxy.ts +172 -0
- package/src/Server/lib/container/Utils.ts +33 -0
- package/src/Util/AsyncSingleton.ts +86 -0
- package/src/Util/Utils.ts +131 -0
- package/src/Validation/Validator.ts +45 -0
- package/tests/API/Request.test.ts +273 -0
- package/tests/API/Response.test.ts +367 -0
- package/tests/BaseEvent/DynamoTransaction.test.ts +272 -0
- package/tests/BaseEvent/EventProcessor.test.ts +263 -0
- package/tests/BaseEvent/Process.test.ts +47 -0
- package/tests/BaseEvent/StepTransaction.test.ts +44 -0
- package/tests/BaseEvent/Transaction.test.ts +402 -0
- package/tests/Cache/Redis-client.test.ts +90 -0
- package/tests/Cache/Redis-cluster.test.ts +100 -0
- package/tests/Config/Config.test.ts +205 -0
- package/tests/Config/EnvironmentVar.test.ts +251 -0
- package/tests/Crypto/Crypto.test.ts +88 -0
- package/tests/Database/DatabaseManager.test.ts +79 -0
- package/tests/Database/integrations/dynamo/DynamoDatabase.test.ts +44 -0
- package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +113 -0
- package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +119 -0
- package/tests/Database/integrations/pg/PostgresDatabase.test.ts +76 -0
- package/tests/Database/integrations/pg/PostgresTransaction.test.ts +118 -0
- package/tests/Logger/Logger.test.ts +215 -0
- package/tests/Mailer/Mailer.test.ts +59 -0
- package/tests/Publisher/Publisher.test.ts +60 -0
- package/tests/Server/RouteResolver.test.ts +116 -0
- package/tests/Server/Router.test.ts +39 -0
- package/tests/Server/lib/ContainerServer.test.ts +531 -0
- package/tests/Server/lib/Server.test.ts +12 -0
- package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
- package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
- package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
- package/tests/Server/lib/container/Proxy.test.ts +268 -0
- package/tests/Server/lib/container/Utils.test.ts +47 -0
- package/tests/Test.utils.ts +78 -0
- package/tests/Utils/Utils.test.ts +229 -0
- package/tests/Validation/Validator.test.ts +82 -0
- package/tsconfig.json +26 -0
- package/tsconfig.smoke.json +26 -0
- package/index.js +0 -88
- package/src/API/IKRequest.js +0 -52
- package/src/API/IKResponse.js +0 -119
- package/src/API/IKUtils.js +0 -51
- package/src/BaseEvent/IKProcess.js +0 -77
- package/src/BaseEvent/IKTransaction.js +0 -139
- package/src/Cache/Prototype/IKCache.js +0 -17
- package/src/Cache/Redis/IKRedis.js +0 -148
- package/src/Database/DDB/IKDB.js +0 -56
- package/src/Database/DDB/IKDBBaseExpression.js +0 -130
- package/src/Database/DDB/IKDBBaseQuery.js +0 -151
- package/src/Database/DDB/IKDBQueryBatchGet.js +0 -37
- package/src/Database/DDB/IKDBQueryBatchWrite.js +0 -64
- package/src/Database/DDB/IKDBQueryDelete.js +0 -34
- package/src/Database/DDB/IKDBQueryGet.js +0 -48
- package/src/Database/DDB/IKDBQueryPut.js +0 -87
- package/src/Database/DDB/IKDBQueryScan.js +0 -45
- package/src/Database/DDB/IKDBQueryTransactionalWrite.js +0 -69
- package/src/Database/DDB/IKDBQueryUpdate.js +0 -221
- package/src/Database/DDB/_IKDBQueryTransactionalRead.js +0 -46
- package/src/Database/PSQL/IKDB.js +0 -41
- package/src/Database/PSQL/IKDBBaseQuery.js +0 -26
- package/src/Database/Prototype/IKDB.js +0 -21
- package/src/Database/Prototype/IKDBBaseQuery.js +0 -14
- package/src/IKDynamoStream.js +0 -42
- package/src/IKEventProcessor.js +0 -42
- package/src/IKGlobals.js +0 -24
- package/src/IKRouter.js +0 -47
- package/src/IKStepTransaction.js +0 -14
- package/src/Logger/IKLogger.js +0 -136
- package/src/Mailer/IKMailer.js +0 -69
- package/src/Publisher/IKPublisher.js +0 -44
- package/src/Tracker/IKExecutionTracker.js +0 -79
- package/src/Validation/IKValidation.js +0 -76
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { SSMClient, GetParameterCommand } from '@aws-sdk/client-ssm'
|
|
2
|
+
import { mockClient } from 'aws-sdk-client-mock'
|
|
3
|
+
import { expect as c_expect } from 'chai'
|
|
4
|
+
|
|
5
|
+
import Configuration from '../../src/Config/Configuration.js'
|
|
6
|
+
import { SampleConfig } from '../Test.utils.js'
|
|
7
|
+
|
|
8
|
+
const SSMMock = mockClient(SSMClient)
|
|
9
|
+
const config = new Configuration<typeof SampleConfig>(SampleConfig, 'my-prefix')
|
|
10
|
+
describe(`Optional remote environment`, () => {
|
|
11
|
+
// reset mock
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
SSMMock.reset()
|
|
14
|
+
config['resetCache']()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('Does not accept sync get (+ compiler error)', async () => {
|
|
18
|
+
let err = null
|
|
19
|
+
try {
|
|
20
|
+
// @ts-expect-error
|
|
21
|
+
config.get('TOKEN_SECRET')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
err = e
|
|
24
|
+
}
|
|
25
|
+
c_expect(err).is.not.null
|
|
26
|
+
c_expect(err?.['message']).is.not.null
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('Optional value with null value', async () => {
|
|
30
|
+
SSMMock.on(GetParameterCommand).resolves({
|
|
31
|
+
Parameter: {
|
|
32
|
+
Value: undefined,
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
const token = await config.asyncGet('TOKEN_SECRET_FALSY')
|
|
36
|
+
c_expect(token).is.undefined
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('Optional value with empty response', async () => {
|
|
40
|
+
SSMMock.on(GetParameterCommand).resolves({})
|
|
41
|
+
const token = await config.asyncGet('TOKEN_SECRET_FALSY')
|
|
42
|
+
c_expect(token).is.undefined
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('Optional value with valid response', async () => {
|
|
46
|
+
const value = 'abc'
|
|
47
|
+
SSMMock.on(GetParameterCommand).resolves({
|
|
48
|
+
Parameter: {
|
|
49
|
+
Value: value,
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
const token = await config.asyncGet('TOKEN_SECRET_FALSY')
|
|
53
|
+
c_expect(token).is.not.undefined
|
|
54
|
+
c_expect(token).to.be.equals(value)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('Optional value rejection', async () => {
|
|
58
|
+
SSMMock.on(GetParameterCommand).rejects(new Error('failed!'))
|
|
59
|
+
const token = await config.asyncGet('TOKEN_SECRET_FALSY')
|
|
60
|
+
c_expect(token).is.undefined
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe(`Required remote environment`, () => {
|
|
65
|
+
// reset mock
|
|
66
|
+
beforeEach(() => {
|
|
67
|
+
SSMMock.reset()
|
|
68
|
+
config['resetCache']()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('Does not accept sync get (+ compiler error)', async () => {
|
|
72
|
+
let err = null
|
|
73
|
+
try {
|
|
74
|
+
// @ts-expect-error
|
|
75
|
+
config.get('TOKEN_SECRET')
|
|
76
|
+
} catch (e) {
|
|
77
|
+
err = e
|
|
78
|
+
}
|
|
79
|
+
c_expect(err).is.not.null
|
|
80
|
+
c_expect(err?.['message']).is.not.null
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test('Required value with null value', async () => {
|
|
84
|
+
SSMMock.on(GetParameterCommand).resolves({
|
|
85
|
+
Parameter: {
|
|
86
|
+
Value: undefined,
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
let err = null
|
|
90
|
+
try {
|
|
91
|
+
await config.asyncGet('TOKEN_SECRET')
|
|
92
|
+
} catch (e) {
|
|
93
|
+
err = e
|
|
94
|
+
}
|
|
95
|
+
c_expect(err).is.not.null
|
|
96
|
+
c_expect(err?.['message']).is.not.null
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('Required value with empty response', async () => {
|
|
100
|
+
SSMMock.on(GetParameterCommand).resolves({})
|
|
101
|
+
let err = null
|
|
102
|
+
try {
|
|
103
|
+
await config.asyncGet('TOKEN_SECRET')
|
|
104
|
+
} catch (e) {
|
|
105
|
+
err = e
|
|
106
|
+
}
|
|
107
|
+
c_expect(err).is.not.null
|
|
108
|
+
c_expect(err?.['message']).is.not.null
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('Required value with valid response', async () => {
|
|
112
|
+
const value = 'abc'
|
|
113
|
+
SSMMock.on(GetParameterCommand).resolves({
|
|
114
|
+
Parameter: {
|
|
115
|
+
Value: value,
|
|
116
|
+
},
|
|
117
|
+
})
|
|
118
|
+
const token = await config.asyncGet('TOKEN_SECRET')
|
|
119
|
+
c_expect(token).is.not.undefined
|
|
120
|
+
c_expect(token).to.be.equals(value)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('Required value rejection', async () => {
|
|
124
|
+
SSMMock.on(GetParameterCommand).rejects(new Error('failed!'))
|
|
125
|
+
let err = null
|
|
126
|
+
try {
|
|
127
|
+
await config.asyncGet('TOKEN_SECRET')
|
|
128
|
+
} catch (e) {
|
|
129
|
+
err = e
|
|
130
|
+
}
|
|
131
|
+
c_expect(err).is.not.null
|
|
132
|
+
c_expect(err?.['message']).is.not.null
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
describe(`Optional local environment`, () => {
|
|
137
|
+
beforeEach(() => {
|
|
138
|
+
config['resetCache']()
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test('Optional value with null value', async () => {
|
|
142
|
+
const token = config.get('PATH123')
|
|
143
|
+
c_expect(token).is.undefined
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe(`Required local environment`, () => {
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
config['resetCache']()
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
test('Test compiler error', async () => {
|
|
153
|
+
let err = null
|
|
154
|
+
try {
|
|
155
|
+
// @ts-expect-error
|
|
156
|
+
await config.asyncGet('PATH')
|
|
157
|
+
} catch (e) {
|
|
158
|
+
err = e
|
|
159
|
+
}
|
|
160
|
+
c_expect(err).is.not.null
|
|
161
|
+
c_expect(err?.['message']).is.not.null
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
test('Required value with null value', async () => {
|
|
165
|
+
let err = null
|
|
166
|
+
try {
|
|
167
|
+
config.get('PATH_FALSY')
|
|
168
|
+
} catch (e) {
|
|
169
|
+
err = e
|
|
170
|
+
}
|
|
171
|
+
c_expect(err).is.not.null
|
|
172
|
+
c_expect(err?.['message']).is.not.null
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
test('Required value with valid response', async () => {
|
|
176
|
+
const key = 'PATH'
|
|
177
|
+
const v = config.get(key)
|
|
178
|
+
c_expect(v).is.not.null
|
|
179
|
+
c_expect(v).to.be.equals(process.env[key])
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
describe(`Caching test`, () => {
|
|
184
|
+
test('Does cache previous fetched value', async () => {
|
|
185
|
+
const value = '123'
|
|
186
|
+
const key = 'TOKEN_SECRET'
|
|
187
|
+
// initial fetch
|
|
188
|
+
SSMMock.on(GetParameterCommand).resolves({
|
|
189
|
+
Parameter: {
|
|
190
|
+
Value: value,
|
|
191
|
+
},
|
|
192
|
+
})
|
|
193
|
+
const v = await config.asyncGet(key)
|
|
194
|
+
c_expect(v).is.not.null
|
|
195
|
+
c_expect(v).to.be.equals(value)
|
|
196
|
+
// subsequent fetch
|
|
197
|
+
SSMMock.reset()
|
|
198
|
+
SSMMock.on(GetParameterCommand).rejects(new Error('failed!'))
|
|
199
|
+
const v2 = await config.asyncGet(key)
|
|
200
|
+
c_expect(v2).is.not.null
|
|
201
|
+
c_expect(v2).to.be.equals(value)
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
export {}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
|
|
2
|
+
import { SSMClient, GetParameterCommand } from '@aws-sdk/client-ssm'
|
|
3
|
+
import { mockClient } from 'aws-sdk-client-mock'
|
|
4
|
+
import { expect } from 'chai'
|
|
5
|
+
|
|
6
|
+
import EnvironmentVar, { EnvironmentType } from '../../src/Config/EnvironmentVar.js'
|
|
7
|
+
|
|
8
|
+
const SSMMock = mockClient(SSMClient)
|
|
9
|
+
const SecretsManagerMock = mockClient(SecretsManagerClient)
|
|
10
|
+
const prefix = '/abc/test-01/'
|
|
11
|
+
|
|
12
|
+
function testRemoteEnv(mock, type, command) {
|
|
13
|
+
describe(`Optional ${type} environment`, () => {
|
|
14
|
+
// reset mock
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
mock.reset()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('Does not accept sync resolve', async () => {
|
|
20
|
+
mock.on(command).resolves({
|
|
21
|
+
...(type == EnvironmentType.PlainRemote
|
|
22
|
+
? {
|
|
23
|
+
Parameter: {
|
|
24
|
+
Value: undefined,
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
: {
|
|
28
|
+
SecretString: undefined,
|
|
29
|
+
}),
|
|
30
|
+
})
|
|
31
|
+
let err = null
|
|
32
|
+
try {
|
|
33
|
+
const env = new EnvironmentVar('abc', type, true, prefix)
|
|
34
|
+
env.syncResolve()
|
|
35
|
+
} catch (e) {
|
|
36
|
+
err = e
|
|
37
|
+
}
|
|
38
|
+
expect(err).is.not.null
|
|
39
|
+
expect(err?.['message']).is.not.null
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('Optional value with null value', async () => {
|
|
43
|
+
mock.on(command).resolves({
|
|
44
|
+
...(type == EnvironmentType.PlainRemote
|
|
45
|
+
? {
|
|
46
|
+
Parameter: {
|
|
47
|
+
Value: undefined,
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
: {
|
|
51
|
+
SecretString: undefined,
|
|
52
|
+
}),
|
|
53
|
+
})
|
|
54
|
+
const env = new EnvironmentVar('abc', type, true, prefix)
|
|
55
|
+
const token = await env.resolve()
|
|
56
|
+
expect(token).is.undefined
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('Optional value with empty response', async () => {
|
|
60
|
+
mock.on(command).resolves({})
|
|
61
|
+
const env = new EnvironmentVar('abc', type, true, prefix)
|
|
62
|
+
const token = await env.resolve()
|
|
63
|
+
expect(token).is.undefined
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test('Optional value with valid response', async () => {
|
|
67
|
+
const value = 'abc'
|
|
68
|
+
mock.on(command).resolves({
|
|
69
|
+
...(type == EnvironmentType.PlainRemote
|
|
70
|
+
? {
|
|
71
|
+
Parameter: {
|
|
72
|
+
Value: value,
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
: {
|
|
76
|
+
SecretString: value,
|
|
77
|
+
}),
|
|
78
|
+
})
|
|
79
|
+
const env = new EnvironmentVar(value, type, true, prefix)
|
|
80
|
+
const token = await env.resolve()
|
|
81
|
+
expect(token).is.not.undefined
|
|
82
|
+
expect(token).to.be.equals(value)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('Optional value rejection', async () => {
|
|
86
|
+
const value = 'abc'
|
|
87
|
+
mock.on(command).rejects(new Error('failed!'))
|
|
88
|
+
const env = new EnvironmentVar(value, type, true, prefix)
|
|
89
|
+
const token = await env.resolve()
|
|
90
|
+
expect(token).is.undefined
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe(`Required ${type} environment`, () => {
|
|
95
|
+
// reset mock
|
|
96
|
+
beforeEach(() => {
|
|
97
|
+
mock.reset()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('Does not accept sync resolve', async () => {
|
|
101
|
+
mock.on(command).resolves({
|
|
102
|
+
...(type == EnvironmentType.PlainRemote
|
|
103
|
+
? {
|
|
104
|
+
Parameter: {
|
|
105
|
+
Value: undefined,
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
: {
|
|
109
|
+
SecretString: undefined,
|
|
110
|
+
}),
|
|
111
|
+
})
|
|
112
|
+
let err = null
|
|
113
|
+
try {
|
|
114
|
+
const env = new EnvironmentVar('abc', type, undefined, prefix)
|
|
115
|
+
env.syncResolve()
|
|
116
|
+
} catch (e) {
|
|
117
|
+
err = e
|
|
118
|
+
}
|
|
119
|
+
expect(err).is.not.null
|
|
120
|
+
expect(err?.['message']).is.not.null
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('Required fails when null', async () => {
|
|
124
|
+
mock.on(command).resolves({
|
|
125
|
+
...(type == EnvironmentType.PlainRemote
|
|
126
|
+
? {
|
|
127
|
+
Parameter: {
|
|
128
|
+
Value: undefined,
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
: {
|
|
132
|
+
SecretString: undefined,
|
|
133
|
+
}),
|
|
134
|
+
})
|
|
135
|
+
let err = null
|
|
136
|
+
try {
|
|
137
|
+
const env = new EnvironmentVar('abc', type, false, prefix)
|
|
138
|
+
await env.resolve()
|
|
139
|
+
} catch (e) {
|
|
140
|
+
err = e
|
|
141
|
+
}
|
|
142
|
+
console.log(err)
|
|
143
|
+
expect(err).is.not.null
|
|
144
|
+
expect(err?.['message']).is.not.null
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test('Required fails when empty response', async () => {
|
|
148
|
+
mock.on(command).resolves({})
|
|
149
|
+
let err = null
|
|
150
|
+
try {
|
|
151
|
+
const env = new EnvironmentVar('abc', type, false, prefix)
|
|
152
|
+
await env.resolve()
|
|
153
|
+
} catch (e) {
|
|
154
|
+
err = e
|
|
155
|
+
}
|
|
156
|
+
expect(err).is.not.null
|
|
157
|
+
expect(err?.['message']).is.not.null
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
test('Required value with valid response', async () => {
|
|
161
|
+
const value = 'abc'
|
|
162
|
+
mock.on(command).resolves({
|
|
163
|
+
...(type == EnvironmentType.PlainRemote
|
|
164
|
+
? {
|
|
165
|
+
Parameter: {
|
|
166
|
+
Value: value,
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
: {
|
|
170
|
+
SecretString: value,
|
|
171
|
+
}),
|
|
172
|
+
})
|
|
173
|
+
const env = new EnvironmentVar(value, type, false, prefix)
|
|
174
|
+
const token = await env.resolve()
|
|
175
|
+
expect(token).is.not.undefined
|
|
176
|
+
expect(token).to.be.equals(value)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('Required value rejection', async () => {
|
|
180
|
+
mock.on(command).rejects(new Error('failed!'))
|
|
181
|
+
let err = null
|
|
182
|
+
try {
|
|
183
|
+
const env = new EnvironmentVar('abc', type, false, prefix)
|
|
184
|
+
await env.resolve()
|
|
185
|
+
} catch (e) {
|
|
186
|
+
err = e
|
|
187
|
+
}
|
|
188
|
+
expect(err).is.not.null
|
|
189
|
+
expect(err?.['message']).is.not.null
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Remote envs test */
|
|
195
|
+
testRemoteEnv(SSMMock, EnvironmentType.PlainRemote, GetParameterCommand)
|
|
196
|
+
testRemoteEnv(SecretsManagerMock, EnvironmentType.SecureRemote, GetSecretValueCommand)
|
|
197
|
+
|
|
198
|
+
describe('Optional Local environment', () => {
|
|
199
|
+
test('Does accept async resolve', async () => {
|
|
200
|
+
const env = new EnvironmentVar('PATH123', EnvironmentType.Local, true, prefix)
|
|
201
|
+
const v = await env.resolve()
|
|
202
|
+
expect(v).is.undefined
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test('Optional value with null value', async () => {
|
|
206
|
+
const env = new EnvironmentVar('PATH123', EnvironmentType.Local, true, prefix)
|
|
207
|
+
const token = env.syncResolve()
|
|
208
|
+
expect(token).is.undefined
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
test('Optional value with valid value', async () => {
|
|
212
|
+
const key = 'PATH'
|
|
213
|
+
const env = new EnvironmentVar(key, EnvironmentType.Local, true, prefix)
|
|
214
|
+
const token = env.syncResolve()
|
|
215
|
+
expect(token).is.not.undefined
|
|
216
|
+
expect(token).to.be.equals(process.env[key])
|
|
217
|
+
})
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
describe('Required local environment', () => {
|
|
221
|
+
test('Does accept async resolve', async () => {
|
|
222
|
+
const key = 'PATH'
|
|
223
|
+
const env = new EnvironmentVar(key, EnvironmentType.Local, false, prefix)
|
|
224
|
+
const v = await env.resolve()
|
|
225
|
+
expect(v).is.not.null
|
|
226
|
+
expect(v).to.be.equals(process.env[key])
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
test('Required fails when null', async () => {
|
|
230
|
+
let err = null
|
|
231
|
+
try {
|
|
232
|
+
const env = new EnvironmentVar('PATH123', EnvironmentType.Local, false, prefix)
|
|
233
|
+
env.syncResolve()
|
|
234
|
+
} catch (e) {
|
|
235
|
+
err = e
|
|
236
|
+
}
|
|
237
|
+
console.log(err)
|
|
238
|
+
expect(err).is.not.null
|
|
239
|
+
expect(err?.['message']).is.not.null
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
test('Required value with valid value', async () => {
|
|
243
|
+
const key = 'PATH'
|
|
244
|
+
const env = new EnvironmentVar(key, EnvironmentType.Local, false, prefix)
|
|
245
|
+
const v = env.syncResolve()
|
|
246
|
+
expect(v).is.not.null
|
|
247
|
+
expect(v).to.be.equals(process.env[key])
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
export {}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { DecryptCommand, EncryptCommand, KMSClient } from '@aws-sdk/client-kms'
|
|
2
|
+
import { mockClient } from 'aws-sdk-client-mock'
|
|
3
|
+
import { expect } from 'chai'
|
|
4
|
+
|
|
5
|
+
import Crypto from '../../src/Crypto/Crypto.js'
|
|
6
|
+
|
|
7
|
+
const KMSMock = mockClient(KMSClient)
|
|
8
|
+
|
|
9
|
+
function fakeEncryption(v) {
|
|
10
|
+
const f = new TextEncoder().encode(v)
|
|
11
|
+
return Buffer.from(f as any, 'utf8').toString('hex')
|
|
12
|
+
}
|
|
13
|
+
function fakeDecryption(v) {
|
|
14
|
+
return new TextEncoder().encode(v)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('Encryption', () => {
|
|
18
|
+
// reset mock
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
KMSMock.reset()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const provider = new Crypto('ca-central-1', 'abc123')
|
|
24
|
+
test('Encrypts json object', async () => {
|
|
25
|
+
const encryptionObj = { userID: 123 }
|
|
26
|
+
KMSMock.on(EncryptCommand).resolves({
|
|
27
|
+
CiphertextBlob: new TextEncoder().encode(JSON.stringify(encryptionObj)),
|
|
28
|
+
})
|
|
29
|
+
const token = await provider.encryptData(encryptionObj)
|
|
30
|
+
expect(token).is.not.null
|
|
31
|
+
expect(token).to.be.equals(fakeEncryption(JSON.stringify(encryptionObj)))
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('Encrypts string', async () => {
|
|
35
|
+
const encryptionText = 'Hello encryption!'
|
|
36
|
+
KMSMock.on(EncryptCommand).resolves({
|
|
37
|
+
CiphertextBlob: new TextEncoder().encode(encryptionText),
|
|
38
|
+
})
|
|
39
|
+
const token = await provider.encryptData(encryptionText)
|
|
40
|
+
expect(token).is.not.null
|
|
41
|
+
expect(token).to.be.equals(fakeEncryption(encryptionText))
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('Fails to encrypt a number', async () => {
|
|
45
|
+
const encryptionText = 123
|
|
46
|
+
KMSMock.on(EncryptCommand).rejects(new Error('failed'))
|
|
47
|
+
const token = await provider.encryptData(encryptionText)
|
|
48
|
+
expect(token).is.null
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('Decryption', () => {
|
|
53
|
+
// reset mock
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
KMSMock.reset()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const provider = new Crypto('ca-central-1', 'abc123')
|
|
59
|
+
test('Decrypts json object', async () => {
|
|
60
|
+
const encryptionObj = { userID: 123 }
|
|
61
|
+
KMSMock.on(DecryptCommand).resolves({
|
|
62
|
+
Plaintext: fakeDecryption(JSON.stringify(encryptionObj)),
|
|
63
|
+
})
|
|
64
|
+
const token = await provider.decryptData(fakeEncryption(JSON.stringify(encryptionObj)))
|
|
65
|
+
expect(token).is.not.null
|
|
66
|
+
expect(token).to.be.equals(JSON.stringify(encryptionObj))
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('Decrypts string', async () => {
|
|
70
|
+
const encryptionText = 'abc123'
|
|
71
|
+
KMSMock.on(DecryptCommand).resolves({
|
|
72
|
+
Plaintext: fakeDecryption(encryptionText),
|
|
73
|
+
})
|
|
74
|
+
const token = await provider.decryptData(fakeEncryption(encryptionText))
|
|
75
|
+
expect(token).is.not.null
|
|
76
|
+
expect(token).to.be.equals(encryptionText)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test('Fails to decrypt a number', async () => {
|
|
80
|
+
const encryptionText = 123
|
|
81
|
+
KMSMock.on(DecryptCommand).rejects(new Error('failed'))
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
const token = await provider.decryptData(encryptionText)
|
|
84
|
+
expect(token).is.null
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
export {}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jest } from '@jest/globals'
|
|
2
|
+
import { expect } from 'chai'
|
|
3
|
+
|
|
4
|
+
import { DatabaseManager } from '../../src/Database/index.js'
|
|
5
|
+
import type { DatabaseType, DbConfig } from '../../src/Database/types.js'
|
|
6
|
+
|
|
7
|
+
type FakeDatabase = { host: string; tableName: string; type: 'pg' | 'kysely' | 'dynamo' }
|
|
8
|
+
|
|
9
|
+
const fakeConfig = (host: string, type: DatabaseType) => {
|
|
10
|
+
return {
|
|
11
|
+
type,
|
|
12
|
+
host,
|
|
13
|
+
} as DbConfig<typeof type>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const fakeNoSQLConfig = (tableName: string, type: DatabaseType) => {
|
|
17
|
+
return {
|
|
18
|
+
type,
|
|
19
|
+
tableName,
|
|
20
|
+
} as DbConfig<typeof type>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('Database Manager', () => {
|
|
24
|
+
test('should correctly create and cache database instances', () => {
|
|
25
|
+
const underTest = new DatabaseManager()
|
|
26
|
+
|
|
27
|
+
underTest['databases'] = {
|
|
28
|
+
pg: jest.fn((config: any) => {
|
|
29
|
+
return { host: config.host, type: 'pg' } as any
|
|
30
|
+
}) as any,
|
|
31
|
+
kysely: jest.fn((config: any) => {
|
|
32
|
+
return { host: config.host, type: 'kysely' } as any
|
|
33
|
+
}) as any,
|
|
34
|
+
dynamo: jest.fn((config: any) => {
|
|
35
|
+
return { tableName: config.tableName, type: 'dynamo' } as any
|
|
36
|
+
}) as any,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const create = config => underTest.create({ ...config }) as unknown as FakeDatabase
|
|
40
|
+
|
|
41
|
+
const pgConfig1 = fakeConfig('localhost', 'pg')
|
|
42
|
+
const pgConfig2 = fakeConfig('other', 'pg')
|
|
43
|
+
const kyselyConfig1 = fakeConfig('localhost', 'pg')
|
|
44
|
+
const kyselyConfig2 = fakeConfig('other', 'pg')
|
|
45
|
+
const dynamoConfig1 = fakeNoSQLConfig('localhost', 'dynamo')
|
|
46
|
+
const dynamoConfig2 = fakeNoSQLConfig('other', 'dynamo')
|
|
47
|
+
|
|
48
|
+
const pg1 = create(pgConfig1)
|
|
49
|
+
const pg2 = create(pgConfig1)
|
|
50
|
+
const pg3 = create(pgConfig2)
|
|
51
|
+
|
|
52
|
+
const kysely1 = create(kyselyConfig1)
|
|
53
|
+
const kysely2 = create(kyselyConfig1)
|
|
54
|
+
const kysely3 = create(kyselyConfig2)
|
|
55
|
+
|
|
56
|
+
const dynamo1 = create(dynamoConfig1)
|
|
57
|
+
const dynamo2 = create(dynamoConfig1)
|
|
58
|
+
const dynamo3 = create(dynamoConfig2)
|
|
59
|
+
|
|
60
|
+
expect(pg1).to.equal(pg2).to.not.equal(pg3)
|
|
61
|
+
|
|
62
|
+
expect(pgConfig1).to.be.deep.equal(pg1).to.be.deep.equal(pg2)
|
|
63
|
+
|
|
64
|
+
expect(pg3).to.be.deep.equal(pgConfig2)
|
|
65
|
+
|
|
66
|
+
expect(kysely1).to.equal(kysely2).to.not.equal(kysely3)
|
|
67
|
+
|
|
68
|
+
expect(kyselyConfig1).to.be.deep.equal(kysely1).to.be.deep.equal(kysely2)
|
|
69
|
+
|
|
70
|
+
expect(kysely3).to.be.deep.equal(kyselyConfig2)
|
|
71
|
+
|
|
72
|
+
expect(dynamo1).to.equal(dynamo2).to.not.equal(dynamo3).to.not.equal(pg1)
|
|
73
|
+
console.log(dynamoConfig1)
|
|
74
|
+
console.log(dynamo1)
|
|
75
|
+
expect(dynamoConfig1).to.be.deep.equal(dynamo1).to.be.deep.equal(dynamo2)
|
|
76
|
+
|
|
77
|
+
expect(dynamo3).to.be.deep.equal(dynamoConfig2)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Agent } from 'https'
|
|
2
|
+
|
|
3
|
+
import { DynamoDB } from '@aws-sdk/client-dynamodb'
|
|
4
|
+
import { jest } from '@jest/globals'
|
|
5
|
+
import { NodeHttpHandler } from '@smithy/node-http-handler'
|
|
6
|
+
|
|
7
|
+
import type { DbConfig } from '../../../../src/Database/index.js'
|
|
8
|
+
import { DynamoDatabase } from '../../../../src/Database/integrations/dynamo/DynamoDatabase.js'
|
|
9
|
+
|
|
10
|
+
const config: DbConfig<'dynamo'> = {
|
|
11
|
+
type: 'dynamo',
|
|
12
|
+
region: 'ca-central-1',
|
|
13
|
+
tableName: 'myTable',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const expectedImplConfig = {
|
|
17
|
+
region: config.region,
|
|
18
|
+
maxAttempts: 3,
|
|
19
|
+
requestHandler: new NodeHttpHandler({
|
|
20
|
+
connectionTimeout: 60000,
|
|
21
|
+
socketTimeout: 60000,
|
|
22
|
+
httpsAgent: new Agent({ keepAlive: false, maxSockets: 50, rejectUnauthorized: true }),
|
|
23
|
+
}),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('DynamoDatabase', () => {
|
|
27
|
+
test('DynamoDatabase', async () => {
|
|
28
|
+
const mockTrans = { a: 'b' } as any
|
|
29
|
+
const mockClient = jest.fn(
|
|
30
|
+
() =>
|
|
31
|
+
({
|
|
32
|
+
test: async () => mockTrans,
|
|
33
|
+
}) as any as DynamoDB
|
|
34
|
+
)
|
|
35
|
+
DynamoDatabase['dynamoProvider'] = mockClient
|
|
36
|
+
|
|
37
|
+
const underTest = new DynamoDatabase(config)
|
|
38
|
+
expect(mockClient).toBeCalledWith(expectedImplConfig)
|
|
39
|
+
|
|
40
|
+
// no transaction
|
|
41
|
+
const trans = await underTest.transaction()
|
|
42
|
+
expect(trans).toBe(null)
|
|
43
|
+
})
|
|
44
|
+
})
|