gcf-common-lib 0.23.7 → 0.23.9

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gcf-common-lib",
3
3
  "description": "",
4
- "version": "0.23.7",
4
+ "version": "0.23.9",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "branches": [
@@ -18,18 +18,19 @@
18
18
  "url": "https://github.com/TopTechnologies/gcf-common.git"
19
19
  },
20
20
  "dependencies": {
21
- "@google-cloud/pubsub": "^3.3.0",
22
- "@google-cloud/secret-manager": "^4.2.1",
23
- "@google-cloud/storage": "^6.9.3",
21
+ "@google-cloud/pubsub": "^3.2.1",
22
+ "@google-cloud/secret-manager": "^4.2.0",
23
+ "@google-cloud/storage": "^6.9.0",
24
+ "bluebird": "^3.7.2",
24
25
  "lodash": "^4.17.21",
25
26
  "moment": "^2.29.4",
26
- "mongodb": "^5.1.0",
27
+ "mongodb": "^4.14.0",
27
28
  "rxjs": "^7.8.0"
28
29
  },
29
30
  "devDependencies": {
30
- "@tsconfig/node18": "^1.0.1",
31
+ "@tsconfig/node14": "^1.0.3",
31
32
  "@types/lodash": "^4.14.191",
32
- "@types/node": "^18.14.1"
33
+ "@types/node": "^14.18.36"
33
34
  },
34
35
  "author": "alert83@gmail.com",
35
36
  "license": "MIT"
package/src/index.js CHANGED
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
@@ -22,96 +31,106 @@ class GcfCommon {
22
31
  * @param handler
23
32
  * @param timeout Seconds
24
33
  */
25
- static async process(event, context, handler, timeout = 535) {
26
- return Promise.race([
27
- (0, utils_1.timeoutAfter)(timeout),
28
- handler(event, context),
29
- ])
30
- .then(async (res) => {
31
- // console.log('res:', res);
32
- await this.publish(event, context, res);
33
- })
34
- .catch(async (err) => {
35
- const fname = process?.env?.K_SERVICE ?? 'UNKNOWN';
36
- const response = {
37
- error: {
38
- name: err.name,
39
- message: `GCF [${fname}]: ${err.message}`,
40
- stack: err.stack,
41
- },
42
- };
43
- await this.publish(event, context, response, { error: '1' }).catch(noop_1.default);
44
- throw err;
34
+ static process(event, context, handler, timeout = 535) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ return Promise.race([
37
+ (0, utils_1.timeoutAfter)(timeout),
38
+ handler(event, context),
39
+ ])
40
+ .then((res) => __awaiter(this, void 0, void 0, function* () {
41
+ // console.log('res:', res);
42
+ yield this.publish(event, context, res);
43
+ }))
44
+ .catch((err) => __awaiter(this, void 0, void 0, function* () {
45
+ var _a, _b;
46
+ const fname = (_b = (_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.K_SERVICE) !== null && _b !== void 0 ? _b : 'UNKNOWN';
47
+ const response = {
48
+ error: {
49
+ name: err.name,
50
+ message: `GCF [${fname}]: ${err.message}`,
51
+ stack: err.stack,
52
+ },
53
+ };
54
+ yield this.publish(event, context, response, { error: '1' }).catch(noop_1.default);
55
+ throw err;
56
+ }));
45
57
  });
46
58
  }
47
- static async publish(event, context, json, attributes) {
48
- const { topic, requestId, env } = await this.getTopic(event, context);
49
- console.log('publish:', topic, env, json, attributes);
50
- if (!(0, isEmpty_1.default)(topic)) {
51
- return exports.pubSub.topic(topic).publishMessage({
52
- json: json ?? {},
53
- attributes: {
54
- ...(0, fromPairs_1.default)(Object.entries(attributes ?? {})
55
- .map(([k, v]) => [k, '' + v])),
56
- env: env ?? '',
57
- requestId: requestId ?? '',
58
- type: 'response',
59
- response: '1',
60
- },
61
- });
62
- }
59
+ static publish(event, context, json, attributes) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ const { topic, requestId, env } = yield this.getTopic(event, context);
62
+ console.log('publish:', topic, env, json, attributes);
63
+ if (!(0, isEmpty_1.default)(topic)) {
64
+ return exports.pubSub.topic(topic).publishMessage({
65
+ json: json !== null && json !== void 0 ? json : {},
66
+ attributes: Object.assign(Object.assign({}, (0, fromPairs_1.default)(Object.entries(attributes !== null && attributes !== void 0 ? attributes : {})
67
+ .map(([k, v]) => [k, '' + v]))), { env: env !== null && env !== void 0 ? env : '', requestId: requestId !== null && requestId !== void 0 ? requestId : '', type: 'response', response: '1' }),
68
+ });
69
+ }
70
+ });
63
71
  }
