@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.
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +1 -1
- package/dist/database/index.d.ts +796 -0
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/index.js +91 -0
- package/dist/database/index.js.map +1 -1
- package/dist/logging/index.d.ts.map +1 -1
- package/dist/logging/index.js +111 -10
- package/dist/logging/index.js.map +1 -1
- package/dist/messaging/index.d.ts +77 -0
- package/dist/messaging/index.d.ts.map +1 -1
- package/dist/messaging/index.js +171 -0
- package/dist/messaging/index.js.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +4 -3
- package/src/config/index.ts +1 -1
- package/src/database/index.ts +143 -0
- package/src/logging/index.ts +124 -12
- package/src/messaging/index.ts +271 -0
- package/src/types/index.ts +2 -0
|
@@ -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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"}
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,oBAAoB;AACpB,iDAAiD;
|
|
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.
|
|
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
|
-
"
|
|
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",
|
package/src/config/index.ts
CHANGED
|
@@ -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('
|
|
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'),
|
package/src/database/index.ts
CHANGED
|
@@ -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;
|
package/src/logging/index.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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(),
|
|
110
|
+
isProduction ? json() : combine(colorize({ level: true }), devConsoleFormat),
|
|
15
111
|
),
|
|
16
|
-
|
|
17
|
-
|
|
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
|
}
|
package/src/messaging/index.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -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;
|