mcp-sunsama 0.15.0 → 0.15.2

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 (92) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/bun.lock +2 -2
  3. package/dist/src/auth/http.js +1 -1
  4. package/dist/src/auth/stdio.d.ts +1 -1
  5. package/dist/src/auth/stdio.d.ts.map +1 -1
  6. package/dist/src/auth/stdio.js +1 -1
  7. package/dist/src/auth/types.d.ts +1 -1
  8. package/dist/src/auth/types.d.ts.map +1 -1
  9. package/dist/src/auth/types.js +1 -1
  10. package/dist/src/main.js +1 -1
  11. package/dist/src/utils/client-resolver.d.ts +1 -1
  12. package/dist/src/utils/client-resolver.d.ts.map +1 -1
  13. package/dist/src/utils/client-resolver.js +1 -1
  14. package/dist/src/utils/task-filters.d.ts +1 -1
  15. package/dist/src/utils/task-filters.d.ts.map +1 -1
  16. package/dist/src/utils/task-trimmer.d.ts +1 -1
  17. package/dist/src/utils/task-trimmer.d.ts.map +1 -1
  18. package/package.json +2 -2
  19. package/src/auth/http.ts +1 -1
  20. package/src/auth/stdio.ts +1 -1
  21. package/src/auth/types.ts +1 -1
  22. package/src/main.ts +1 -1
  23. package/src/tools/task-tools.ts +1 -1
  24. package/src/utils/client-resolver.ts +1 -1
  25. package/src/utils/task-filters.ts +1 -1
  26. package/src/utils/task-trimmer.ts +1 -1
  27. package/dist/auth/http.d.ts +0 -23
  28. package/dist/auth/http.d.ts.map +0 -1
  29. package/dist/auth/http.js +0 -160
  30. package/dist/auth/stdio.d.ts +0 -13
  31. package/dist/auth/stdio.d.ts.map +0 -1
  32. package/dist/auth/stdio.js +0 -28
  33. package/dist/auth/types.d.ts +0 -11
  34. package/dist/auth/types.d.ts.map +0 -1
  35. package/dist/auth/types.js +0 -1
  36. package/dist/config/session-config.d.ts +0 -49
  37. package/dist/config/session-config.d.ts.map +0 -1
  38. package/dist/config/session-config.js +0 -54
  39. package/dist/config/transport.d.ts +0 -12
  40. package/dist/config/transport.d.ts.map +0 -1
  41. package/dist/config/transport.js +0 -27
  42. package/dist/context/index.d.ts +0 -9
  43. package/dist/context/index.d.ts.map +0 -1
  44. package/dist/context/index.js +0 -5
  45. package/dist/main.d.ts +0 -3
  46. package/dist/main.d.ts.map +0 -1
  47. package/dist/main.js +0 -58
  48. package/dist/resources/index.d.ts +0 -13
  49. package/dist/resources/index.d.ts.map +0 -1
  50. package/dist/resources/index.js +0 -166
  51. package/dist/schemas.d.ts +0 -658
  52. package/dist/schemas.d.ts.map +0 -1
  53. package/dist/schemas.js +0 -193
  54. package/dist/schemas.test.d.ts +0 -2
  55. package/dist/schemas.test.d.ts.map +0 -1
  56. package/dist/schemas.test.js +0 -857
  57. package/dist/session/session-manager.d.ts +0 -53
  58. package/dist/session/session-manager.d.ts.map +0 -1
  59. package/dist/session/session-manager.js +0 -141
  60. package/dist/tools/index.d.ts +0 -11
  61. package/dist/tools/index.d.ts.map +0 -1
  62. package/dist/tools/index.js +0 -12
  63. package/dist/tools/shared.d.ts +0 -63
  64. package/dist/tools/shared.d.ts.map +0 -1
  65. package/dist/tools/shared.js +0 -84
  66. package/dist/tools/stream-tools.d.ts +0 -13
  67. package/dist/tools/stream-tools.d.ts.map +0 -1
  68. package/dist/tools/stream-tools.js +0 -12
  69. package/dist/tools/task-tools.d.ts +0 -91
  70. package/dist/tools/task-tools.d.ts.map +0 -1
  71. package/dist/tools/task-tools.js +0 -271
  72. package/dist/tools/user-tools.d.ts +0 -13
  73. package/dist/tools/user-tools.d.ts.map +0 -1
  74. package/dist/tools/user-tools.js +0 -13
  75. package/dist/transports/http.d.ts +0 -8
  76. package/dist/transports/http.d.ts.map +0 -1
  77. package/dist/transports/http.js +0 -245
  78. package/dist/transports/stdio.d.ts +0 -3
  79. package/dist/transports/stdio.d.ts.map +0 -1
  80. package/dist/transports/stdio.js +0 -11
  81. package/dist/utils/client-resolver.d.ts +0 -8
  82. package/dist/utils/client-resolver.d.ts.map +0 -1
  83. package/dist/utils/client-resolver.js +0 -23
  84. package/dist/utils/task-filters.d.ts +0 -29
  85. package/dist/utils/task-filters.d.ts.map +0 -1
  86. package/dist/utils/task-filters.js +0 -42
  87. package/dist/utils/task-trimmer.d.ts +0 -50
  88. package/dist/utils/task-trimmer.d.ts.map +0 -1
  89. package/dist/utils/task-trimmer.js +0 -59
  90. package/dist/utils/to-tsv.d.ts +0 -8
  91. package/dist/utils/to-tsv.d.ts.map +0 -1
  92. package/dist/utils/to-tsv.js +0 -64
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # mcp-sunsama
2
2
 
