@heavybit/pendoadmin-shared-lib 1.1.5 → 1.1.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,oBAAoB;AACpB,iDAAiD;AAyEjD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAe,EACf,kBAAkC;IAElC,IAAI,IAAI,CAAC,YAAY,IAAI,kBAAkB,EAAE,CAAC;QAC5C,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC;AACxB,CAAC;AAwJD,iDAAiD;AACjD,uBAAuB;AACvB,iDAAiD;AAEjD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,WAAW;IACpB,UAAU,EAAE,cAAc;IAC1B,UAAU,EAAE,cAAc;IAC1B,UAAU,EAAE,cAAc;IAC1B,gBAAgB,EAAE,oBAAoB;IACtC,aAAa,EAAE,iBAAiB;IAChC,cAAc,EAAE,kBAAkB;IAClC,YAAY,EAAE,gBAAgB;CACtB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,oBAAoB;AACpB,iDAAiD;AA2EjD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAe,EACf,kBAAkC;IAElC,IAAI,IAAI,CAAC,YAAY,IAAI,kBAAkB,EAAE,CAAC;QAC5C,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC;AACxB,CAAC;AAwJD,iDAAiD;AACjD,uBAAuB;AACvB,iDAAiD;AAEjD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,WAAW;IACpB,UAAU,EAAE,cAAc;IAC1B,UAAU,EAAE,cAAc;IAC1B,UAAU,EAAE,cAAc;IAC1B,gBAAgB,EAAE,oBAAoB;IACtC,aAAa,EAAE,iBAAiB;IAChC,cAAc,EAAE,kBAAkB;IAClC,YAAY,EAAE,gBAAgB;CACtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heavybit/pendoadmin-shared-lib",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Shared library for PendoAdmin microservices",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -96,14 +96,16 @@
96
96
  "jsonwebtoken": "^9.0.2",
97
97
  "knex": "^3.1.0",
98
98
  "mysql2": "^3.11.0",
99
+ "rate-limiter-flexible": "^5.0.0",
99
100
  "uuid": "^10.0.0",
100
101
  "winston": "^3.14.0",
101
- "rate-limiter-flexible": "^5.0.0",
102
+ "winston-daily-rotate-file": "^5.0.0",
102
103
  "zod": "^3.23.0"
103
104
  },
