opticedge-cloud-utils 1.1.13 → 1.1.15

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 CHANGED
@@ -1,2 +1,2 @@
1
- # Ignore compiled output
2
- dist/
1
+ # Ignore compiled output
2
+ dist/
package/.eslintrc.js CHANGED
@@ -1,30 +1,30 @@
1
- module.exports = {
2
- root: true,
3
- parser: '@typescript-eslint/parser',
4
- parserOptions: {
5
- ecmaVersion: 2020, // modern JS features
6
- sourceType: 'module'
7
- },
8
- env: {
9
- node: true,
10
- jest: true,
11
- es2020: true
12
- },
13
- plugins: ['@typescript-eslint', 'jest'],
14
- extends: [
15
- 'eslint:recommended',
16
- 'plugin:@typescript-eslint/recommended',
17
- 'plugin:jest/recommended',
18
- 'plugin:prettier/recommended'
19
- ],
20
- rules: {
21
- // Your custom rules here, for example:
22
- 'no-console': 'warn',
23
- '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }]
24
- },
25
- settings: {
26
- jest: {
27
- version: 29 // or your jest version
28
- }
29
- }
30
- }
1
+ module.exports = {
2
+ root: true,
3
+ parser: '@typescript-eslint/parser',
4
+ parserOptions: {
5
+ ecmaVersion: 2020, // modern JS features
6
+ sourceType: 'module'
7
+ },
8
+ env: {
9
+ node: true,
10
+ jest: true,
11
+ es2020: true
12
+ },
13
+ plugins: ['@typescript-eslint', 'jest'],
14
+ extends: [
15
+ 'eslint:recommended',
16
+ 'plugin:@typescript-eslint/recommended',
17
+ 'plugin:jest/recommended',
18
+ 'plugin:prettier/recommended'
19
+ ],
20
+ rules: {
21
+ // Your custom rules here, for example:
22
+ 'no-console': 'warn',
23
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }]
24
+ },
25
+ settings: {
26
+ jest: {
27
+ version: 29 // or your jest version
28
+ }
29
+ }
30
+ }
package/.prettierignore CHANGED
@@ -1,4 +1,4 @@
1
- node_modules
2
- dist
3
- build
4
- coverage
1
+ node_modules
2
+ dist
3
+ build
4
+ coverage
package/.prettierrc CHANGED
@@ -1,8 +1,8 @@
1
- {
2
- "singleQuote": true,
3
- "semi": false,
4
- "trailingComma": "none",
5
- "printWidth": 100,
6
- "tabWidth": 2,
7
- "arrowParens": "avoid"
8
- }
1
+ {
2
+ "singleQuote": true,
3
+ "semi": false,
4
+ "trailingComma": "none",
5
+ "printWidth": 100,
6
+ "tabWidth": 2,
7
+ "arrowParens": "avoid"
8
+ }
@@ -0,0 +1 @@
1
+ export declare function chunkByBytes(arr: any[], maxBytes?: number): any[][];
package/dist/chunk.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.chunkByBytes = chunkByBytes;
5
+ function chunkByBytes(arr, maxBytes = 700000) {
6
+ // 700KB safe default
7
+ const chunks = [];
8
+ let current = [];
9
+ let curBytes = 0;
10
+ for (const item of arr) {
11
+ const s = JSON.stringify(item);
12
+ const b = Buffer.byteLength(s, 'utf8');
13
+ // if a single item exceeds maxBytes, push it alone (or skip)
14
+ if (b > maxBytes) {
15
+ // optionally log and skip - here we'll push as its own chunk
16
+ if (current.length) {
17
+ chunks.push(current);
18
+ current = [];
19
+ curBytes = 0;
20
+ }
21
+ chunks.push([item]);
22
+ continue;
23
+ }
24
+ if (curBytes + b > maxBytes) {
25
+ chunks.push(current);
26
+ current = [item];
27
+ curBytes = b;
28
+ }
29
+ else {
30
+ current.push(item);
31
+ curBytes += b;
32
+ }
33
+ }
34
+ if (current.length)
35
+ chunks.push(current);
36
+ return chunks;
37
+ }
package/dist/env.js CHANGED
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.getEnv = getEnv;
4
5
  function getEnv(name, fallback) {
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from './db/mongo3';
4
4
  export * from './tw/utils';
5
5
  export * from './tw/wallet';
6
6
  export * from './auth';
7
+ export * from './chunk';
7
8
  export * from './env';
8
9
  export * from './parser';
9
10
  export * from './regex';
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ __exportStar(require("./db/mongo3"), exports);
20
20
  __exportStar(require("./tw/utils"), exports);
21
21
  __exportStar(require("./tw/wallet"), exports);
22
22
  __exportStar(require("./auth"), exports);
23
+ __exportStar(require("./chunk"), exports);
23
24
  __exportStar(require("./env"), exports);
24
25
  __exportStar(require("./parser"), exports);
25
26
  __exportStar(require("./regex"), exports);
package/jest.config.js CHANGED
@@ -1,12 +1,12 @@
1
- const { createDefaultPreset } = require('ts-jest')
2
-
3
- const tsJestTransformCfg = createDefaultPreset().transform
4
-
5
- /** @type {import("jest").Config} **/
6
- module.exports = {
7
- testEnvironment: 'node',
8
- transform: {
9
- ...tsJestTransformCfg
10
- },
11
- testPathIgnorePatterns: ['/node_modules/', '/dist/']
12
- }
1
+ const { createDefaultPreset } = require('ts-jest')
2
+
3
+ const tsJestTransformCfg = createDefaultPreset().transform
4
+
5
+ /** @type {import("jest").Config} **/
6
+ module.exports = {
7
+ testEnvironment: 'node',
8
+ transform: {
9
+ ...tsJestTransformCfg
10
+ },
11
+ testPathIgnorePatterns: ['/node_modules/', '/dist/']
12
+ }
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "opticedge-cloud-utils",
3
- "version": "1.1.13",
4
- "description": "Common utilities for cloud functions",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "scripts": {
8
- "clean": "rimraf dist coverage *.tsbuildinfo",
9
- "build": "npm run clean && tsc",
10
- "prepare": "npm run build",
11
- "test": "jest --coverage",
12
- "lint": "eslint . --ext .ts --fix",
13
- "format": "prettier --write .",
14
- "fix": "npm run lint && npm run format"
15
- },
16
- "author": "Evans Musonda",
17
- "license": "MIT",
18
- "dependencies": {
19
- "@google-cloud/secret-manager": "^6.0.1",
20
- "@google-cloud/tasks": "^6.1.0",
21
- "axios": "^1.10.0",
22
- "google-auth-library": "^9.15.1",
23
- "mongodb": "^6.16.0"
24
- },
25
- "devDependencies": {
26
- "@google-cloud/functions-framework": "^4.0.0",
27
- "@types/jest": "^29.5.14",
28
- "@types/node": "^22.15.23",
29
- "@typescript-eslint/eslint-plugin": "^8.33.0",
30
- "@typescript-eslint/parser": "^8.33.0",
31
- "eslint": "^8.57.1",
32
- "eslint-config-prettier": "^10.1.5",
33
- "eslint-plugin-jest": "^28.11.1",
34
- "eslint-plugin-prettier": "^5.4.0",
35
- "jest": "^29.7.0",
36
- "prettier": "^3.5.3",
37
- "ts-jest": "^29.3.4",
38
- "typescript": "^5.8.3"
39
- }
40
- }
1
+ {
2
+ "name": "opticedge-cloud-utils",
3
+ "version": "1.1.15",
4
+ "description": "Common utilities for cloud functions",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "clean": "rimraf dist coverage *.tsbuildinfo",
9
+ "build": "npm run clean && tsc",
10
+ "prepare": "npm run build",
11
+ "test": "jest --coverage",
12
+ "lint": "eslint . --ext .ts --fix",
13
+ "format": "prettier --write .",
14
+ "fix": "npm run lint && npm run format"
15
+ },
16
+ "author": "Evans Musonda",
17
+ "license": "MIT",
18
+ "dependencies": {
19
+ "@google-cloud/secret-manager": "^6.0.1",
20
+ "@google-cloud/tasks": "^6.1.0",
21
+ "axios": "^1.10.0",
22
+ "google-auth-library": "^9.15.1",
23
+ "mongodb": "^7.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@google-cloud/functions-framework": "^4.0.0",
27
+ "@types/jest": "^29.5.14",
28
+ "@types/node": "^22.15.23",
29
+ "@typescript-eslint/eslint-plugin": "^8.33.0",
30
+ "@typescript-eslint/parser": "^8.33.0",
31
+ "eslint": "^8.57.1",
32
+ "eslint-config-prettier": "^10.1.5",
33
+ "eslint-plugin-jest": "^28.11.1",
34
+ "eslint-plugin-prettier": "^5.4.0",
35
+ "jest": "^29.7.0",
36
+ "prettier": "^3.5.3",
37
+ "ts-jest": "^29.3.4",
38
+ "typescript": "^5.8.3"
39
+ }
40
+ }
package/src/auth.ts CHANGED
@@ -1,29 +1,29 @@
1
- import { OAuth2Client } from 'google-auth-library'
2
- import { Request } from '@google-cloud/functions-framework'
3
-
4
- interface VerifyOptions {
5
- allowedAudience: string
6
- allowedServiceAccount: string
7
- }
8
-
9
- export async function verifyRequest(req: Request, options: VerifyOptions): Promise<boolean> {
10
- const authHeader = req.headers['authorization']
11
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
12
- return false
13
- }
14
-
15
- const token = authHeader.split(' ')[1]
16
- const client = new OAuth2Client()
17
-
18
- try {
19
- const ticket = await client.verifyIdToken({
20
- idToken: token,
21
- audience: options.allowedAudience
22
- })
23
-
24
- const payload = ticket.getPayload()
25
- return payload?.email === options.allowedServiceAccount
26
- } catch {
27
- return false
28
- }
29
- }
1
+ import { OAuth2Client } from 'google-auth-library'
2
+ import { Request } from '@google-cloud/functions-framework'
3
+
4
+ interface VerifyOptions {
5
+ allowedAudience: string
6
+ allowedServiceAccount: string
7
+ }
8
+
9
+ export async function verifyRequest(req: Request, options: VerifyOptions): Promise<boolean> {
10
+ const authHeader = req.headers['authorization']
11
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
12
+ return false
13
+ }
14
+
15
+ const token = authHeader.split(' ')[1]
16
+ const client = new OAuth2Client()
17
+
18
+ try {
19
+ const ticket = await client.verifyIdToken({
20
+ idToken: token,
21
+ audience: options.allowedAudience
22
+ })
23
+
24
+ const payload = ticket.getPayload()
25
+ return payload?.email === options.allowedServiceAccount
26
+ } catch {
27
+ return false
28
+ }
29
+ }
package/src/chunk.ts ADDED
@@ -0,0 +1,33 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ export function chunkByBytes(arr: any[], maxBytes = 700_000) {
4
+ // 700KB safe default
5
+ const chunks: any[][] = []
6
+ let current: any[] = []
7
+ let curBytes = 0
8
+ for (const item of arr) {
9
+ const s = JSON.stringify(item)
10
+ const b = Buffer.byteLength(s, 'utf8')
11
+ // if a single item exceeds maxBytes, push it alone (or skip)
12
+ if (b > maxBytes) {
13
+ // optionally log and skip - here we'll push as its own chunk
14
+ if (current.length) {
15
+ chunks.push(current)
16
+ current = []
17
+ curBytes = 0
18
+ }
19
+ chunks.push([item])
20
+ continue
21
+ }
22
+ if (curBytes + b > maxBytes) {
23
+ chunks.push(current)
24
+ current = [item]
25
+ curBytes = b
26
+ } else {
27
+ current.push(item)
28
+ curBytes += b
29
+ }
30
+ }
31
+ if (current.length) chunks.push(current)
32
+ return chunks
33
+ }
package/src/db/mongo.ts CHANGED
@@ -1,45 +1,45 @@
1
- import { MongoClient, Db, Collection, Document } from 'mongodb'
2
- import { getSecret } from '../secrets'
3
-
4
- let client: MongoClient
5
- let db: Db
6
- let connectPromise: Promise<void> | undefined
7
-
8
- export async function connectToMongo(projectId: string, uriSecret: string, dbName: string) {
9
- if (db) return // already connected
10
-
11
- if (!connectPromise) {
12
- connectPromise = (async () => {
13
- const uri = await getSecret(projectId, uriSecret)
14
- client = new MongoClient(uri)
15
- await client.connect()
16
- db = client.db(dbName)
17
- })()
18
- }
19
-
20
- await connectPromise
21
- }
22
-
23
- export async function connectToMongoWithUri(uri: string, dbName: string) {
24
- if (db) return // already connected
25
-
26
- if (!connectPromise) {
27
- connectPromise = (async () => {
28
- client = new MongoClient(uri)
29
- await client.connect()
30
- db = client.db(dbName)
31
- })()
32
- }
33
-
34
- await connectPromise
35
- }
36
-
37
- export function getDb(): Db {
38
- if (!db) throw new Error('Mongo not initialized. Call connectToMongo(...) first.')
39
- return db
40
- }
41
-
42
- export function getCollection<T extends Document = Document>(name: string): Collection<T> {
43
- if (!db) throw new Error('Mongo not initialized')
44
- return db.collection<T>(name)
45
- }
1
+ import { MongoClient, Db, Collection, Document } from 'mongodb'
2
+ import { getSecret } from '../secrets'
3
+
4
+ let client: MongoClient
5
+ let db: Db
6
+ let connectPromise: Promise<void> | undefined
7
+
8
+ export async function connectToMongo(projectId: string, uriSecret: string, dbName: string) {
9
+ if (db) return // already connected
10
+
11
+ if (!connectPromise) {
12
+ connectPromise = (async () => {
13
+ const uri = await getSecret(projectId, uriSecret)
14
+ client = new MongoClient(uri)
15
+ await client.connect()
16
+ db = client.db(dbName)
17
+ })()
18
+ }
19
+
20
+ await connectPromise
21
+ }
22
+
23
+ export async function connectToMongoWithUri(uri: string, dbName: string) {
24
+ if (db) return // already connected
25
+
26
+ if (!connectPromise) {
27
+ connectPromise = (async () => {
28
+ client = new MongoClient(uri)
29
+ await client.connect()
30
+ db = client.db(dbName)
31
+ })()
32
+ }
33
+
34
+ await connectPromise
35
+ }
36
+
37
+ export function getDb(): Db {
38
+ if (!db) throw new Error('Mongo not initialized. Call connectToMongo(...) first.')
39
+ return db
40
+ }
41
+
42
+ export function getCollection<T extends Document = Document>(name: string): Collection<T> {
43
+ if (!db) throw new Error('Mongo not initialized')
44
+ return db.collection<T>(name)
45
+ }
package/src/db/mongo2.ts CHANGED
@@ -1,45 +1,45 @@
1
- // Multi DB safe util
2
- import { MongoClient, Db, Collection, Document } from 'mongodb'
3
- import { getSecret } from '../secrets'
4
-
5
- let client: MongoClient
6
- let connectPromise: Promise<void> | undefined
7
-
8
- export async function connectToMongo2(projectId: string, uriSecret: string) {
9
- if (client) return // already connected
10
-
11
- if (!connectPromise) {
12
- connectPromise = (async () => {
13
- const uri = await getSecret(projectId, uriSecret)
14
- client = new MongoClient(uri)
15
- await client.connect()
16
- })()
17
- }
18
-
19
- await connectPromise
20
- }
21
-
22
- export async function connectToMongoWithUri2(uri: string) {
23
- if (client) return // already connected
24
-
25
- if (!connectPromise) {
26
- connectPromise = (async () => {
27
- client = new MongoClient(uri)
28
- await client.connect()
29
- })()
30
- }
31
-
32
- await connectPromise
33
- }
34
-
35
- export function getDb2(dbName: string): Db {
36
- if (!client) throw new Error('Mongo not initialized')
37
- return client.db(dbName)
38
- }
39
-
40
- export function getCollection2<T extends Document = Document>(
41
- dbName: string,
42
- collectionName: string
43
- ): Collection<T> {
44
- return getDb2(dbName).collection<T>(collectionName)
45
- }
1
+ // Multi DB safe util
2
+ import { MongoClient, Db, Collection, Document } from 'mongodb'
3
+ import { getSecret } from '../secrets'
4
+
5
+ let client: MongoClient
6
+ let connectPromise: Promise<void> | undefined
7
+
8
+ export async function connectToMongo2(projectId: string, uriSecret: string) {
9
+ if (client) return // already connected
10
+
11
+ if (!connectPromise) {
12
+ connectPromise = (async () => {
13
+ const uri = await getSecret(projectId, uriSecret)
14
+ client = new MongoClient(uri)
15
+ await client.connect()
16
+ })()
17
+ }
18
+
19
+ await connectPromise
20
+ }
21
+
22
+ export async function connectToMongoWithUri2(uri: string) {
23
+ if (client) return // already connected
24
+
25
+ if (!connectPromise) {
26
+ connectPromise = (async () => {
27
+ client = new MongoClient(uri)
28
+ await client.connect()
29
+ })()
30
+ }
31
+
32
+ await connectPromise
33
+ }
34
+
35
+ export function getDb2(dbName: string): Db {
36
+ if (!client) throw new Error('Mongo not initialized')
37
+ return client.db(dbName)
38
+ }
39
+
40
+ export function getCollection2<T extends Document = Document>(
41
+ dbName: string,
42
+ collectionName: string
43
+ ): Collection<T> {
44
+ return getDb2(dbName).collection<T>(collectionName)
45
+ }
package/src/db/mongo3.ts CHANGED
@@ -1,63 +1,63 @@
1
- // Multi cluster safe util
2
- import { MongoClient, Db, Collection, Document } from 'mongodb'
3
- import { getSecret } from '../secrets'
4
-
5
- const clients: Map<string, MongoClient> = new Map()
6
- const connectPromises: Map<string, Promise<void>> = new Map()
7
-
8
- export async function connectToMongo3(projectId: string, uriSecret: string): Promise<MongoClient> {
9
- if (clients.has(uriSecret)) {
10
- return clients.get(uriSecret)!
11
- }
12
-
13
- if (!connectPromises.has(uriSecret)) {
14
- const promise = (async () => {
15
- const uri = await getSecret(projectId, uriSecret)
16
- const client = new MongoClient(uri)
17
- await client.connect()
18
- clients.set(uriSecret, client)
19
- })()
20
-
21
- connectPromises.set(uriSecret, promise)
22
- }
23
-
24
- await connectPromises.get(uriSecret)!
25
-
26
- return clients.get(uriSecret)!
27
- }
28
-
29
- export async function connectToMongoWithUri3(uri: string): Promise<MongoClient> {
30
- if (!connectPromises.has(uri)) {
31
- const promise = (async () => {
32
- const client = new MongoClient(uri)
33
- await client.connect()
34
- clients.set(uri, client)
35
- })()
36
-
37
- connectPromises.set(uri, promise)
38
- }
39
-
40
- await connectPromises.get(uri)!
41
-
42
- return clients.get(uri)!
43
- }
44
-
45
- export function getDb3(uriSecret: string, dbName: string): Db {
46
- const client = clients.get(uriSecret)
47
- if (!client) {
48
- throw new Error(`Mongo client for secret "${uriSecret}" not initialized`)
49
- }
50
-
51
- return client.db(dbName)
52
- }
53
-
54
- export function getCollection3<T extends Document = Document>(
55
- uriSecret: string,
56
- dbName: string,
57
- collectionName: string
58
- ): Collection<T> {
59
- return getDb3(uriSecret, dbName).collection<T>(collectionName)
60
- }
61
-
62
- export const __mongoClients = clients
63
- export const __connectPromises = connectPromises
1
+ // Multi cluster safe util
2
+ import { MongoClient, Db, Collection, Document } from 'mongodb'
3
+ import { getSecret } from '../secrets'
4
+
5
+ const clients: Map<string, MongoClient> = new Map()
6
+ const connectPromises: Map<string, Promise<void>> = new Map()
7
+
8
+ export async function connectToMongo3(projectId: string, uriSecret: string): Promise<MongoClient> {
9
+ if (clients.has(uriSecret)) {
10
+ return clients.get(uriSecret)!
11
+ }
12
+
13
+ if (!connectPromises.has(uriSecret)) {
14
+ const promise = (async () => {
15
+ const uri = await getSecret(projectId, uriSecret)
16
+ const client = new MongoClient(uri)
17
+ await client.connect()
18
+ clients.set(uriSecret, client)
19
+ })()
20
+
21
+ connectPromises.set(uriSecret, promise)
22
+ }
23
+
24
+ await connectPromises.get(uriSecret)!
25
+
26
+ return clients.get(uriSecret)!
27
+ }
28
+
29
+ export async function connectToMongoWithUri3(uri: string): Promise<MongoClient> {
30
+ if (!connectPromises.has(uri)) {
31
+ const promise = (async () => {
32
+ const client = new MongoClient(uri)
33
+ await client.connect()
34
+ clients.set(uri, client)
35
+ })()
36
+
37
+ connectPromises.set(uri, promise)
38
+ }
39
+
40
+ await connectPromises.get(uri)!
41
+
42
+ return clients.get(uri)!
43
+ }
44
+
45
+ export function getDb3(uriSecret: string, dbName: string): Db {
46
+ const client = clients.get(uriSecret)
47
+ if (!client) {
48
+ throw new Error(`Mongo client for secret "${uriSecret}" not initialized`)
49
+ }
50
+
51
+ return client.db(dbName)
52
+ }
53
+
54
+ export function getCollection3<T extends Document = Document>(
55
+ uriSecret: string,
56
+ dbName: string,
57
+ collectionName: string
58
+ ): Collection<T> {
59
+ return getDb3(uriSecret, dbName).collection<T>(collectionName)
60
+ }
61
+
62
+ export const __mongoClients = clients
63
+ export const __connectPromises = connectPromises