dooor-shared-config 0.1.0 → 0.3.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 CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./topics";
2
- export * from "./messages";
3
- export * from "./pubsubClient";
1
+ export { SERVICES, getRequestTopic, getResponseTopic, getAppResponseTopic, 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, publishToApp, subscribeToRequests, subscribeToResponses, createMessageConsumer, type MessageHandler, } from "./pubsubClient";
package/dist/index.js CHANGED
@@ -1,20 +1,30 @@
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
- __exportStar(require("./topics"), exports);
18
- __exportStar(require("./messages"), exports);
19
- __exportStar(require("./pubsubClient"), exports);
3
+ exports.createMessageConsumer = exports.subscribeToResponses = exports.subscribeToRequests = exports.publishToApp = 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.getAppResponseTopic = 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, "getAppResponseTopic", { enumerable: true, get: function () { return topics_1.getAppResponseTopic; } });
10
+ Object.defineProperty(exports, "parseResponseTopic", { enumerable: true, get: function () { return topics_1.parseResponseTopic; } });
11
+ Object.defineProperty(exports, "isRequestTopic", { enumerable: true, get: function () { return topics_1.isRequestTopic; } });
12
+ Object.defineProperty(exports, "isResponseTopic", { enumerable: true, get: function () { return topics_1.isResponseTopic; } });
13
+ // Message types and helpers
14
+ var messages_1 = require("./messages");
15
+ Object.defineProperty(exports, "createEnvelope", { enumerable: true, get: function () { return messages_1.createEnvelope; } });
16
+ // PubSub client and utilities
17
+ var pubsubClient_1 = require("./pubsubClient");
18
+ Object.defineProperty(exports, "getPubSubClient", { enumerable: true, get: function () { return pubsubClient_1.getPubSubClient; } });
19
+ Object.defineProperty(exports, "resetPubSubClient", { enumerable: true, get: function () { return pubsubClient_1.resetPubSubClient; } });
20
+ Object.defineProperty(exports, "getTopic", { enumerable: true, get: function () { return pubsubClient_1.getTopic; } });
21
+ Object.defineProperty(exports, "getServiceRequestTopic", { enumerable: true, get: function () { return pubsubClient_1.getServiceRequestTopic; } });
22
+ Object.defineProperty(exports, "getServiceResponseTopic", { enumerable: true, get: function () { return pubsubClient_1.getServiceResponseTopic; } });
23
+ Object.defineProperty(exports, "publishJson", { enumerable: true, get: function () { return pubsubClient_1.publishJson; } });
24
+ Object.defineProperty(exports, "publishRequest", { enumerable: true, get: function () { return pubsubClient_1.publishRequest; } });
25
+ Object.defineProperty(exports, "publishResponse", { enumerable: true, get: function () { return pubsubClient_1.publishResponse; } });
26
+ Object.defineProperty(exports, "publishToApp", { enumerable: true, get: function () { return pubsubClient_1.publishToApp; } });
27
+ Object.defineProperty(exports, "subscribeToRequests", { enumerable: true, get: function () { return pubsubClient_1.subscribeToRequests; } });
28
+ Object.defineProperty(exports, "subscribeToResponses", { enumerable: true, get: function () { return pubsubClient_1.subscribeToResponses; } });
29
+ Object.defineProperty(exports, "createMessageConsumer", { enumerable: true, get: function () { return pubsubClient_1.createMessageConsumer; } });
20
30
  //# 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":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,6CAA2B;AAC3B,iDAA+B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,mCAUkB;AAThB,kGAAA,QAAQ,OAAA;AACR,yGAAA,eAAe,OAAA;AACf,0GAAA,gBAAgB,OAAA;AAChB,6GAAA,mBAAmB,OAAA;AACnB,4GAAA,kBAAkB,OAAA;AAClB,wGAAA,cAAc,OAAA;AACd,yGAAA,eAAe,OAAA;AAKjB,4BAA4B;AAC5B,uCAoBoB;AAnBlB,0GAAA,cAAc,OAAA;AAqBhB,8BAA8B;AAC9B,+CAcwB;AAbtB,+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,4GAAA,YAAY,OAAA;AACZ,mHAAA,mBAAmB,OAAA;AACnB,oHAAA,oBAAoB,OAAA;AACpB,qHAAA,qBAAqB,OAAA"}
