opticedge-cloud-utils 1.1.17 → 1.1.18
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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/pub.d.ts +1 -0
- package/dist/pub.js +38 -0
- package/package.json +2 -1
- package/src/index.ts +1 -0
- package/src/pub.ts +41 -0
- package/tests/pub.test.ts +85 -0
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ __exportStar(require("./auth"), exports);
|
|
|
23
23
|
__exportStar(require("./chunk"), exports);
|
|
24
24
|
__exportStar(require("./env"), exports);
|
|
25
25
|
__exportStar(require("./parser"), exports);
|
|
26
|
+
__exportStar(require("./pub"), exports);
|
|
26
27
|
__exportStar(require("./regex"), exports);
|
|
27
28
|
__exportStar(require("./retry"), exports);
|
|
28
29
|
__exportStar(require("./secrets"), exports);
|
package/dist/pub.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function publishMessage(projectId: string, topicName: string, envelope: Record<string, unknown>): Promise<string>;
|
package/dist/pub.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.publishMessage = publishMessage;
|
|
4
|
+
// src/pub.ts
|
|
5
|
+
const pubsub_1 = require("@google-cloud/pubsub");
|
|
6
|
+
const pubsubCache = new Map();
|
|
7
|
+
function getPubSub(projectId) {
|
|
8
|
+
if (!projectId)
|
|
9
|
+
throw new Error('projectId is required');
|
|
10
|
+
let ps = pubsubCache.get(projectId);
|
|
11
|
+
if (!ps) {
|
|
12
|
+
ps = new pubsub_1.PubSub({ projectId });
|
|
13
|
+
pubsubCache.set(projectId, ps);
|
|
14
|
+
}
|
|
15
|
+
return ps;
|
|
16
|
+
}
|
|
17
|
+
async function publishMessage(projectId, topicName, envelope) {
|
|
18
|
+
if (!projectId)
|
|
19
|
+
throw new Error('projectId is required');
|
|
20
|
+
if (!topicName)
|
|
21
|
+
throw new Error('topicName is required');
|
|
22
|
+
if (envelope === undefined)
|
|
23
|
+
throw new Error('envelope is required');
|
|
24
|
+
try {
|
|
25
|
+
const pubsub = getPubSub(projectId);
|
|
26
|
+
const topic = pubsub.topic(topicName);
|
|
27
|
+
const data = Buffer.from(JSON.stringify(envelope));
|
|
28
|
+
const messageId = await topic.publishMessage({
|
|
29
|
+
data
|
|
30
|
+
});
|
|
31
|
+
console.info(`INFO: Pub/Sub publish project=${projectId} topic=${topicName} msg_id=${messageId}`);
|
|
32
|
+
return messageId;
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.error('ERROR: publish failed:', err);
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opticedge-cloud-utils",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18",
|
|
4
4
|
"description": "Common utilities for cloud functions",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"author": "Evans Musonda",
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"@google-cloud/pubsub": "^5.2.0",
|
|
19
20
|
"@google-cloud/secret-manager": "^6.0.1",
|
|
20
21
|
"@google-cloud/tasks": "^6.1.0",
|
|
21
22
|
"axios": "^1.10.0",
|
package/src/index.ts
CHANGED
package/src/pub.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/pub.ts
|
|
2
|
+
import { PubSub } from '@google-cloud/pubsub'
|
|
3
|
+
|
|
4
|
+
const pubsubCache = new Map<string, PubSub>()
|
|
5
|
+
|
|
6
|
+
function getPubSub(projectId: string): PubSub {
|
|
7
|
+
if (!projectId) throw new Error('projectId is required')
|
|
8
|
+
let ps = pubsubCache.get(projectId)
|
|
9
|
+
if (!ps) {
|
|
10
|
+
ps = new PubSub({ projectId })
|
|
11
|
+
pubsubCache.set(projectId, ps)
|
|
12
|
+
}
|
|
13
|
+
return ps
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function publishMessage(
|
|
17
|
+
projectId: string,
|
|
18
|
+
topicName: string,
|
|
19
|
+
envelope: Record<string, unknown>
|
|
20
|
+
): Promise<string> {
|
|
21
|
+
if (!projectId) throw new Error('projectId is required')
|
|
22
|
+
if (!topicName) throw new Error('topicName is required')
|
|
23
|
+
if (envelope === undefined) throw new Error('envelope is required')
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const pubsub = getPubSub(projectId)
|
|
27
|
+
const topic = pubsub.topic(topicName)
|
|
28
|
+
const data = Buffer.from(JSON.stringify(envelope))
|
|
29
|
+
const messageId = await topic.publishMessage({
|
|
30
|
+
data
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
console.info(
|
|
34
|
+
`INFO: Pub/Sub publish project=${projectId} topic=${topicName} msg_id=${messageId}`
|
|
35
|
+
)
|
|
36
|
+
return messageId
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error('ERROR: publish failed:', err)
|
|
39
|
+
throw err
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// tests/pub.test.ts
|
|
2
|
+
jest.mock('@google-cloud/pubsub', () => {
|
|
3
|
+
const instances: any[] = []
|
|
4
|
+
|
|
5
|
+
class PubSub {
|
|
6
|
+
opts: any
|
|
7
|
+
topics = new Map<string, any>()
|
|
8
|
+
constructor(opts?: any) {
|
|
9
|
+
this.opts = opts
|
|
10
|
+
instances.push(this)
|
|
11
|
+
}
|
|
12
|
+
topic(name: string) {
|
|
13
|
+
if (!this.topics.has(name)) {
|
|
14
|
+
const publishMessage = jest.fn(({ data }: { data: Buffer }) =>
|
|
15
|
+
Promise.resolve(`${this.opts?.projectId}-${name}`)
|
|
16
|
+
)
|
|
17
|
+
this.topics.set(name, { publishMessage })
|
|
18
|
+
}
|
|
19
|
+
return this.topics.get(name)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return { PubSub, __instances: instances }
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const path = '../src/pub'
|
|
27
|
+
|
|
28
|
+
describe('publishMessage', () => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
// Ensure a fresh module load so the mocked PubSub and src/pub share the same mock instance
|
|
31
|
+
jest.resetModules()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('publishes and returns messageId, sends JSON buffer', async () => {
|
|
35
|
+
const mockPubsub = require('@google-cloud/pubsub')
|
|
36
|
+
const { publishMessage } = require(path)
|
|
37
|
+
const envelope = { hello: 'world' }
|
|
38
|
+
|
|
39
|
+
const msgId = await publishMessage('project-1', 'topic-a', envelope)
|
|
40
|
+
expect(msgId).toBe('project-1-topic-a')
|
|
41
|
+
|
|
42
|
+
const instance = mockPubsub.__instances[0]
|
|
43
|
+
expect(instance).toBeDefined()
|
|
44
|
+
|
|
45
|
+
const publishMock = instance.topics.get('topic-a').publishMessage
|
|
46
|
+
expect(publishMock).toHaveBeenCalledTimes(1)
|
|
47
|
+
|
|
48
|
+
const callArg = publishMock.mock.calls[0][0]
|
|
49
|
+
expect(callArg).toHaveProperty('data')
|
|
50
|
+
expect(callArg.data.toString()).toBe(JSON.stringify(envelope))
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('throws on missing arguments', async () => {
|
|
54
|
+
const { publishMessage } = require(path)
|
|
55
|
+
await expect(publishMessage('', 't', {})).rejects.toThrow('projectId is required')
|
|
56
|
+
await expect(publishMessage('p', '', {})).rejects.toThrow('topicName is required')
|
|
57
|
+
await expect(publishMessage('p', 't', undefined as any)).rejects.toThrow('envelope is required')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('caches one PubSub instance per project', async () => {
|
|
61
|
+
const mockPubsub = require('@google-cloud/pubsub')
|
|
62
|
+
const { publishMessage } = require(path)
|
|
63
|
+
|
|
64
|
+
await publishMessage('project-1', 'topic-x', { a: 1 })
|
|
65
|
+
await publishMessage('project-1', 'topic-x', { b: 2 })
|
|
66
|
+
|
|
67
|
+
const instances = mockPubsub.__instances
|
|
68
|
+
expect(instances.length).toBe(1)
|
|
69
|
+
const publishMock = instances[0].topics.get('topic-x').publishMessage
|
|
70
|
+
expect(publishMock).toHaveBeenCalledTimes(2)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test('creates separate PubSub instances for different projects', async () => {
|
|
74
|
+
const mockPubsub = require('@google-cloud/pubsub')
|
|
75
|
+
const { publishMessage } = require(path)
|
|
76
|
+
|
|
77
|
+
await publishMessage('project-A', 't1', { x: 1 })
|
|
78
|
+
await publishMessage('project-B', 't2', { y: 2 })
|
|
79
|
+
|
|
80
|
+
const instances = mockPubsub.__instances
|
|
81
|
+
expect(instances.length).toBe(2)
|
|
82
|
+
expect(instances[0].opts).toEqual({ projectId: 'project-A' })
|
|
83
|
+
expect(instances[1].opts).toEqual({ projectId: 'project-B' })
|
|
84
|
+
})
|
|
85
|
+
})
|