@lobu/core 3.0.13 → 3.0.19

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.
Files changed (67) hide show
  1. package/dist/__tests__/fixtures/mock-redis.d.ts +3 -0
  2. package/dist/__tests__/fixtures/mock-redis.d.ts.map +1 -1
  3. package/dist/__tests__/fixtures/mock-redis.js +12 -0
  4. package/dist/__tests__/fixtures/mock-redis.js.map +1 -1
  5. package/dist/__tests__/secret-refs.test.d.ts +2 -0
  6. package/dist/__tests__/secret-refs.test.d.ts.map +1 -0
  7. package/dist/__tests__/secret-refs.test.js +29 -0
  8. package/dist/__tests__/secret-refs.test.js.map +1 -0
  9. package/dist/agent-store.d.ts +33 -6
  10. package/dist/agent-store.d.ts.map +1 -1
  11. package/dist/agent-store.js.map +1 -1
  12. package/dist/api-types.d.ts +1 -5
  13. package/dist/api-types.d.ts.map +1 -1
  14. package/dist/index.d.ts +5 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +7 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/integration-types.d.ts +9 -1
  19. package/dist/integration-types.d.ts.map +1 -1
  20. package/dist/lobu-toml-schema.d.ts +168 -0
  21. package/dist/lobu-toml-schema.d.ts.map +1 -0
  22. package/dist/lobu-toml-schema.js +108 -0
  23. package/dist/lobu-toml-schema.js.map +1 -0
  24. package/dist/secret-refs.d.ts +11 -0
  25. package/dist/secret-refs.d.ts.map +1 -0
  26. package/dist/secret-refs.js +31 -0
  27. package/dist/secret-refs.js.map +1 -0
  28. package/dist/types.d.ts +29 -8
  29. package/dist/types.d.ts.map +1 -1
  30. package/dist/types.js +5 -3
  31. package/dist/types.js.map +1 -1
  32. package/package.json +14 -4
  33. package/src/__tests__/encryption.test.ts +0 -103
  34. package/src/__tests__/fixtures/factories.ts +0 -76
  35. package/src/__tests__/fixtures/index.ts +0 -9
  36. package/src/__tests__/fixtures/mock-fetch.ts +0 -32
  37. package/src/__tests__/fixtures/mock-queue.ts +0 -50
  38. package/src/__tests__/fixtures/mock-redis.ts +0 -300
  39. package/src/__tests__/retry.test.ts +0 -134
  40. package/src/__tests__/sanitize.test.ts +0 -158
  41. package/src/agent-policy.ts +0 -207
  42. package/src/agent-store.ts +0 -220
  43. package/src/api-types.ts +0 -256
  44. package/src/command-registry.ts +0 -73
  45. package/src/constants.ts +0 -60
  46. package/src/errors.ts +0 -220
  47. package/src/index.ts +0 -131
  48. package/src/integration-types.ts +0 -26
  49. package/src/logger.ts +0 -248
  50. package/src/modules.ts +0 -184
  51. package/src/otel.ts +0 -307
  52. package/src/plugin-types.ts +0 -46
  53. package/src/provider-config-types.ts +0 -54
  54. package/src/redis/base-store.ts +0 -200
  55. package/src/sentry.ts +0 -56
  56. package/src/trace.ts +0 -32
  57. package/src/types.ts +0 -440
  58. package/src/utils/encryption.ts +0 -78
  59. package/src/utils/env.ts +0 -50
  60. package/src/utils/json.ts +0 -37
  61. package/src/utils/lock.ts +0 -75
  62. package/src/utils/mcp-tool-instructions.ts +0 -5
  63. package/src/utils/retry.ts +0 -91
  64. package/src/utils/sanitize.ts +0 -127
  65. package/src/worker/auth.ts +0 -100
  66. package/src/worker/transport.ts +0 -107
  67. package/tsconfig.json +0 -20