64
- static async getTopic(event, context) {
65
- /** t_{GUID}__{YYYY-MM-DD} */
66
- let topic;
67
- let requestId;
68
- let env;
69
- switch (context?.eventType) {
70
- case 'google.storage.object.finalize': {
71
- const gsEvent = event;
72
- ({ topic, requestId, env } = gsEvent?.metadata ?? {});
73
- if (!topic && context?.resource?.type === 'storage#object') {
74
- const [meta] = await exports.storage.bucket(gsEvent.bucket).file(gsEvent.name).getMetadata();
75
- ({ topic, requestId, env } = meta?.metadata ?? {});
72
+ static getTopic(event, context) {
73
+ var _a, _b, _c, _d;
74
+ return __awaiter(this, void 0, void 0, function* () {
75
+ /** t_{GUID}__{YYYY-MM-DD} */
76
+ let topic;
77
+ let requestId;
78
+ let env;
79
+ switch (context === null || context === void 0 ? void 0 : context.eventType) {
80
+ case 'google.storage.object.finalize': {
81
+ const gsEvent = event;
82
+ ({ topic, requestId, env } = (_a = gsEvent === null || gsEvent === void 0 ? void 0 : gsEvent.metadata) !== null && _a !== void 0 ? _a : {});
83
+ if (!topic && ((_b = context === null || context === void 0 ? void 0 : context.resource) === null || _b === void 0 ? void 0 : _b.type) === 'storage#object') {
84
+ const [meta] = yield exports.storage.bucket(gsEvent.bucket).file(gsEvent.name).getMetadata();
85
+ ({ topic, requestId, env } = (_c = meta === null || meta === void 0 ? void 0 : meta.metadata) !== null && _c !== void 0 ? _c : {});
86
+ }
87
+ break;
88
+ }
89
+ case 'google.pubsub.topic.publish': {
90
+ const psEvent = event;
91
+ ({ topic, requestId, env } = (_d = psEvent === null || psEvent === void 0 ? void 0 : psEvent.attributes) !== null && _d !== void 0 ? _d : {});
92
+ break;
76
93
  }
77
- break;
78
- }
79
- case 'google.pubsub.topic.publish': {
80
- const psEvent = event;
81
- ({ topic, requestId, env } = psEvent?.attributes ?? {});
82
- break;
83
94
  }
84
- }
85
- return { topic, requestId, env };
95
+ return { topic, requestId, env };
96
+ });
86
97
  }
87
- static async getOptions(event, context) {
88
- switch (context?.eventType) {
89
- case 'google.storage.object.finalize': {
90
- const gsEvent = event;
91
- if (gsEvent?.metadata?.options) {
92
- return JSON.parse(gsEvent?.metadata?.options ?? '{}');
98
+ static getOptions(event, context) {
99
+ var _a, _b, _c, _d, _e, _f, _g;
100
+ return __awaiter(this, void 0, void 0, function* () {
101
+ switch (context === null || context === void 0 ? void 0 : context.eventType) {
102
+ case 'google.storage.object.finalize': {
103
+ const gsEvent = event;
104
+ if ((_a = gsEvent === null || gsEvent === void 0 ? void 0 : gsEvent.metadata) === null || _a === void 0 ? void 0 : _a.options) {
105
+ return JSON.parse((_c = (_b = gsEvent === null || gsEvent === void 0 ? void 0 : gsEvent.metadata) === null || _b === void 0 ? void 0 : _b.options) !== null && _c !== void 0 ? _c : '{}');
106
+ }
107
+ else {
108
+ const file = exports.storage.bucket(gsEvent.bucket).file(gsEvent.name);
109
+ const [meta] = yield file.getMetadata();
110
+ return JSON.parse((_e = (_d = meta === null || meta === void 0 ? void 0 : meta.metadata) === null || _d === void 0 ? void 0 : _d.options) !== null && _e !== void 0 ? _e : '{}');
111
+ }
93
112
  }
94
- else {
95
- const file = exports.storage.bucket(gsEvent.bucket).file(gsEvent.name);
96
- const [meta] = await file.getMetadata();
97
- return JSON.parse(meta?.metadata?.options ?? '{}');
113
+ case 'google.pubsub.topic.publish': {
114
+ const psEvent = event;
115
+ return JSON.parse((_g = (_f = psEvent === null || psEvent === void 0 ? void 0 : psEvent.attributes) === null || _f === void 0 ? void 0 : _f.options) !== null && _g !== void 0 ? _g : '{}');
98
116
  }
99
117
  }
100
- case 'google.pubsub.topic.publish': {
101
- const psEvent = event;
102
- return JSON.parse(psEvent?.attributes?.options ?? '{}');
103
- }
104
- }
118
+ });
105
119
  }
106
- static async getSecret(name, version) {
107
- const projectId = await exports.secretClient.getProjectId();
108
- const secretName = `projects/${projectId}/secrets/${name}`;
109
- const secretVersion = `${secretName}/versions/${version ?? 'latest'}`;
110
- const [response] = await exports.secretClient.accessSecretVersion({ name: secretVersion });
111
- return response?.payload?.data?.toString();
120
+ static getSecret(name, version) {
121
+ var _a, _b;
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ const projectId = yield exports.secretClient.getProjectId();
124
+ const secretName = `projects/${projectId}/secrets/${name}`;
125
+ const secretVersion = `${secretName}/versions/${version !== null && version !== void 0 ? version : 'latest'}`;
126
+ const [response] = yield exports.secretClient.accessSecretVersion({ name: secretVersion });
127
+ return (_b = (_a = response === null || response === void 0 ? void 0 : response.payload) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.toString();
128
+ });
112
129
  }
113
- static async getSecrets(names, versions) {
114
- return Promise.all(names.map(async (name, idx) => this.getSecret(name, versions?.[idx]).catch()));
130
+ static getSecrets(names, versions) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ return Promise.all(names.map((name, idx) => __awaiter(this, void 0, void 0, function* () { return this.getSecret(name, versions === null || versions === void 0 ? void 0 : versions[idx]).catch(); })));
133
+ });
115
134
  }
116
135
  }
117
136
  exports.GcfCommon = GcfCommon;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.MongoHelper = void 0;
13
+ class MongoHelper {
14
+ static collectionExists(client, name) {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ const db = client.db();
17
+ const collections = yield db.listCollections({ name }, { nameOnly: true }).toArray();
18
+ return collections.length > 0;
19
+ });
20
+ }
21
+ static collectionSafeGet(client, name, options, afterCreate) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ const db = client.db();
24
+ let coll;
25
+ if (yield this.collectionExists(client, name)) {
26
+ coll = db.collection(name);
27
+ }
28
+ else {
29
+ coll = yield db.createCollection(name, options);
30
+ afterCreate && (yield afterCreate(coll));
31
+ }
32
+ return coll;
33
+ });
34
+ }
35
+ }
36
+ exports.MongoHelper = MongoHelper;
@@ -0,0 +1,30 @@
1
+ import {Collection, CreateCollectionOptions, MongoClient} from "mongodb";
2
+ import {Document} from "bson";
3
+
4
+ export class MongoHelper {
5
+ static async collectionExists(client: MongoClient, name: string) {
6
+ const db = client.db();
7
+ const collections = await db.listCollections({name}, {nameOnly: true}).toArray();
8
+ return collections.length > 0;
9
+ }
10
+
11
+ static async collectionSafeGet<TSchema extends Document = Document>(
12
+ client: MongoClient,
13
+ name: string,
14
+ options?: CreateCollectionOptions,
15
+ afterCreate?: (col: Collection<TSchema>) => Promise<void>,
16
+ ) {
17
+ const db = client.db();
18
+ let coll: Collection<TSchema>;
19
+
20
+ if (await this.collectionExists(client, name)) {
21
+ coll = db.collection<TSchema>(name);
22
+ } else {
23
+ coll = await db.createCollection<TSchema>(name, options);
24
+ afterCreate && (await afterCreate(coll));
25
+ }
26
+
27
+ return coll;
28
+ }
29
+
30
+ }
package/src/mongo-lock.js CHANGED
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
13
  };
