triangle-utils 1.3.4 → 1.4.1
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/dist/src/UtilsBedrock.d.ts +8 -0
- package/dist/src/{Utils_Bedrock.js → UtilsBedrock.js} +7 -4
- package/dist/src/UtilsBee.d.ts +8 -0
- package/dist/src/{Utils_Bee.js → UtilsBee.js} +13 -8
- package/dist/src/UtilsCognito.d.ts +12 -0
- package/dist/src/UtilsCognito.js +110 -0
- package/dist/src/{Utils_DynamoDB.d.ts → UtilsDynamoDB.d.ts} +6 -8
- package/dist/src/{Utils_DynamoDB.js → UtilsDynamoDB.js} +18 -18
- package/dist/src/UtilsMisc.d.ts +32 -0
- package/dist/src/UtilsMisc.js +156 -0
- package/dist/src/{Utils_S3.d.ts → UtilsS3.d.ts} +3 -5
- package/dist/src/{Utils_S3.js → UtilsS3.js} +3 -3
- package/dist/src/{Utils_S3Vectors.d.ts → UtilsS3Vectors.d.ts} +5 -8
- package/dist/src/{Utils_S3Vectors.js → UtilsS3Vectors.js} +4 -4
- package/dist/src/UtilsYoutube.d.ts +6 -0
- package/dist/src/{Utils_Youtube.js → UtilsYoutube.js} +8 -7
- package/dist/src/index.d.ts +28 -0
- package/dist/src/index.js +36 -0
- package/dist/src/types/{Config.d.ts → TriangleUtilsConfig.d.ts} +1 -3
- package/package.json +9 -9
- package/src/{Utils_Bedrock.ts → UtilsBedrock.ts} +10 -8
- package/src/{Utils_Bee.ts → UtilsBee.ts} +21 -15
- package/src/UtilsCognito.ts +116 -0
- package/src/{Utils_DynamoDB.ts → UtilsDynamoDB.ts} +22 -23
- package/src/UtilsMisc.ts +188 -0
- package/src/{Utils_S3.ts → UtilsS3.ts} +4 -5
- package/src/{Utils_S3Vectors.ts → UtilsS3Vectors.ts} +6 -7
- package/src/{Utils_Youtube.ts → UtilsYoutube.ts} +9 -9
- package/src/index.ts +43 -0
- package/src/types/TriangleUtilsConfig.ts +6 -0
- package/test/Utils.test.ts +135 -24
- package/vite.config.ts +10 -0
- package/dist/src/Utils.d.ts +0 -17
- package/dist/src/Utils.js +0 -24
- package/dist/src/Utils_Bedrock.d.ts +0 -10
- package/dist/src/Utils_Bee.d.ts +0 -11
- package/dist/src/Utils_Misc.d.ts +0 -30
- package/dist/src/Utils_Misc.js +0 -627
- package/dist/src/Utils_Youtube.d.ts +0 -8
- package/src/Utils.ts +0 -28
- package/src/Utils_Misc.ts +0 -678
- package/src/types/Config.ts +0 -9
- /package/dist/src/types/{Config.js → TriangleUtilsConfig.js} +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { UtilsDynamoDB } from "./UtilsDynamoDB.js";
|
|
2
|
+
import { UtilsS3 } from "./UtilsS3.js";
|
|
3
|
+
import { UtilsBedrock } from "./UtilsBedrock.js";
|
|
4
|
+
import { UtilsBee } from "./UtilsBee.js";
|
|
5
|
+
import { UtilsS3Vectors } from "./UtilsS3Vectors.js";
|
|
6
|
+
import { UtilsCognito } from "./UtilsCognito.js";
|
|
7
|
+
import { UtilsMisc } from "./UtilsMisc.js";
|
|
8
|
+
import { UtilsYoutube } from "./UtilsYoutube.js";
|
|
9
|
+
export class TriangleUtils extends UtilsMisc {
|
|
10
|
+
dynamodb;
|
|
11
|
+
s3;
|
|
12
|
+
s3vectors;
|
|
13
|
+
bedrock;
|
|
14
|
+
cognito;
|
|
15
|
+
bee;
|
|
16
|
+
youtube;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super(config);
|
|
19
|
+
this.dynamodb = new UtilsDynamoDB(config.region);
|
|
20
|
+
this.s3 = new UtilsS3(config.region);
|
|
21
|
+
this.s3vectors = new UtilsS3Vectors(config.region);
|
|
22
|
+
this.bedrock = new UtilsBedrock(config.region);
|
|
23
|
+
this.cognito = new UtilsCognito(config.region);
|
|
24
|
+
this.bee = new UtilsBee(config.scraping_bee_api_key);
|
|
25
|
+
this.youtube = new UtilsYoutube(config.youtube_api_key);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export * from "./types/TriangleUtilsConfig.js";
|
|
29
|
+
export * from "./UtilsMisc.js";
|
|
30
|
+
export * from "./UtilsDynamoDB.js";
|
|
31
|
+
export * from "./UtilsS3.js";
|
|
32
|
+
export * from "./UtilsBedrock.js";
|
|
33
|
+
export * from "./UtilsBee.js";
|
|
34
|
+
export * from "./UtilsS3Vectors.js";
|
|
35
|
+
export * from "./UtilsCognito.js";
|
|
36
|
+
export * from "./UtilsYoutube.js";
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "triangle-utils",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"main": "dist/src/
|
|
3
|
+
"version": "1.4.1",
|
|
4
|
+
"main": "dist/src/index.js",
|
|
5
5
|
"directories": {
|
|
6
|
-
"test": "
|
|
6
|
+
"test": "vitest"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
|
-
"test": "
|
|
9
|
+
"test": "vitest",
|
|
10
10
|
"build": "tsc && tsc-alias"
|
|
11
11
|
},
|
|
12
12
|
"author": "",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"type": "module",
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@aws-sdk/client-bedrock-runtime": "^3.953.0",
|
|
18
|
+
"@aws-sdk/client-cognito-identity-provider": "^3.1004.0",
|
|
18
19
|
"@aws-sdk/client-dynamodb": "^3.953.0",
|
|
19
20
|
"@aws-sdk/client-s3": "^3.953.0",
|
|
20
21
|
"@aws-sdk/client-s3vectors": "^3.953.0",
|
|
@@ -24,20 +25,19 @@
|
|
|
24
25
|
"@types/nodemailer": "^7.0.9",
|
|
25
26
|
"googleapis": "^170.0.0",
|
|
26
27
|
"nodemailer": "^7.0.11",
|
|
27
|
-
"scrapingbee": "^1.8.2"
|
|
28
|
-
"triangle-utils": "^1.0.34",
|
|
29
|
-
"tsc-alias": "^1.8.16"
|
|
28
|
+
"scrapingbee": "^1.8.2"
|
|
30
29
|
},
|
|
31
30
|
"devDependencies": {
|
|
32
31
|
"@eslint/js": "^9.39.2",
|
|
33
32
|
"@types/jest": "^30.0.0",
|
|
34
33
|
"eslint": "^9.39.2",
|
|
35
34
|
"globals": "^17.3.0",
|
|
36
|
-
"jest": "^30.2.0",
|
|
37
35
|
"jiti": "^2.6.1",
|
|
38
36
|
"ts-jest": "^29.4.6",
|
|
37
|
+
"tsc-alias": "^1.8.16",
|
|
39
38
|
"tsx": "^4.21.0",
|
|
40
39
|
"typescript": "^5.9.3",
|
|
41
|
-
"typescript-eslint": "^8.55.0"
|
|
40
|
+
"typescript-eslint": "^8.55.0",
|
|
41
|
+
"vitest": "^4.0.18"
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { BedrockRuntime } from "@aws-sdk/client-bedrock-runtime"
|
|
2
|
-
import { Config } from "./types/Config"
|
|
3
2
|
|
|
4
|
-
export class
|
|
3
|
+
export class UtilsBedrock {
|
|
5
4
|
|
|
6
|
-
readonly bedrock : BedrockRuntime
|
|
7
|
-
readonly text_decoder : TextDecoder
|
|
5
|
+
private readonly bedrock : BedrockRuntime
|
|
6
|
+
private readonly text_decoder : TextDecoder
|
|
8
7
|
|
|
9
|
-
constructor(
|
|
10
|
-
this.bedrock = new BedrockRuntime({ region:
|
|
8
|
+
constructor(region : string) {
|
|
9
|
+
this.bedrock = new BedrockRuntime({ region: region })
|
|
11
10
|
this.text_decoder = new TextDecoder()
|
|
12
11
|
}
|
|
13
12
|
|
|
@@ -68,7 +67,7 @@ export class Utils_Bedrock {
|
|
|
68
67
|
return undefined
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
async titan_invoke(text : string) : Promise<
|
|
70
|
+
async titan_invoke(text : string) : Promise<number[] | undefined> {
|
|
72
71
|
for (let i = 0; i < 3; i++) {
|
|
73
72
|
try {
|
|
74
73
|
const output = await this.bedrock.invokeModel({
|
|
@@ -79,7 +78,10 @@ export class Utils_Bedrock {
|
|
|
79
78
|
contentType : "application/json"
|
|
80
79
|
})
|
|
81
80
|
const response = JSON.parse(this.text_decoder.decode(output.body))
|
|
82
|
-
|
|
81
|
+
if (response.embedding !== undefined && Array.isArray(response.embedding) && response.embedding.every((i : any) => typeof i === "number")) {
|
|
82
|
+
const embedding : number[] = response.embedding
|
|
83
|
+
return embedding
|
|
84
|
+
}
|
|
83
85
|
} catch (error) {
|
|
84
86
|
if (error instanceof Error) {
|
|
85
87
|
console.log(error.stack)
|
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
import { ScrapingBeeClient } from "scrapingbee"
|
|
2
|
-
import { Config } from "./types/Config"
|
|
3
2
|
|
|
4
|
-
export class
|
|
3
|
+
export class UtilsBee {
|
|
5
4
|
|
|
6
|
-
readonly
|
|
7
|
-
readonly
|
|
8
|
-
readonly text_decoder : TextDecoder
|
|
5
|
+
private readonly bee : ScrapingBeeClient | undefined
|
|
6
|
+
private readonly text_decoder : TextDecoder
|
|
9
7
|
|
|
10
|
-
constructor(
|
|
11
|
-
this.
|
|
12
|
-
this.bee = config.scraping_bee_api_key !== undefined ? new ScrapingBeeClient(config.scraping_bee_api_key) : undefined
|
|
8
|
+
constructor(scraping_bee_api_key : string | undefined) {
|
|
9
|
+
this.bee = scraping_bee_api_key !== undefined ? new ScrapingBeeClient(scraping_bee_api_key) : undefined
|
|
13
10
|
this.text_decoder = new TextDecoder()
|
|
14
11
|
}
|
|
15
12
|
|
|
16
|
-
async get(url : string, params : Record<string, string> = {}) {
|
|
13
|
+
async get(url : string, params : Record<string, string | number | boolean> = {}) {
|
|
17
14
|
if (this.bee === undefined) {
|
|
18
15
|
return undefined
|
|
19
16
|
}
|
|
20
17
|
for (let i = 0; i < 3; i++) {
|
|
21
18
|
try {
|
|
22
|
-
const response = await this.bee.
|
|
19
|
+
const response = await this.bee.htmlApi({
|
|
23
20
|
url : url,
|
|
24
21
|
params : params
|
|
25
22
|
})
|
|
@@ -40,7 +37,7 @@ export class Utils_Bee {
|
|
|
40
37
|
return undefined
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
async google_search(query : string, news : boolean = false) {
|
|
40
|
+
async google_search(query : string, news : boolean = false) : Promise<Record<string, any>[] | undefined> {
|
|
44
41
|
if (this.bee === undefined) {
|
|
45
42
|
return undefined
|
|
46
43
|
}
|
|
@@ -56,13 +53,22 @@ export class Utils_Bee {
|
|
|
56
53
|
console.log("Failed to Google:", response.status)
|
|
57
54
|
continue
|
|
58
55
|
}
|
|
59
|
-
const data = response.data
|
|
60
|
-
|
|
56
|
+
const data : Record<string, any> = JSON.parse(response.data.toString("utf-8"))
|
|
57
|
+
|
|
58
|
+
if (data.news_results === undefined || data.organic_results === undefined) {
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
const results : Record<string, any>[] | undefined = news ? data.news_results : data.organic_results
|
|
62
|
+
|
|
61
63
|
|
|
62
64
|
if (results === undefined) {
|
|
63
65
|
console.log("Failed to Google.")
|
|
64
66
|
continue
|
|
65
67
|
}
|
|
68
|
+
if (!Array.isArray(results)) {
|
|
69
|
+
console.log("Results are not an array.")
|
|
70
|
+
return
|
|
71
|
+
}
|
|
66
72
|
return results
|
|
67
73
|
} catch {
|
|
68
74
|
console.log("Failed to Google.")
|
|
@@ -72,7 +78,7 @@ export class Utils_Bee {
|
|
|
72
78
|
return undefined
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
async youtube_search(query : string, options = {}) {
|
|
81
|
+
async youtube_search(query : string, options = {}) : Promise<Record<string, any>[] | undefined> {
|
|
76
82
|
if (this.bee === undefined) {
|
|
77
83
|
return undefined
|
|
78
84
|
}
|
|
@@ -86,7 +92,7 @@ export class Utils_Bee {
|
|
|
86
92
|
console.log("Failed to YouTube Search:", response.status)
|
|
87
93
|
continue
|
|
88
94
|
}
|
|
89
|
-
const data = response.data
|
|
95
|
+
const data : Record<string, any> = JSON.parse(response.data.toString("utf-8"))
|
|
90
96
|
const results = data.results
|
|
91
97
|
|
|
92
98
|
if (results === undefined) {
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { CognitoIdentityProvider, NotAuthorizedException } from "@aws-sdk/client-cognito-identity-provider"
|
|
2
|
+
|
|
3
|
+
export class UtilsCognito {
|
|
4
|
+
|
|
5
|
+
private readonly cognito : CognitoIdentityProvider
|
|
6
|
+
|
|
7
|
+
constructor(region : string) {
|
|
8
|
+
this.cognito = new CognitoIdentityProvider({ region : region })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async admin_get_user(user_pool_id : string, username : string) {
|
|
12
|
+
try {
|
|
13
|
+
return await this.cognito.adminGetUser({
|
|
14
|
+
UserPoolId : user_pool_id,
|
|
15
|
+
Username : username
|
|
16
|
+
})
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return undefined
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async admin_create_user(user_pool_id : string, username : string, user_id : string) {
|
|
23
|
+
try {
|
|
24
|
+
return await this.cognito.adminCreateUser({
|
|
25
|
+
UserPoolId : user_pool_id,
|
|
26
|
+
Username : username,
|
|
27
|
+
UserAttributes : [
|
|
28
|
+
{ Name : "preferred_username", Value : user_id },
|
|
29
|
+
{ Name : "email_verified", Value : "true" }
|
|
30
|
+
]
|
|
31
|
+
})
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof Error) {
|
|
34
|
+
return new Error(error.toString().replace("Exception: ", ""))
|
|
35
|
+
}
|
|
36
|
+
return new Error()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async admin_reset_password(user_pool_id : string, username : string) {
|
|
41
|
+
const user = await this.admin_get_user(user_pool_id, username)
|
|
42
|
+
if (user === undefined) {
|
|
43
|
+
return new Error("User does not exist.")
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return await this.cognito.adminCreateUser({
|
|
47
|
+
UserPoolId : user_pool_id,
|
|
48
|
+
Username : username,
|
|
49
|
+
MessageAction : "RESEND"
|
|
50
|
+
})
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (error instanceof Error) {
|
|
53
|
+
return new Error(error.toString().replace("Exception: ", ""))
|
|
54
|
+
}
|
|
55
|
+
return new Error()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async get_user_id(token : string) : Promise<string | undefined> {
|
|
60
|
+
try {
|
|
61
|
+
const user_info = await this.cognito.getUser({
|
|
62
|
+
AccessToken : token
|
|
63
|
+
})
|
|
64
|
+
const user_attributes = user_info.UserAttributes
|
|
65
|
+
if (user_attributes === undefined) {
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
const user_attribute = user_attributes.filter(attribute => attribute.Name === "preferred_username")[0]
|
|
69
|
+
const user_id = user_attribute.Value
|
|
70
|
+
return user_id
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (error instanceof NotAuthorizedException) {
|
|
73
|
+
return undefined
|
|
74
|
+
}
|
|
75
|
+
throw error
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async get_new_token(client_id : string, client_secret : string, refresh_token : string) : Promise<string | undefined> {
|
|
80
|
+
try {
|
|
81
|
+
const response = await this.cognito.getTokensFromRefreshToken({
|
|
82
|
+
ClientId : client_id,
|
|
83
|
+
ClientSecret : client_secret,
|
|
84
|
+
RefreshToken : refresh_token
|
|
85
|
+
})
|
|
86
|
+
const new_auth_result = response.AuthenticationResult
|
|
87
|
+
if (new_auth_result === undefined) {
|
|
88
|
+
return undefined
|
|
89
|
+
}
|
|
90
|
+
const new_token = new_auth_result.AccessToken
|
|
91
|
+
return new_token
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return undefined
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async sign_out(token : string) {
|
|
98
|
+
await this.cognito.globalSignOut({
|
|
99
|
+
AccessToken : token
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async admin_disable_user(user_pool_id : string, username : string) : Promise<void> {
|
|
104
|
+
await this.cognito.adminDisableUser({
|
|
105
|
+
UserPoolId : user_pool_id,
|
|
106
|
+
Username : username,
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async admin_delete_user(user_pool_id : string, username : string) : Promise<void> {
|
|
111
|
+
await this.cognito.adminDeleteUser({
|
|
112
|
+
UserPoolId : user_pool_id,
|
|
113
|
+
Username : username,
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { AttributeValue, DynamoDB, QueryCommandInput, QueryCommandOutput, ScanCommandInput, ScanCommandOutput, UpdateItemCommandInput } from "@aws-sdk/client-dynamodb"
|
|
2
|
-
import { Config } from "./types/Config"
|
|
3
2
|
|
|
4
|
-
function convert_output(
|
|
5
|
-
if (
|
|
6
|
-
return
|
|
7
|
-
} else if (
|
|
8
|
-
return Number(
|
|
9
|
-
} else if (
|
|
10
|
-
return
|
|
11
|
-
} else if (
|
|
12
|
-
return new Set(
|
|
13
|
-
} else if (
|
|
14
|
-
return Object.fromEntries(Object.entries(
|
|
15
|
-
} else if (
|
|
16
|
-
return
|
|
3
|
+
function convert_output(dynamodb_output : AttributeValue) : string | boolean | number | any[] | Set<any> | Record<string, any> | undefined {
|
|
4
|
+
if (dynamodb_output.S !== undefined) {
|
|
5
|
+
return dynamodb_output.S
|
|
6
|
+
} else if (dynamodb_output.N !== undefined) {
|
|
7
|
+
return Number(dynamodb_output.N)
|
|
8
|
+
} else if (dynamodb_output.L !== undefined) {
|
|
9
|
+
return dynamodb_output.L.map((a : AttributeValue) => convert_output(a))
|
|
10
|
+
} else if (dynamodb_output.SS !== undefined) {
|
|
11
|
+
return new Set(dynamodb_output.SS)
|
|
12
|
+
} else if (dynamodb_output.M !== undefined) {
|
|
13
|
+
return Object.fromEntries(Object.entries(dynamodb_output.M).map(([key, value]) => [key, convert_output(value)]))
|
|
14
|
+
} else if (dynamodb_output.BOOL !== undefined) {
|
|
15
|
+
return dynamodb_output.BOOL
|
|
17
16
|
}
|
|
18
17
|
return undefined
|
|
19
18
|
}
|
|
@@ -84,12 +83,12 @@ async function compile_pages(
|
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
export class
|
|
86
|
+
export class UtilsDynamoDB {
|
|
88
87
|
|
|
89
|
-
readonly dynamodb : DynamoDB
|
|
88
|
+
private readonly dynamodb : DynamoDB
|
|
90
89
|
|
|
91
|
-
constructor(
|
|
92
|
-
this.dynamodb = new DynamoDB({ region :
|
|
90
|
+
constructor(region : string) {
|
|
91
|
+
this.dynamodb = new DynamoDB({ region : region })
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
async scan(
|
|
@@ -241,16 +240,16 @@ export class Utils_DynamoDB {
|
|
|
241
240
|
reverse? : boolean,
|
|
242
241
|
compile? : boolean
|
|
243
242
|
} = {}
|
|
244
|
-
) : Promise<Record<string, any>[]
|
|
243
|
+
) : Promise<Record<string, any>[]>{
|
|
245
244
|
const reverse = options.reverse !== undefined ? options.reverse : false
|
|
246
245
|
const compile = options.compile !== undefined ? options.compile : true
|
|
247
246
|
if (Object.keys(primary_key).length !== 1 || Object.keys(secondary_key_prefix).length !== 1) {
|
|
248
|
-
return
|
|
247
|
+
return []
|
|
249
248
|
}
|
|
250
249
|
const converted_primary_value = convert_input(Object.values(primary_key)[0])
|
|
251
250
|
const converted_secondary_prefix_value = convert_input(Object.values(secondary_key_prefix)[0])
|
|
252
251
|
if (converted_primary_value === undefined || converted_secondary_prefix_value === undefined) {
|
|
253
|
-
return
|
|
252
|
+
return []
|
|
254
253
|
}
|
|
255
254
|
const request : QueryCommandInput = {
|
|
256
255
|
TableName : table,
|
|
@@ -271,7 +270,7 @@ export class Utils_DynamoDB {
|
|
|
271
270
|
async query_range(
|
|
272
271
|
table : string,
|
|
273
272
|
primary_key : Record<string, any>,
|
|
274
|
-
secondary_key_range : Record<string, string|number[]>,
|
|
273
|
+
secondary_key_range : Record<string, (string|number)[]>,
|
|
275
274
|
options : {
|
|
276
275
|
reverse? : boolean,
|
|
277
276
|
compile? : boolean
|
|
@@ -388,7 +387,7 @@ export class Utils_DynamoDB {
|
|
|
388
387
|
await this.dynamodb.updateItem(request)
|
|
389
388
|
}
|
|
390
389
|
|
|
391
|
-
async create(table : string, key : Record<string, any>, attributes : Record<string, any
|
|
390
|
+
async create(table : string, key : Record<string, any>, attributes : Record<string, any> = {}) : Promise<void> {
|
|
392
391
|
const item = await this.get(table, key, true)
|
|
393
392
|
if (item !== undefined) {
|
|
394
393
|
return
|
package/src/UtilsMisc.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as nodemailer from "nodemailer"
|
|
2
|
+
import * as crypto from "crypto"
|
|
3
|
+
|
|
4
|
+
import { TriangleUtilsConfig } from "./types/TriangleUtilsConfig"
|
|
5
|
+
|
|
6
|
+
interface Encryption {
|
|
7
|
+
iv : string,
|
|
8
|
+
ciphertext : string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class UtilsMisc {
|
|
12
|
+
|
|
13
|
+
readonly config : TriangleUtilsConfig
|
|
14
|
+
readonly transporter
|
|
15
|
+
|
|
16
|
+
constructor(config : TriangleUtilsConfig) {
|
|
17
|
+
this.config = config
|
|
18
|
+
if (config.google_email !== undefined && config.google_app_password !== undefined) {
|
|
19
|
+
this.transporter = nodemailer.createTransport({
|
|
20
|
+
service: "Gmail",
|
|
21
|
+
host: "smtp.gmail.com",
|
|
22
|
+
port: 465,
|
|
23
|
+
secure: true,
|
|
24
|
+
auth: {
|
|
25
|
+
user: config.google_email,
|
|
26
|
+
pass: config.google_app_password,
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async send_email(recipient : string, subject : string, text : string) : Promise<boolean> {
|
|
33
|
+
if (this.transporter === undefined) {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
for (let i = 0; i < 3; i++) {
|
|
37
|
+
try {
|
|
38
|
+
await this.transporter.sendMail({
|
|
39
|
+
from: this.config.alerts_email,
|
|
40
|
+
to: recipient,
|
|
41
|
+
subject: subject,
|
|
42
|
+
text: text
|
|
43
|
+
})
|
|
44
|
+
return true
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.log("EMAIL ERROR", error)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async admin_alert(text : string) : Promise<boolean> {
|
|
53
|
+
console.log("ADMIN ALERT:", text)
|
|
54
|
+
return await this.send_email(this.config.google_email, "ADMIN ALERT", text)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async safe_run(f : () => Promise<any>) : Promise<void> {
|
|
58
|
+
try {
|
|
59
|
+
await f()
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (!(error instanceof Error)) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
if (error.stack !== undefined) {
|
|
65
|
+
await this.admin_alert(error.stack.toString())
|
|
66
|
+
} else {
|
|
67
|
+
await this.admin_alert(error.toString())
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async iterate<T>(inputs : T[], f : (input : T) => Promise<any>, concurrency : number = 1, print_indices : boolean = false) {
|
|
73
|
+
let index = 0
|
|
74
|
+
let iterators = []
|
|
75
|
+
for (let i = 0; i < concurrency; i++) {
|
|
76
|
+
iterators.push((async () => {
|
|
77
|
+
while (index < inputs.length) {
|
|
78
|
+
index += 1
|
|
79
|
+
if (print_indices) {
|
|
80
|
+
console.log(i + ":" + (index - 1) + "/" + inputs.length)
|
|
81
|
+
}
|
|
82
|
+
await this.safe_run(() => f(inputs[index - 1]))
|
|
83
|
+
}
|
|
84
|
+
})())
|
|
85
|
+
}
|
|
86
|
+
await Promise.all(iterators)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
static async wait(duration : number) {
|
|
91
|
+
return new Promise(resolve => setTimeout(resolve, duration))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static get_current_time() {
|
|
95
|
+
return (new Date()).toISOString()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static get_current_milliseconds() {
|
|
99
|
+
return (new Date()).getTime()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static async sha256(input : string) : Promise<string> {
|
|
103
|
+
const text_encoder = new TextEncoder()
|
|
104
|
+
const input_buffer = text_encoder.encode(input);
|
|
105
|
+
|
|
106
|
+
const hash_buffer = await crypto.subtle.digest("SHA-256", input_buffer)
|
|
107
|
+
|
|
108
|
+
const hash_array = Array.from(new Uint8Array(hash_buffer))
|
|
109
|
+
|
|
110
|
+
const hash = hash_array.map(b => b.toString(16).padStart(2, "0")).join("")
|
|
111
|
+
return hash
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static encrypt(secret_key : string, text : string) : Encryption {
|
|
115
|
+
const iv = crypto.randomBytes(16)
|
|
116
|
+
const cipher = crypto.createCipheriv("aes-256-cbc", Buffer.from(secret_key, "hex"), iv)
|
|
117
|
+
let ciphertext = cipher.update(text, "utf8", "hex")
|
|
118
|
+
ciphertext += cipher.final("hex")
|
|
119
|
+
return {
|
|
120
|
+
iv: iv.toString("hex"),
|
|
121
|
+
ciphertext: ciphertext
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static decrypt(secret_key : string, encryption : Encryption) : string {
|
|
126
|
+
const iv = encryption.iv
|
|
127
|
+
const ciphertext = encryption.ciphertext
|
|
128
|
+
const decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(secret_key, "hex"), Buffer.from(iv, "hex"))
|
|
129
|
+
let text = decipher.update(ciphertext, "hex", "utf8")
|
|
130
|
+
text += decipher.final("utf8")
|
|
131
|
+
return text
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static get_secret_hash(username : string, cognito_client_id : string, cognito_client_secret : string) : string {
|
|
135
|
+
const secret_hash = crypto.createHmac("sha256", cognito_client_secret)
|
|
136
|
+
.update(username + cognito_client_id)
|
|
137
|
+
.digest("base64")
|
|
138
|
+
return secret_hash
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
static get_chunk_indices(text_length : number, max_length = 2500, overlap = 50) : [number, number][] {
|
|
142
|
+
const num_chunks = Math.ceil((text_length + overlap) / max_length)
|
|
143
|
+
const chunk_length = Math.ceil((text_length - overlap) / num_chunks + overlap)
|
|
144
|
+
const chunk_indices : [number, number][] = []
|
|
145
|
+
for (let i = 0; i < num_chunks; i++) {
|
|
146
|
+
chunk_indices.push([
|
|
147
|
+
(chunk_length - overlap) * i,
|
|
148
|
+
(chunk_length - overlap) * i + chunk_length
|
|
149
|
+
])
|
|
150
|
+
}
|
|
151
|
+
return chunk_indices
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
static chunkify(text : string, max_length = 2500, overlap = 50) : {
|
|
155
|
+
chunk_index : [number, number],
|
|
156
|
+
chunk_text : string
|
|
157
|
+
}[] {
|
|
158
|
+
const chunk_indices = this.get_chunk_indices(text.length, max_length, overlap)
|
|
159
|
+
const chunks = chunk_indices.map(chunk_index => ({
|
|
160
|
+
chunk_index : chunk_index,
|
|
161
|
+
chunk_text : text.substring(...chunk_index)
|
|
162
|
+
}))
|
|
163
|
+
return chunks
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
static chunkify_lined(text : string, max_length = 2500, overlap = 50) : {
|
|
167
|
+
chunk_index : [number, number],
|
|
168
|
+
chunk_text : string
|
|
169
|
+
}[] {
|
|
170
|
+
const chunk_indices : [number, number][] = this.get_chunk_indices(text.length, max_length, overlap)
|
|
171
|
+
const lined_chunk_indices : [number, number][] = []
|
|
172
|
+
for (const chunk_index of chunk_indices) {
|
|
173
|
+
const lined_chunk_index : [number, number] = [
|
|
174
|
+
text.lastIndexOf("\n", chunk_index[0]) + 1,
|
|
175
|
+
text.indexOf("\n", chunk_index[1]) + 1
|
|
176
|
+
]
|
|
177
|
+
if (lined_chunk_index[1] < lined_chunk_index[0]) {
|
|
178
|
+
lined_chunk_index[1] += text.length
|
|
179
|
+
}
|
|
180
|
+
lined_chunk_indices.push(lined_chunk_index)
|
|
181
|
+
}
|
|
182
|
+
return lined_chunk_indices.map(chunk_index => ({
|
|
183
|
+
chunk_index : chunk_index,
|
|
184
|
+
chunk_text : text.substring(...chunk_index)
|
|
185
|
+
}))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { S3, NoSuchKey, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"
|
|
2
2
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
|
|
3
|
-
import { Config } from "./types/Config"
|
|
4
3
|
|
|
5
4
|
interface S3Key {
|
|
6
5
|
Bucket : string,
|
|
@@ -17,12 +16,12 @@ function parse_s3_filename(s3_filename : string) : S3Key | undefined {
|
|
|
17
16
|
return { Bucket : bucket, Key : filename }
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
export class
|
|
19
|
+
export class UtilsS3 {
|
|
21
20
|
|
|
22
|
-
readonly s3 : S3
|
|
21
|
+
private readonly s3 : S3
|
|
23
22
|
|
|
24
|
-
constructor(
|
|
25
|
-
this.s3 = new S3({ region :
|
|
23
|
+
constructor(region : string) {
|
|
24
|
+
this.s3 = new S3({ region : region })
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
async file_exists(s3_filename : string) {
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { ListVectorsCommandInput, S3Vectors } from "@aws-sdk/client-s3vectors"
|
|
2
|
-
import { Config } from "./types/Config"
|
|
3
2
|
|
|
4
|
-
interface Vector {
|
|
3
|
+
export interface Vector {
|
|
5
4
|
key : string,
|
|
6
5
|
data : number[],
|
|
7
6
|
metadata : any
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
export class
|
|
9
|
+
export class UtilsS3Vectors {
|
|
11
10
|
|
|
12
|
-
readonly s3vectors : S3Vectors
|
|
11
|
+
private readonly s3vectors : S3Vectors
|
|
13
12
|
|
|
14
|
-
constructor(
|
|
15
|
-
this.s3vectors = new S3Vectors({ region :
|
|
13
|
+
constructor(region : string) {
|
|
14
|
+
this.s3vectors = new S3Vectors({ region : region })
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
async scan(vector_bucket : string, vector_index : string) : Promise<string[]> {
|
|
@@ -134,7 +133,7 @@ export class Utils_S3Vectors {
|
|
|
134
133
|
}
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
async query(vector_bucket : string, vector_index : string, data : number[], num_vectors : number, filters : Record<string, any> =
|
|
136
|
+
async query(vector_bucket : string, vector_index : string, data : number[], num_vectors : number, filters : Record<string, any> | undefined = undefined) {
|
|
138
137
|
const response = await this.s3vectors.queryVectors({
|
|
139
138
|
vectorBucketName : vector_bucket,
|
|
140
139
|
indexName : vector_index,
|