package/src/logger.ts DELETED
@@ -1,248 +0,0 @@
1
- // Use simple console.log-based logger by default (unbuffered, 12-factor compliant)
2
- // Set USE_WINSTON_LOGGER=true only if you need Winston features (file rotation, multiple transports)
3
- const USE_WINSTON_LOGGER = process.env.USE_WINSTON_LOGGER === "true";
4
- // Use JSON format for structured logging (better for Loki parsing in production)
5
- const USE_JSON_FORMAT = process.env.LOG_FORMAT === "json";
6
-
7
- import winston from "winston";
8
- import { getSentry } from "./sentry";
9
-
10
- export interface Logger {
11
- error: (message: any, ...args: any[]) => void;
12
- warn: (message: any, ...args: any[]) => void;
13
- info: (message: any, ...args: any[]) => void;
14
- debug: (message: any, ...args: any[]) => void;
15
- }
16
-
17
- // Simple console logger fallback for environments where Winston doesn't work (Bun + Alpine)
18
- // Supports both formats: logger.info("message", data) AND pino-style logger.info({ data }, "message")
19
- function createConsoleLogger(serviceName: string): Logger {
20
- const level = process.env.LOG_LEVEL || "info";
21
- const levels: Record<string, number> = {
22
- error: 0,
23
- warn: 1,
24
- info: 2,
25
- debug: 3,
26
- };
27
- const currentLevel = levels[level] ?? 2;
28
-
29
- const formatMessage = (lvl: string, message: any, ...args: any[]): string => {
30
- const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
31
- let msgStr: string;
32
- let meta: any = null;
33
-
34
- // Handle pino-style format: logger.info({ key: value }, "message")
35
- if (
36
- typeof message === "object" &&
37
- message !== null &&
38
- !Array.isArray(message) &&
39
- !(message instanceof Error)
40
- ) {
41
- if (args.length > 0 && typeof args[0] === "string") {
42
- // First arg is metadata object, second arg is the actual message
43
- msgStr = args[0];
44
- meta = message;
45
- args = args.slice(1);
46
- } else {
47
- // Just an object, stringify it
48
- try {
49
- msgStr = JSON.stringify(message);
50
- } catch {
51
- msgStr = "[object]";
52
- }
53
- }
54
- } else {
55
- msgStr = String(message);
56
- }
57
-
58
- // Append remaining args
59
- if (args.length > 0) {
60
- try {
61
- msgStr += ` ${JSON.stringify(args.length === 1 ? args[0] : args)}`;
62
- } catch {
63
- msgStr += " [unserializable]";
64
- }
65
- }
66
-
67
- // Append metadata object
68
- if (meta) {
69
- try {
70
- msgStr += ` ${JSON.stringify(meta)}`;
71
- } catch {
72
- msgStr += " [meta unserializable]";
73
- }
74
- }
75
-
76
- return `[${timestamp}] [${lvl}] [${serviceName}] ${msgStr}`;
77
- };
78
-
79
- return {
80
- error: (message: any, ...args: any[]) => {
81
- if (currentLevel >= 0)
82
- console.error(formatMessage("error", message, ...args));
83
- },
84
- warn: (message: any, ...args: any[]) => {
85
- if (currentLevel >= 1)
86
- console.warn(formatMessage("warn", message, ...args));
87
- },
88
- info: (message: any, ...args: any[]) => {
89
- if (currentLevel >= 2)
90
- console.log(formatMessage("info", message, ...args));
91
- },
92
- debug: (message: any, ...args: any[]) => {
93
- if (currentLevel >= 3)
94
- console.log(formatMessage("debug", message, ...args));
95
- },
96
- };
97
- }
98
-
99
- /**
100
- * Custom Winston transport that sends errors to Sentry
101
- */
102
- class SentryTransport extends winston.transports.Stream {
103
- constructor() {
104
- super({ stream: process.stdout });
105
- }
106
-
107
- log(info: any, callback: () => void) {
108
- setImmediate(() => {
109
- this.emit("logged", info);
110
- });
111
-
112
- // Only send errors and warnings to Sentry
113
- if (info.level === "error" || info.level === "warn") {
114
- const Sentry = getSentry();
115
- if (Sentry) {
116
- try {
117
- // Extract error object if present
118
- const errorObj =
119
- info.error || (info.message instanceof Error ? info.message : null);
120
-
121
- if (errorObj instanceof Error) {
122
- Sentry.captureException(errorObj, {
123
- level: info.level === "error" ? "error" : "warning",
124
- tags: {
125
- service: info.service,
126
- },
127
- extra: {
128
- ...info,
129
- message: info.message,
130
- },
131
- });
132
- } else {
133
- // Send as message if no Error object
134
- Sentry.captureMessage(String(info.message), {
135
- level: info.level === "error" ? "error" : "warning",
136
- tags: {
137
- service: info.service,
138
- },
139
- extra: info,
140
- });
141
- }
142
- } catch (_err) {
143
- // Ignore Sentry errors to avoid breaking logging
144
- }
145
- }
146
- }
147
-
148
- callback();
149
- }
150
- }
151
-
152
- /**
153
- * Creates a logger instance for a specific service
154
- * Provides consistent logging format across all packages with level and timestamp
155
- * @param serviceName The name of the service using the logger
156
- * @returns A console logger by default, or Winston logger if USE_WINSTON_LOGGER=true
157
- */
158
- export function createLogger(serviceName: string): Logger {
159
- // Use simple console.log logger by default (unbuffered, 12-factor compliant)
160
- // Set USE_WINSTON_LOGGER=true for Winston features (file rotation, multiple transports)
161
- if (!USE_WINSTON_LOGGER) {
162
- return createConsoleLogger(serviceName);
163
- }
164
-
165
- const isProduction = process.env.NODE_ENV === "production";
166
- const level = process.env.LOG_LEVEL || "info";
167
-
168
- // JSON format for structured logging (better for Loki/Grafana parsing)
169
- const jsonFormat = winston.format.combine(
170
- winston.format.timestamp({ format: "YYYY-MM-DDTHH:mm:ss.SSSZ" }),
171
- winston.format.json()
172
- );
173
-
174
- // Human-readable format for development
175
- const humanFormat = winston.format.combine(
176
- ...(isProduction ? [] : [winston.format.colorize()]),
177
- winston.format.printf(({ timestamp, level, message, service, ...meta }) => {
178
- let metaStr = "";
179
- if (Object.keys(meta).length) {
180
- try {
181
- metaStr = ` ${JSON.stringify(meta, null, 0)}`;
182
- } catch (_err) {
183
- // Handle circular structures with a safer approach
184
- try {
185
- const seen = new WeakSet();
186
- metaStr = ` ${JSON.stringify(meta, (_key, value) => {
187
- if (typeof value === "object" && value !== null) {
188
- if (seen.has(value)) {
189
- return "[Circular Reference]";
190
- }
191
- seen.add(value);
192
-
193
- if (value instanceof Error) {
194
- return {
195
- name: value.name,
196
- message: value.message,
197
- stack: value.stack?.split("\n")[0], // Only first line of stack
198
- };
199
- }
200
- }
201
- return value;
202
- })}`;
203
- } catch (_err2) {
204
- // Final fallback if even the circular handler fails
205
- metaStr = " [Object too complex to serialize]";
206
- }
207
- }
208
- }
209
- return `[${timestamp}] [${level}] [${service}] ${message}${metaStr}`;
210
- })
211
- );
212
-
213
- const transports: winston.transport[] = [
214
- new winston.transports.Console({
215
- format: USE_JSON_FORMAT ? jsonFormat : humanFormat,
216
- }),
217
- ];
218
-
219
- const logger = winston.createLogger({
220
- level,
221
- format: winston.format.combine(
222
- winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
223
- winston.format.errors({ stack: true }),
224
- winston.format.splat()
225
- ),
226
- defaultMeta: { service: serviceName },
227
- transports,
228
- });
229
-
230
- // Add Sentry transport in production or if SENTRY_DSN is set
231
- // Deferred to avoid circular dependency with sentry.ts
232
- // The check is inside setImmediate to ensure SentryTransport class is fully initialized
233
- setImmediate(() => {
234
- if (isProduction || process.env.SENTRY_DSN) {
235
- try {
236
- const transport = new SentryTransport();
237
- logger.add(transport);
238
- } catch {
239
- // Ignore errors during Sentry transport setup
240
- }
241
- }
242
- });
243
-
244
- return logger;
245
- }
246
-
247
- // Default logger instance for backward compatibility
248
- export const logger = createLogger("shared");
package/src/modules.ts DELETED
@@ -1,184 +0,0 @@
1
- import { createLogger } from "./logger";
2
-
3
- const logger = createLogger("modules");
4
-
5
- // ============================================================================
6
- // Module Type Definitions
7
- // ============================================================================
8
-
9
- export interface ModuleInterface<_TModuleData = unknown> {
10
- /** Module identifier */
11
- name: string;
12
-
13
- /** Check if module should be enabled based on environment */
14
- isEnabled(): boolean;
15
-
16
- /** Initialize module - called once at startup */
17
- init(): Promise<void>;
18
-
19
- /** Register HTTP endpoints with Express app */
20
- registerEndpoints(app: any): void;
21
- }
22
-
23
- export interface WorkerContext {
24
- workspaceDir: string;
25
- userId: string;
26
- conversationId: string;
27
- }
28
-
29
- export interface WorkerModule<TModuleData = unknown>
30
- extends ModuleInterface<TModuleData> {
31
- /** Initialize workspace - called when worker starts session */
32
- initWorkspace(config: any): Promise<void>;
33
-
34
- /** Called at session start - can modify system prompt */
35
- onSessionStart(context: ModuleSessionContext): Promise<ModuleSessionContext>;
36
-
37
- /** Called at session end - can add action buttons */
38
- onSessionEnd(context: ModuleSessionContext): Promise<ActionButton[]>;
39
-
40
- /** Collect module-specific data before sending response. Return null if no data. */
41
- onBeforeResponse(context: WorkerContext): Promise<TModuleData | null>;
42
- }
43
-
44
- export interface ModuleSessionContext {
45
- userId: string;
46
- conversationId: string;
47
- systemPrompt: string;
48
- workspace?: any;
49
- }
50
-
51
- export interface ActionButton {
52
- text: string;
53
- action_id: string;
54
- style?: "primary" | "danger";
55
- value?: string;
56
- url?: string;
57
- }
58
-
59
- // ============================================================================
60
- // Module Registry
61
- // ============================================================================
62
-
63
- export interface IModuleRegistry {
64
- register(module: ModuleInterface): void;
65
- getWorkerModules(): WorkerModule[];
66
- registerAvailableModules(modulePackages?: string[]): Promise<void>;
67
- initAll(): Promise<void>;
68
- registerEndpoints(app: any): void;
69
- /** Return all registered modules as base ModuleInterface array. */
70
- getModules(): ModuleInterface[];
71
- }
72
-
73
- /**
74
- * Module registry for managing plugin modules across the application.
75
- *
76
- * Modules must be explicitly registered by calling `register()` before use.
77
- * This allows each package (dispatcher, worker) to load only the modules it needs.
78
- *
79
- * For production: use the global `moduleRegistry` instance
80
- * For testing: create a new instance to avoid shared state
81
- *
82
- * @example
83
- * // In gateway/worker
84
- * import { MyModule } from './my-module';
85
- * moduleRegistry.register(new MyModule());
86
- * await moduleRegistry.initAll();
87
- *
88
- * @example
89
- * // In tests
90
- * const testRegistry = new ModuleRegistry();
91
- * testRegistry.register(mockModule);
92
- */
93
- export class ModuleRegistry implements IModuleRegistry {
94
- private modules: Map<string, ModuleInterface> = new Map();
95
-
96
- register(module: ModuleInterface): void {
97
- if (module.isEnabled()) {
98
- this.modules.set(module.name, module);
99
- }
100
- }
101
-
102
- /**
103
- * Automatically discover and register available modules.
104
- * Tries to import module packages and registers them if available.
105
- *
106
- * @param modulePackages - List of module package names to try loading.
107
- * Users can provide custom modules to register.
108
- *
109
- * @example
110
- * // Register custom modules
111
- * await moduleRegistry.registerAvailableModules([
112
- * '@mycompany/slack-module',
113
- * '@mycompany/jira-module'
114
- * ]);
115
- */
116
- async registerAvailableModules(modulePackages: string[] = []): Promise<void> {
117
- for (const packageName of modulePackages) {
118
- try {
119
- // Dynamic import to avoid build-time dependencies
120
- const moduleExports = await import(packageName);
121
-
122
- // Try common export patterns
123
- const ModuleClass =
124
- moduleExports.default ||
125
- Object.values(moduleExports).find(
126
- (exp) => typeof exp === "function" && exp.name.endsWith("Module")
127
- );
128
-
129
- if (ModuleClass && typeof ModuleClass === "function") {
130
- const moduleInstance = new (ModuleClass as any)();
131
- if (!this.modules.has(moduleInstance.name)) {
132
- this.register(moduleInstance);
133
- logger.debug(`${packageName} registered`);
134
- }
135
- } else {
136
- logger.debug(`${packageName}: No module class found in exports`);
137
- }
138
- } catch {
139
- logger.debug(`${packageName} not available`);
140
- }
141
- }
142
- }
143
-
144
- async initAll(): Promise<void> {
145
- for (const module of this.modules.values()) {
146
- if (module.init) {
147
- logger.debug(`Initializing module: ${module.name}`);
148
- await module.init();
149
- logger.debug(`Module ${module.name} initialized`);
150
- }
151
- }
152
- }
153
-
154
- registerEndpoints(app: any): void {
155
- for (const module of this.modules.values()) {
156
- if (module.registerEndpoints) {
157
- try {
158
- module.registerEndpoints(app);
159
- } catch (error) {
160
- logger.error(
161
- `Failed to register endpoints for module ${module.name}:`,
162
- error
163
- );
164
- }
165
- }
166
- }
167
- }
168
-
169
- getWorkerModules(): WorkerModule[] {
170
- return Array.from(this.modules.values()).filter(
171
- (m): m is WorkerModule => "onBeforeResponse" in m
172
- );
173
- }
174
-
175
- getModules(): ModuleInterface[] {
176
- return Array.from(this.modules.values());
177
- }
178
- }
179
-
180
- /**
181
- * Global registry instance for production use.
182
- * For testing, create separate instances: `new ModuleRegistry()`
183
- */
184
- export const moduleRegistry = new ModuleRegistry();