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 CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./topics";
2
- export * from "./messages";
3
- export * from "./pubsubClient";
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
- __exportStar(require("./topics"), exports);
18
- __exportStar(require("./messages"), exports);
19
- __exportStar(require("./pubsubClient"), exports);
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":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,6CAA2B;AAC3B,iDAA+B"}
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"}
@@ -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,114 @@
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, 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 + 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 };
@@ -1,12 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TOPICS = void 0;
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, "TOPICS", { enumerable: true, get: function () { return topics_1.TOPICS; } });
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
- * Helper to publish a JSON-encoded message with optional attributes.
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.publish(dataBuffer, attributes ?? {});
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
@@ -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,51 @@
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 + 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
- * Convenience constants for each topic, for nicer imports.
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 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";
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.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;
7
12
  const topics_json_1 = __importDefault(require("./topics.json"));
8
- exports.TOPICS = topics_json_1.default;
13
+ exports.topicsConfig = topics_json_1.default;
9
14
  /**
10
- * Convenience constants for each topic, for nicer imports.
11
- * Using type assertions to preserve literal types for message contracts.
15
+ * Service names as defined in the configuration
12
16
  */
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;
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
@@ -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,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
- "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"
7
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dooor-shared-config",
3
- "version": "0.1.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
@@ -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
-