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.
Files changed (43) hide show
  1. package/dist/src/UtilsBedrock.d.ts +8 -0
  2. package/dist/src/{Utils_Bedrock.js → UtilsBedrock.js} +7 -4
  3. package/dist/src/UtilsBee.d.ts +8 -0
  4. package/dist/src/{Utils_Bee.js → UtilsBee.js} +13 -8
  5. package/dist/src/UtilsCognito.d.ts +12 -0
  6. package/dist/src/UtilsCognito.js +110 -0
  7. package/dist/src/{Utils_DynamoDB.d.ts → UtilsDynamoDB.d.ts} +6 -8
  8. package/dist/src/{Utils_DynamoDB.js → UtilsDynamoDB.js} +18 -18
  9. package/dist/src/UtilsMisc.d.ts +32 -0
  10. package/dist/src/UtilsMisc.js +156 -0
  11. package/dist/src/{Utils_S3.d.ts → UtilsS3.d.ts} +3 -5
  12. package/dist/src/{Utils_S3.js → UtilsS3.js} +3 -3
  13. package/dist/src/{Utils_S3Vectors.d.ts → UtilsS3Vectors.d.ts} +5 -8
  14. package/dist/src/{Utils_S3Vectors.js → UtilsS3Vectors.js} +4 -4
  15. package/dist/src/UtilsYoutube.d.ts +6 -0
  16. package/dist/src/{Utils_Youtube.js → UtilsYoutube.js} +8 -7
  17. package/dist/src/index.d.ts +28 -0
  18. package/dist/src/index.js +36 -0
  19. package/dist/src/types/{Config.d.ts → TriangleUtilsConfig.d.ts} +1 -3
  20. package/package.json +9 -9
  21. package/src/{Utils_Bedrock.ts → UtilsBedrock.ts} +10 -8
  22. package/src/{Utils_Bee.ts → UtilsBee.ts} +21 -15
  23. package/src/UtilsCognito.ts +116 -0
  24. package/src/{Utils_DynamoDB.ts → UtilsDynamoDB.ts} +22 -23
  25. package/src/UtilsMisc.ts +188 -0
  26. package/src/{Utils_S3.ts → UtilsS3.ts} +4 -5
  27. package/src/{Utils_S3Vectors.ts → UtilsS3Vectors.ts} +6 -7
  28. package/src/{Utils_Youtube.ts → UtilsYoutube.ts} +9 -9
  29. package/src/index.ts +43 -0
  30. package/src/types/TriangleUtilsConfig.ts +6 -0
  31. package/test/Utils.test.ts +135 -24
  32. package/vite.config.ts +10 -0
  33. package/dist/src/Utils.d.ts +0 -17
  34. package/dist/src/Utils.js +0 -24
  35. package/dist/src/Utils_Bedrock.d.ts +0 -10
  36. package/dist/src/Utils_Bee.d.ts +0 -11
  37. package/dist/src/Utils_Misc.d.ts +0 -30
  38. package/dist/src/Utils_Misc.js +0 -627
  39. package/dist/src/Utils_Youtube.d.ts +0 -8
  40. package/src/Utils.ts +0 -28
  41. package/src/Utils_Misc.ts +0 -678
  42. package/src/types/Config.ts +0 -9
  43. /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";
@@ -1,8 +1,6 @@
1
- export interface Config {
1
+ export interface TriangleUtilsConfig {
2
2
  region: string;
3
- google_app_password?: string;
4
3
  scraping_bee_api_key?: string;
5
4
  youtube_api_key?: string;
6
- citizenportal_api_key?: string;
7
5
  [key: string]: any;
8
6
  }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "triangle-utils",
3
- "version": "1.3.4",
4
- "main": "dist/src/Utils.js",
3
+ "version": "1.4.1",
4
+ "main": "dist/src/index.js",
5
5
  "directories": {
6
- "test": "test"
6
+ "test": "vitest"
7
7
  },
8
8
  "scripts": {
9
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
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 Utils_Bedrock {
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(config : Config) {
10
- this.bedrock = new BedrockRuntime({ region: config.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<string | undefined> {
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
- return response.embedding
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 Utils_Bee {
3
+ export class UtilsBee {
5
4
 
6
- readonly config : Config
7
- readonly bee : ScrapingBeeClient | undefined
8
- readonly text_decoder : TextDecoder
5
+ private readonly bee : ScrapingBeeClient | undefined
6
+ private readonly text_decoder : TextDecoder
9
7
 
10
- constructor(config : Config) {
11
- this.config = config
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.get({
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
- const results = news ? data.news_results : data.organic_results
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(dynamoobject : AttributeValue) : string | boolean | number | any[] | Set<any> | Record<string, any> | undefined {
5
- if (dynamoobject.S !== undefined) {
6
- return dynamoobject.S
7
- } else if (dynamoobject.N !== undefined) {
8
- return Number(dynamoobject.N)
9
- } else if (dynamoobject.L !== undefined) {
10
- return dynamoobject.L.map((a : AttributeValue) => convert_output(a))
11
- } else if (dynamoobject.SS !== undefined) {
12
- return new Set(dynamoobject.SS)
13
- } else if (dynamoobject.M !== undefined) {
14
- return Object.fromEntries(Object.entries(dynamoobject.M).map(([key, value]) => [key, convert_output(value)]))
15
- } else if (dynamoobject.BOOL !== undefined) {
16
- return dynamoobject.BOOL
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 Utils_DynamoDB {
86
+ export class UtilsDynamoDB {
88
87
 
89
- readonly dynamodb : DynamoDB
88
+ private readonly dynamodb : DynamoDB
90
89
 
91
- constructor(config : Config) {
92
- this.dynamodb = new DynamoDB({ region : config.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>[] | undefined>{
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 undefined
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 undefined
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[]> = {}) : Promise<void> {
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
@@ -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 Utils_S3 {
19
+ export class UtilsS3 {
21
20
 
22
- readonly s3 : S3
21
+ private readonly s3 : S3
23
22
 
24
- constructor(config : Config) {
25
- this.s3 = new S3({ region : config.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 Utils_S3Vectors {
9
+ export class UtilsS3Vectors {
11
10
 
12
- readonly s3vectors : S3Vectors
11
+ private readonly s3vectors : S3Vectors
13
12
 
14
- constructor(config : Config) {
15
- this.s3vectors = new S3Vectors({ region : config.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,