3
+ ## 0.15.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 6128d4c: Fix Node.js v20 compatibility by using sunsama-api subpath exports. Updates all imports to use explicit subpath exports ('sunsama-api/client' and 'sunsama-api/types') instead of root import, resolving ESM/CommonJS interoperability issues.
8
+
9
+ ## 0.15.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 8924946: Bump sunsama-api to version 0.11.2
14
+
3
15
  ## 0.15.0
4
16
 
5
17
  ### Minor Changes
package/bun.lock CHANGED
@@ -9,7 +9,7 @@
9
9
  "cors": "^2.8.5",
10
10
  "express": "^5.1.0",
11
11
  "papaparse": "^5.5.3",
12
- "sunsama-api": "0.11.1",
12
+ "sunsama-api": "0.11.2",
13
13
  "zod": "3.24.4",
14
14
  },
15
15
  "devDependencies": {
@@ -396,7 +396,7 @@
396
396
 
397
397
  "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
398
398
 
399
- "sunsama-api": ["sunsama-api@0.11.1", "", { "dependencies": { "graphql": "^16.11.0", "graphql-tag": "^2.12.6", "marked": "^14.1.3", "tough-cookie": "^5.1.2", "tslib": "^2.8.1", "turndown": "^7.2.0", "yjs": "^13.6.27", "zod": "^3.25.64" } }, "sha512-+2vhhswHXg1Bv3oA21Jj6UEojqsBnh6+Nu2IcOs8KA+fAEHwPITNjpEW4aYh7/jBBmGDkAssZ6zimRV/rmZh4A=="],
399
+ "sunsama-api": ["sunsama-api@0.11.2", "", { "dependencies": { "graphql": "^16.11.0", "graphql-tag": "^2.12.6", "marked": "^14.1.3", "tough-cookie": "^5.1.2", "tslib": "^2.8.1", "turndown": "^7.2.0", "yjs": "^13.6.27", "zod": "^3.25.64" } }, "sha512-tyBrCai6Z0jEmRXkwGY+0PlXJTAwE3IJXXRCDcGFwpFPxFO5fyxw6mqM/RhYu7OGhP3AF7w4CikvEOBDaFXvKA=="],
400
400
 
401
401
  "term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="],
402
402
 
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "crypto";
2
- import { SunsamaClient } from "sunsama-api";
2
+ import { SunsamaClient } from "sunsama-api/client";
3
3
  import { getSessionConfig } from "../config/session-config.js";
4
4
  // Client cache with TTL management (keyed by credential hash for security)
