@cyanheads/pubchem-mcp-server 1.0.1
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/LICENSE +201 -0
- package/README.md +236 -0
- package/dist/config/index.d.ts +98 -0
- package/dist/config/index.js +326 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +214 -0
- package/dist/mcp-server/server.d.ts +21 -0
- package/dist/mcp-server/server.js +124 -0
- package/dist/mcp-server/tools/fetchAssaySummary/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchAssaySummary/index.js +7 -0
- package/dist/mcp-server/tools/fetchAssaySummary/logic.d.ts +71 -0
- package/dist/mcp-server/tools/fetchAssaySummary/logic.js +96 -0
- package/dist/mcp-server/tools/fetchAssaySummary/registration.d.ts +12 -0
- package/dist/mcp-server/tools/fetchAssaySummary/registration.js +68 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/index.js +7 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/logic.d.ts +131 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/logic.js +100 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/registration.d.ts +13 -0
- package/dist/mcp-server/tools/fetchCompoundProperties/registration.js +52 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/index.js +7 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/logic.d.ts +89 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/logic.js +145 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/registration.d.ts +13 -0
- package/dist/mcp-server/tools/fetchCompoundXrefs/registration.js +52 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/index.d.ts +7 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/index.js +7 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/logic.d.ts +69 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/logic.js +97 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/registration.d.ts +13 -0
- package/dist/mcp-server/tools/fetchSubstanceDetails/registration.js +79 -0
- package/dist/mcp-server/tools/getCompoundImage/index.d.ts +7 -0
- package/dist/mcp-server/tools/getCompoundImage/index.js +7 -0
- package/dist/mcp-server/tools/getCompoundImage/logic.d.ts +42 -0
- package/dist/mcp-server/tools/getCompoundImage/logic.js +68 -0
- package/dist/mcp-server/tools/getCompoundImage/registration.d.ts +12 -0
- package/dist/mcp-server/tools/getCompoundImage/registration.js +57 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/index.js +7 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/logic.d.ts +35 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/logic.js +64 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchAssaysByTarget/registration.js +62 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/logic.d.ts +35 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/logic.js +59 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchCompoundByIdentifier/registration.js +51 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/logic.d.ts +38 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/logic.js +75 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchCompoundsByFormula/registration.js +62 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/logic.d.ts +41 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/logic.js +82 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/registration.d.ts +12 -0
- package/dist/mcp-server/tools/searchCompoundsBySimilarity/registration.js +62 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/index.d.ts +7 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/index.js +7 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/logic.d.ts +41 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/logic.js +78 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/registration.d.ts +13 -0
- package/dist/mcp-server/tools/searchCompoundsByStructure/registration.js +63 -0
- package/dist/mcp-server/transports/auth/core/authContext.d.ts +33 -0
- package/dist/mcp-server/transports/auth/core/authContext.js +24 -0
- package/dist/mcp-server/transports/auth/core/authTypes.d.ts +17 -0
- package/dist/mcp-server/transports/auth/core/authTypes.js +5 -0
- package/dist/mcp-server/transports/auth/core/authUtils.d.ts +18 -0
- package/dist/mcp-server/transports/auth/core/authUtils.js +45 -0
- package/dist/mcp-server/transports/auth/index.d.ts +10 -0
- package/dist/mcp-server/transports/auth/index.js +9 -0
- package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.d.ts +27 -0
- package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.js +149 -0
- package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.d.ts +20 -0
- package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.js +124 -0
- package/dist/mcp-server/transports/httpErrorHandler.d.ts +26 -0
- package/dist/mcp-server/transports/httpErrorHandler.js +73 -0
- package/dist/mcp-server/transports/httpTransport.d.ts +21 -0
- package/dist/mcp-server/transports/httpTransport.js +208 -0
- package/dist/mcp-server/transports/stdioTransport.d.ts +42 -0
- package/dist/mcp-server/transports/stdioTransport.js +63 -0
- package/dist/services/pubchem/pubchemApiClient.d.ts +52 -0
- package/dist/services/pubchem/pubchemApiClient.js +120 -0
- package/dist/types-global/errors.d.ts +127 -0
- package/dist/types-global/errors.js +126 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.js +20 -0
- package/dist/utils/internal/errorHandler.d.ts +176 -0
- package/dist/utils/internal/errorHandler.js +335 -0
- package/dist/utils/internal/index.d.ts +9 -0
- package/dist/utils/internal/index.js +9 -0
- package/dist/utils/internal/logger.d.ts +148 -0
- package/dist/utils/internal/logger.js +430 -0
- package/dist/utils/internal/requestContext.d.ts +83 -0
- package/dist/utils/internal/requestContext.js +72 -0
- package/dist/utils/metrics/index.d.ts +7 -0
- package/dist/utils/metrics/index.js +7 -0
- package/dist/utils/metrics/tokenCounter.d.ts +35 -0
- package/dist/utils/metrics/tokenCounter.js +110 -0
- package/dist/utils/network/fetchWithTimeout.d.ts +21 -0
- package/dist/utils/network/fetchWithTimeout.js +59 -0
- package/dist/utils/network/index.d.ts +6 -0
- package/dist/utils/network/index.js +5 -0
- package/dist/utils/parsing/dateParser.d.ts +73 -0
- package/dist/utils/parsing/dateParser.js +107 -0
- package/dist/utils/parsing/index.d.ts +8 -0
- package/dist/utils/parsing/index.js +8 -0
- package/dist/utils/parsing/jsonParser.d.ts +82 -0
- package/dist/utils/parsing/jsonParser.js +126 -0
- package/dist/utils/scheduling/index.d.ts +6 -0
- package/dist/utils/scheduling/index.js +6 -0
- package/dist/utils/scheduling/scheduler.d.ts +72 -0
- package/dist/utils/scheduling/scheduler.js +152 -0
- package/dist/utils/security/idGenerator.d.ts +137 -0
- package/dist/utils/security/idGenerator.js +215 -0
- package/dist/utils/security/index.d.ts +9 -0
- package/dist/utils/security/index.js +9 -0
- package/dist/utils/security/rateLimiter.d.ts +108 -0
- package/dist/utils/security/rateLimiter.js +179 -0
- package/dist/utils/security/sanitization.d.ts +184 -0
- package/dist/utils/security/sanitization.js +453 -0
- package/package.json +108 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a utility class for parsing potentially partial JSON strings.
|
|
3
|
+
* It wraps the 'partial-json' npm library and includes functionality to handle
|
|
4
|
+
* optional <think>...</think> blocks often found at the beginning of LLM outputs.
|
|
5
|
+
* @module src/utils/parsing/jsonParser
|
|
6
|
+
*/
|
|
7
|
+
import { parse as parsePartialJson, Allow as PartialJsonAllow, } from "partial-json";
|
|
8
|
+
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
|
|
9
|
+
import { logger, requestContextService } from "../index.js";
|
|
10
|
+
/**
|
|
11
|
+
* Enum mirroring `partial-json`'s `Allow` constants. These specify
|
|
12
|
+
* what types of partial JSON structures are permissible during parsing.
|
|
13
|
+
* They can be combined using bitwise OR (e.g., `Allow.STR | Allow.OBJ`).
|
|
14
|
+
*
|
|
15
|
+
* The available properties are:
|
|
16
|
+
* - `STR`: Allow partial string.
|
|
17
|
+
* - `NUM`: Allow partial number.
|
|
18
|
+
* - `ARR`: Allow partial array.
|
|
19
|
+
* - `OBJ`: Allow partial object.
|
|
20
|
+
* - `NULL`: Allow partial null.
|
|
21
|
+
* - `BOOL`: Allow partial boolean.
|
|
22
|
+
* - `NAN`: Allow partial NaN. (Note: Standard JSON does not support NaN)
|
|
23
|
+
* - `INFINITY`: Allow partial Infinity. (Note: Standard JSON does not support Infinity)
|
|
24
|
+
* - `_INFINITY`: Allow partial -Infinity. (Note: Standard JSON does not support -Infinity)
|
|
25
|
+
* - `INF`: Allow both partial Infinity and -Infinity.
|
|
26
|
+
* - `SPECIAL`: Allow all special values (NaN, Infinity, -Infinity).
|
|
27
|
+
* - `ATOM`: Allow all atomic values (strings, numbers, booleans, null, special values).
|
|
28
|
+
* - `COLLECTION`: Allow all collection values (objects, arrays).
|
|
29
|
+
* - `ALL`: Allow all value types to be partial (default for `partial-json`'s parse).
|
|
30
|
+
* @see {@link https://github.com/promplate/partial-json-parser-js} for more details.
|
|
31
|
+
*/
|
|
32
|
+
export const Allow = PartialJsonAllow;
|
|
33
|
+
/**
|
|
34
|
+
* Regular expression to find a <think> block at the start of a string.
|
|
35
|
+
* Captures content within <think>...</think> (Group 1) and the rest of the string (Group 2).
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
const thinkBlockRegex = /^<think>([\s\S]*?)<\/think>\s*([\s\S]*)$/;
|
|
39
|
+
/**
|
|
40
|
+
* Utility class for parsing potentially partial JSON strings.
|
|
41
|
+
* Wraps the 'partial-json' library for robust JSON parsing, handling
|
|
42
|
+
* incomplete structures and optional <think> blocks from LLMs.
|
|
43
|
+
*/
|
|
44
|
+
export class JsonParser {
|
|
45
|
+
/**
|
|
46
|
+
* Parses a JSON string, which may be partial or prefixed with a <think> block.
|
|
47
|
+
* If a <think> block is present, its content is logged, and parsing proceeds on the
|
|
48
|
+
* remainder. Uses 'partial-json' to handle incomplete JSON.
|
|
49
|
+
*
|
|
50
|
+
* @template T The expected type of the parsed JSON object. Defaults to `any`.
|
|
51
|
+
* @param jsonString - The JSON string to parse.
|
|
52
|
+
* @param allowPartial - Bitwise OR combination of `Allow` constants specifying permissible
|
|
53
|
+
* partial JSON types. Defaults to `Allow.ALL`.
|
|
54
|
+
* @param context - Optional `RequestContext` for logging and error correlation.
|
|
55
|
+
* @returns The parsed JavaScript value.
|
|
56
|
+
* @throws {McpError} If the string is empty after processing or if `partial-json` fails.
|
|
57
|
+
*/
|
|
58
|
+
parse(jsonString, allowPartial = Allow.ALL, context) {
|
|
59
|
+
let stringToParse = jsonString;
|
|
60
|
+
const match = jsonString.match(thinkBlockRegex);
|
|
61
|
+
if (match) {
|
|
62
|
+
const thinkContent = match[1].trim();
|
|
63
|
+
const restOfString = match[2];
|
|
64
|
+
const logContext = context ||
|
|
65
|
+
requestContextService.createRequestContext({
|
|
66
|
+
operation: "JsonParser.thinkBlock",
|
|
67
|
+
});
|
|
68
|
+
if (thinkContent) {
|
|
69
|
+
logger.debug("LLM <think> block detected and logged.", {
|
|
70
|
+
...logContext,
|
|
71
|
+
thinkContent,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
logger.debug("Empty LLM <think> block detected.", logContext);
|
|
76
|
+
}
|
|
77
|
+
stringToParse = restOfString;
|
|
78
|
+
}
|
|
79
|
+
stringToParse = stringToParse.trim();
|
|
80
|
+
if (!stringToParse) {
|
|
81
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, "JSON string is empty after removing <think> block and trimming.", context);
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
return parsePartialJson(stringToParse, allowPartial);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
const errorLogContext = context ||
|
|
88
|
+
requestContextService.createRequestContext({
|
|
89
|
+
operation: "JsonParser.parseError",
|
|
90
|
+
});
|
|
91
|
+
logger.error("Failed to parse JSON content.", {
|
|
92
|
+
...errorLogContext,
|
|
93
|
+
errorDetails: error.message,
|
|
94
|
+
contentAttempted: stringToParse.substring(0, 200),
|
|
95
|
+
});
|
|
96
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Failed to parse JSON: ${error.message}`, {
|
|
97
|
+
...context,
|
|
98
|
+
originalContentSample: stringToParse.substring(0, 200) +
|
|
99
|
+
(stringToParse.length > 200 ? "..." : ""),
|
|
100
|
+
rawError: error instanceof Error ? error.stack : String(error),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Singleton instance of the `JsonParser`.
|
|
107
|
+
* Use this instance to parse JSON strings, with support for partial JSON and <think> blocks.
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* import { jsonParser, Allow, requestContextService } from './utils';
|
|
111
|
+
* const context = requestContextService.createRequestContext({ operation: 'TestJsonParsing' });
|
|
112
|
+
*
|
|
113
|
+
* const fullJson = '{"key": "value"}';
|
|
114
|
+
* const parsedFull = jsonParser.parse(fullJson, Allow.ALL, context);
|
|
115
|
+
* console.log(parsedFull); // Output: { key: 'value' }
|
|
116
|
+
*
|
|
117
|
+
* const partialObject = '<think>This is a thought.</think>{"key": "value", "arr": [1,';
|
|
118
|
+
* try {
|
|
119
|
+
* const parsedPartial = jsonParser.parse(partialObject, undefined, context);
|
|
120
|
+
* console.log(parsedPartial);
|
|
121
|
+
* } catch (e) {
|
|
122
|
+
* console.error("Parsing partial object failed:", e);
|
|
123
|
+
* }
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export const jsonParser = new JsonParser();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a singleton service for scheduling and managing cron jobs.
|
|
3
|
+
* This service wraps the 'node-cron' library to offer a unified interface for
|
|
4
|
+
* defining, starting, stopping, and listing recurring tasks within the application.
|
|
5
|
+
* @module src/utils/scheduling/scheduler
|
|
6
|
+
*/
|
|
7
|
+
import { ScheduledTask } from "node-cron";
|
|
8
|
+
import { RequestContext } from "../internal/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Represents a scheduled job managed by the SchedulerService.
|
|
11
|
+
*/
|
|
12
|
+
export interface Job {
|
|
13
|
+
/** A unique identifier for the job. */
|
|
14
|
+
id: string;
|
|
15
|
+
/** The cron pattern defining the job's schedule. */
|
|
16
|
+
schedule: string;
|
|
17
|
+
/** A description of what the job does. */
|
|
18
|
+
description: string;
|
|
19
|
+
/** The underlying 'node-cron' task instance. */
|
|
20
|
+
task: ScheduledTask;
|
|
21
|
+
/** Indicates whether the job is currently running. */
|
|
22
|
+
isRunning: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A singleton service for scheduling and managing cron jobs.
|
|
26
|
+
*/
|
|
27
|
+
export declare class SchedulerService {
|
|
28
|
+
private static instance;
|
|
29
|
+
private jobs;
|
|
30
|
+
/** @private */
|
|
31
|
+
private constructor();
|
|
32
|
+
/**
|
|
33
|
+
* Gets the singleton instance of the SchedulerService.
|
|
34
|
+
* @returns The singleton SchedulerService instance.
|
|
35
|
+
*/
|
|
36
|
+
static getInstance(): SchedulerService;
|
|
37
|
+
/**
|
|
38
|
+
* Schedules a new job.
|
|
39
|
+
*
|
|
40
|
+
* @param id - A unique identifier for the job.
|
|
41
|
+
* @param schedule - The cron pattern for the schedule (e.g., '* * * * *').
|
|
42
|
+
* @param taskFunction - The function to execute on schedule. It receives a RequestContext.
|
|
43
|
+
* @param description - A description of the job.
|
|
44
|
+
* @returns The newly created Job object.
|
|
45
|
+
*/
|
|
46
|
+
schedule(id: string, schedule: string, taskFunction: (context: RequestContext) => void | Promise<void>, description: string): Job;
|
|
47
|
+
/**
|
|
48
|
+
* Starts a scheduled job.
|
|
49
|
+
* @param id - The ID of the job to start.
|
|
50
|
+
*/
|
|
51
|
+
start(id: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Stops a scheduled job.
|
|
54
|
+
* @param id - The ID of the job to stop.
|
|
55
|
+
*/
|
|
56
|
+
stop(id: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Removes a job from the scheduler. The job is stopped before being removed.
|
|
59
|
+
* @param id - The ID of the job to remove.
|
|
60
|
+
*/
|
|
61
|
+
remove(id: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Gets a list of all scheduled jobs.
|
|
64
|
+
* @returns An array of all Job objects.
|
|
65
|
+
*/
|
|
66
|
+
listJobs(): Job[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The singleton instance of the SchedulerService.
|
|
70
|
+
* Use this instance for all job scheduling operations.
|
|
71
|
+
*/
|
|
72
|
+
export declare const schedulerService: SchedulerService;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a singleton service for scheduling and managing cron jobs.
|
|
3
|
+
* This service wraps the 'node-cron' library to offer a unified interface for
|
|
4
|
+
* defining, starting, stopping, and listing recurring tasks within the application.
|
|
5
|
+
* @module src/utils/scheduling/scheduler
|
|
6
|
+
*/
|
|
7
|
+
import cron from "node-cron";
|
|
8
|
+
import { logger } from "../internal/index.js";
|
|
9
|
+
import { requestContextService } from "../internal/requestContext.js";
|
|
10
|
+
/**
|
|
11
|
+
* A singleton service for scheduling and managing cron jobs.
|
|
12
|
+
*/
|
|
13
|
+
export class SchedulerService {
|
|
14
|
+
/** @private */
|
|
15
|
+
constructor() {
|
|
16
|
+
this.jobs = new Map();
|
|
17
|
+
logger.info("SchedulerService initialized.", {
|
|
18
|
+
requestId: "scheduler-init",
|
|
19
|
+
timestamp: new Date().toISOString(),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gets the singleton instance of the SchedulerService.
|
|
24
|
+
* @returns The singleton SchedulerService instance.
|
|
25
|
+
*/
|
|
26
|
+
static getInstance() {
|
|
27
|
+
if (!SchedulerService.instance) {
|
|
28
|
+
SchedulerService.instance = new SchedulerService();
|
|
29
|
+
}
|
|
30
|
+
return SchedulerService.instance;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Schedules a new job.
|
|
34
|
+
*
|
|
35
|
+
* @param id - A unique identifier for the job.
|
|
36
|
+
* @param schedule - The cron pattern for the schedule (e.g., '* * * * *').
|
|
37
|
+
* @param taskFunction - The function to execute on schedule. It receives a RequestContext.
|
|
38
|
+
* @param description - A description of the job.
|
|
39
|
+
* @returns The newly created Job object.
|
|
40
|
+
*/
|
|
41
|
+
schedule(id, schedule, taskFunction, description) {
|
|
42
|
+
if (this.jobs.has(id)) {
|
|
43
|
+
throw new Error(`Job with ID '${id}' already exists.`);
|
|
44
|
+
}
|
|
45
|
+
if (!cron.validate(schedule)) {
|
|
46
|
+
throw new Error(`Invalid cron schedule: ${schedule}`);
|
|
47
|
+
}
|
|
48
|
+
const task = cron.schedule(schedule, async () => {
|
|
49
|
+
const job = this.jobs.get(id);
|
|
50
|
+
if (job && job.isRunning) {
|
|
51
|
+
logger.warning(`Job '${id}' is already running. Skipping this execution.`, {
|
|
52
|
+
requestId: `job-skip-${id}`,
|
|
53
|
+
timestamp: new Date().toISOString(),
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (job) {
|
|
58
|
+
job.isRunning = true;
|
|
59
|
+
}
|
|
60
|
+
const context = requestContextService.createRequestContext({
|
|
61
|
+
jobId: id,
|
|
62
|
+
schedule,
|
|
63
|
+
});
|
|
64
|
+
logger.info(`Starting job '${id}'...`, context);
|
|
65
|
+
try {
|
|
66
|
+
await Promise.resolve(taskFunction(context));
|
|
67
|
+
logger.info(`Job '${id}' completed successfully.`, context);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
logger.error(`Job '${id}' failed.`, error, context);
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
if (job) {
|
|
74
|
+
job.isRunning = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}, {
|
|
78
|
+
scheduled: false, // Do not start immediately
|
|
79
|
+
});
|
|
80
|
+
const newJob = {
|
|
81
|
+
id,
|
|
82
|
+
schedule,
|
|
83
|
+
description,
|
|
84
|
+
task,
|
|
85
|
+
isRunning: false,
|
|
86
|
+
};
|
|
87
|
+
this.jobs.set(id, newJob);
|
|
88
|
+
logger.info(`Job '${id}' scheduled: ${description}`, {
|
|
89
|
+
requestId: `job-schedule-${id}`,
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
});
|
|
92
|
+
return newJob;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Starts a scheduled job.
|
|
96
|
+
* @param id - The ID of the job to start.
|
|
97
|
+
*/
|
|
98
|
+
start(id) {
|
|
99
|
+
const job = this.jobs.get(id);
|
|
100
|
+
if (!job) {
|
|
101
|
+
throw new Error(`Job with ID '${id}' not found.`);
|
|
102
|
+
}
|
|
103
|
+
job.task.start();
|
|
104
|
+
logger.info(`Job '${id}' started.`, {
|
|
105
|
+
requestId: `job-start-${id}`,
|
|
106
|
+
timestamp: new Date().toISOString(),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Stops a scheduled job.
|
|
111
|
+
* @param id - The ID of the job to stop.
|
|
112
|
+
*/
|
|
113
|
+
stop(id) {
|
|
114
|
+
const job = this.jobs.get(id);
|
|
115
|
+
if (!job) {
|
|
116
|
+
throw new Error(`Job with ID '${id}' not found.`);
|
|
117
|
+
}
|
|
118
|
+
job.task.stop();
|
|
119
|
+
logger.info(`Job '${id}' stopped.`, {
|
|
120
|
+
requestId: `job-stop-${id}`,
|
|
121
|
+
timestamp: new Date().toISOString(),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Removes a job from the scheduler. The job is stopped before being removed.
|
|
126
|
+
* @param id - The ID of the job to remove.
|
|
127
|
+
*/
|
|
128
|
+
remove(id) {
|
|
129
|
+
const job = this.jobs.get(id);
|
|
130
|
+
if (!job) {
|
|
131
|
+
throw new Error(`Job with ID '${id}' not found.`);
|
|
132
|
+
}
|
|
133
|
+
job.task.stop();
|
|
134
|
+
this.jobs.delete(id);
|
|
135
|
+
logger.info(`Job '${id}' removed.`, {
|
|
136
|
+
requestId: `job-remove-${id}`,
|
|
137
|
+
timestamp: new Date().toISOString(),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Gets a list of all scheduled jobs.
|
|
142
|
+
* @returns An array of all Job objects.
|
|
143
|
+
*/
|
|
144
|
+
listJobs() {
|
|
145
|
+
return Array.from(this.jobs.values());
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The singleton instance of the SchedulerService.
|
|
150
|
+
* Use this instance for all job scheduling operations.
|
|
151
|
+
*/
|
|
152
|
+
export const schedulerService = SchedulerService.getInstance();
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines the structure for configuring entity prefixes.
|
|
3
|
+
* Keys are entity type names (e.g., "project", "task"), and values are their corresponding ID prefixes (e.g., "PROJ", "TASK").
|
|
4
|
+
*/
|
|
5
|
+
export interface EntityPrefixConfig {
|
|
6
|
+
[key: string]: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Defines options for customizing ID generation.
|
|
10
|
+
*/
|
|
11
|
+
export interface IdGenerationOptions {
|
|
12
|
+
length?: number;
|
|
13
|
+
separator?: string;
|
|
14
|
+
charset?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A generic ID Generator class for creating and managing unique, prefixed identifiers.
|
|
18
|
+
* Allows defining custom prefixes, generating random strings, and validating/normalizing IDs.
|
|
19
|
+
*/
|
|
20
|
+
export declare class IdGenerator {
|
|
21
|
+
/**
|
|
22
|
+
* Default character set for the random part of the ID.
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
25
|
+
private static DEFAULT_CHARSET;
|
|
26
|
+
/**
|
|
27
|
+
* Default separator character between prefix and random part.
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
private static DEFAULT_SEPARATOR;
|
|
31
|
+
/**
|
|
32
|
+
* Default length for the random part of the ID.
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
private static DEFAULT_LENGTH;
|
|
36
|
+
/**
|
|
37
|
+
* Stores the mapping of entity types to their prefixes.
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
private entityPrefixes;
|
|
41
|
+
/**
|
|
42
|
+
* Stores a reverse mapping from prefixes (case-insensitive) to entity types.
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
45
|
+
private prefixToEntityType;
|
|
46
|
+
/**
|
|
47
|
+
* Constructs an `IdGenerator` instance.
|
|
48
|
+
* @param entityPrefixes - An initial map of entity types to their prefixes.
|
|
49
|
+
*/
|
|
50
|
+
constructor(entityPrefixes?: EntityPrefixConfig);
|
|
51
|
+
/**
|
|
52
|
+
* Sets or updates the entity prefix configuration and rebuilds the internal reverse lookup map.
|
|
53
|
+
* @param entityPrefixes - A map where keys are entity type names and values are their desired ID prefixes.
|
|
54
|
+
*/
|
|
55
|
+
setEntityPrefixes(entityPrefixes: EntityPrefixConfig): void;
|
|
56
|
+
/**
|
|
57
|
+
* Retrieves a copy of the current entity prefix configuration.
|
|
58
|
+
* @returns The current entity prefix configuration.
|
|
59
|
+
*/
|
|
60
|
+
getEntityPrefixes(): EntityPrefixConfig;
|
|
61
|
+
/**
|
|
62
|
+
* Generates a cryptographically secure random string.
|
|
63
|
+
* @param length - The desired length of the random string. Defaults to `IdGenerator.DEFAULT_LENGTH`.
|
|
64
|
+
* @param charset - The character set to use. Defaults to `IdGenerator.DEFAULT_CHARSET`.
|
|
65
|
+
* @returns The generated random string.
|
|
66
|
+
*/
|
|
67
|
+
generateRandomString(length?: number, charset?: string): string;
|
|
68
|
+
/**
|
|
69
|
+
* Generates a unique ID, optionally prepended with a prefix.
|
|
70
|
+
* @param prefix - An optional prefix for the ID.
|
|
71
|
+
* @param options - Optional parameters for ID generation (length, separator, charset).
|
|
72
|
+
* @returns A unique identifier string.
|
|
73
|
+
*/
|
|
74
|
+
generate(prefix?: string, options?: IdGenerationOptions): string;
|
|
75
|
+
/**
|
|
76
|
+
* Generates a unique ID for a specified entity type, using its configured prefix.
|
|
77
|
+
* @param entityType - The type of entity (must be registered).
|
|
78
|
+
* @param options - Optional parameters for ID generation.
|
|
79
|
+
* @returns A unique identifier string for the entity (e.g., "PROJ_A6B3J0").
|
|
80
|
+
* @throws {McpError} If the `entityType` is not registered.
|
|
81
|
+
*/
|
|
82
|
+
generateForEntity(entityType: string, options?: IdGenerationOptions): string;
|
|
83
|
+
/**
|
|
84
|
+
* Validates if an ID conforms to the expected format for a specific entity type.
|
|
85
|
+
* @param id - The ID string to validate.
|
|
86
|
+
* @param entityType - The expected entity type of the ID.
|
|
87
|
+
* @param options - Optional parameters used during generation for validation consistency.
|
|
88
|
+
* The `charset` from these options will be used for validation.
|
|
89
|
+
* @returns `true` if the ID is valid, `false` otherwise.
|
|
90
|
+
*/
|
|
91
|
+
isValid(id: string, entityType: string, options?: IdGenerationOptions): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Escapes special characters in a string for use in a regular expression.
|
|
94
|
+
* @param str - The string to escape.
|
|
95
|
+
* @returns The escaped string.
|
|
96
|
+
* @private
|
|
97
|
+
*/
|
|
98
|
+
private escapeRegex;
|
|
99
|
+
/**
|
|
100
|
+
* Strips the prefix and separator from an ID string.
|
|
101
|
+
* @param id - The ID string (e.g., "PROJ_A6B3J0").
|
|
102
|
+
* @param separator - The separator used in the ID. Defaults to `IdGenerator.DEFAULT_SEPARATOR`.
|
|
103
|
+
* @returns The ID part without the prefix, or the original ID if separator not found.
|
|
104
|
+
*/
|
|
105
|
+
stripPrefix(id: string, separator?: string): string;
|
|
106
|
+
/**
|
|
107
|
+
* Determines the entity type from an ID string by its prefix (case-insensitive).
|
|
108
|
+
* @param id - The ID string (e.g., "PROJ_A6B3J0").
|
|
109
|
+
* @param separator - The separator used in the ID. Defaults to `IdGenerator.DEFAULT_SEPARATOR`.
|
|
110
|
+
* @returns The determined entity type.
|
|
111
|
+
* @throws {McpError} If ID format is invalid or prefix is unknown.
|
|
112
|
+
*/
|
|
113
|
+
getEntityType(id: string, separator?: string): string;
|
|
114
|
+
/**
|
|
115
|
+
* Normalizes an entity ID to ensure the prefix matches the registered case
|
|
116
|
+
* and the random part is uppercase. Note: This assumes the charset characters
|
|
117
|
+
* have a meaningful uppercase version if case-insensitivity is desired for the random part.
|
|
118
|
+
* For default charset (A-Z0-9), this is fine. For custom charsets, behavior might vary.
|
|
119
|
+
* @param id - The ID to normalize (e.g., "proj_a6b3j0").
|
|
120
|
+
* @param separator - The separator used in the ID. Defaults to `IdGenerator.DEFAULT_SEPARATOR`.
|
|
121
|
+
* @returns The normalized ID (e.g., "PROJ_A6B3J0").
|
|
122
|
+
* @throws {McpError} If the entity type cannot be determined from the ID.
|
|
123
|
+
*/
|
|
124
|
+
normalize(id: string, separator?: string): string;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Default singleton instance of the `IdGenerator`.
|
|
128
|
+
* Initialize with `idGenerator.setEntityPrefixes({})` to configure.
|
|
129
|
+
*/
|
|
130
|
+
export declare const idGenerator: IdGenerator;
|
|
131
|
+
/**
|
|
132
|
+
* Generates a standard Version 4 UUID (Universally Unique Identifier).
|
|
133
|
+
* Uses the Node.js `crypto` module. This function is independent of the IdGenerator instance
|
|
134
|
+
* to prevent circular dependencies when used by other utilities like requestContextService.
|
|
135
|
+
* @returns A new UUID string.
|
|
136
|
+
*/
|
|
137
|
+
export declare const generateUUID: () => string;
|