dooor-shared-config 0.1.0
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 +3 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +100 -0
- package/dist/messages.js +3 -0
- package/dist/messages.js.map +1 -0
- package/dist/pubsubClient.d.ts +14 -0
- package/dist/pubsubClient.js +34 -0
- package/dist/pubsubClient.js.map +1 -0
- package/dist/topics.d.ts +18 -0
- package/dist/topics.js +18 -0
- package/dist/topics.js.map +1 -0
- package/dist/topics.json +7 -0
- package/package.json +29 -0
- package/src/index.ts +4 -0
- package/src/messages.ts +138 -0
- package/src/pubsubClient.ts +40 -0
- package/src/topics.json +8 -0
- package/src/topics.ts +17 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./topics"), exports);
|
|
18
|
+
__exportStar(require("./messages"), exports);
|
|
19
|
+
__exportStar(require("./pubsubClient"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,6CAA2B;AAC3B,iDAA+B"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base envelope shared across all ATLAS Pub/Sub messages.
|
|
3
|
+
* This is intentionally generic so Cortex (Python) and Node
|
|
4
|
+
* services can both rely on a stable shape.
|
|
5
|
+
*/
|
|
6
|
+
export interface AtlasEnvelope<TPayload = unknown> {
|
|
7
|
+
/**
|
|
8
|
+
* High-level action being performed, e.g. INGEST, RAG.
|
|
9
|
+
*/
|
|
10
|
+
action: string;
|
|
11
|
+
/**
|
|
12
|
+
* Logical source application, e.g. "scaffold".
|
|
13
|
+
*/
|
|
14
|
+
appId: string;
|
|
15
|
+
/**
|
|
16
|
+
* Correlation id for tracing a flow end-to-end.
|
|
17
|
+
*/
|
|
18
|
+
correlationId: string;
|
|
19
|
+
/**
|
|
20
|
+
* ISO8601 timestamp (when the message was created).
|
|
21
|
+
*/
|
|
22
|
+
timestamp: string;
|
|
23
|
+
/**
|
|
24
|
+
* Arbitrary payload specific to the topic / flow.
|
|
25
|
+
*/
|
|
26
|
+
payload: TPayload;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Message contracts per topic, based on the high-level flows
|
|
30
|
+
* in the sequence diagram.
|
|
31
|
+
*/
|
|
32
|
+
export interface FileUploadPayload {
|
|
33
|
+
/**
|
|
34
|
+
* Identifier of the uploaded file in the upstream app (Scaffold).
|
|
35
|
+
* Can be used by Ingestion to call Cortex /records.create.
|
|
36
|
+
*/
|
|
37
|
+
uploadId: string;
|
|
38
|
+
fileName?: string;
|
|
39
|
+
mimeType?: string;
|
|
40
|
+
sizeBytes?: number;
|
|
41
|
+
}
|
|
42
|
+
export interface FileUploadMessage extends AtlasEnvelope<FileUploadPayload> {
|
|
43
|
+
topic: "file-upload.scaffold";
|
|
44
|
+
action: "INGEST";
|
|
45
|
+
}
|
|
46
|
+
export interface FileReadyPayload {
|
|
47
|
+
/**
|
|
48
|
+
* Identifier of the record inside CortexDB.
|
|
49
|
+
*/
|
|
50
|
+
recordId: string;
|
|
51
|
+
}
|
|
52
|
+
export interface FileReadyMessage extends AtlasEnvelope<FileReadyPayload> {
|
|
53
|
+
topic: "file-ready.scaffold";
|
|
54
|
+
}
|
|
55
|
+
export interface AiRequestPayload {
|
|
56
|
+
/**
|
|
57
|
+
* Natural language query sent by the user.
|
|
58
|
+
*/
|
|
59
|
+
query: string;
|
|
60
|
+
/**
|
|
61
|
+
* Optional record or file that should scope the RAG context.
|
|
62
|
+
*/
|
|
63
|
+
recordId?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface AiRequestMessage extends AtlasEnvelope<AiRequestPayload> {
|
|
66
|
+
topic: "ai-request.scaffold";
|
|
67
|
+
action: "RAG";
|
|
68
|
+
}
|
|
69
|
+
export interface AiResponsePayload {
|
|
70
|
+
/**
|
|
71
|
+
* Final answer shown to the end user.
|
|
72
|
+
*/
|
|
73
|
+
replyText: string;
|
|
74
|
+
/**
|
|
75
|
+
* Optional trace identifier for debugging.
|
|
76
|
+
*/
|
|
77
|
+
traceId?: string;
|
|
78
|
+
}
|
|
79
|
+
export interface AiResponseMessage extends AtlasEnvelope<AiResponsePayload> {
|
|
80
|
+
topic: "ai-response.scaffold";
|
|
81
|
+
}
|
|
82
|
+
export interface InsightReadyPayload {
|
|
83
|
+
/**
|
|
84
|
+
* The record in CortexDB that these insights belong to.
|
|
85
|
+
*/
|
|
86
|
+
recordId: string;
|
|
87
|
+
/**
|
|
88
|
+
* Structured KPIs / metrics extracted from the AI response.
|
|
89
|
+
* Shape is intentionally open so teams can iterate quickly.
|
|
90
|
+
*/
|
|
91
|
+
insights: Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
export interface InsightReadyMessage extends AtlasEnvelope<InsightReadyPayload> {
|
|
94
|
+
topic: "insight-ready.scaffold";
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Union type for any ATLAS message.
|
|
98
|
+
*/
|
|
99
|
+
export type AtlasMessage = FileUploadMessage | FileReadyMessage | AiRequestMessage | AiResponseMessage | InsightReadyMessage;
|
|
100
|
+
export type AtlasPayload = FileUploadPayload | FileReadyPayload | AiRequestPayload | AiResponsePayload | InsightReadyPayload;
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PubSub, type ClientConfig, type Topic } from "@google-cloud/pubsub";
|
|
2
|
+
import { TOPICS, type TopicName } from "./topics";
|
|
3
|
+
/**
|
|
4
|
+
* Creates (or returns a cached) PubSub client.
|
|
5
|
+
* Configuration is driven by standard Google environment variables
|
|
6
|
+
* (GOOGLE_CLOUD_PROJECT, credentials, PUBSUB_EMULATOR_HOST, etc).
|
|
7
|
+
*/
|
|
8
|
+
export declare function getPubSubClient(options?: ClientConfig): PubSub;
|
|
9
|
+
export declare function getTopic(topicName: TopicName, options?: ClientConfig): Topic;
|
|
10
|
+
/**
|
|
11
|
+
* Helper to publish a JSON-encoded message with optional attributes.
|
|
12
|
+
*/
|
|
13
|
+
export declare function publishJson(topicName: TopicName, message: unknown, attributes?: Record<string, string>, pubSubOptions?: ClientConfig): Promise<string>;
|
|
14
|
+
export { TOPICS };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TOPICS = void 0;
|
|
4
|
+
exports.getPubSubClient = getPubSubClient;
|
|
5
|
+
exports.getTopic = getTopic;
|
|
6
|
+
exports.publishJson = publishJson;
|
|
7
|
+
const pubsub_1 = require("@google-cloud/pubsub");
|
|
8
|
+
const topics_1 = require("./topics");
|
|
9
|
+
Object.defineProperty(exports, "TOPICS", { enumerable: true, get: function () { return topics_1.TOPICS; } });
|
|
10
|
+
let cachedPubSub = null;
|
|
11
|
+
/**
|
|
12
|
+
* Creates (or returns a cached) PubSub client.
|
|
13
|
+
* Configuration is driven by standard Google environment variables
|
|
14
|
+
* (GOOGLE_CLOUD_PROJECT, credentials, PUBSUB_EMULATOR_HOST, etc).
|
|
15
|
+
*/
|
|
16
|
+
function getPubSubClient(options) {
|
|
17
|
+
if (!cachedPubSub) {
|
|
18
|
+
cachedPubSub = new pubsub_1.PubSub(options);
|
|
19
|
+
}
|
|
20
|
+
return cachedPubSub;
|
|
21
|
+
}
|
|
22
|
+
function getTopic(topicName, options) {
|
|
23
|
+
const client = getPubSubClient(options);
|
|
24
|
+
return client.topic(topicName);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Helper to publish a JSON-encoded message with optional attributes.
|
|
28
|
+
*/
|
|
29
|
+
async function publishJson(topicName, message, attributes, pubSubOptions) {
|
|
30
|
+
const topic = getTopic(topicName, pubSubOptions);
|
|
31
|
+
const dataBuffer = Buffer.from(JSON.stringify(message));
|
|
32
|
+
return topic.publish(dataBuffer, attributes ?? {});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=pubsubClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pubsubClient.js","sourceRoot":"","sources":["../src/pubsubClient.ts"],"names":[],"mappings":";;;AAUA,0CAKC;AAED,4BAGC;AAKD,kCAWC;AApCD,iDAA6E;AAC7E,qCAAkD;AAqCzC,uFArCA,eAAM,OAqCA;AAnCf,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC;;;;GAIG;AACH,SAAgB,eAAe,CAAC,OAAsB;IACpD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,IAAI,eAAM,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAgB,QAAQ,CAAC,SAAoB,EAAE,OAAsB;IACnE,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,WAAW,CAC/B,SAAoB,EACpB,OAAgB,EAChB,UAAmC,EACnC,aAA4B;IAE5B,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAEjD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAExD,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/topics.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const TOPICS: {
|
|
2
|
+
fileUpload: string;
|
|
3
|
+
fileReady: string;
|
|
4
|
+
aiRequest: string;
|
|
5
|
+
aiResponse: string;
|
|
6
|
+
insightReady: string;
|
|
7
|
+
};
|
|
8
|
+
export type TopicKey = keyof typeof TOPICS;
|
|
9
|
+
export type TopicName = (typeof TOPICS)[TopicKey];
|
|
10
|
+
/**
|
|
11
|
+
* Convenience constants for each topic, for nicer imports.
|
|
12
|
+
* Using type assertions to preserve literal types for message contracts.
|
|
13
|
+
*/
|
|
14
|
+
export declare const FILE_UPLOAD_TOPIC: "file-upload.scaffold";
|
|
15
|
+
export declare const FILE_READY_TOPIC: "file-ready.scaffold";
|
|
16
|
+
export declare const AI_REQUEST_TOPIC: "ai-request.scaffold";
|
|
17
|
+
export declare const AI_RESPONSE_TOPIC: "ai-response.scaffold";
|
|
18
|
+
export declare const INSIGHT_READY_TOPIC: "insight-ready.scaffold";
|
package/dist/topics.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.INSIGHT_READY_TOPIC = exports.AI_RESPONSE_TOPIC = exports.AI_REQUEST_TOPIC = exports.FILE_READY_TOPIC = exports.FILE_UPLOAD_TOPIC = exports.TOPICS = void 0;
|
|
7
|
+
const topics_json_1 = __importDefault(require("./topics.json"));
|
|
8
|
+
exports.TOPICS = topics_json_1.default;
|
|
9
|
+
/**
|
|
10
|
+
* Convenience constants for each topic, for nicer imports.
|
|
11
|
+
* Using type assertions to preserve literal types for message contracts.
|
|
12
|
+
*/
|
|
13
|
+
exports.FILE_UPLOAD_TOPIC = exports.TOPICS.fileUpload;
|
|
14
|
+
exports.FILE_READY_TOPIC = exports.TOPICS.fileReady;
|
|
15
|
+
exports.AI_REQUEST_TOPIC = exports.TOPICS.aiRequest;
|
|
16
|
+
exports.AI_RESPONSE_TOPIC = exports.TOPICS.aiResponse;
|
|
17
|
+
exports.INSIGHT_READY_TOPIC = exports.TOPICS.insightReady;
|
|
18
|
+
//# sourceMappingURL=topics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../src/topics.ts"],"names":[],"mappings":";;;;;;AAAA,gEAAmC;AAEtB,QAAA,MAAM,GAAG,qBAAM,CAAC;AAK7B;;;GAGG;AACU,QAAA,iBAAiB,GAAG,cAAM,CAAC,UAAoC,CAAC;AAChE,QAAA,gBAAgB,GAAG,cAAM,CAAC,SAAkC,CAAC;AAC7D,QAAA,gBAAgB,GAAG,cAAM,CAAC,SAAkC,CAAC;AAC7D,QAAA,iBAAiB,GAAG,cAAM,CAAC,UAAoC,CAAC;AAChE,QAAA,mBAAmB,GAAG,cAAM,CAAC,YAAwC,CAAC"}
|
package/dist/topics.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dooor-shared-config",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared Pub/Sub topics, message contracts and client for Dooor AI services",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/dooor/mono.git",
|
|
11
|
+
"directory": "packages/shared-config"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p tsconfig.json",
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@google-cloud/pubsub": "^4.9.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^5.6.3"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
package/src/index.ts
ADDED
package/src/messages.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { TopicName } from "./topics";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base envelope shared across all ATLAS Pub/Sub messages.
|
|
5
|
+
* This is intentionally generic so Cortex (Python) and Node
|
|
6
|
+
* services can both rely on a stable shape.
|
|
7
|
+
*/
|
|
8
|
+
export interface AtlasEnvelope<TPayload = unknown> {
|
|
9
|
+
/**
|
|
10
|
+
* High-level action being performed, e.g. INGEST, RAG.
|
|
11
|
+
*/
|
|
12
|
+
action: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Logical source application, e.g. "scaffold".
|
|
16
|
+
*/
|
|
17
|
+
appId: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Correlation id for tracing a flow end-to-end.
|
|
21
|
+
*/
|
|
22
|
+
correlationId: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* ISO8601 timestamp (when the message was created).
|
|
26
|
+
*/
|
|
27
|
+
timestamp: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Arbitrary payload specific to the topic / flow.
|
|
31
|
+
*/
|
|
32
|
+
payload: TPayload;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Message contracts per topic, based on the high-level flows
|
|
37
|
+
* in the sequence diagram.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
export interface FileUploadPayload {
|
|
41
|
+
/**
|
|
42
|
+
* Identifier of the uploaded file in the upstream app (Scaffold).
|
|
43
|
+
* Can be used by Ingestion to call Cortex /records.create.
|
|
44
|
+
*/
|
|
45
|
+
uploadId: string;
|
|
46
|
+
fileName?: string;
|
|
47
|
+
mimeType?: string;
|
|
48
|
+
sizeBytes?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface FileUploadMessage
|
|
52
|
+
extends AtlasEnvelope<FileUploadPayload> {
|
|
53
|
+
topic: "file-upload.scaffold";
|
|
54
|
+
action: "INGEST";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface FileReadyPayload {
|
|
58
|
+
/**
|
|
59
|
+
* Identifier of the record inside CortexDB.
|
|
60
|
+
*/
|
|
61
|
+
recordId: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface FileReadyMessage
|
|
65
|
+
extends AtlasEnvelope<FileReadyPayload> {
|
|
66
|
+
topic: "file-ready.scaffold";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface AiRequestPayload {
|
|
70
|
+
/**
|
|
71
|
+
* Natural language query sent by the user.
|
|
72
|
+
*/
|
|
73
|
+
query: string;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Optional record or file that should scope the RAG context.
|
|
77
|
+
*/
|
|
78
|
+
recordId?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface AiRequestMessage
|
|
82
|
+
extends AtlasEnvelope<AiRequestPayload> {
|
|
83
|
+
topic: "ai-request.scaffold";
|
|
84
|
+
action: "RAG";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface AiResponsePayload {
|
|
88
|
+
/**
|
|
89
|
+
* Final answer shown to the end user.
|
|
90
|
+
*/
|
|
91
|
+
replyText: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Optional trace identifier for debugging.
|
|
95
|
+
*/
|
|
96
|
+
traceId?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface AiResponseMessage
|
|
100
|
+
extends AtlasEnvelope<AiResponsePayload> {
|
|
101
|
+
topic: "ai-response.scaffold";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface InsightReadyPayload {
|
|
105
|
+
/**
|
|
106
|
+
* The record in CortexDB that these insights belong to.
|
|
107
|
+
*/
|
|
108
|
+
recordId: string;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Structured KPIs / metrics extracted from the AI response.
|
|
112
|
+
* Shape is intentionally open so teams can iterate quickly.
|
|
113
|
+
*/
|
|
114
|
+
insights: Record<string, unknown>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface InsightReadyMessage
|
|
118
|
+
extends AtlasEnvelope<InsightReadyPayload> {
|
|
119
|
+
topic: "insight-ready.scaffold";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Union type for any ATLAS message.
|
|
124
|
+
*/
|
|
125
|
+
export type AtlasMessage =
|
|
126
|
+
| FileUploadMessage
|
|
127
|
+
| FileReadyMessage
|
|
128
|
+
| AiRequestMessage
|
|
129
|
+
| AiResponseMessage
|
|
130
|
+
| InsightReadyMessage;
|
|
131
|
+
|
|
132
|
+
export type AtlasPayload =
|
|
133
|
+
| FileUploadPayload
|
|
134
|
+
| FileReadyPayload
|
|
135
|
+
| AiRequestPayload
|
|
136
|
+
| AiResponsePayload
|
|
137
|
+
| InsightReadyPayload;
|
|
138
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PubSub, type ClientConfig, type Topic } from "@google-cloud/pubsub";
|
|
2
|
+
import { TOPICS, type TopicName } from "./topics";
|
|
3
|
+
|
|
4
|
+
let cachedPubSub: PubSub | null = null;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates (or returns a cached) PubSub client.
|
|
8
|
+
* Configuration is driven by standard Google environment variables
|
|
9
|
+
* (GOOGLE_CLOUD_PROJECT, credentials, PUBSUB_EMULATOR_HOST, etc).
|
|
10
|
+
*/
|
|
11
|
+
export function getPubSubClient(options?: ClientConfig): PubSub {
|
|
12
|
+
if (!cachedPubSub) {
|
|
13
|
+
cachedPubSub = new PubSub(options);
|
|
14
|
+
}
|
|
15
|
+
return cachedPubSub;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getTopic(topicName: TopicName, options?: ClientConfig): Topic {
|
|
19
|
+
const client = getPubSubClient(options);
|
|
20
|
+
return client.topic(topicName);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Helper to publish a JSON-encoded message with optional attributes.
|
|
25
|
+
*/
|
|
26
|
+
export async function publishJson(
|
|
27
|
+
topicName: TopicName,
|
|
28
|
+
message: unknown,
|
|
29
|
+
attributes?: Record<string, string>,
|
|
30
|
+
pubSubOptions?: ClientConfig
|
|
31
|
+
): Promise<string> {
|
|
32
|
+
const topic = getTopic(topicName, pubSubOptions);
|
|
33
|
+
|
|
34
|
+
const dataBuffer = Buffer.from(JSON.stringify(message));
|
|
35
|
+
|
|
36
|
+
return topic.publish(dataBuffer, attributes ?? {});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { TOPICS };
|
|
40
|
+
|
package/src/topics.json
ADDED
package/src/topics.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import topics from "./topics.json";
|
|
2
|
+
|
|
3
|
+
export const TOPICS = topics;
|
|
4
|
+
|
|
5
|
+
export type TopicKey = keyof typeof TOPICS;
|
|
6
|
+
export type TopicName = (typeof TOPICS)[TopicKey];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Convenience constants for each topic, for nicer imports.
|
|
10
|
+
* Using type assertions to preserve literal types for message contracts.
|
|
11
|
+
*/
|
|
12
|
+
export const FILE_UPLOAD_TOPIC = TOPICS.fileUpload as "file-upload.scaffold";
|
|
13
|
+
export const FILE_READY_TOPIC = TOPICS.fileReady as "file-ready.scaffold";
|
|
14
|
+
export const AI_REQUEST_TOPIC = TOPICS.aiRequest as "ai-request.scaffold";
|
|
15
|
+
export const AI_RESPONSE_TOPIC = TOPICS.aiResponse as "ai-response.scaffold";
|
|
16
|
+
export const INSIGHT_READY_TOPIC = TOPICS.insightReady as "insight-ready.scaffold";
|
|
17
|
+
|