@@ -7,19 +16,21 @@ exports.MongoLock = void 0;
7
16
  const moment_1 = __importDefault(require("moment"));
8
17
  const noop_1 = __importDefault(require("lodash/noop"));
9
18
  const rxjs_1 = require("rxjs");
19
+ const mongo_helper_1 = require("./mongo-helper");
10
20
  class MongoLock {
11
- client;
12
21
  constructor(client) {
13
22
  this.client = client;
14
23
  }
15
- async getCollection() {
16
- const locksColl = this.client.db().collection('locks');
17
- await locksColl.indexExists('expiresAt')
18
- .then(async (exists) => {
19
- if (!exists)
20
- await locksColl.createIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 });
24
+ getCollection() {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ const locksColl = yield mongo_helper_1.MongoHelper.collectionSafeGet(this.client, 'locks');
27
+ yield locksColl.indexExists('expiresAt')
28
+ .then((exists) => __awaiter(this, void 0, void 0, function* () {
29
+ if (!exists)
30
+ yield locksColl.createIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 });
31
+ }));
32
+ return locksColl;
21
33
  });
22
- return locksColl;
23
34
  }
24
35
  /**
25
36
  * Create the MongoDB collection and an expiring index on a field named "expiresAt".
@@ -27,39 +38,45 @@ class MongoLock {
27
38
  * db.createCollection('locks');
28
39
  * db.locks.createIndex( { "expiresAt": 1 }, { expireAfterSeconds: 0 } )
29
40
  **/
