dooor-shared-config 0.1.0 → 0.2.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 -3
- package/dist/index.js +25 -17
- package/dist/index.js.map +1 -1
- package/dist/messages.d.ts +93 -25
- package/dist/messages.js +13 -0
- package/dist/messages.js.map +1 -1
- package/dist/pubsubClient.d.ts +106 -6
- package/dist/pubsubClient.js +171 -4
- package/dist/pubsubClient.js.map +1 -1
- package/dist/topics.d.ts +48 -15
- package/dist/topics.js +67 -9
- package/dist/topics.js.map +1 -1
- package/dist/topics.json +6 -5
- package/package.json +2 -3
- package/src/index.ts +0 -4
- package/src/messages.ts +0 -138
- package/src/pubsubClient.ts +0 -40
- package/src/topics.json +0 -8
- package/src/topics.ts +0 -17
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export { SERVICES, getRequestTopic, getResponseTopic, parseResponseTopic, isRequestTopic, isResponseTopic, type ServiceKey, type ServiceTopic, } from "./topics";
|
|
2
|
+
export { createEnvelope, type AtlasEnvelope, type IngestionRequestPayload, type IngestionRequestMessage, type IngestionResponsePayload, type IngestionResponseMessage, type AiRequestPayload, type AiRequestMessage, type AiResponsePayload, type AiResponseMessage, type ExtractionRequestPayload, type ExtractionRequestMessage, type ExtractionResponsePayload, type ExtractionResponseMessage, type AtlasRequestMessage, type AtlasResponseMessage, type AtlasMessage, type AtlasRequestPayload, type AtlasResponsePayload, } from "./messages";
|
|
3
|
+
export { getPubSubClient, resetPubSubClient, getTopic, getServiceRequestTopic, getServiceResponseTopic, publishJson, publishRequest, publishResponse, subscribeToRequests, subscribeToResponses, createMessageConsumer, type MessageHandler, } from "./pubsubClient";
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
3
|
+
exports.createMessageConsumer = exports.subscribeToResponses = exports.subscribeToRequests = exports.publishResponse = exports.publishRequest = exports.publishJson = exports.getServiceResponseTopic = exports.getServiceRequestTopic = exports.getTopic = exports.resetPubSubClient = exports.getPubSubClient = exports.createEnvelope = exports.isResponseTopic = exports.isRequestTopic = exports.parseResponseTopic = exports.getResponseTopic = exports.getRequestTopic = exports.SERVICES = void 0;
|
|
4
|
+
// Topics and topic utilities
|
|
5
|
+
var topics_1 = require("./topics");
|
|
6
|
+
Object.defineProperty(exports, "SERVICES", { enumerable: true, get: function () { return topics_1.SERVICES; } });
|
|
7
|
+
Object.defineProperty(exports, "getRequestTopic", { enumerable: true, get: function () { return topics_1.getRequestTopic; } });
|
|
8
|
+
Object.defineProperty(exports, "getResponseTopic", { enumerable: true, get: function () { return topics_1.getResponseTopic; } });
|
|
9
|
+
Object.defineProperty(exports, "parseResponseTopic", { enumerable: true, get: function () { return topics_1.parseResponseTopic; } });
|
|
10
|
+
Object.defineProperty(exports, "isRequestTopic", { enumerable: true, get: function () { return topics_1.isRequestTopic; } });
|
|
11
|
+
Object.defineProperty(exports, "isResponseTopic", { enumerable: true, get: function () { return topics_1.isResponseTopic; } });
|
|
12
|
+
// Message types and helpers
|
|
13
|
+
var messages_1 = require("./messages");
|
|
14
|
+
Object.defineProperty(exports, "createEnvelope", { enumerable: true, get: function () { return messages_1.createEnvelope; } });
|
|
15
|
+
// PubSub client and utilities
|
|
16
|
+
var pubsubClient_1 = require("./pubsubClient");
|
|
17
|
+
Object.defineProperty(exports, "getPubSubClient", { enumerable: true, get: function () { return pubsubClient_1.getPubSubClient; } });
|
|
18
|
+
Object.defineProperty(exports, "resetPubSubClient", { enumerable: true, get: function () { return pubsubClient_1.resetPubSubClient; } });
|
|
19
|
+
Object.defineProperty(exports, "getTopic", { enumerable: true, get: function () { return pubsubClient_1.getTopic; } });
|
|
20
|
+
Object.defineProperty(exports, "getServiceRequestTopic", { enumerable: true, get: function () { return pubsubClient_1.getServiceRequestTopic; } });
|
|
21
|
+
Object.defineProperty(exports, "getServiceResponseTopic", { enumerable: true, get: function () { return pubsubClient_1.getServiceResponseTopic; } });
|
|
22
|
+
Object.defineProperty(exports, "publishJson", { enumerable: true, get: function () { return pubsubClient_1.publishJson; } });
|
|
23
|
+
Object.defineProperty(exports, "publishRequest", { enumerable: true, get: function () { return pubsubClient_1.publishRequest; } });
|
|
24
|
+
Object.defineProperty(exports, "publishResponse", { enumerable: true, get: function () { return pubsubClient_1.publishResponse; } });
|
|
25
|
+
Object.defineProperty(exports, "subscribeToRequests", { enumerable: true, get: function () { return pubsubClient_1.subscribeToRequests; } });
|
|
26
|
+
Object.defineProperty(exports, "subscribeToResponses", { enumerable: true, get: function () { return pubsubClient_1.subscribeToResponses; } });
|
|
27
|
+
Object.defineProperty(exports, "createMessageConsumer", { enumerable: true, get: function () { return pubsubClient_1.createMessageConsumer; } });
|
|
20
28
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,mCASkB;AARhB,kGAAA,QAAQ,OAAA;AACR,yGAAA,eAAe,OAAA;AACf,0GAAA,gBAAgB,OAAA;AAChB,4GAAA,kBAAkB,OAAA;AAClB,wGAAA,cAAc,OAAA;AACd,yGAAA,eAAe,OAAA;AAKjB,4BAA4B;AAC5B,uCAoBoB;AAnBlB,0GAAA,cAAc,OAAA;AAqBhB,8BAA8B;AAC9B,+CAawB;AAZtB,+GAAA,eAAe,OAAA;AACf,iHAAA,iBAAiB,OAAA;AACjB,wGAAA,QAAQ,OAAA;AACR,sHAAA,sBAAsB,OAAA;AACtB,uHAAA,uBAAuB,OAAA;AACvB,2GAAA,WAAW,OAAA;AACX,8GAAA,cAAc,OAAA;AACd,+GAAA,eAAe,OAAA;AACf,mHAAA,mBAAmB,OAAA;AACnB,oHAAA,oBAAoB,OAAA;AACpB,qHAAA,qBAAqB,OAAA"}
|
package/dist/messages.d.ts
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export interface AtlasEnvelope<TPayload = unknown> {
|
|
7
7
|
/**
|
|
8
|
-
* High-level action being performed, e.g. INGEST, RAG.
|
|
8
|
+
* High-level action being performed, e.g. INGEST, RAG, EXTRACT.
|
|
9
9
|
*/
|
|
10
10
|
action: string;
|
|
11
11
|
/**
|
|
12
|
-
* Logical source application, e.g. "scaffold".
|
|
12
|
+
* Logical source application, e.g. "scaffold", "myapp".
|
|
13
|
+
* Used to determine the response topic.
|
|
13
14
|
*/
|
|
14
15
|
appId: string;
|
|
15
16
|
/**
|
|
@@ -26,31 +27,49 @@ export interface AtlasEnvelope<TPayload = unknown> {
|
|
|
26
27
|
payload: TPayload;
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
-
* in the sequence diagram.
|
|
30
|
+
* Helper to create a new envelope with current timestamp
|
|
31
31
|
*/
|
|
32
|
-
export
|
|
32
|
+
export declare function createEnvelope<TPayload>(action: string, appId: string, correlationId: string, payload: TPayload): AtlasEnvelope<TPayload>;
|
|
33
|
+
export interface IngestionRequestPayload {
|
|
33
34
|
/**
|
|
34
|
-
* Identifier of the uploaded file in the upstream app
|
|
35
|
-
* Can be used by Ingestion to call Cortex /records.create.
|
|
35
|
+
* Identifier of the uploaded file in the upstream app.
|
|
36
36
|
*/
|
|
37
37
|
uploadId: string;
|
|
38
38
|
fileName?: string;
|
|
39
39
|
mimeType?: string;
|
|
40
40
|
sizeBytes?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Optional: database in CortexDB to store the record
|
|
43
|
+
*/
|
|
44
|
+
database?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Optional: collection in CortexDB
|
|
47
|
+
*/
|
|
48
|
+
collection?: string;
|
|
41
49
|
}
|
|
42
|
-
export interface
|
|
43
|
-
topic: "file-upload.scaffold";
|
|
50
|
+
export interface IngestionRequestMessage extends AtlasEnvelope<IngestionRequestPayload> {
|
|
44
51
|
action: "INGEST";
|
|
45
52
|
}
|
|
46
|
-
export interface
|
|
53
|
+
export interface IngestionResponsePayload {
|
|
47
54
|
/**
|
|
48
|
-
*
|
|
55
|
+
* Status of the ingestion: success, error, processing
|
|
49
56
|
*/
|
|
50
|
-
|
|
57
|
+
status: "success" | "error" | "processing";
|
|
58
|
+
/**
|
|
59
|
+
* Record ID in CortexDB (if successful)
|
|
60
|
+
*/
|
|
61
|
+
recordId?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Error message (if failed)
|
|
64
|
+
*/
|
|
65
|
+
error?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Original upload ID for correlation
|
|
68
|
+
*/
|
|
69
|
+
uploadId: string;
|
|
51
70
|
}
|
|
52
|
-
export interface
|
|
53
|
-
|
|
71
|
+
export interface IngestionResponseMessage extends AtlasEnvelope<IngestionResponsePayload> {
|
|
72
|
+
action: "INGEST_RESPONSE";
|
|
54
73
|
}
|
|
55
74
|
export interface AiRequestPayload {
|
|
56
75
|
/**
|
|
@@ -61,9 +80,16 @@ export interface AiRequestPayload {
|
|
|
61
80
|
* Optional record or file that should scope the RAG context.
|
|
62
81
|
*/
|
|
63
82
|
recordId?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Optional: specific database to search
|
|
85
|
+
*/
|
|
86
|
+
database?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Optional: specific collection to search
|
|
89
|
+
*/
|
|
90
|
+
collection?: string;
|
|
64
91
|
}
|
|
65
92
|
export interface AiRequestMessage extends AtlasEnvelope<AiRequestPayload> {
|
|
66
|
-
topic: "ai-request.scaffold";
|
|
67
93
|
action: "RAG";
|
|
68
94
|
}
|
|
69
95
|
export interface AiResponsePayload {
|
|
@@ -75,26 +101,68 @@ export interface AiResponsePayload {
|
|
|
75
101
|
* Optional trace identifier for debugging.
|
|
76
102
|
*/
|
|
77
103
|
traceId?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Sources used to generate the response
|
|
106
|
+
*/
|
|
107
|
+
sources?: Array<{
|
|
108
|
+
recordId: string;
|
|
109
|
+
snippet?: string;
|
|
110
|
+
score?: number;
|
|
111
|
+
}>;
|
|
78
112
|
}
|
|
79
113
|
export interface AiResponseMessage extends AtlasEnvelope<AiResponsePayload> {
|
|
80
|
-
|
|
114
|
+
action: "RAG_RESPONSE";
|
|
115
|
+
}
|
|
116
|
+
export interface ExtractionRequestPayload {
|
|
117
|
+
/**
|
|
118
|
+
* The record in CortexDB to extract insights from
|
|
119
|
+
*/
|
|
120
|
+
recordId: string;
|
|
121
|
+
/**
|
|
122
|
+
* Optional: AI response text to extract insights from
|
|
123
|
+
*/
|
|
124
|
+
aiResponseText?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Optional: specific extraction types to perform
|
|
127
|
+
*/
|
|
128
|
+
extractionTypes?: string[];
|
|
81
129
|
}
|
|
82
|
-
export interface
|
|
130
|
+
export interface ExtractionRequestMessage extends AtlasEnvelope<ExtractionRequestPayload> {
|
|
131
|
+
action: "EXTRACT";
|
|
132
|
+
}
|
|
133
|
+
export interface ExtractionResponsePayload {
|
|
134
|
+
/**
|
|
135
|
+
* Status of the extraction
|
|
136
|
+
*/
|
|
137
|
+
status: "success" | "error" | "processing";
|
|
83
138
|
/**
|
|
84
|
-
* The record
|
|
139
|
+
* The record these insights belong to
|
|
85
140
|
*/
|
|
86
141
|
recordId: string;
|
|
87
142
|
/**
|
|
88
|
-
* Structured KPIs / metrics extracted
|
|
143
|
+
* Structured KPIs / metrics extracted.
|
|
89
144
|
* Shape is intentionally open so teams can iterate quickly.
|
|
90
145
|
*/
|
|
91
|
-
insights
|
|
146
|
+
insights?: Record<string, unknown>;
|
|
147
|
+
/**
|
|
148
|
+
* Error message (if failed)
|
|
149
|
+
*/
|
|
150
|
+
error?: string;
|
|
92
151
|
}
|
|
93
|
-
export interface
|
|
94
|
-
|
|
152
|
+
export interface ExtractionResponseMessage extends AtlasEnvelope<ExtractionResponsePayload> {
|
|
153
|
+
action: "EXTRACT_RESPONSE";
|
|
95
154
|
}
|
|
96
155
|
/**
|
|
97
|
-
* Union type for
|
|
156
|
+
* Union type for request messages (sent TO services)
|
|
157
|
+
*/
|
|
158
|
+
export type AtlasRequestMessage = IngestionRequestMessage | AiRequestMessage | ExtractionRequestMessage;
|
|
159
|
+
/**
|
|
160
|
+
* Union type for response messages (sent FROM services)
|
|
161
|
+
*/
|
|
162
|
+
export type AtlasResponseMessage = IngestionResponseMessage | AiResponseMessage | ExtractionResponseMessage;
|
|
163
|
+
/**
|
|
164
|
+
* Union type for any ATLAS message
|
|
98
165
|
*/
|
|
99
|
-
export type AtlasMessage =
|
|
100
|
-
export type
|
|
166
|
+
export type AtlasMessage = AtlasRequestMessage | AtlasResponseMessage;
|
|
167
|
+
export type AtlasRequestPayload = IngestionRequestPayload | AiRequestPayload | ExtractionRequestPayload;
|
|
168
|
+
export type AtlasResponsePayload = IngestionResponsePayload | AiResponsePayload | ExtractionResponsePayload;
|
package/dist/messages.js
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEnvelope = createEnvelope;
|
|
4
|
+
/**
|
|
5
|
+
* Helper to create a new envelope with current timestamp
|
|
6
|
+
*/
|
|
7
|
+
function createEnvelope(action, appId, correlationId, payload) {
|
|
8
|
+
return {
|
|
9
|
+
action,
|
|
10
|
+
appId,
|
|
11
|
+
correlationId,
|
|
12
|
+
timestamp: new Date().toISOString(),
|
|
13
|
+
payload,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
3
16
|
//# sourceMappingURL=messages.js.map
|
package/dist/messages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":";;AAsCA,wCAaC;AAhBD;;GAEG;AACH,SAAgB,cAAc,CAC5B,MAAc,EACd,KAAa,EACb,aAAqB,EACrB,OAAiB;IAEjB,OAAO;QACL,MAAM;QACN,KAAK;QACL,aAAa;QACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO;KACR,CAAC;AACJ,CAAC"}
|
package/dist/pubsubClient.d.ts
CHANGED
|
@@ -1,14 +1,114 @@
|
|
|
1
|
-
import { PubSub, type ClientConfig, type Topic } from "@google-cloud/pubsub";
|
|
2
|
-
import {
|
|
1
|
+
import { PubSub, type ClientConfig, type Topic, type Subscription, type Message } from "@google-cloud/pubsub";
|
|
2
|
+
import { SERVICES, getRequestTopic, getResponseTopic, type ServiceKey } from "./topics";
|
|
3
|
+
import type { AtlasEnvelope } from "./messages";
|
|
3
4
|
/**
|
|
4
5
|
* Creates (or returns a cached) PubSub client.
|
|
5
6
|
* Configuration is driven by standard Google environment variables
|
|
6
7
|
* (GOOGLE_CLOUD_PROJECT, credentials, PUBSUB_EMULATOR_HOST, etc).
|
|
7
8
|
*/
|
|
8
9
|
export declare function getPubSubClient(options?: ClientConfig): PubSub;
|
|
9
|
-
export declare function getTopic(topicName: TopicName, options?: ClientConfig): Topic;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Reset the cached PubSub client (useful for testing)
|
|
12
12
|
*/
|
|
13
|
-
export declare function
|
|
14
|
-
|
|
13
|
+
export declare function resetPubSubClient(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Get a topic reference by name
|
|
16
|
+
*/
|
|
17
|
+
export declare function getTopic(topicName: string, options?: ClientConfig): Topic;
|
|
18
|
+
/**
|
|
19
|
+
* Get the request topic for a service
|
|
20
|
+
*/
|
|
21
|
+
export declare function getServiceRequestTopic(service: ServiceKey, options?: ClientConfig): Topic;
|
|
22
|
+
/**
|
|
23
|
+
* Get the response topic for a service + app combination
|
|
24
|
+
*/
|
|
25
|
+
export declare function getServiceResponseTopic(service: ServiceKey, appId: string, options?: ClientConfig): Topic;
|
|
26
|
+
/**
|
|
27
|
+
* Helper to publish a JSON-encoded message to any topic
|
|
28
|
+
*/
|
|
29
|
+
export declare function publishJson(topicName: string, message: unknown, attributes?: Record<string, string>, pubSubOptions?: ClientConfig): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Publish a request message to a service
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* await publishRequest("ingestion", {
|
|
35
|
+
* action: "INGEST",
|
|
36
|
+
* appId: "scaffold",
|
|
37
|
+
* correlationId: "uuid-123",
|
|
38
|
+
* timestamp: new Date().toISOString(),
|
|
39
|
+
* payload: { uploadId: "file-123" }
|
|
40
|
+
* });
|
|
41
|
+
*/
|
|
42
|
+
export declare function publishRequest<T>(service: ServiceKey, message: AtlasEnvelope<T>, attributes?: Record<string, string>, pubSubOptions?: ClientConfig): Promise<string>;
|
|
43
|
+
/**
|
|
44
|
+
* Publish a response message back to the requesting app.
|
|
45
|
+
* Uses the appId from the original request to determine the response topic.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Service receives a request with appId: "scaffold"
|
|
49
|
+
* // Service publishes response to "ingestion-service-response.scaffold"
|
|
50
|
+
* await publishResponse("ingestion", "scaffold", {
|
|
51
|
+
* action: "INGEST_RESPONSE",
|
|
52
|
+
* appId: "ingestion-service",
|
|
53
|
+
* correlationId: "uuid-123",
|
|
54
|
+
* timestamp: new Date().toISOString(),
|
|
55
|
+
* payload: { status: "success", recordId: "rec-456", uploadId: "file-123" }
|
|
56
|
+
* });
|
|
57
|
+
*/
|
|
58
|
+
export declare function publishResponse<T>(service: ServiceKey, targetAppId: string, message: AtlasEnvelope<T>, attributes?: Record<string, string>, pubSubOptions?: ClientConfig): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Subscribe to a service's request topic.
|
|
61
|
+
* Returns the subscription for attaching message handlers.
|
|
62
|
+
*
|
|
63
|
+
* @param service - The service to subscribe to
|
|
64
|
+
* @param subscriptionName - Name of the subscription (will be created if it doesn't exist)
|
|
65
|
+
* @param options - PubSub client options
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* const sub = await subscribeToRequests("ingestion", "ingestion-service-sub");
|
|
69
|
+
* sub.on("message", (message) => {
|
|
70
|
+
* const data = JSON.parse(message.data.toString());
|
|
71
|
+
* // Process request...
|
|
72
|
+
* message.ack();
|
|
73
|
+
* });
|
|
74
|
+
*/
|
|
75
|
+
export declare function subscribeToRequests(service: ServiceKey, subscriptionName: string, options?: ClientConfig): Promise<Subscription>;
|
|
76
|
+
/**
|
|
77
|
+
* Subscribe to responses for a specific app.
|
|
78
|
+
* This is used by apps to receive responses from services.
|
|
79
|
+
*
|
|
80
|
+
* @param service - The service to receive responses from
|
|
81
|
+
* @param appId - The app's identifier
|
|
82
|
+
* @param subscriptionName - Name of the subscription
|
|
83
|
+
* @param options - PubSub client options
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* // App "scaffold" subscribes to responses from ingestion service
|
|
87
|
+
* const sub = await subscribeToResponses("ingestion", "scaffold", "scaffold-ingestion-responses");
|
|
88
|
+
* sub.on("message", (message) => {
|
|
89
|
+
* const data = JSON.parse(message.data.toString());
|
|
90
|
+
* // Handle response...
|
|
91
|
+
* message.ack();
|
|
92
|
+
* });
|
|
93
|
+
*/
|
|
94
|
+
export declare function subscribeToResponses(service: ServiceKey, appId: string, subscriptionName: string, options?: ClientConfig): Promise<Subscription>;
|
|
95
|
+
/**
|
|
96
|
+
* Helper type for message handlers
|
|
97
|
+
*/
|
|
98
|
+
export type MessageHandler<T> = (envelope: AtlasEnvelope<T>, message: Message, ack: () => void, nack: () => void) => Promise<void> | void;
|
|
99
|
+
/**
|
|
100
|
+
* Create a simple message consumer that handles JSON parsing and error handling
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* const subscription = await subscribeToRequests("ingestion", "ingestion-sub");
|
|
104
|
+
* createMessageConsumer(subscription, async (envelope, message, ack, nack) => {
|
|
105
|
+
* try {
|
|
106
|
+
* // Process the envelope...
|
|
107
|
+
* ack();
|
|
108
|
+
* } catch (err) {
|
|
109
|
+
* nack();
|
|
110
|
+
* }
|
|
111
|
+
* });
|
|
112
|
+
*/
|
|
113
|
+
export declare function createMessageConsumer<T>(subscription: Subscription, handler: MessageHandler<T>, onError?: (error: Error, message: Message) => void): void;
|
|
114
|
+
export { SERVICES, getRequestTopic, getResponseTopic };
|
package/dist/pubsubClient.js
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getResponseTopic = exports.getRequestTopic = exports.SERVICES = void 0;
|
|
4
4
|
exports.getPubSubClient = getPubSubClient;
|
|
5
|
+
exports.resetPubSubClient = resetPubSubClient;
|
|
5
6
|
exports.getTopic = getTopic;
|
|
7
|
+
exports.getServiceRequestTopic = getServiceRequestTopic;
|
|
8
|
+
exports.getServiceResponseTopic = getServiceResponseTopic;
|
|
6
9
|
exports.publishJson = publishJson;
|
|
10
|
+
exports.publishRequest = publishRequest;
|
|
11
|
+
exports.publishResponse = publishResponse;
|
|
12
|
+
exports.subscribeToRequests = subscribeToRequests;
|
|
13
|
+
exports.subscribeToResponses = subscribeToResponses;
|
|
14
|
+
exports.createMessageConsumer = createMessageConsumer;
|
|
7
15
|
const pubsub_1 = require("@google-cloud/pubsub");
|
|
8
16
|
const topics_1 = require("./topics");
|
|
9
|
-
Object.defineProperty(exports, "
|
|
17
|
+
Object.defineProperty(exports, "SERVICES", { enumerable: true, get: function () { return topics_1.SERVICES; } });
|
|
18
|
+
Object.defineProperty(exports, "getRequestTopic", { enumerable: true, get: function () { return topics_1.getRequestTopic; } });
|
|
19
|
+
Object.defineProperty(exports, "getResponseTopic", { enumerable: true, get: function () { return topics_1.getResponseTopic; } });
|
|
10
20
|
let cachedPubSub = null;
|
|
11
21
|
/**
|
|
12
22
|
* Creates (or returns a cached) PubSub client.
|
|
@@ -19,16 +29,173 @@ function getPubSubClient(options) {
|
|
|
19
29
|
}
|
|
20
30
|
return cachedPubSub;
|
|
21
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Reset the cached PubSub client (useful for testing)
|
|
34
|
+
*/
|
|
35
|
+
function resetPubSubClient() {
|
|
36
|
+
cachedPubSub = null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get a topic reference by name
|
|
40
|
+
*/
|
|
22
41
|
function getTopic(topicName, options) {
|
|
23
42
|
const client = getPubSubClient(options);
|
|
24
43
|
return client.topic(topicName);
|
|
25
44
|
}
|
|
26
45
|
/**
|
|
27
|
-
*
|
|
46
|
+
* Get the request topic for a service
|
|
47
|
+
*/
|
|
48
|
+
function getServiceRequestTopic(service, options) {
|
|
49
|
+
const topicName = (0, topics_1.getRequestTopic)(service);
|
|
50
|
+
return getTopic(topicName, options);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the response topic for a service + app combination
|
|
54
|
+
*/
|
|
55
|
+
function getServiceResponseTopic(service, appId, options) {
|
|
56
|
+
const topicName = (0, topics_1.getResponseTopic)(service, appId);
|
|
57
|
+
return getTopic(topicName, options);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Helper to publish a JSON-encoded message to any topic
|
|
28
61
|
*/
|
|
29
62
|
async function publishJson(topicName, message, attributes, pubSubOptions) {
|
|
30
63
|
const topic = getTopic(topicName, pubSubOptions);
|
|
31
64
|
const dataBuffer = Buffer.from(JSON.stringify(message));
|
|
32
|
-
return topic.
|
|
65
|
+
return topic.publishMessage({ data: dataBuffer, attributes: attributes ?? {} });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Publish a request message to a service
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* await publishRequest("ingestion", {
|
|
72
|
+
* action: "INGEST",
|
|
73
|
+
* appId: "scaffold",
|
|
74
|
+
* correlationId: "uuid-123",
|
|
75
|
+
* timestamp: new Date().toISOString(),
|
|
76
|
+
* payload: { uploadId: "file-123" }
|
|
77
|
+
* });
|
|
78
|
+
*/
|
|
79
|
+
async function publishRequest(service, message, attributes, pubSubOptions) {
|
|
80
|
+
const topicName = (0, topics_1.getRequestTopic)(service);
|
|
81
|
+
return publishJson(topicName, message, attributes, pubSubOptions);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Publish a response message back to the requesting app.
|
|
85
|
+
* Uses the appId from the original request to determine the response topic.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Service receives a request with appId: "scaffold"
|
|
89
|
+
* // Service publishes response to "ingestion-service-response.scaffold"
|
|
90
|
+
* await publishResponse("ingestion", "scaffold", {
|
|
91
|
+
* action: "INGEST_RESPONSE",
|
|
92
|
+
* appId: "ingestion-service",
|
|
93
|
+
* correlationId: "uuid-123",
|
|
94
|
+
* timestamp: new Date().toISOString(),
|
|
95
|
+
* payload: { status: "success", recordId: "rec-456", uploadId: "file-123" }
|
|
96
|
+
* });
|
|
97
|
+
*/
|
|
98
|
+
async function publishResponse(service, targetAppId, message, attributes, pubSubOptions) {
|
|
99
|
+
const topicName = (0, topics_1.getResponseTopic)(service, targetAppId);
|
|
100
|
+
return publishJson(topicName, message, attributes, pubSubOptions);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Subscribe to a service's request topic.
|
|
104
|
+
* Returns the subscription for attaching message handlers.
|
|
105
|
+
*
|
|
106
|
+
* @param service - The service to subscribe to
|
|
107
|
+
* @param subscriptionName - Name of the subscription (will be created if it doesn't exist)
|
|
108
|
+
* @param options - PubSub client options
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const sub = await subscribeToRequests("ingestion", "ingestion-service-sub");
|
|
112
|
+
* sub.on("message", (message) => {
|
|
113
|
+
* const data = JSON.parse(message.data.toString());
|
|
114
|
+
* // Process request...
|
|
115
|
+
* message.ack();
|
|
116
|
+
* });
|
|
117
|
+
*/
|
|
118
|
+
async function subscribeToRequests(service, subscriptionName, options) {
|
|
119
|
+
const client = getPubSubClient(options);
|
|
120
|
+
const topicName = (0, topics_1.getRequestTopic)(service);
|
|
121
|
+
// Check if subscription exists, create if not
|
|
122
|
+
const subscription = client.subscription(subscriptionName);
|
|
123
|
+
const [exists] = await subscription.exists();
|
|
124
|
+
if (!exists) {
|
|
125
|
+
const topic = client.topic(topicName);
|
|
126
|
+
const [topicExists] = await topic.exists();
|
|
127
|
+
if (!topicExists) {
|
|
128
|
+
await topic.create();
|
|
129
|
+
}
|
|
130
|
+
await topic.createSubscription(subscriptionName);
|
|
131
|
+
}
|
|
132
|
+
return subscription;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Subscribe to responses for a specific app.
|
|
136
|
+
* This is used by apps to receive responses from services.
|
|
137
|
+
*
|
|
138
|
+
* @param service - The service to receive responses from
|
|
139
|
+
* @param appId - The app's identifier
|
|
140
|
+
* @param subscriptionName - Name of the subscription
|
|
141
|
+
* @param options - PubSub client options
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* // App "scaffold" subscribes to responses from ingestion service
|
|
145
|
+
* const sub = await subscribeToResponses("ingestion", "scaffold", "scaffold-ingestion-responses");
|
|
146
|
+
* sub.on("message", (message) => {
|
|
147
|
+
* const data = JSON.parse(message.data.toString());
|
|
148
|
+
* // Handle response...
|
|
149
|
+
* message.ack();
|
|
150
|
+
* });
|
|
151
|
+
*/
|
|
152
|
+
async function subscribeToResponses(service, appId, subscriptionName, options) {
|
|
153
|
+
const client = getPubSubClient(options);
|
|
154
|
+
const topicName = (0, topics_1.getResponseTopic)(service, appId);
|
|
155
|
+
const subscription = client.subscription(subscriptionName);
|
|
156
|
+
const [exists] = await subscription.exists();
|
|
157
|
+
if (!exists) {
|
|
158
|
+
const topic = client.topic(topicName);
|
|
159
|
+
const [topicExists] = await topic.exists();
|
|
160
|
+
if (!topicExists) {
|
|
161
|
+
await topic.create();
|
|
162
|
+
}
|
|
163
|
+
await topic.createSubscription(subscriptionName);
|
|
164
|
+
}
|
|
165
|
+
return subscription;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Create a simple message consumer that handles JSON parsing and error handling
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* const subscription = await subscribeToRequests("ingestion", "ingestion-sub");
|
|
172
|
+
* createMessageConsumer(subscription, async (envelope, message, ack, nack) => {
|
|
173
|
+
* try {
|
|
174
|
+
* // Process the envelope...
|
|
175
|
+
* ack();
|
|
176
|
+
* } catch (err) {
|
|
177
|
+
* nack();
|
|
178
|
+
* }
|
|
179
|
+
* });
|
|
180
|
+
*/
|
|
181
|
+
function createMessageConsumer(subscription, handler, onError) {
|
|
182
|
+
subscription.on("message", async (message) => {
|
|
183
|
+
try {
|
|
184
|
+
const envelope = JSON.parse(message.data.toString());
|
|
185
|
+
await handler(envelope, message, () => message.ack(), () => message.nack());
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
if (onError) {
|
|
189
|
+
onError(err, message);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.error("[PubSub] Error processing message:", err);
|
|
193
|
+
message.nack();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
subscription.on("error", (err) => {
|
|
198
|
+
console.error("[PubSub] Subscription error:", err);
|
|
199
|
+
});
|
|
33
200
|
}
|
|
34
201
|
//# sourceMappingURL=pubsubClient.js.map
|
package/dist/pubsubClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pubsubClient.js","sourceRoot":"","sources":["../src/pubsubClient.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"pubsubClient.js","sourceRoot":"","sources":["../src/pubsubClient.ts"],"names":[],"mappings":"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"}
|
package/dist/topics.d.ts
CHANGED
|
@@ -1,18 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import topicsConfig from "./topics.json";
|
|
2
|
+
/**
|
|
3
|
+
* Service names as defined in the configuration
|
|
4
|
+
*/
|
|
5
|
+
export declare const SERVICES: {
|
|
6
|
+
ingestion: string;
|
|
7
|
+
ai: string;
|
|
8
|
+
extraction: string;
|
|
7
9
|
};
|
|
8
|
-
export type
|
|
9
|
-
export type
|
|
10
|
+
export type ServiceKey = keyof typeof SERVICES;
|
|
11
|
+
export type ServiceTopic = (typeof SERVICES)[ServiceKey];
|
|
12
|
+
/**
|
|
13
|
+
* Get the request topic for a service.
|
|
14
|
+
* Request topics are fixed per service: "ingestion-service", "ai-service", etc.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* getRequestTopic("ingestion") // => "ingestion-service"
|
|
18
|
+
*/
|
|
19
|
+
export declare function getRequestTopic(service: ServiceKey): ServiceTopic;
|
|
20
|
+
/**
|
|
21
|
+
* Get the response topic for a service + app combination.
|
|
22
|
+
* Response topics are dynamic: "{service}-response.{appId}"
|
|
23
|
+
*
|
|
24
|
+
* This allows multiple apps to use the same service and receive
|
|
25
|
+
* responses on their own dedicated topic.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* getResponseTopic("ingestion", "scaffold") // => "ingestion-service-response.scaffold"
|
|
29
|
+
* getResponseTopic("ai", "myapp") // => "ai-service-response.myapp"
|
|
30
|
+
*/
|
|
31
|
+
export declare function getResponseTopic(service: ServiceKey, appId: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Parse a response topic to extract service and appId
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* parseResponseTopic("ingestion-service-response.scaffold")
|
|
37
|
+
* // => { service: "ingestion", appId: "scaffold" }
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseResponseTopic(topic: string): {
|
|
40
|
+
service: ServiceKey | null;
|
|
41
|
+
appId: string | null;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Check if a topic is a request topic
|
|
45
|
+
*/
|
|
46
|
+
export declare function isRequestTopic(topic: string): boolean;
|
|
10
47
|
/**
|
|
11
|
-
*
|
|
12
|
-
* Using type assertions to preserve literal types for message contracts.
|
|
48
|
+
* Check if a topic is a response topic
|
|
13
49
|
*/
|
|
14
|
-
export declare
|
|
15
|
-
export
|
|
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";
|
|
50
|
+
export declare function isResponseTopic(topic: string): boolean;
|
|
51
|
+
export { topicsConfig };
|
package/dist/topics.js
CHANGED
|
@@ -3,16 +3,74 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.topicsConfig = exports.SERVICES = void 0;
|
|
7
|
+
exports.getRequestTopic = getRequestTopic;
|
|
8
|
+
exports.getResponseTopic = getResponseTopic;
|
|
9
|
+
exports.parseResponseTopic = parseResponseTopic;
|
|
10
|
+
exports.isRequestTopic = isRequestTopic;
|
|
11
|
+
exports.isResponseTopic = isResponseTopic;
|
|
7
12
|
const topics_json_1 = __importDefault(require("./topics.json"));
|
|
8
|
-
exports.
|
|
13
|
+
exports.topicsConfig = topics_json_1.default;
|
|
9
14
|
/**
|
|
10
|
-
*
|
|
11
|
-
* Using type assertions to preserve literal types for message contracts.
|
|
15
|
+
* Service names as defined in the configuration
|
|
12
16
|
*/
|
|
13
|
-
exports.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
exports.SERVICES = topics_json_1.default.services;
|
|
18
|
+
/**
|
|
19
|
+
* Get the request topic for a service.
|
|
20
|
+
* Request topics are fixed per service: "ingestion-service", "ai-service", etc.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* getRequestTopic("ingestion") // => "ingestion-service"
|
|
24
|
+
*/
|
|
25
|
+
function getRequestTopic(service) {
|
|
26
|
+
return exports.SERVICES[service];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the response topic for a service + app combination.
|
|
30
|
+
* Response topics are dynamic: "{service}-response.{appId}"
|
|
31
|
+
*
|
|
32
|
+
* This allows multiple apps to use the same service and receive
|
|
33
|
+
* responses on their own dedicated topic.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* getResponseTopic("ingestion", "scaffold") // => "ingestion-service-response.scaffold"
|
|
37
|
+
* getResponseTopic("ai", "myapp") // => "ai-service-response.myapp"
|
|
38
|
+
*/
|
|
39
|
+
function getResponseTopic(service, appId) {
|
|
40
|
+
const serviceTopic = exports.SERVICES[service];
|
|
41
|
+
return `${serviceTopic}${topics_json_1.default.responsePrefix}.${appId}`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parse a response topic to extract service and appId
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* parseResponseTopic("ingestion-service-response.scaffold")
|
|
48
|
+
* // => { service: "ingestion", appId: "scaffold" }
|
|
49
|
+
*/
|
|
50
|
+
function parseResponseTopic(topic) {
|
|
51
|
+
const responsePrefix = topics_json_1.default.responsePrefix;
|
|
52
|
+
for (const [key, serviceTopic] of Object.entries(exports.SERVICES)) {
|
|
53
|
+
const prefix = `${serviceTopic}${responsePrefix}.`;
|
|
54
|
+
if (topic.startsWith(prefix)) {
|
|
55
|
+
return {
|
|
56
|
+
service: key,
|
|
57
|
+
appId: topic.slice(prefix.length),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { service: null, appId: null };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a topic is a request topic
|
|
65
|
+
*/
|
|
66
|
+
function isRequestTopic(topic) {
|
|
67
|
+
return Object.values(exports.SERVICES).includes(topic);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if a topic is a response topic
|
|
71
|
+
*/
|
|
72
|
+
function isResponseTopic(topic) {
|
|
73
|
+
const responsePrefix = topics_json_1.default.responsePrefix;
|
|
74
|
+
return Object.values(exports.SERVICES).some(serviceTopic => topic.startsWith(`${serviceTopic}${responsePrefix}.`));
|
|
75
|
+
}
|
|
18
76
|
//# sourceMappingURL=topics.js.map
|
package/dist/topics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../src/topics.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../src/topics.ts"],"names":[],"mappings":";;;;;;AAgBA,0CAEC;AAaD,4CAGC;AASD,gDAcC;AAKD,wCAEC;AAKD,0CAKC;AA1ED,gEAAyC;AA6EhC,uBA7EF,qBAAY,CA6EE;AA3ErB;;GAEG;AACU,QAAA,QAAQ,GAAG,qBAAY,CAAC,QAAQ,CAAC;AAI9C;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,OAAmB;IACjD,OAAO,gBAAQ,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,gBAAgB,CAAC,OAAmB,EAAE,KAAa;IACjE,MAAM,YAAY,GAAG,gBAAQ,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,GAAG,YAAY,GAAG,qBAAY,CAAC,cAAc,IAAI,KAAK,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAAC,KAAa;IAC9C,MAAM,cAAc,GAAG,qBAAY,CAAC,cAAc,CAAC;IAEnD,KAAK,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAQ,CAAC,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,GAAG,YAAY,GAAG,cAAc,GAAG,CAAC;QACnD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,OAAO;gBACL,OAAO,EAAE,GAAiB;gBAC1B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;aAClC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,KAAa;IAC1C,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAQ,CAAC,CAAC,QAAQ,CAAC,KAAqB,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,SAAgB,eAAe,CAAC,KAAa;IAC3C,MAAM,cAAc,GAAG,qBAAY,CAAC,cAAc,CAAC;IACnD,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CACjD,KAAK,CAAC,UAAU,CAAC,GAAG,YAAY,GAAG,cAAc,GAAG,CAAC,CACtD,CAAC;AACJ,CAAC"}
|
package/dist/topics.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"services": {
|
|
3
|
+
"ingestion": "ingestion-service",
|
|
4
|
+
"ai": "ai-service",
|
|
5
|
+
"extraction": "extraction-service"
|
|
6
|
+
},
|
|
7
|
+
"responsePrefix": "-response"
|
|
7
8
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dooor-shared-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared Pub/Sub topics, message contracts and client for Dooor AI services",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
"directory": "packages/shared-config"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
-
"dist"
|
|
15
|
-
"src"
|
|
14
|
+
"dist"
|
|
16
15
|
],
|
|
17
16
|
"scripts": {
|
|
18
17
|
"build": "tsc -p tsconfig.json",
|
package/src/index.ts
DELETED
package/src/messages.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
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
|
-
|
package/src/pubsubClient.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
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
DELETED
package/src/topics.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
|