@@ -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
- * Message contracts per topic, based on the high-level flows
30
- * in the sequence diagram.
30
+ * Helper to create a new envelope with current timestamp
31
31
  */
32
- export interface FileUploadPayload {
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 (Scaffold).
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 FileUploadMessage extends AtlasEnvelope<FileUploadPayload> {
43
- topic: "file-upload.scaffold";
50
+ export interface IngestionRequestMessage extends AtlasEnvelope<IngestionRequestPayload> {
44
51
  action: "INGEST";
45
52
  }
46
- export interface FileReadyPayload {
53
+ export interface IngestionResponsePayload {
47
54
  /**
48
- * Identifier of the record inside CortexDB.
55
+ * Status of the ingestion: success, error, processing
49
56
  */
50
- recordId: string;
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 FileReadyMessage extends AtlasEnvelope<FileReadyPayload> {
53
- topic: "file-ready.scaffold";
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
- topic: "ai-response.scaffold";
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 InsightReadyPayload {
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 in CortexDB that these insights belong to.
139
+ * The record these insights belong to
85
140
  */
86
141
  recordId: string;
87
142
  /**
88
- * Structured KPIs / metrics extracted from the AI response.
143
+ * Structured KPIs / metrics extracted.
89
144
  * Shape is intentionally open so teams can iterate quickly.
90
145
  */
91
- insights: Record<string, unknown>;
146
+ insights?: Record<string, unknown>;
147
+ /**
148
+ * Error message (if failed)
149
+ */
150
+ error?: string;
92
151
  }
93
- export interface InsightReadyMessage extends AtlasEnvelope<InsightReadyPayload> {
94
- topic: "insight-ready.scaffold";
152
+ export interface ExtractionResponseMessage extends AtlasEnvelope<ExtractionResponsePayload> {
153
+ action: "EXTRACT_RESPONSE";
95
154
  }
96
155
  /**
97
- * Union type for any ATLAS message.
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 = FileUploadMessage | FileReadyMessage | AiRequestMessage | AiResponseMessage | InsightReadyMessage;
100
- export type AtlasPayload = FileUploadPayload | FileReadyPayload | AiRequestPayload | AiResponsePayload | InsightReadyPayload;
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
@@ -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"}
@@ -1,14 +1,120 @@
1
- import { PubSub, type ClientConfig, type Topic } from "@google-cloud/pubsub";
2
- import { TOPICS, type TopicName } from "./topics";
1
+ import { PubSub, type ClientConfig, type Topic, type Subscription, type Message } from "@google-cloud/pubsub";
2
+ import { SERVICES, getRequestTopic, getResponseTopic, getAppResponseTopic, 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
- * Helper to publish a JSON-encoded message with optional attributes.
11
+ * Reset the cached PubSub client (useful for testing)
12
12
  */
13
- export declare function publishJson(topicName: TopicName, message: unknown, attributes?: Record<string, string>, pubSubOptions?: ClientConfig): Promise<string>;
14
- export { TOPICS };
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
24
+ */
25
+ export declare function getServiceResponseTopic(service: ServiceKey, 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 to the service's fixed response topic.
45
+ * The appId is preserved in the message envelope so the cortex gateway
46
+ * can route it to the correct app.
47
+ *
48
+ * @example
49
+ * // Service publishes response to "ingestion-service-response"
50
+ * await publishResponse("ingestion", {
51
+ * action: "INGEST_RESPONSE",
52
+ * appId: "scaffold",
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, 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 from a service.
78
+ * Used by the cortex gateway to receive responses and route them to apps.
79
+ *
80
+ * @param service - The service to receive responses from
81
+ * @param subscriptionName - Name of the subscription
82
+ * @param options - PubSub client options
83
+ *
84
+ * @example
85
+ * const sub = await subscribeToResponses("ingestion", "cortex-ingestion-responses");
86
+ * sub.on("message", (message) => {
87
+ * const data = JSON.parse(message.data.toString());
88
+ * // Route to app based on data.appId...
89
+ * message.ack();
90
+ * });
91
+ */
92
+ export declare function subscribeToResponses(service: ServiceKey, subscriptionName: string, options?: ClientConfig): Promise<Subscription>;
93
+ /**
94
+ * Helper type for message handlers
95
+ */
96
+ export type MessageHandler<T> = (envelope: AtlasEnvelope<T>, message: Message, ack: () => void, nack: () => void) => Promise<void> | void;
97
+ /**
98
+ * Create a simple message consumer that handles JSON parsing and error handling
99
+ *
100
+ * @example
101
+ * const subscription = await subscribeToRequests("ingestion", "ingestion-sub");
102
+ * createMessageConsumer(subscription, async (envelope, message, ack, nack) => {
103
+ * try {
104
+ * // Process the envelope...
105
+ * ack();
106
+ * } catch (err) {
107
+ * nack();
108
+ * }
109
+ * });
110
+ */
111
+ export declare function createMessageConsumer<T>(subscription: Subscription, handler: MessageHandler<T>, onError?: (error: Error, message: Message) => void): void; /**
112
+ * Publish a message to an app-specific response topic.
113
+ * Used by the cortex gateway to forward service responses to the correct app.
114
+ *
115
+ * @example
116
+ * await publishToApp("bi-app", responseEnvelope);
117
+ * // publishes to "bi-app-responses"
118
+ */
119
+ export declare function publishToApp<T>(appId: string, message: AtlasEnvelope<T>, attributes?: Record<string, string>, pubSubOptions?: ClientConfig): Promise<string>;
120
+ export { SERVICES, getRequestTopic, getResponseTopic, getAppResponseTopic };
@@ -1,12 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TOPICS = void 0;
3
+ exports.getAppResponseTopic = 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;
15
+ exports.publishToApp = publishToApp;
7
16
  const pubsub_1 = require("@google-cloud/pubsub");
8
17
  const topics_1 = require("./topics");
9
- Object.defineProperty(exports, "TOPICS", { enumerable: true, get: function () { return topics_1.TOPICS; } });
18
+ Object.defineProperty(exports, "SERVICES", { enumerable: true, get: function () { return topics_1.SERVICES; } });
19
+ Object.defineProperty(exports, "getRequestTopic", { enumerable: true, get: function () { return topics_1.getRequestTopic; } });
20
+ Object.defineProperty(exports, "getResponseTopic", { enumerable: true, get: function () { return topics_1.getResponseTopic; } });
21
+ Object.defineProperty(exports, "getAppResponseTopic", { enumerable: true, get: function () { return topics_1.getAppResponseTopic; } });
10
22
  let cachedPubSub = null;
11
23
  /**
12
24
  * Creates (or returns a cached) PubSub client.
@@ -19,16 +31,182 @@ function getPubSubClient(options) {
19
31
  }
20
32
  return cachedPubSub;
21
33
  }
34
+ /**
35
+ * Reset the cached PubSub client (useful for testing)
36
+ */
37
+ function resetPubSubClient() {
38
+ cachedPubSub = null;
39
+ }
40
+ /**
41
+ * Get a topic reference by name
42
+ */
22
43
  function getTopic(topicName, options) {
23
44
  const client = getPubSubClient(options);
24
45
  return client.topic(topicName);
25
46
  }
26
47
  /**
27
- * Helper to publish a JSON-encoded message with optional attributes.
48
+ * Get the request topic for a service
49
+ */
50
+ function getServiceRequestTopic(service, options) {
51
+ const topicName = (0, topics_1.getRequestTopic)(service);
52
+ return getTopic(topicName, options);
53
+ }
54
+ /**
55
+ * Get the response topic for a service
56
+ */
57
+ function getServiceResponseTopic(service, options) {
58
+ const topicName = (0, topics_1.getResponseTopic)(service);
59
+ return getTopic(topicName, options);
60
+ }
61
+ /**
62
+ * Helper to publish a JSON-encoded message to any topic
28
63
  */
29
64
  async function publishJson(topicName, message, attributes, pubSubOptions) {
30
65
  const topic = getTopic(topicName, pubSubOptions);
31
66
  const dataBuffer = Buffer.from(JSON.stringify(message));
32
- return topic.publish(dataBuffer, attributes ?? {});
67
+ return topic.publishMessage({ data: dataBuffer, attributes: attributes ?? {} });
68
+ }
69
+ /**
70
+ * Publish a request message to a service
71
+ *
72
+ * @example
73
+ * await publishRequest("ingestion", {
74
+ * action: "INGEST",
75
+ * appId: "scaffold",
76
+ * correlationId: "uuid-123",
77
+ * timestamp: new Date().toISOString(),
78
+ * payload: { uploadId: "file-123" }
79
+ * });
80
+ */
81
+ async function publishRequest(service, message, attributes, pubSubOptions) {
82
+ const topicName = (0, topics_1.getRequestTopic)(service);
83
+ return publishJson(topicName, message, attributes, pubSubOptions);
84
+ }
85
+ /**
86
+ * Publish a response message to the service's fixed response topic.
87
+ * The appId is preserved in the message envelope so the cortex gateway
88
+ * can route it to the correct app.
89
+ *
90
+ * @example
91
+ * // Service publishes response to "ingestion-service-response"
92
+ * await publishResponse("ingestion", {
93
+ * action: "INGEST_RESPONSE",
94
+ * appId: "scaffold",
95
+ * correlationId: "uuid-123",
96
+ * timestamp: new Date().toISOString(),
97
+ * payload: { status: "success", recordId: "rec-456", uploadId: "file-123" }
98
+ * });
99
+ */
100
+ async function publishResponse(service, message, attributes, pubSubOptions) {
101
+ const topicName = (0, topics_1.getResponseTopic)(service);
102
+ return publishJson(topicName, message, attributes, pubSubOptions);
103
+ }
104
+ /**
105
+ * Subscribe to a service's request topic.
106
+ * Returns the subscription for attaching message handlers.
107
+ *
108
+ * @param service - The service to subscribe to
109
+ * @param subscriptionName - Name of the subscription (will be created if it doesn't exist)
110
+ * @param options - PubSub client options
111
+ *
112
+ * @example
113
+ * const sub = await subscribeToRequests("ingestion", "ingestion-service-sub");
114
+ * sub.on("message", (message) => {
115
+ * const data = JSON.parse(message.data.toString());
116
+ * // Process request...
117
+ * message.ack();
118
+ * });
119
+ */
120
+ async function subscribeToRequests(service, subscriptionName, options) {
121
+ const client = getPubSubClient(options);
122
+ const topicName = (0, topics_1.getRequestTopic)(service);
123
+ // Check if subscription exists, create if not
124
+ const subscription = client.subscription(subscriptionName);
125
+ const [exists] = await subscription.exists();
126
+ if (!exists) {
127
+ const topic = client.topic(topicName);
128
+ const [topicExists] = await topic.exists();
129
+ if (!topicExists) {
130
+ await topic.create();
131
+ }
132
+ await topic.createSubscription(subscriptionName);
133
+ }
134
+ return subscription;
135
+ }
136
+ /**
137
+ * Subscribe to responses from a service.
138
+ * Used by the cortex gateway to receive responses and route them to apps.
139
+ *
140
+ * @param service - The service to receive responses from
141
+ * @param subscriptionName - Name of the subscription
142
+ * @param options - PubSub client options
143
+ *
144
+ * @example
145
+ * const sub = await subscribeToResponses("ingestion", "cortex-ingestion-responses");
146
+ * sub.on("message", (message) => {
147
+ * const data = JSON.parse(message.data.toString());
148
+ * // Route to app based on data.appId...
149
+ * message.ack();
150
+ * });
151
+ */
152
+ async function subscribeToResponses(service, subscriptionName, options) {
153
+ const client = getPubSubClient(options);
154
+ const topicName = (0, topics_1.getResponseTopic)(service);
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
+ });
200
+ } /**
201
+ * Publish a message to an app-specific response topic.
202
+ * Used by the cortex gateway to forward service responses to the correct app.
203
+ *
204
+ * @example
205
+ * await publishToApp("bi-app", responseEnvelope);
206
+ * // publishes to "bi-app-responses"
207
+ */
208
+ async function publishToApp(appId, message, attributes, pubSubOptions) {
209
+ const topicName = (0, topics_1.getAppResponseTopic)(appId);
210
+ return publishJson(topicName, message, attributes, pubSubOptions);
33
211
  }
34
212
  //# sourceMappingURL=pubsubClient.js.map
@@ -1 +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"}
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,58 @@
1
- export declare const TOPICS: {
2
- fileUpload: string;
3
- fileReady: string;
4
- aiRequest: string;
5
- aiResponse: string;
6
- insightReady: string;
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 TopicKey = keyof typeof TOPICS;
9
- export type TopicName = (typeof TOPICS)[TopicKey];
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.
22
+ * Response topics are fixed per service: "{service}-response"
23
+ *
24
+ * The appId is included in the message envelope so the cortex gateway
25
+ * can route responses to the correct app.
26
+ *
27
+ * @example
28
+ * getResponseTopic("ingestion") // => "ingestion-service-response"
29
+ * getResponseTopic("ai") // => "ai-service-response"
30
+ */
31
+ export declare function getResponseTopic(service: ServiceKey): string;
32
+ /**
33
+ * Parse a response topic to extract the service
34
+ *
35
+ * @example
36
+ * parseResponseTopic("ingestion-service-response")
37
+ * // => { service: "ingestion" }
38
+ */
39
+ export declare function parseResponseTopic(topic: string): {
40
+ service: ServiceKey | null;
41
+ };
42
+ /**
43
+ * Check if a topic is a request topic
44
+ */
45
+ export declare function isRequestTopic(topic: string): boolean;
46
+ /**
47
+ * Check if a topic is a response topic
48
+ */
49
+ export declare function isResponseTopic(topic: string): boolean;
10
50
  /**
11
- * Convenience constants for each topic, for nicer imports.
12
- * Using type assertions to preserve literal types for message contracts.
51
+ * Get the response topic for a specific app.
52
+ * Used by the cortex gateway to forward service responses to the correct app.
53
+ *
54
+ * @example
55
+ * getAppResponseTopic("bi-app") // => "bi-app-responses"
13
56
  */
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";
57
+ export declare function getAppResponseTopic(appId: string): string;
58
+ export { topicsConfig };
package/dist/topics.js CHANGED
@@ -3,16 +3,81 @@ 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.INSIGHT_READY_TOPIC = exports.AI_RESPONSE_TOPIC = exports.AI_REQUEST_TOPIC = exports.FILE_READY_TOPIC = exports.FILE_UPLOAD_TOPIC = exports.TOPICS = void 0;
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;
12
+ exports.getAppResponseTopic = getAppResponseTopic;
7
13
  const topics_json_1 = __importDefault(require("./topics.json"));
8
- exports.TOPICS = topics_json_1.default;
14
+ exports.topicsConfig = topics_json_1.default;
9
15
  /**
10
- * Convenience constants for each topic, for nicer imports.
11
- * Using type assertions to preserve literal types for message contracts.
16
+ * Service names as defined in the configuration
12
17
  */
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
+ exports.SERVICES = topics_json_1.default.services;
19
+ /**
20
+ * Get the request topic for a service.
21
+ * Request topics are fixed per service: "ingestion-service", "ai-service", etc.
22
+ *
23
+ * @example
24
+ * getRequestTopic("ingestion") // => "ingestion-service"
25
+ */
26
+ function getRequestTopic(service) {
27
+ return exports.SERVICES[service];
28
+ }
29
+ /**
30
+ * Get the response topic for a service.
31
+ * Response topics are fixed per service: "{service}-response"
32
+ *
33
+ * The appId is included in the message envelope so the cortex gateway
34
+ * can route responses to the correct app.
35
+ *
36
+ * @example
37
+ * getResponseTopic("ingestion") // => "ingestion-service-response"
38
+ * getResponseTopic("ai") // => "ai-service-response"
39
+ */
40
+ function getResponseTopic(service) {
41
+ const serviceTopic = exports.SERVICES[service];
42
+ return `${serviceTopic}${topics_json_1.default.responsePrefix}`;
43
+ }
44
+ /**
45
+ * Parse a response topic to extract the service
46
+ *
47
+ * @example
48
+ * parseResponseTopic("ingestion-service-response")
49
+ * // => { service: "ingestion" }
50
+ */
51
+ function parseResponseTopic(topic) {
52
+ const responsePrefix = topics_json_1.default.responsePrefix;
53
+ for (const [key, serviceTopic] of Object.entries(exports.SERVICES)) {
54
+ if (topic === `${serviceTopic}${responsePrefix}`) {
55
+ return { service: key };
56
+ }
57
+ }
58
+ return { service: null };
59
+ }
60
+ /**
61
+ * Check if a topic is a request topic
62
+ */
63
+ function isRequestTopic(topic) {
64
+ return Object.values(exports.SERVICES).includes(topic);
65
+ }
66
+ /**
67
+ * Check if a topic is a response topic
68
+ */
69
+ function isResponseTopic(topic) {
70
+ const responsePrefix = topics_json_1.default.responsePrefix;
71
+ return Object.values(exports.SERVICES).some(serviceTopic => topic === `${serviceTopic}${responsePrefix}`);
72
+ }
73
+ /**
74
+ * Get the response topic for a specific app.
75
+ * Used by the cortex gateway to forward service responses to the correct app.
76
+ *
77
+ * @example
78
+ * getAppResponseTopic("bi-app") // => "bi-app-responses"
79
+ */
80
+ function getAppResponseTopic(appId) {
81
+ return `${appId}${topics_json_1.default.appResponseSuffix}`;
82
+ }
18
83
  //# sourceMappingURL=topics.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"topics.js","sourceRoot":"","sources":["../src/topics.ts"],"names":[],"mappings":";;;;;;AAgBA,0CAEC;AAaD,4CAGC;AASD,gDAUC;AAKD,wCAEC;AAKD,0CAKC;AASD,kDAEC;AAjFD,gEAAyC;AAoFhC,uBApFF,qBAAY,CAoFE;AAlFrB;;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;IAClD,MAAM,YAAY,GAAG,gBAAQ,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,GAAG,YAAY,GAAG,qBAAY,CAAC,cAAc,EAAE,CAAC;AACzD,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,IAAI,KAAK,KAAK,GAAG,YAAY,GAAG,cAAc,EAAE,EAAE,CAAC;YACjD,OAAO,EAAE,OAAO,EAAE,GAAiB,EAAE,CAAC;QACxC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,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,KAAK,GAAG,YAAY,GAAG,cAAc,EAAE,CAC7C,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CAAC,KAAa;IAC/C,OAAO,GAAG,KAAK,GAAG,qBAAY,CAAC,iBAAiB,EAAE,CAAC;AACrD,CAAC"}
package/dist/topics.json CHANGED
@@ -1,7 +1,9 @@
1
1
  {
2
- "fileUpload": "file-upload.scaffold",
3
- "fileReady": "file-ready.scaffold",
4
- "aiRequest": "ai-request.scaffold",
5
- "aiResponse": "ai-response.scaffold",
6
- "insightReady": "insight-ready.scaffold"
2
+ "services": {
3
+ "ingestion": "ingestion-service",
4
+ "ai": "ai-service",
5
+ "extraction": "extraction-service"
6
+ },
7
+ "responsePrefix": "-response",
8
+ "appResponseSuffix": "-responses"
7
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dooor-shared-config",
3
- "version": "0.1.0",
3
+ "version": "0.3.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
@@ -1,4 +0,0 @@
1
- export * from "./topics";
2
- export * from "./messages";
3
- export * from "./pubsubClient";
4
-
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
-
@@ -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
@@ -1,8 +0,0 @@
1
- {
2
- "fileUpload": "file-upload.scaffold",
3
- "fileReady": "file-ready.scaffold",
4
- "aiRequest": "ai-request.scaffold",
5
- "aiResponse": "ai-response.scaffold",
6
- "insightReady": "insight-ready.scaffold"
7
- }
8
-
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
-