30
- async acquireLock(name, ttlSeconds) {
31
- const collection = await this.getCollection();
32
- // Entry gets removed automatically due to an expiry index in Mongo
33
- const expiresAt = (0, moment_1.default)().add(ttlSeconds, 'seconds').toDate();
34
- try {
35
- await collection.insertOne({
36
- _id: name,
37
- expiresAt,
38
- });
39
- return true;
40
- }
41
- catch (ex) {
42
- // 11000 means duplicate key error, which is expected on an active lock
43
- if (ex?.code !== 11000) {
44
- // Unexpected error, what happened here :o
45
- throw ex;
41
+ acquireLock(name, ttlSeconds) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ const collection = yield this.getCollection();
44
+ // Entry gets removed automatically due to an expiry index in Mongo
45
+ const expiresAt = (0, moment_1.default)().add(ttlSeconds, 'seconds').toDate();
46
+ try {
47
+ yield collection.insertOne({
48
+ _id: name,
49
+ expiresAt,
50
+ });
51
+ return true;
52
+ }
53
+ catch (ex) {
54
+ // 11000 means duplicate key error, which is expected on an active lock
55
+ if ((ex === null || ex === void 0 ? void 0 : ex.code) !== 11000) {
56
+ // Unexpected error, what happened here :o
57
+ throw ex;
58
+ }
59
+ // As we got a duplicate key exception, no lock could be acquired
60
+ return false;
46
61
  }
47
- // As we got a duplicate key exception, no lock could be acquired
48
- return false;
49
- }
62
+ });
50
63
  }
51
- async releaseLock(name) {
52
- const collection = await this.getCollection();
53
- return collection.deleteOne({ _id: name });
64
+ releaseLock(name) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ const collection = yield this.getCollection();
67
+ return collection.deleteOne({ _id: name });
68
+ });
54
69
  }
