@unson/brainbase-mcp 0.10.15 → 0.11.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.
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Small HTTP-host helpers shared by Brainbase servers: a structured error with
3
+ * client-safe JSON, an async route wrapper, and a JSON logger that masks
4
+ * secrets. They carry no organization, tenant, or deployment concept.
5
+ */
6
+ type UnknownRecord = Record<string, unknown>;
7
+ export interface ErrorCodeEntry {
8
+ code: string;
9
+ statusCode: number;
10
+ }
11
+ /** Standard error codes. `code` is safe to expose to clients. */
12
+ export declare const ErrorCodes: {
13
+ VALIDATION_ERROR: {
14
+ code: string;
15
+ statusCode: number;
16
+ };
17
+ INVALID_DATE_FORMAT: {
18
+ code: string;
19
+ statusCode: number;
20
+ };
21
+ MISSING_REQUIRED_FIELD: {
22
+ code: string;
23
+ statusCode: number;
24
+ };
25
+ UNSUPPORTED_FORMAT: {
26
+ code: string;
27
+ statusCode: number;
28
+ };
29
+ UNAUTHORIZED: {
30
+ code: string;
31
+ statusCode: number;
32
+ };
33
+ FORBIDDEN: {
34
+ code: string;
35
+ statusCode: number;
36
+ };
37
+ CROSS_TENANT_CANDIDATE: {
38
+ code: string;
39
+ statusCode: number;
40
+ };
41
+ PROJECT_NOT_FOUND: {
42
+ code: string;
43
+ statusCode: number;
44
+ };
45
+ SESSION_NOT_FOUND: {
46
+ code: string;
47
+ statusCode: number;
48
+ };
49
+ TASK_NOT_FOUND: {
50
+ code: string;
51
+ statusCode: number;
52
+ };
53
+ SCHEDULE_NOT_FOUND: {
54
+ code: string;
55
+ statusCode: number;
56
+ };
57
+ WORKTREE_NOT_FOUND: {
58
+ code: string;
59
+ statusCode: number;
60
+ };
61
+ EVENT_NOT_FOUND: {
62
+ code: string;
63
+ statusCode: number;
64
+ };
65
+ CONFLICT: {
66
+ code: string;
67
+ statusCode: number;
68
+ };
69
+ PORT_IN_USE: {
70
+ code: string;
71
+ statusCode: number;
72
+ };
73
+ INTERNAL_ERROR: {
74
+ code: string;
75
+ statusCode: number;
76
+ };
77
+ DATABASE_ERROR: {
78
+ code: string;
79
+ statusCode: number;
80
+ };
81
+ PROJECT_CATALOG_UNAVAILABLE: {
82
+ code: string;
83
+ statusCode: number;
84
+ };
85
+ TIMEOUT: {
86
+ code: string;
87
+ statusCode: number;
88
+ };
89
+ };
90
+ export interface AppErrorOptions {
91
+ details?: UnknownRecord | null;
92
+ cause?: unknown;
93
+ }
94
+ export interface AppErrorLog {
95
+ code: string;
96
+ message: string;
97
+ statusCode: number;
98
+ timestamp: string;
99
+ details?: UnknownRecord;
100
+ cause?: string;
101
+ }
102
+ /** A structured error: the message and code go to clients, details stay in logs. */
103
+ export declare class AppError extends Error {
104
+ readonly code: string;
105
+ readonly statusCode: number;
106
+ readonly timestamp: string;
107
+ readonly details: UnknownRecord | null;
108
+ cause?: unknown;
109
+ constructor(message: string, errorCode: ErrorCodeEntry, options?: AppErrorOptions);
110
+ /** Client-safe JSON. It never includes details. */
111
+ toJSON(): {
112
+ error: {
113
+ code: string;
114
+ message: string;
115
+ timestamp: string;
116
+ };
117
+ };
118
+ /** Log object, including details and the cause message. */
119
+ toLog(): AppErrorLog;
120
+ static isAppError(error: unknown): error is AppError;
121
+ static notFound(resource: string, id: string): AppError;
122
+ static validation(message: string, details?: UnknownRecord): AppError;
123
+ static unauthorized(message?: string): AppError;
124
+ static forbidden(message?: string, details?: UnknownRecord): AppError;
125
+ static conflict(message: string, details?: UnknownRecord): AppError;
126
+ static internal(message?: string, cause?: Error): AppError;
127
+ }
128
+ type RouteHandler = (req: any, res: any, next: (error?: unknown) => unknown) => unknown;
129
+ /** Wraps an async route handler so that a rejection reaches the error middleware. */
130
+ export declare function asyncHandler(fn: RouteHandler): (req: any, res: any, next: (error?: unknown) => unknown) => void;
131
+ /** JSON-line logger that masks secrets. DEBUG enables debug lines. */
132
+ export declare const logger: {
133
+ info(msg: string, data?: UnknownRecord): void;
134
+ warn(msg: string, data?: UnknownRecord): void;
135
+ error(msg: string, data?: Error | (UnknownRecord & {
136
+ error?: unknown;
137
+ })): void;
138
+ debug(msg: string, data?: UnknownRecord): void;
139
+ };
140
+ export {};
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Small HTTP-host helpers shared by Brainbase servers: a structured error with
3
+ * client-safe JSON, an async route wrapper, and a JSON logger that masks
4
+ * secrets. They carry no organization, tenant, or deployment concept.
5
+ */
6
+ /** Standard error codes. `code` is safe to expose to clients. */
7
+ export const ErrorCodes = {
8
+ VALIDATION_ERROR: { code: 'VALIDATION_ERROR', statusCode: 400 },
9
+ INVALID_DATE_FORMAT: { code: 'INVALID_DATE_FORMAT', statusCode: 400 },
10
+ MISSING_REQUIRED_FIELD: { code: 'MISSING_REQUIRED_FIELD', statusCode: 400 },
11
+ UNSUPPORTED_FORMAT: { code: 'UNSUPPORTED_FORMAT', statusCode: 400 },
12
+ UNAUTHORIZED: { code: 'UNAUTHORIZED', statusCode: 401 },
13
+ FORBIDDEN: { code: 'FORBIDDEN', statusCode: 403 },
14
+ CROSS_TENANT_CANDIDATE: { code: 'CROSS_TENANT_CANDIDATE', statusCode: 403 },
15
+ PROJECT_NOT_FOUND: { code: 'PROJECT_NOT_FOUND', statusCode: 404 },
16
+ SESSION_NOT_FOUND: { code: 'SESSION_NOT_FOUND', statusCode: 404 },
17
+ TASK_NOT_FOUND: { code: 'TASK_NOT_FOUND', statusCode: 404 },
18
+ SCHEDULE_NOT_FOUND: { code: 'SCHEDULE_NOT_FOUND', statusCode: 404 },
19
+ WORKTREE_NOT_FOUND: { code: 'WORKTREE_NOT_FOUND', statusCode: 404 },
20
+ EVENT_NOT_FOUND: { code: 'EVENT_NOT_FOUND', statusCode: 404 },
21
+ CONFLICT: { code: 'CONFLICT', statusCode: 409 },
22
+ PORT_IN_USE: { code: 'PORT_IN_USE', statusCode: 409 },
23
+ INTERNAL_ERROR: { code: 'INTERNAL_ERROR', statusCode: 500 },
24
+ DATABASE_ERROR: { code: 'DATABASE_ERROR', statusCode: 500 },
25
+ PROJECT_CATALOG_UNAVAILABLE: { code: 'PROJECT_CATALOG_UNAVAILABLE', statusCode: 503 },
26
+ TIMEOUT: { code: 'TIMEOUT', statusCode: 504 },
27
+ };
28
+ /** A structured error: the message and code go to clients, details stay in logs. */
29
+ export class AppError extends Error {
30
+ code;
31
+ statusCode;
32
+ timestamp;
33
+ details;
34
+ cause;
35
+ constructor(message, errorCode, options = {}) {
36
+ super(message);
37
+ this.name = 'AppError';
38
+ this.code = errorCode.code;
39
+ this.statusCode = errorCode.statusCode;
40
+ this.timestamp = new Date().toISOString();
41
+ this.details = options.details || null;
42
+ if (options.cause)
43
+ this.cause = options.cause;
44
+ }
45
+ /** Client-safe JSON. It never includes details. */
46
+ toJSON() {
47
+ return { error: { code: this.code, message: this.message, timestamp: this.timestamp } };
48
+ }
49
+ /** Log object, including details and the cause message. */
50
+ toLog() {
51
+ const log = {
52
+ code: this.code,
53
+ message: this.message,
54
+ statusCode: this.statusCode,
55
+ timestamp: this.timestamp,
56
+ };
57
+ if (this.details)
58
+ log.details = this.details;
59
+ if (this.cause)
60
+ log.cause = this.cause instanceof Error ? this.cause.message : String(this.cause);
61
+ return log;
62
+ }
63
+ static isAppError(error) {
64
+ return error instanceof AppError;
65
+ }
66
+ static notFound(resource, id) {
67
+ const dynamicCode = ErrorCodes[`${resource.toUpperCase()}_NOT_FOUND`];
68
+ return new AppError(`${resource} '${id}' not found`, dynamicCode || ErrorCodes.SESSION_NOT_FOUND);
69
+ }
70
+ static validation(message, details) {
71
+ return new AppError(message, ErrorCodes.VALIDATION_ERROR, { details });
72
+ }
73
+ static unauthorized(message = 'Unauthorized') {
74
+ return new AppError(message, ErrorCodes.UNAUTHORIZED);
75
+ }
76
+ static forbidden(message = 'Forbidden', details) {
77
+ return new AppError(message, ErrorCodes.FORBIDDEN, { details });
78
+ }
79
+ static conflict(message, details) {
80
+ return new AppError(message, ErrorCodes.CONFLICT, { details });
81
+ }
82
+ static internal(message = 'Internal server error', cause) {
83
+ return new AppError(message, ErrorCodes.INTERNAL_ERROR, { cause });
84
+ }
85
+ }
86
+ /** Wraps an async route handler so that a rejection reaches the error middleware. */
87
+ export function asyncHandler(fn) {
88
+ return (req, res, next) => {
89
+ Promise.resolve(fn(req, res, next)).catch((error) => {
90
+ next(error);
91
+ });
92
+ };
93
+ }
94
+ const SENSITIVE_KEYS = [
95
+ 'password', 'token', 'secret', 'key', 'credential', 'auth', 'apikey', 'api_key',
96
+ 'access_token', 'refresh_token', 'private', 'cookie', 'session',
97
+ ];
98
+ const SENSITIVE_PATH_PATTERNS = [/\/\.env/, /\/credentials/, /\/secrets/, /\/\.ssh/, /\/\.gnupg/];
99
+ function redact(value, depth = 0) {
100
+ if (depth > 10)
101
+ return '[MAX_DEPTH]';
102
+ if (value === null || value === undefined)
103
+ return value;
104
+ if (typeof value !== 'object') {
105
+ if (typeof value === 'string') {
106
+ if (/^eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+$/.test(value))
107
+ return '[JWT_REDACTED]';
108
+ if (/^[a-fA-F0-9]{32,}$/.test(value))
109
+ return '[HEX_KEY_REDACTED]';
110
+ if (SENSITIVE_PATH_PATTERNS.some((pattern) => pattern.test(value)))
111
+ return '[SENSITIVE_PATH_REDACTED]';
112
+ }
113
+ return value;
114
+ }
115
+ if (Array.isArray(value))
116
+ return value.map((item) => redact(item, depth + 1));
117
+ const result = {};
118
+ for (const [key, item] of Object.entries(value)) {
119
+ const lowerKey = key.toLowerCase();
120
+ result[key] = SENSITIVE_KEYS.some((sensitive) => lowerKey.includes(sensitive)) ? '[REDACTED]' : redact(item, depth + 1);
121
+ }
122
+ return result;
123
+ }
124
+ function formatLog(level, msg, data = {}) {
125
+ const masked = redact(data);
126
+ return JSON.stringify({
127
+ timestamp: new Date().toISOString(),
128
+ level,
129
+ msg,
130
+ ...(masked && typeof masked === 'object' && !Array.isArray(masked) ? masked : {}),
131
+ });
132
+ }
133
+ /** JSON-line logger that masks secrets. DEBUG enables debug lines. */
134
+ export const logger = {
135
+ info(msg, data = {}) {
136
+ console.log(formatLog('info', msg, data));
137
+ },
138
+ warn(msg, data = {}) {
139
+ console.warn(formatLog('warn', msg, data));
140
+ },
141
+ error(msg, data = {}) {
142
+ let entry;
143
+ if (data instanceof Error) {
144
+ entry = { error: data.message, stack: data.stack };
145
+ }
146
+ else if (data.error instanceof Error) {
147
+ entry = { ...data, error: data.error.message, stack: data.error.stack };
148
+ }
149
+ else {
150
+ entry = data;
151
+ }
152
+ console.error(formatLog('error', msg, entry));
153
+ },
154
+ debug(msg, data = {}) {
155
+ if (process.env.DEBUG)
156
+ console.log(formatLog('debug', msg, data));
157
+ },
158
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unson/brainbase-mcp",
3
- "version": "0.10.15",
3
+ "version": "0.11.0",
4
4
  "description": "Local-first Brainbase judgment OS that lets supported AI agents reuse a user's approved goals, priorities, decisions, and judgment criteria.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -191,6 +191,10 @@
191
191
  "types": "./dist/execution-authority-http.d.ts",
192
192
  "import": "./dist/execution-authority-http.js"
193
193
  },
194
+ "./server-support": {
195
+ "types": "./dist/server-support.d.ts",
196
+ "import": "./dist/server-support.js"
197
+ },
194
198
  "./company-os-impact-review": {
195
199
  "types": "./dist/company-os-impact-review.d.ts",
196
200
  "import": "./dist/company-os-impact-review.js"
@@ -344,5 +348,5 @@
344
348
  "engines": {
345
349
  "node": ">=20"
346
350
  },
347
- "gitHead": "04f1192c75877ca241970ee379c274e37c6693cc"
351
+ "gitHead": "070f39f8014fbbe224bb4615ef89999aeeb8d0a5"
348
352
  }