104
105
  "devDependencies": {
105
106
  "@nestjs/common": "^11.1.14",
106
107
  "@nestjs/core": "^11.1.14",
108
+ "@nestjs/websockets": "^11.0.0",
107
109
  "@types/amqplib": "^0.10.5",
108
110
  "@types/bcrypt": "^5.0.2",
109
111
  "@types/express": "^5.0.6",
@@ -111,7 +113,6 @@
111
113
  "@types/jsonwebtoken": "^9.0.7",
112
114
  "@types/node": "^20.14.0",
113
115
  "@types/uuid": "^10.0.0",
114
- "@nestjs/websockets": "^11.0.0",
115
116
  "drizzle-orm": "^0.30.0",
116
117
  "express": "^5.2.1",
117
118
  "ioredis": "^5.4.0",
@@ -14,7 +14,7 @@ export const baseEnvSchema = z.object({
14
14
  DB_PASSWORD: z.string().default(''),
15
15
  DB_NAME: z.string(),
16
16
  JWT_SECRET: z.string().min(16),
17
- JWT_ACCESS_EXPIRY: z.string().default('15m'),
17
+ JWT_ACCESS_EXPIRY: z.string().default('24h'),
18
18
  JWT_REFRESH_EXPIRY: z.string().default('7d'),
19
19
  RABBITMQ_URL: z.string().url().default('amqp://localhost:5672'),
20
20
  REDIS_URL: z.string().default('redis://localhost:6379'),
@@ -1,4 +1,147 @@
1
1
  import knex, { Knex } from 'knex';
2
+ import {
3
+ mysqlTable,
4
+ varchar,
5
+ boolean,
6
+ datetime,
7
+ timestamp,
8
+ int,
9
+ text,
10
+ json,
11
+ index,
12
+ uniqueIndex,
13
+ } from 'drizzle-orm/mysql-core';
14
+
15
+ // ─── SHARED DRIZZLE SCHEMAS ────────────────────────────────
16
+ // These tables are common across multiple services (ussd, auth, etc.)
17
+ // Define once here to avoid duplicating schema files.
18
+
19
+ export const companies = mysqlTable(
20
+ 'companies',
21
+ {
22
+ id: varchar('id', { length: 36 }).primaryKey(),
23
+ name: varchar('name', { length: 255 }).notNull(),
24
+ companySlug: varchar('company_slug', { length: 255 }).notNull(),
25
+ ussdCode: varchar('ussd_code', { length: 20 }),
26
+ email: varchar('email', { length: 255 }),
27
+ phone: varchar('phone', { length: 20 }),
28
+ address: text('address'),
29
+ city: varchar('city', { length: 100 }),
30
+ country: varchar('country', { length: 100 }),
31
+ logo: varchar('logo', { length: 500 }),
32
+ isActive: boolean('is_active').notNull().default(true),
33
+ isSystem: boolean('is_system').notNull().default(false),
34
+ createdAt: timestamp('created_at').defaultNow(),
35
+ updatedAt: timestamp('updated_at').defaultNow().onUpdateNow(),
36
+ },
37
+ (t) => ({
38
+ companySlugUnique: uniqueIndex('companies_slug_unique').on(t.companySlug),
39
+ }),
40
+ );
41
+ export type Company = typeof companies.$inferSelect;
42
+ export type NewCompany = typeof companies.$inferInsert;
43
+
44
+ export const users = mysqlTable(
45
+ 'users',
46
+ {
47
+ id: varchar('id', { length: 36 }).primaryKey(),
48
+ email: varchar('email', { length: 255 }).notNull(),
49
+ fullName: varchar('full_name', { length: 255 }),
50
+ firstName: varchar('first_name', { length: 100 }),
51
+ lastName: varchar('last_name', { length: 100 }),
52
+ companyId: varchar('company_id', { length: 36 }),
53
+ isActive: boolean('is_active').notNull().default(true),
54
+ isSuperAdmin: boolean('is_super_admin').notNull().default(false),
55
+ suspendedAt: datetime('suspended_at'),
56
+ suspendedReason: varchar('suspended_reason', { length: 500 }),
57
+ lastLoginAt: datetime('last_login_at'),
58
+ createdAt: timestamp('created_at').defaultNow(),
59
+ updatedAt: timestamp('updated_at').defaultNow().onUpdateNow(),
60
+ },
61
+ (t) => ({
62
+ companyIdx: index('users_company_idx').on(t.companyId),
63
+ }),
64
+ );
65
+ export type User = typeof users.$inferSelect;
66
+ export type NewUser = typeof users.$inferInsert;
67
+
68
+ export const permissions = mysqlTable(
69
+ 'permissions',
70
+ {
71
+ id: varchar('id', { length: 36 }).primaryKey(),
72
+ name: varchar('name', { length: 100 }).notNull().unique(),
73
+ resource: varchar('resource', { length: 50 }).notNull(),
74
+ action: varchar('action', { length: 50 }).notNull(),
75
+ description: varchar('description', { length: 255 }),
76
+ isRestricted: boolean('is_restricted').notNull().default(false),
77
+ createdAt: timestamp('created_at').defaultNow(),
78
+ updatedAt: timestamp('updated_at').defaultNow().onUpdateNow(),
79
+ },
80
+ (t) => ({
81
+ resourceActionIdx: index('permissions_resource_action_idx').on(t.resource, t.action),
82
+ }),
83
+ );
84
+ export type Permission = typeof permissions.$inferSelect;
85
+ export type NewPermission = typeof permissions.$inferInsert;
86
+
87
+ export const roles = mysqlTable(
88
+ 'roles',
89
+ {
90
+ id: varchar('id', { length: 36 }).primaryKey(),
91
+ name: varchar('name', { length: 100 }).notNull(),
92
+ roleSlug: varchar('role_slug', { length: 100 }),
93
+ description: varchar('description', { length: 255 }),
94
+ isSystemRole: boolean('is_system_role'),
95
+ isSystem: boolean('is_system').notNull().default(false),
96
+ isEditable: boolean('is_editable').notNull().default(true),
97
+ companyId: varchar('company_id', { length: 36 }),
98
+ createdAt: timestamp('created_at').defaultNow(),
99
+ updatedAt: timestamp('updated_at').defaultNow().onUpdateNow(),
100
+ },
101
+ (t) => ({
102
+ companyIdx: index('roles_company_idx').on(t.companyId),
103
+ }),
104
+ );
105
+ export type Role = typeof roles.$inferSelect;
106
+ export type NewRole = typeof roles.$inferInsert;
107
+
108
+ export const rolePermissions = mysqlTable(
109
+ 'role_permissions',
110
+ {
111
+ id: varchar('id', { length: 36 }).primaryKey(),
112
+ roleId: varchar('role_id', { length: 36 }).notNull(),
113
+ permissionId: varchar('permission_id', { length: 36 }).notNull(),
114
+ },
115
+ (t) => ({
116
+ rolePermUnique: uniqueIndex('role_permissions_unique').on(t.roleId, t.permissionId),
117
+ roleIdx: index('role_permissions_role_idx').on(t.roleId),
118
+ }),
119
+ );
120
+
121
+ export const apiKeys = mysqlTable(
122
+ 'company_api_keys',
123
+ {
124
+ id: varchar('id', { length: 36 }).primaryKey(),
125
+ companyId: varchar('company_id', { length: 36 }).notNull(),
126
+ name: varchar('name', { length: 255 }).notNull(),
127
+ clientId: varchar('client_id', { length: 255 }).notNull().unique(),
128
+ clientSecretHash: varchar('client_secret_hash', { length: 255 }).notNull(),
129
+ clientSecretPrefix: varchar('client_secret_prefix', { length: 10 }).notNull(),
130
+ scopes: json('scopes'),
131
+ rateLimitPerMinute: int('rate_limit_per_minute').default(60),
132
+ isActive: boolean('is_active').notNull().default(true),
133
+ isTestKey: boolean('is_test_key').notNull().default(false),
134
+ expiresAt: datetime('expires_at'),
135
+ lastUsedAt: datetime('last_used_at'),
136
+ createdAt: timestamp('created_at').defaultNow(),
137
+ updatedAt: timestamp('updated_at').defaultNow().onUpdateNow(),
138
+ },
139
+ (t) => ({
140
+ companyActiveIdx: index('api_keys_company_active_idx').on(t.companyId, t.isActive),
141
+ }),
142
+ );
143
+ export type ApiKey = typeof apiKeys.$inferSelect;
144
+ export type NewApiKey = typeof apiKeys.$inferInsert;
2
145
 
3
146
  export interface DatabaseConfig {
4
147
  host: string;
@@ -1,31 +1,143 @@
1
1
  import winston from 'winston';
2
+ import DailyRotateFile from 'winston-daily-rotate-file';
3
+ import { mkdirSync } from 'fs';
4
+ import { resolve } from 'path';
2
5
 
3
- const { combine, timestamp, json, errors, colorize, simple } = winston.format;
6
+ const { combine, timestamp, json, errors, colorize, printf, splat } = winston.format;
7
+
8
+ /**
9
+ * Custom dev console format that renders meta cleanly and warns when callers
10
+ * pass a Promise as the message (a common forgotten-await bug).
11
+ *
12
+ * info: SMS sent { batchId: 'xyz', recipients: 1 }
13
+ * error: DB failed Error: connection refused
14
+ * at ...stack...
15
+ */
16
+ const devConsoleFormat = printf((info) => {
17
+ const { level, message, timestamp: ts, service, stack, ...rest } = info as Record<string, unknown> & {
18
+ level: string;
19
+ message: unknown;
20
+ timestamp?: string;
21
+ service?: string;
22
+ stack?: string;
23
+ };
24
+
25
+ // Detect forgotten-await: someone passed a Promise as the message.
26
+ let renderedMessage: string;
27
+ if (message && typeof (message as { then?: unknown }).then === 'function') {
28
+ renderedMessage = '[Promise — forgot to await?]';
29
+ } else if (message instanceof Error) {
30
+ renderedMessage = message.message;
31
+ } else if (typeof message === 'object' && message !== null) {
32
+ renderedMessage = JSON.stringify(message);
33
+ } else {
34
+ renderedMessage = String(message ?? '');
35
+ }
36
+
37
+ // Strip winston-internal symbols/keys before serialising meta
38
+ const meta: Record<string, unknown> = {};
39
+ for (const [k, v] of Object.entries(rest)) {
40
+ if (k === 'splat' || k.startsWith('Symbol(')) continue;
41
+ meta[k] = v;
42
+ }
43
+
44
+ const metaStr = Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : '';
45
+ const tag = service ? `[${service}] ` : '';
46
+ const stackStr = stack ? `\n${stack}` : '';
47
+ return `${ts ?? ''} ${level}: ${tag}${renderedMessage}${metaStr}${stackStr}`;
48
+ });
49
+
50
+ /**
51
+ * LOG_TARGET controls where logs are shipped:
52
+ * console — stdout only (default for dev)
53
+ * file — rotating files only
54
+ * both — stdout + rotating files (default for staging/production)
55
+ *
56
+ * LOG_DIR — directory for log files (default: /app/logs)
57
+ * LOG_MAX_SIZE — max size per log file before rotation (default: 20m)
58
+ * LOG_MAX_FILES — retention period or count, e.g. 14d or 30 (default: 14d)
59
+ */
60
+ function resolveLogTarget(): 'console' | 'file' | 'both' {
61
+ const raw = (process.env.LOG_TARGET || 'console').toLowerCase().trim();
62
+ if (raw === 'file' || raw === 'both') return raw;
63
+ return 'console';
64
+ }
65
+
66
+ function buildFileTransports(service: string, level: string): DailyRotateFile[] {
67
+ const logDir = resolve(process.env.LOG_DIR || '/app/logs');
68
+ const maxSize = process.env.LOG_MAX_SIZE || '20m';
69
+ const maxFiles = process.env.LOG_MAX_FILES || '14d';
70
+
71
+ try {
72
+ mkdirSync(logDir, { recursive: true });
73
+ } catch {
74
+ // Ignore — directory may already exist or be read-only
75
+ }
76
+
77
+ const shared = {
78
+ dirname: logDir,
79
+ datePattern: 'YYYY-MM-DD',
80
+ zippedArchive: true,
81
+ maxSize,
82
+ maxFiles,
83
+ format: combine(errors({ stack: true }), splat(), timestamp(), json()),
84
+ };
85
+
86
+ return [
87
+ new DailyRotateFile({
88
+ ...shared,
89
+ filename: `${service}-%DATE%-combined.log`,
90
+ level,
91
+ }),
92
+ new DailyRotateFile({
93
+ ...shared,
94
+ filename: `${service}-%DATE%-error.log`,
95
+ level: 'error',
96
+ }),
97
+ ];
98
+ }
4
99
 
5
100
  export function createLogger(service: string, level?: string): winston.Logger {
6
101
  const isProduction = process.env.NODE_ENV === 'production';
102
+ const resolvedLevel = level || process.env.LOG_LEVEL || (isProduction ? 'info' : 'debug');
103
+ const target = resolveLogTarget();
7
104
 
8
- return winston.createLogger({
9
- level: level || process.env.LOG_LEVEL || (isProduction ? 'info' : 'debug'),
10
- defaultMeta: { service },
105
+ const consoleTransport = new winston.transports.Console({
11
106
  format: combine(
12
107
  errors({ stack: true }),
108
+ splat(),
13
109
  timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
14
- isProduction ? json() : combine(colorize(), simple())
110
+ isProduction ? json() : combine(colorize({ level: true }), devConsoleFormat),
15
111
  ),
16
- transports: [
17
- new winston.transports.Console(),
18
- ],
112
+ });
113
+
114
+ const transports: winston.transport[] = [];
115
+ if (target === 'console' || target === 'both') transports.push(consoleTransport);
116
+ if (target === 'file' || target === 'both') transports.push(...buildFileTransports(service, resolvedLevel));
117
+
118
+ return winston.createLogger({
119
+ level: resolvedLevel,
120
+ defaultMeta: { service },
121
+ format: combine(errors({ stack: true }), splat(), timestamp()),
122
+ transports,
19
123
  });
20
124
  }
21
125
 
22
126
  export function createAuditLogger(service: string): winston.Logger {
127
+ const target = resolveLogTarget();
128
+
129
+ const consoleTransport = new winston.transports.Console({
130
+ format: combine(splat(), timestamp(), json()),
131
+ });
132
+
133
+ const transports: winston.transport[] = [];
134
+ if (target === 'console' || target === 'both') transports.push(consoleTransport);
135
+ if (target === 'file' || target === 'both') transports.push(...buildFileTransports(`${service}-audit`, 'info'));
136
+
23
137
  return winston.createLogger({
24
138
  level: 'info',
25
139
  defaultMeta: { service, type: 'audit' },
26
- format: combine(timestamp(), json()),
27
- transports: [
28
- new winston.transports.Console(),
29
- ],
140
+ format: combine(splat(), timestamp(), json()),
141
+ transports,
30
142
  });
31
143
  }
@@ -1,5 +1,6 @@
1
1
  import amqplib from 'amqplib';
2
2
  import type { Channel, ChannelModel, ConsumeMessage } from 'amqplib';
3
+ import { v4 as uuidv4 } from 'uuid';
3
4
  import { createLogger } from '../logging/index.js';
4
5
 
5
6
  const logger = createLogger('rabbitmq');
@@ -81,6 +82,8 @@ export const EVENTS = {
81
82
  AI_COMPLETION_SUCCESS: 'ai.completion.success',
82
83
  AI_COMPLETION_FAILED: 'ai.completion.failed',
83
84
  AI_ANOMALY_DETECTED: 'ai.anomaly.detected',
85
+ AI_RPC_REQUEST: 'ai.rpc.request',
86
+ AI_PROVIDER_FALLBACK: 'ai.provider.fallback',
84
87
 
85
88
  // Gateway events
86
89
  GATEWAY_REQUEST_COMPLETED: 'gateway.request.completed',
@@ -92,6 +95,11 @@ export const EXCHANGES = {
92
95
  COMMANDS: 'pendoadmin.commands',
93
96
  } as const;
94
97
 
98
+ /** RPC queue names for direct service-to-service calls */
99
+ export const RPC_QUEUES = {
100
+ AI_REQUESTS: 'ai.rpc.requests',
101
+ } as const;
102
+
95
103
  // ── RabbitMQ Client ───────────────────────────────────
96
104
 
97
105
  export class RabbitMQClient {
@@ -181,3 +189,266 @@ export class RabbitMQClient {
181
189
  await this.connection?.close();
182
190
  }
183
191
  }
192
+
193
+ // ── RPC Types ─────────────────────────────────────────
194
+
195
+ export type RPCHandler = (payload: Record<string, unknown>) => Promise<Record<string, unknown>>;
196
+
197
+ // ── RabbitMQ RPC Client ───────────────────────────────
198
+ // Sends RPC requests and waits for responses via an exclusive callback queue.
199
+
200
+ export class RabbitMQRPCClient {
201
+ private connection: ChannelModel | null = null;
202
+ private channel: Channel | null = null;
203
+ private callbackQueue: string | null = null;
204
+ private pending = new Map<string, {
205
+ resolve: (val: Record<string, unknown>) => void;
206
+ reject: (err: Error) => void;
207
+ timer: ReturnType<typeof setTimeout>;
208
+ }>();
209
+ private isConnected = false;
210
+
211
+ constructor(private readonly url: string) {}
212
+
213
+ async connect(): Promise<void> {
214
+ this.connection = await amqplib.connect(this.url);
215
+ this.channel = await this.connection.createChannel();
216
+
217
+ const q = await this.channel.assertQueue('', { exclusive: true, autoDelete: true });
218
+ this.callbackQueue = q.queue;
219
+
220
+ this.channel.consume(this.callbackQueue, (msg: ConsumeMessage | null) => {
221
+ if (!msg) return;
222
+ const correlationId = msg.properties.correlationId as string;
223
+ const entry = this.pending.get(correlationId);
224
+ if (entry) {
225
+ clearTimeout(entry.timer);
226
+ this.pending.delete(correlationId);
227
+ try {
228
+ const response = JSON.parse(msg.content.toString()) as Record<string, unknown>;
229
+ entry.resolve(response);
230
+ } catch {
231
+ entry.reject(new Error('Failed to parse RPC response'));
232
+ }
233
+ }
234
+ this.channel!.ack(msg);
235
+ }, { noAck: false });
236
+
237
+ this.isConnected = true;
238
+ logger.info('RPC client connected', { callbackQueue: this.callbackQueue });
239
+
240
+ this.connection.on('error', (err) => {
241
+ logger.error('RPC client connection error', { error: err.message });
242
+ this.isConnected = false;
243
+ });
244
+
245
+ this.connection.on('close', () => {
246
+ logger.warn('RPC client connection closed');
247
+ this.isConnected = false;
248
+ });
249
+ }
250
+
251
+ async call(queueName: string, payload: Record<string, unknown>, timeoutMs = 30000): Promise<Record<string, unknown>> {
252
+ if (!this.isConnected || !this.channel || !this.callbackQueue) {
253
+ throw new Error('RPC client not connected');
254
+ }
255
+
256
+ const correlationId = uuidv4();
257
+
258
+ return new Promise<Record<string, unknown>>((resolve, reject) => {
259
+ const timer = setTimeout(() => {
260
+ this.pending.delete(correlationId);
261
+ reject(new Error(`RPC timeout after ${timeoutMs}ms for queue=${queueName}`));
262
+ }, timeoutMs);
263
+
264
+ this.pending.set(correlationId, { resolve, reject, timer });
265
+
266
+ this.channel!.sendToQueue(
267
+ queueName,
268
+ Buffer.from(JSON.stringify(payload)),
269
+ {
270
+ correlationId,
271
+ replyTo: this.callbackQueue!,
272
+ persistent: true,
273
+ contentType: 'application/json',
274
+ },
275
+ );
276
+ });
277
+ }
278
+
279
+ async close(): Promise<void> {
280
+ for (const [, entry] of this.pending) {
281
+ clearTimeout(entry.timer);
282
+ entry.reject(new Error('RPC client closing'));
283
+ }
284
+ this.pending.clear();
285
+ await this.channel?.close();
286
+ await this.connection?.close();
287
+ this.isConnected = false;
288
+ }
289
+ }
290
+
291
+ // ── RabbitMQ RPC Server ───────────────────────────────
292
+ // Listens on a durable queue and dispatches to a handler, replying via correlationId.
293
+
294
+ export class RabbitMQRPCServer {
295
+ private connection: ChannelModel | null = null;
296
+ private channel: Channel | null = null;
297
+ private isConnected = false;
298
+
299
+ constructor(
300
+ private readonly url: string,
301
+ private readonly queueName: string,
302
+ ) {}
303
+
304
+ async connect(): Promise<void> {
305
+ this.connection = await amqplib.connect(this.url);
306
+ this.channel = await this.connection.createChannel();
307
+ await this.channel.prefetch(5);
308
+ await this.channel.assertQueue(this.queueName, { durable: true, autoDelete: false });
309
+ this.isConnected = true;
310
+ logger.info('RPC server connected', { queue: this.queueName });
311
+
312
+ this.connection.on('error', (err) => {
313
+ logger.error('RPC server connection error', { error: err.message });
314
+ this.isConnected = false;
315
+ });
316
+
317
+ this.connection.on('close', () => {
318
+ logger.warn('RPC server connection closed, reconnecting in 5s...');
319
+ this.isConnected = false;
320
+ setTimeout(() => this.connect(), 5000);
321
+ });
322
+ }
323
+
324
+ async startConsuming(handler: RPCHandler): Promise<void> {
325
+ if (!this.isConnected || !this.channel) {
326
+ throw new Error('RPC server not connected');
327
+ }
328
+
329
+ await this.channel.consume(this.queueName, async (msg: ConsumeMessage | null) => {
330
+ if (!msg) return;
331
+
332
+ const correlationId = msg.properties.correlationId as string;
333
+ const replyTo = msg.properties.replyTo as string;
334
+
335
+ try {
336
+ const payload = JSON.parse(msg.content.toString()) as Record<string, unknown>;
337
+ logger.info('RPC request received', { queue: this.queueName, correlationId });
338
+
339
+ const response = await handler(payload);
340
+
341
+ if (replyTo && correlationId) {
342
+ this.channel!.sendToQueue(
343
+ replyTo,
344
+ Buffer.from(JSON.stringify(response)),
345
+ { correlationId, contentType: 'application/json', persistent: true },
346
+ );
347
+ }
348
+
349
+ this.channel!.ack(msg);
350
+ } catch (error) {
351
+ logger.error('RPC handler error', { queue: this.queueName, error: (error as Error).message });
352
+
353
+ if (replyTo && correlationId) {
354
+ this.channel!.sendToQueue(
355
+ replyTo,
356
+ Buffer.from(JSON.stringify({ success: false, error: (error as Error).message })),
357
+ { correlationId, contentType: 'application/json' },
358
+ );
359
+ }
360
+
361
+ this.channel!.nack(msg, false, false);
362
+ }
363
+ }, { noAck: false });
364
+
365
+ logger.info('RPC server listening', { queue: this.queueName });
366
+ }
367
+
368
+ async close(): Promise<void> {
369
+ await this.channel?.close();
370
+ await this.connection?.close();
371
+ this.isConnected = false;
372
+ }
373
+ }
374
+
375
+ // ── AI RPC Types & Client ─────────────────────────────
376
+ // Pre-built convenience client for calling the AI service via RPC.
377
+
378
+ export type AiRpcAction = 'complete' | 'chat.oneshot' | 'chat.message' | 'providers.list' | 'providers.resolve-chain';
379
+
380
+ export interface AiRpcRequest {
381
+ action: AiRpcAction;
382
+ promptSlug?: string;
383
+ userMessage?: string;
384
+ variables?: Record<string, string>;
385
+ providerId?: string;
386
+ model?: string;
387
+ companyId?: string;
388
+ userId?: string;
389
+ conversationId?: string;
390
+ messages?: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>;
391
+ temperature?: number;
392
+ maxTokens?: number;
393
+ }
394
+
395
+ export interface AiRpcResponse {
396
+ success: boolean;
397
+ data?: unknown;
398
+ error?: string;
399
+ }
400
+
401
+ export class AiRpcClient {
402
+ private rpcClient: RabbitMQRPCClient;
403
+
404
+ constructor(amqpUrl: string) {
405
+ this.rpcClient = new RabbitMQRPCClient(amqpUrl);
406
+ }
407
+
408
+ async connect(): Promise<void> {
409
+ await this.rpcClient.connect();
410
+ }
411
+
412
+ async call(request: AiRpcRequest, timeoutMs = 30000): Promise<AiRpcResponse> {
413
+ const result = await this.rpcClient.call(
414
+ RPC_QUEUES.AI_REQUESTS,
415
+ request as unknown as Record<string, unknown>,
416
+ timeoutMs,
417
+ );
418
+ return result as unknown as AiRpcResponse;
419
+ }
420
+
421
+ async oneShot(
422
+ promptSlug: string,
423
+ userMessage: string,
424
+ options: {
425
+ variables?: Record<string, string>;
426
+ companyId?: string;
427
+ userId?: string;
428
+ providerId?: string;
429
+ model?: string;
430
+ } = {},
431
+ ): Promise<AiRpcResponse> {
432
+ return this.call({ action: 'chat.oneshot', promptSlug, userMessage, ...options });
433
+ }
434
+
435
+ async complete(
436
+ messages: Array<{ role: 'system' | 'user' | 'assistant'; content: string }>,
437
+ options: {
438
+ temperature?: number;
439
+ maxTokens?: number;
440
+ providerId?: string;
441
+ model?: string;
442
+ } = {},
443
+ ): Promise<AiRpcResponse> {
444
+ return this.call({ action: 'complete', messages, ...options });
445
+ }
446
+
447
+ async listProviders(): Promise<AiRpcResponse> {
448
+ return this.call({ action: 'providers.list' });
449
+ }
450
+
451
+ async close(): Promise<void> {
452
+ await this.rpcClient.close();
453
+ }
454
+ }
@@ -53,6 +53,8 @@ export interface IJwtPayload {
53
53
  roles: string[];
54
54
  permissions: string[];
55
55
  isSuperAdmin: boolean;
56
+ /** Whether the user has completed post-login OTP verification for this session. */
57
+ otpVerified?: boolean;
56
58
  iat?: number;
57
59
  exp?: number;
58
60
  iss?: string;