55
- async acquireAndExecute(name, ttlSeconds, wait, fn) {
56
- const delay = 200;
57
- const count = Math.round((1000 / delay) * ttlSeconds);
58
- return (0, rxjs_1.lastValueFrom)((0, rxjs_1.defer)(() => (0, rxjs_1.from)(this.acquireLock(name, ttlSeconds))).pipe((0, rxjs_1.map)(locked => {
59
- console.log(locked);
60
- if (!locked)
61
- throw locked;
62
- }), wait ? (0, rxjs_1.retry)({ count, delay }) : rxjs_1.identity, (0, rxjs_1.switchMap)(() => fn().finally(() => this.releaseLock(name).catch(noop_1.default)))));
70
+ acquireAndExecute(name, ttlSeconds, wait, fn) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ const delay = 200;
73
+ const count = Math.round((1000 / delay) * ttlSeconds);
74
+ return (0, rxjs_1.lastValueFrom)((0, rxjs_1.defer)(() => (0, rxjs_1.from)(this.acquireLock(name, ttlSeconds))).pipe((0, rxjs_1.map)(locked => {
75
+ console.log(locked);
76
+ if (!locked)
77
+ throw locked;
78
+ }), wait ? (0, rxjs_1.retry)({ count, delay }) : rxjs_1.identity, (0, rxjs_1.switchMap)(() => fn().finally(() => this.releaseLock(name).catch(noop_1.default)))));
79
+ });
63
80
  }
64
81
  }
65
82
  exports.MongoLock = MongoLock;
package/src/mongo-lock.ts CHANGED
@@ -2,6 +2,7 @@ import {MongoClient, MongoError} from "mongodb";
2
2
  import moment from "moment";
3
3
  import noop from "lodash/noop";
4
4
  import {defer, from, identity, lastValueFrom, map, retry, switchMap} from "rxjs";
5
+ import {MongoHelper} from "./mongo-helper";
5
6
 
6
7
  export class MongoLock {
7
8
 
@@ -9,7 +10,7 @@ export class MongoLock {
9
10
  }
10
11
 
11
12
  async getCollection() {
12
- const locksColl = this.client.db().collection('locks');
13
+ const locksColl = await MongoHelper.collectionSafeGet(this.client, 'locks' );
13
14
  await locksColl.indexExists('expiresAt')
14
15
  .then(async exists => {
15
16
  if (!exists) await locksColl.createIndex({"expiresAt": 1}, {expireAfterSeconds: 0});
package/src/utils.js CHANGED
@@ -1,15 +1,26 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.A1ToColNum = exports.colNumToA1 = exports.A1ToIndex = exports.indexToA1 = exports.timeoutAfter = void 0;
4
13
  /**
5
14
  *
6
15
  * @param seconds Google function timeout limit (max: 9 min)
7
16
  */
8
- async function timeoutAfter(seconds = 540) {
9
- return new Promise((resolve, reject) => {
10
- setTimeout(() => {
11
- reject(new Error(`${seconds} seconds timeout exceeded`));
12
- }, seconds * 1000);
17
+ function timeoutAfter(seconds = 540) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ return new Promise((resolve, reject) => {
20
+ setTimeout(() => {
21
+ reject(new Error(`${seconds} seconds timeout exceeded`));
22
+ }, seconds * 1000);
23
+ });
13
24
  });
14
25
  }
15
26
  exports.timeoutAfter = timeoutAfter;
package/tsconfig.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "$schema": "http://json.schemastore.org/tsconfig",
3
- "extends": "@tsconfig/node18/tsconfig.json",
3
+ "extends": "@tsconfig/node14/tsconfig.json",
4
4
  "compilerOptions": {
5
- },
6
- "exclude": [
7
- "node_modules/**",
8
- "**/*.d.ts"
9
- ]
5
+ "target": "ES6",
6
+ "lib": [
7
+ "ES2018",
8
+ "ES2019",
9
+ "ES2020",
10
+ "ES2021",
11
+ "ESNext"
12
+ ]
13
+ }
10
14
  }