5
5
  const clientCache = new Map();
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
  /**
3
3
  * Initialize stdio authentication using environment variables
4
4
  * @throws {Error} If credentials are missing or authentication fails
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAWlE;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,aAAa,CAAC,CAMrE"}
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOnD;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAWlE;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,aAAa,CAAC,CAMrE"}
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
  /**
3
3
  * Cached authentication promise to prevent concurrent auth attempts
4
4
  */
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
  /**
3
3
  * Session data interface for HTTP transport
4
4
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB"}
@@ -1 +1 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
package/dist/src/main.js CHANGED
@@ -9,7 +9,7 @@ import { apiDocumentationResource } from "./resources/index.js";
9
9
  (async () => {
10
10
  const server = new McpServer({
11
11
  name: "Sunsama API Server",
12
- version: "0.15.0",
12
+ version: "0.15.2",
13
13
  instructions: `
14
14
  This MCP server provides access to the Sunsama API for task and project management.
15
15
 
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
  /**
3
3
  * Gets the appropriate SunsamaClient instance based on context
4
4
  * - HTTP transport: Uses session-scoped client from request
@@ -1 +1 @@
1
- {"version":3,"file":"client-resolver.d.ts","sourceRoot":"","sources":["../../../src/utils/client-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAK5C;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBrE"}
1
+ {"version":3,"file":"client-resolver.d.ts","sourceRoot":"","sources":["../../../src/utils/client-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKnD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBrE"}
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
  import { getGlobalSunsamaClient } from "../auth/stdio.js";
3
3
  import { sessionManager } from "../transports/http.js";
4
4
  /**
@@ -1,4 +1,4 @@
1
- import type { Task } from "sunsama-api";
1
+ import type { Task } from "sunsama-api/types";
2
2
  import type { CompletionFilter } from "../schemas.js";
3
3
  /**
4
4
  * Filters an array of tasks based on completion status.
@@ -1 +1 @@
1
- {"version":3,"file":"task-filters.d.ts","sourceRoot":"","sources":["../../../src/utils/task-filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,EAAE,CAoBvF"}
1
+ {"version":3,"file":"task-filters.d.ts","sourceRoot":"","sources":["../../../src/utils/task-filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,EAAE,CAoBvF"}
@@ -1,4 +1,4 @@
1
- import type { Task, TaskIntegration } from "sunsama-api";
1
+ import type { Task, TaskIntegration } from "sunsama-api/types";
2
2
  /**
3
3
  * Trimmed task type containing only essential properties for API responses.
4
4
  * Reduces response size by 60-80% while preserving core task information.
@@ -1 +1 @@
1
- {"version":3,"file":"task-trimmer.d.ts","sourceRoot":"","sources":["../../../src/utils/task-trimmer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAC/B,KAAK,GACL,MAAM,GACN,WAAW,GACX,YAAY,GACZ,WAAW,GACX,cAAc,GACd,aAAa,GACb,cAAc,GACd,cAAc,GACd,SAAS,GACT,OAAO,GACP,WAAW,CACd,GAAG;IACF,2EAA2E;IAC3E,WAAW,EAAE;QACX,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QACpC,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;IACT,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CA4B3D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAEjE"}
1
+ {"version":3,"file":"task-trimmer.d.ts","sourceRoot":"","sources":["../../../src/utils/task-trimmer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAC/B,KAAK,GACL,MAAM,GACN,WAAW,GACX,YAAY,GACZ,WAAW,GACX,cAAc,GACd,aAAa,GACb,cAAc,GACd,cAAc,GACd,SAAS,GACT,OAAO,GACP,WAAW,CACd,GAAG;IACF,2EAA2E;IAC3E,WAAW,EAAE;QACX,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QACpC,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;IACT,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CA4B3D;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAEjE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-sunsama",
3
- "version": "0.15.0",
3
+ "version": "0.15.2",
4
4
  "description": "MCP server for Sunsama API integration",
5
5
  "type": "module",
6
6
  "private": false,
@@ -31,7 +31,7 @@
31
31
  "cors": "^2.8.5",
32
32
  "express": "^5.1.0",
33
33
  "papaparse": "^5.5.3",
34
- "sunsama-api": "0.11.1",
34
+ "sunsama-api": "0.11.2",
35
35
  "zod": "3.24.4"
36
36
  },
37
37
  "devDependencies": {
package/src/auth/http.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "crypto";
2
- import { SunsamaClient } from "sunsama-api";
2
+ import { SunsamaClient } from "sunsama-api/client";
3
3
  import type { SessionData } from "./types.js";
4
4
  import { getSessionConfig } from "../config/session-config.js";
5
5
 
package/src/auth/stdio.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
 
3
3
  /**
4
4
  * Cached authentication promise to prevent concurrent auth attempts
package/src/auth/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
 
3
3
  /**
4
4
  * Session data interface for HTTP transport
package/src/main.ts CHANGED
@@ -10,7 +10,7 @@ import { apiDocumentationResource } from "./resources/index.js";
10
10
  (async () => {
11
11
  const server = new McpServer({
12
12
  name: "Sunsama API Server",
13
- version: "0.15.0",
13
+ version: "0.15.2",
14
14
  instructions: `
15
15
  This MCP server provides access to the Sunsama API for task and project management.
16
16
 
@@ -1,4 +1,4 @@
1
- import type { CreateTaskOptions } from "sunsama-api";
1
+ import type { CreateTaskOptions } from "sunsama-api/types";
2
2
  import {
3
3
  type CreateTaskInput,
4
4
  createTaskSchema,
@@ -1,4 +1,4 @@
1
- import { SunsamaClient } from "sunsama-api";
1
+ import { SunsamaClient } from "sunsama-api/client";
2
2
  import { getGlobalSunsamaClient } from "../auth/stdio.js";
3
3
  import type { SessionData } from "../auth/types.js";
4
4
  import { sessionManager } from "../transports/http.js";
@@ -1,4 +1,4 @@
1
- import type { Task } from "sunsama-api";
1
+ import type { Task } from "sunsama-api/types";
2
2
  import type { CompletionFilter } from "../schemas.js";
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import type { Task, TaskIntegration } from "sunsama-api";
1
+ import type { Task, TaskIntegration } from "sunsama-api/types";
2
2
 
3
3
  /**
4
4
  * Trimmed task type containing only essential properties for API responses.
@@ -1,23 +0,0 @@
1
- import type { SessionData } from "./types.js";
2
- /**
3
- * Parse HTTP Basic Auth credentials from Authorization header
4
- */
5
- export declare function parseBasicAuth(authHeader: string): {
6
- email: string;
7
- password: string;
8
- };
9
- export declare function startClientCacheCleanup(): void;
10
- /**
11
- * Stop periodic cleanup (for graceful shutdown)
12
- */
13
- export declare function stopClientCacheCleanup(): void;
14
- /**
15
- * Cleanup all cached clients (for graceful shutdown)
16
- */
17
- export declare function cleanupAllClients(): void;
18
- /**
19
- * Authenticate HTTP request and get or create cached client
20
- * Uses secure cache key (password hash) and race condition protection
21
- */
22
- export declare function authenticateHttpRequest(authHeader?: string): Promise<SessionData>;
23
- //# sourceMappingURL=http.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/auth/http.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAe9C;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAUtF;AA+CD,wBAAgB,uBAAuB,IAAI,IAAI,CAQ9C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAM7C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAYxC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CAiEtB"}
package/dist/auth/http.js DELETED
@@ -1,160 +0,0 @@
1
- import { createHash } from "crypto";
2
- import { SunsamaClient } from "sunsama-api";
3
- import { getSessionConfig } from "../config/session-config.js";
4
- // Client cache with TTL management (keyed by credential hash for security)
5
- const clientCache = new Map();
6
- // Pending authentication promises to prevent race conditions
7
- const authPromises = new Map();
8
- // Configuration - loaded from environment
9
- const sessionConfig = getSessionConfig();
10
- const CLIENT_IDLE_TIMEOUT = sessionConfig.CLIENT_IDLE_TIMEOUT;
11
- const CLIENT_MAX_LIFETIME = sessionConfig.CLIENT_MAX_LIFETIME;
12
- const CLEANUP_INTERVAL = sessionConfig.CLEANUP_INTERVAL;
13
- /**
14
- * Parse HTTP Basic Auth credentials from Authorization header
15
- */
16
- export function parseBasicAuth(authHeader) {
17
- const base64Credentials = authHeader.replace('Basic ', '');
18
- const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
19
- const [email, password] = credentials.split(':');
20
- if (!email || !password) {
21
- throw new Error("Invalid Basic Auth format");
22
- }
23
- return { email, password };
24
- }
25
- /**
26
- * Generate secure cache key from credentials
27
- * Uses SHA-256 hash to prevent authentication bypass vulnerability
28
- */
29
- function getCacheKey(email, password) {
30
- return createHash('sha256')
31
- .update(`${email}:${password}`)
32
- .digest('hex');
33
- }
34
- /**
35
- * Check if a cached client is still valid based on TTL
36
- */
37
- function isClientValid(sessionData) {
38
- const now = Date.now();
39
- const idleTime = now - sessionData.lastAccessedAt;
40
- const lifetime = now - sessionData.createdAt;
41
- return idleTime < CLIENT_IDLE_TIMEOUT && lifetime < CLIENT_MAX_LIFETIME;
42
- }
43
- /**
44
- * Cleanup expired clients from cache
45
- */
46
- function cleanupExpiredClients() {
47
- const now = Date.now();
48
- for (const [cacheKey, sessionData] of clientCache.entries()) {
49
- if (!isClientValid(sessionData)) {
50
- console.error(`[Client Cache] Expiring stale client for ${sessionData.email}`);
51
- try {
52
- sessionData.sunsamaClient.logout();
53
- }
54
- catch (err) {
55
- console.error(`[Client Cache] Error logging out client for ${sessionData.email}:`, err);
56
- }
57
- clientCache.delete(cacheKey);
58
- }
59
- }
60
- }
61
- /**
62
- * Start periodic cleanup of expired clients
63
- */
64
- let cleanupTimer = null;
65
- export function startClientCacheCleanup() {
66
- if (cleanupTimer)
67
- return; // Already started
68
- cleanupTimer = setInterval(() => {
69
- cleanupExpiredClients();
70
- }, CLEANUP_INTERVAL);
71
- console.error('[Client Cache] Started periodic cleanup');
72
- }
73
- /**
74
- * Stop periodic cleanup (for graceful shutdown)
75
- */
76
- export function stopClientCacheCleanup() {
77
- if (cleanupTimer) {
78
- clearInterval(cleanupTimer);
79
- cleanupTimer = null;
80
- console.error('[Client Cache] Stopped periodic cleanup');
81
- }
82
- }
83
- /**
84
- * Cleanup all cached clients (for graceful shutdown)
85
- */
86
- export function cleanupAllClients() {
87
- console.error('[Client Cache] Cleaning up all cached clients');
88
- for (const [email, sessionData] of clientCache.entries()) {
89
- try {
90
- sessionData.sunsamaClient.logout();
91
- }
92
- catch (err) {
93
- console.error(`[Client Cache] Error logging out client for ${email}:`, err);
94
- }
95
- }
96
- clientCache.clear();
97
- }
98
- /**
99
- * Authenticate HTTP request and get or create cached client
100
- * Uses secure cache key (password hash) and race condition protection
101
- */
102
- export async function authenticateHttpRequest(authHeader) {
103
- if (!authHeader || !authHeader.startsWith('Basic ')) {
104
- throw new Error("Basic Auth required");
105
- }
106
- const { email, password } = parseBasicAuth(authHeader);
107
- const cacheKey = getCacheKey(email, password);
108
- const now = Date.now();
109
- // Check for pending authentication (race condition protection)
110
- if (authPromises.has(cacheKey)) {
111
- console.error(`[Client Cache] Waiting for pending authentication for ${email}`);
112
- return await authPromises.get(cacheKey);
113
- }
114
- // Check cache first
115
- if (clientCache.has(cacheKey)) {
116
- const cached = clientCache.get(cacheKey);
117
- // Check if still valid (lazy expiration)
118
- if (isClientValid(cached)) {
119
- console.error(`[Client Cache] Reusing cached client for ${email}`);
120
- // Update last accessed time (sliding window)
121
- cached.lastAccessedAt = now;
122
- return cached;
123
- }
124
- else {
125
- console.error(`[Client Cache] Cached client expired for ${email}, re-authenticating`);
126
- // Cleanup expired client
127
- try {
128
- cached.sunsamaClient.logout();
129
- }
130
- catch (err) {
131
- console.error(`[Client Cache] Error logging out expired client:`, err);
132
- }
133
- clientCache.delete(cacheKey);
134
- }
135
- }
136
- // Create authentication promise to prevent concurrent authentications
137
- console.error(`[Client Cache] Creating new client for ${email}`);
138
- const authPromise = (async () => {
139
- try {
140
- const sunsamaClient = new SunsamaClient();
141
- await sunsamaClient.login(email, password);
142
- const sessionData = {
143
- sunsamaClient,
144
- email,
145
- createdAt: now,
146
- lastAccessedAt: now
147
- };
148
- clientCache.set(cacheKey, sessionData);
149
- console.error(`[Client Cache] Cached new client for ${email} (total: ${clientCache.size})`);
150
- return sessionData;
151
- }
152
- finally {
153
- // Always remove from pending map
154
- authPromises.delete(cacheKey);
155
- }
156
- })();
157
- // Store promise to prevent concurrent authentications
158
- authPromises.set(cacheKey, authPromise);
159
- return authPromise;
160
- }
@@ -1,13 +0,0 @@
1
- import { SunsamaClient } from "sunsama-api";
2
- /**
3
- * Initialize stdio authentication using environment variables
4
- * @throws {Error} If credentials are missing or authentication fails
5
- */
6
- export declare function initializeStdioAuth(): Promise<SunsamaClient>;
7
- /**
8
- * Get the global Sunsama client instance for stdio transport
9
- * @returns {Promise<SunsamaClient>} The authenticated global client
10
- * @throws {Error} If credentials are missing or authentication fails
11
- */
12
- export declare function getGlobalSunsamaClient(): Promise<SunsamaClient>;
13
- //# sourceMappingURL=stdio.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/auth/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAWlE;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,aAAa,CAAC,CAMrE"}
@@ -1,28 +0,0 @@
1
- import { SunsamaClient } from "sunsama-api";
2
- /**
3
- * Cached authentication promise to prevent concurrent auth attempts
4
- */
5
- let authenticationPromise = null;
6
- /**
7
- * Initialize stdio authentication using environment variables
8
- * @throws {Error} If credentials are missing or authentication fails
9
- */
10
- export async function initializeStdioAuth() {
11
- if (!process.env.SUNSAMA_EMAIL || !process.env.SUNSAMA_PASSWORD) {
12
- throw new Error("Sunsama credentials not configured. Please set SUNSAMA_EMAIL and SUNSAMA_PASSWORD environment variables.");
13
- }
14
- const sunsamaClient = new SunsamaClient();
15
- await sunsamaClient.login(process.env.SUNSAMA_EMAIL, process.env.SUNSAMA_PASSWORD);
16
- return sunsamaClient;
17
- }
18
- /**
19
- * Get the global Sunsama client instance for stdio transport
20
- * @returns {Promise<SunsamaClient>} The authenticated global client
21
- * @throws {Error} If credentials are missing or authentication fails
22
- */
23
- export async function getGlobalSunsamaClient() {
24
- if (!authenticationPromise) {
25
- authenticationPromise = initializeStdioAuth();
26
- }
27
- return authenticationPromise;
28
- }
@@ -1,11 +0,0 @@
1
- import { SunsamaClient } from "sunsama-api";
2
- /**
3
- * Session data interface for HTTP transport
4
- */
5
- export interface SessionData extends Record<string, unknown> {
6
- sunsamaClient: SunsamaClient;
7
- email: string;
8
- createdAt: number;
9
- lastAccessedAt: number;
10
- }
11
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB"}
@@ -1 +0,0 @@
1
- import { SunsamaClient } from "sunsama-api";
@@ -1,49 +0,0 @@
1
- import { z } from "zod";
2
- declare const SessionConfigSchema: z.ZodObject<{
3
- CLIENT_IDLE_TIMEOUT: z.ZodDefault<z.ZodPipeline<z.ZodEffects<z.ZodString, number, string>, z.ZodNumber>>;
4
- CLIENT_MAX_LIFETIME: z.ZodDefault<z.ZodPipeline<z.ZodEffects<z.ZodString, number, string>, z.ZodNumber>>;
5
- TRANSPORT_IDLE_TIMEOUT: z.ZodDefault<z.ZodPipeline<z.ZodEffects<z.ZodString, number, string>, z.ZodNumber>>;
6
- TRANSPORT_MAX_LIFETIME: z.ZodDefault<z.ZodPipeline<z.ZodEffects<z.ZodString, number, string>, z.ZodNumber>>;
7
- CLEANUP_INTERVAL: z.ZodDefault<z.ZodPipeline<z.ZodEffects<z.ZodString, number, string>, z.ZodNumber>>;
8
- }, "strip", z.ZodTypeAny, {
9
- CLIENT_IDLE_TIMEOUT: number;
10
- CLIENT_MAX_LIFETIME: number;
11
- TRANSPORT_IDLE_TIMEOUT: number;
12
- TRANSPORT_MAX_LIFETIME: number;
13
- CLEANUP_INTERVAL: number;
14
- }, {
15
- CLIENT_IDLE_TIMEOUT?: string | undefined;
16
- CLIENT_MAX_LIFETIME?: string | undefined;
17
- TRANSPORT_IDLE_TIMEOUT?: string | undefined;
18
- TRANSPORT_MAX_LIFETIME?: string | undefined;
19
- CLEANUP_INTERVAL?: string | undefined;
20
- }>;
21
- export type SessionConfig = z.infer<typeof SessionConfigSchema>;
22
- export declare function getSessionConfig(): SessionConfig;
23
- export {};
24
- /**
25
- * Session TTL Behavior:
26
- *
27
- * 1. Idle Timeout (sliding window):
28
- * - Resets on each access
29
- * - Session stays alive as long as it's used
30
- * - Applied to both client and transport/session caches
31
- *
32
- * 2. Max Lifetime (absolute):
33
- * - Never resets, absolute from creation time
34
- * - Ensures sessions don't live forever
35
- * - Security feature to force re-authentication
36
- *
37
- * 3. Cleanup Strategy:
38
- * - Lazy: Checked on access (fast path)
39
- * - Active: Periodic sweep (configurable interval)
40
- * - Graceful: All sessions closed on shutdown
41
- *
42
- * Environment Variables:
43
- * - CLIENT_IDLE_TIMEOUT: Client idle timeout in ms (default: 600000 = 10 min)
44
- * - CLIENT_MAX_LIFETIME: Client max lifetime in ms (default: 3600000 = 1 hour)
45
- * - TRANSPORT_IDLE_TIMEOUT: Session idle timeout in ms (default: 900000 = 15 min)
46
- * - TRANSPORT_MAX_LIFETIME: Session max lifetime in ms (default: 7200000 = 2 hours)
47
- * - CLEANUP_INTERVAL: Cleanup check interval in ms (default: 300000 = 5 min)
48
- */
49
- //# sourceMappingURL=session-config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-config.d.ts","sourceRoot":"","sources":["../../src/config/session-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;EA4BvB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
@@ -1,54 +0,0 @@
1
- import { z } from "zod";
2
- const SessionConfigSchema = z.object({
3
- // Client cache timeouts
4
- CLIENT_IDLE_TIMEOUT: z.string()
5
- .transform(val => parseInt(val, 10))
6
- .pipe(z.number().min(60000)) // Min 1 minute
7
- .default("600000"), // 10 minutes
8
- CLIENT_MAX_LIFETIME: z.string()
9
- .transform(val => parseInt(val, 10))
10
- .pipe(z.number().min(300000)) // Min 5 minutes
11
- .default("3600000"), // 1 hour
12
- // Transport/session cache timeouts
13
- TRANSPORT_IDLE_TIMEOUT: z.string()
14
- .transform(val => parseInt(val, 10))
15
- .pipe(z.number().min(60000)) // Min 1 minute
16
- .default("900000"), // 15 minutes
17
- TRANSPORT_MAX_LIFETIME: z.string()
18
- .transform(val => parseInt(val, 10))
19
- .pipe(z.number().min(300000)) // Min 5 minutes
20
- .default("7200000"), // 2 hours
21
- // Cleanup interval
22
- CLEANUP_INTERVAL: z.string()
23
- .transform(val => parseInt(val, 10))
24
- .pipe(z.number().min(60000)) // Min 1 minute
25
- .default("300000"), // 5 minutes
26
- });
27
- export function getSessionConfig() {
28
- return SessionConfigSchema.parse(process.env);
29
- }
30
- /**
31
- * Session TTL Behavior:
32
- *
33
- * 1. Idle Timeout (sliding window):
34
- * - Resets on each access
35
- * - Session stays alive as long as it's used
36
- * - Applied to both client and transport/session caches
37
- *
38
- * 2. Max Lifetime (absolute):
39
- * - Never resets, absolute from creation time
40
- * - Ensures sessions don't live forever
41
- * - Security feature to force re-authentication
42
- *
43
- * 3. Cleanup Strategy:
44
- * - Lazy: Checked on access (fast path)
45
- * - Active: Periodic sweep (configurable interval)
46
- * - Graceful: All sessions closed on shutdown
47
- *
48
- * Environment Variables:
49
- * - CLIENT_IDLE_TIMEOUT: Client idle timeout in ms (default: 600000 = 10 min)
50
- * - CLIENT_MAX_LIFETIME: Client max lifetime in ms (default: 3600000 = 1 hour)
51
- * - TRANSPORT_IDLE_TIMEOUT: Session idle timeout in ms (default: 900000 = 15 min)
52
- * - TRANSPORT_MAX_LIFETIME: Session max lifetime in ms (default: 7200000 = 2 hours)
53
- * - CLEANUP_INTERVAL: Cleanup check interval in ms (default: 300000 = 5 min)
54
- */
@@ -1,12 +0,0 @@
1
- export type TransportType = "stdio" | "http";
2
- export type TransportConfig = {
3
- transportType: "stdio";
4
- } | {
5
- transportType: "http";
6
- httpStream: {
7
- port: number;
8
- endpoint: `/${string}`;
9
- };
10
- };
11
- export declare function getTransportConfig(): TransportConfig;
12
- //# sourceMappingURL=transport.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/config/transport.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7C,MAAM,MAAM,eAAe,GACvB;IAAE,aAAa,EAAE,OAAO,CAAA;CAAE,GAC1B;IACE,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAC;KACxB,CAAC;CACH,CAAC;AAgBN,wBAAgB,kBAAkB,IAAI,eAAe,CAcpD"}
@@ -1,27 +0,0 @@
1
- import { z } from "zod";
2
- const TransportEnvSchema = z.object({
3
- TRANSPORT_MODE: z.enum(["stdio", "http"]).default("stdio"),
4
- PORT: z.string()
5
- .transform(val => parseInt(val, 10))
6
- .pipe(z.number().min(1).max(65535))
7
- .default("8080"),
8
- HTTP_ENDPOINT: z.string()
9
- .refine(val => val.startsWith("/"), {
10
- message: "HTTP_ENDPOINT must start with '/'"
11
- })
12
- .transform(val => val)
13
- .default("/mcp")
14
- });
15
- export function getTransportConfig() {
16
- const env = TransportEnvSchema.parse(process.env);
17
- if (env.TRANSPORT_MODE === "http") {
18
- return {
19
- transportType: "http",
20
- httpStream: {
21
- port: env.PORT,
22
- endpoint: env.HTTP_ENDPOINT
23
- }
24
- };
25
- }
26
- return { transportType: "stdio" };
27
- }
@@ -1,9 +0,0 @@
1
- export interface SessionData {
2
- [key: string]: any;
3
- }
4
- declare class Context {
5
- session: SessionData;
6
- }
7
- declare const context: Context;
8
- export default context;
9
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context/index.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,WAAW;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,cAAM,OAAO;IACF,OAAO,EAAE,WAAW,CAAM;CACpC;AAED,QAAA,MAAM,OAAO,SAAgB,CAAC;AAC9B,eAAe,OAAO,CAAC"}