@ankimcp/anki-mcp-server 0.18.5 → 0.19.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.
Files changed (231) hide show
  1. package/README.md +204 -139
  2. package/bin/ankimcp.js +10 -1
  3. package/dist/app-config.service.d.ts +20 -0
  4. package/dist/app-config.service.js +73 -0
  5. package/dist/app-config.service.js.map +1 -0
  6. package/dist/app.module.d.ts +4 -2
  7. package/dist/app.module.js +99 -11
  8. package/dist/app.module.js.map +1 -1
  9. package/dist/bootstrap.d.ts +6 -1
  10. package/dist/bootstrap.js +7 -2
  11. package/dist/bootstrap.js.map +1 -1
  12. package/dist/cli/__tests__/cli-output.manual.d.ts +2 -0
  13. package/dist/cli/__tests__/cli-output.manual.js +14 -0
  14. package/dist/cli/__tests__/cli-output.manual.js.map +1 -0
  15. package/dist/cli/args.d.ts +16 -0
  16. package/dist/{cli.js → cli/args.js} +42 -9
  17. package/dist/cli/args.js.map +1 -0
  18. package/dist/cli/cli-output.d.ts +17 -0
  19. package/dist/cli/cli-output.js +60 -0
  20. package/dist/cli/cli-output.js.map +1 -0
  21. package/dist/cli/index.d.ts +3 -0
  22. package/dist/cli/index.js +20 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/cli/spinner.d.ts +1 -0
  25. package/dist/cli/spinner.js +16 -0
  26. package/dist/cli/spinner.js.map +1 -0
  27. package/dist/config/config.factory.d.ts +13 -0
  28. package/dist/config/config.factory.js +32 -0
  29. package/dist/config/config.factory.js.map +1 -0
  30. package/dist/config/config.schema.d.ts +31 -0
  31. package/dist/config/config.schema.js +54 -0
  32. package/dist/config/config.schema.js.map +1 -0
  33. package/dist/config/index.d.ts +3 -0
  34. package/dist/config/index.js +11 -0
  35. package/dist/config/index.js.map +1 -0
  36. package/dist/http/guards/origin-validation.guard.d.ts +1 -0
  37. package/dist/http/guards/origin-validation.guard.js +5 -3
  38. package/dist/http/guards/origin-validation.guard.js.map +1 -1
  39. package/dist/main-http.js +23 -11
  40. package/dist/main-http.js.map +1 -1
  41. package/dist/main-stdio.js +10 -9
  42. package/dist/main-stdio.js.map +1 -1
  43. package/dist/main-tunnel.d.ts +1 -0
  44. package/dist/main-tunnel.js +27 -0
  45. package/dist/main-tunnel.js.map +1 -0
  46. package/dist/mcp/clients/anki-connect.client.js +3 -3
  47. package/dist/mcp/clients/anki-connect.client.js.map +1 -1
  48. package/dist/mcp/primitives/essential/index.d.ts +1 -0
  49. package/dist/mcp/primitives/essential/index.js +8 -1
  50. package/dist/mcp/primitives/essential/index.js.map +1 -1
  51. package/dist/mcp/primitives/essential/tools/add-note.tool.d.ts +2 -3
  52. package/dist/mcp/primitives/essential/tools/add-note.tool.js +2 -9
  53. package/dist/mcp/primitives/essential/tools/add-note.tool.js.map +1 -1
  54. package/dist/mcp/primitives/essential/tools/add-notes.tool.d.ts +1 -2
  55. package/dist/mcp/primitives/essential/tools/add-notes.tool.js +2 -23
  56. package/dist/mcp/primitives/essential/tools/add-notes.tool.js.map +1 -1
  57. package/dist/mcp/primitives/essential/tools/add-tags.tool.d.ts +1 -2
  58. package/dist/mcp/primitives/essential/tools/add-tags.tool.js +2 -4
  59. package/dist/mcp/primitives/essential/tools/add-tags.tool.js.map +1 -1
  60. package/dist/mcp/primitives/essential/tools/change-deck.tool.d.ts +1 -2
  61. package/dist/mcp/primitives/essential/tools/change-deck.tool.js +2 -4
  62. package/dist/mcp/primitives/essential/tools/change-deck.tool.js.map +1 -1
  63. package/dist/mcp/primitives/essential/tools/clear-unused-tags.tool.d.ts +1 -2
  64. package/dist/mcp/primitives/essential/tools/clear-unused-tags.tool.js +2 -4
  65. package/dist/mcp/primitives/essential/tools/clear-unused-tags.tool.js.map +1 -1
  66. package/dist/mcp/primitives/essential/tools/collection-stats/collection-stats.tool.d.ts +1 -2
  67. package/dist/mcp/primitives/essential/tools/collection-stats/collection-stats.tool.js +2 -12
  68. package/dist/mcp/primitives/essential/tools/collection-stats/collection-stats.tool.js.map +1 -1
  69. package/dist/mcp/primitives/essential/tools/create-deck.tool.d.ts +1 -2
  70. package/dist/mcp/primitives/essential/tools/create-deck.tool.js +2 -4
  71. package/dist/mcp/primitives/essential/tools/create-deck.tool.js.map +1 -1
  72. package/dist/mcp/primitives/essential/tools/create-model.tool.d.ts +1 -2
  73. package/dist/mcp/primitives/essential/tools/create-model.tool.js +2 -6
  74. package/dist/mcp/primitives/essential/tools/create-model.tool.js.map +1 -1
  75. package/dist/mcp/primitives/essential/tools/deck-stats.tool.d.ts +1 -2
  76. package/dist/mcp/primitives/essential/tools/deck-stats.tool.js +3 -7
  77. package/dist/mcp/primitives/essential/tools/deck-stats.tool.js.map +1 -1
  78. package/dist/mcp/primitives/essential/tools/delete-media-file.tool.d.ts +1 -2
  79. package/dist/mcp/primitives/essential/tools/delete-media-file.tool.js +2 -4
  80. package/dist/mcp/primitives/essential/tools/delete-media-file.tool.js.map +1 -1
  81. package/dist/mcp/primitives/essential/tools/delete-notes.tool.d.ts +2 -3
  82. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js +2 -6
  83. package/dist/mcp/primitives/essential/tools/delete-notes.tool.js.map +1 -1
  84. package/dist/mcp/primitives/essential/tools/find-notes.tool.d.ts +1 -2
  85. package/dist/mcp/primitives/essential/tools/find-notes.tool.js +2 -6
  86. package/dist/mcp/primitives/essential/tools/find-notes.tool.js.map +1 -1
  87. package/dist/mcp/primitives/essential/tools/get-cards.tool.d.ts +1 -2
  88. package/dist/mcp/primitives/essential/tools/get-cards.tool.js +2 -6
  89. package/dist/mcp/primitives/essential/tools/get-cards.tool.js.map +1 -1
  90. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.d.ts +1 -2
  91. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js +2 -6
  92. package/dist/mcp/primitives/essential/tools/get-due-cards.tool.js.map +1 -1
  93. package/dist/mcp/primitives/essential/tools/get-media-files-names.tool.d.ts +1 -2
  94. package/dist/mcp/primitives/essential/tools/get-media-files-names.tool.js +2 -4
  95. package/dist/mcp/primitives/essential/tools/get-media-files-names.tool.js.map +1 -1
  96. package/dist/mcp/primitives/essential/tools/get-tags.tool.d.ts +1 -2
  97. package/dist/mcp/primitives/essential/tools/get-tags.tool.js +2 -6
  98. package/dist/mcp/primitives/essential/tools/get-tags.tool.js.map +1 -1
  99. package/dist/mcp/primitives/essential/tools/list-decks.tool.d.ts +1 -2
  100. package/dist/mcp/primitives/essential/tools/list-decks.tool.js +2 -4
  101. package/dist/mcp/primitives/essential/tools/list-decks.tool.js.map +1 -1
  102. package/dist/mcp/primitives/essential/tools/model-field-names.tool.d.ts +1 -2
  103. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js +2 -7
  104. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js.map +1 -1
  105. package/dist/mcp/primitives/essential/tools/model-names.tool.d.ts +1 -2
  106. package/dist/mcp/primitives/essential/tools/model-names.tool.js +2 -6
  107. package/dist/mcp/primitives/essential/tools/model-names.tool.js.map +1 -1
  108. package/dist/mcp/primitives/essential/tools/model-styling.tool.d.ts +1 -2
  109. package/dist/mcp/primitives/essential/tools/model-styling.tool.js +2 -6
  110. package/dist/mcp/primitives/essential/tools/model-styling.tool.js.map +1 -1
  111. package/dist/mcp/primitives/essential/tools/notes-info.tool.d.ts +1 -2
  112. package/dist/mcp/primitives/essential/tools/notes-info.tool.js +2 -6
  113. package/dist/mcp/primitives/essential/tools/notes-info.tool.js.map +1 -1
  114. package/dist/mcp/primitives/essential/tools/present-card.tool.d.ts +2 -3
  115. package/dist/mcp/primitives/essential/tools/present-card.tool.js +2 -5
  116. package/dist/mcp/primitives/essential/tools/present-card.tool.js.map +1 -1
  117. package/dist/mcp/primitives/essential/tools/rate-card.tool.d.ts +1 -2
  118. package/dist/mcp/primitives/essential/tools/rate-card.tool.js +2 -5
  119. package/dist/mcp/primitives/essential/tools/rate-card.tool.js.map +1 -1
  120. package/dist/mcp/primitives/essential/tools/remove-tags.tool.d.ts +1 -2
  121. package/dist/mcp/primitives/essential/tools/remove-tags.tool.js +2 -4
  122. package/dist/mcp/primitives/essential/tools/remove-tags.tool.js.map +1 -1
  123. package/dist/mcp/primitives/essential/tools/replace-tags.tool.d.ts +1 -2
  124. package/dist/mcp/primitives/essential/tools/replace-tags.tool.js +2 -4
  125. package/dist/mcp/primitives/essential/tools/replace-tags.tool.js.map +1 -1
  126. package/dist/mcp/primitives/essential/tools/retrieve-media-file.tool.d.ts +1 -2
  127. package/dist/mcp/primitives/essential/tools/retrieve-media-file.tool.js +2 -4
  128. package/dist/mcp/primitives/essential/tools/retrieve-media-file.tool.js.map +1 -1
  129. package/dist/mcp/primitives/essential/tools/review-stats/review-stats.tool.d.ts +1 -2
  130. package/dist/mcp/primitives/essential/tools/review-stats/review-stats.tool.js +2 -8
  131. package/dist/mcp/primitives/essential/tools/review-stats/review-stats.tool.js.map +1 -1
  132. package/dist/mcp/primitives/essential/tools/store-media-file.tool.d.ts +1 -2
  133. package/dist/mcp/primitives/essential/tools/store-media-file.tool.js +2 -4
  134. package/dist/mcp/primitives/essential/tools/store-media-file.tool.js.map +1 -1
  135. package/dist/mcp/primitives/essential/tools/sync.tool.d.ts +1 -2
  136. package/dist/mcp/primitives/essential/tools/sync.tool.js +2 -4
  137. package/dist/mcp/primitives/essential/tools/sync.tool.js.map +1 -1
  138. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.d.ts +2 -3
  139. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js +2 -6
  140. package/dist/mcp/primitives/essential/tools/update-model-styling.tool.js.map +1 -1
  141. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.d.ts +1 -2
  142. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js +2 -5
  143. package/dist/mcp/primitives/essential/tools/update-note-fields.tool.js.map +1 -1
  144. package/dist/mcp/primitives/gui/index.d.ts +1 -0
  145. package/dist/mcp/primitives/gui/index.js +8 -1
  146. package/dist/mcp/primitives/gui/index.js.map +1 -1
  147. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.d.ts +1 -2
  148. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.js +2 -5
  149. package/dist/mcp/primitives/gui/tools/gui-add-cards.tool.js.map +1 -1
  150. package/dist/mcp/primitives/gui/tools/gui-browse.tool.d.ts +1 -2
  151. package/dist/mcp/primitives/gui/tools/gui-browse.tool.js +2 -4
  152. package/dist/mcp/primitives/gui/tools/gui-browse.tool.js.map +1 -1
  153. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.d.ts +1 -2
  154. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.js +2 -4
  155. package/dist/mcp/primitives/gui/tools/gui-current-card.tool.js.map +1 -1
  156. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.d.ts +1 -2
  157. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.js +2 -4
  158. package/dist/mcp/primitives/gui/tools/gui-deck-browser.tool.js.map +1 -1
  159. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.d.ts +1 -2
  160. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.js +2 -4
  161. package/dist/mcp/primitives/gui/tools/gui-deck-overview.tool.js.map +1 -1
  162. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.d.ts +1 -2
  163. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.js +2 -4
  164. package/dist/mcp/primitives/gui/tools/gui-edit-note.tool.js.map +1 -1
  165. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.d.ts +1 -2
  166. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.js +2 -4
  167. package/dist/mcp/primitives/gui/tools/gui-select-card.tool.js.map +1 -1
  168. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.d.ts +1 -2
  169. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.js +2 -4
  170. package/dist/mcp/primitives/gui/tools/gui-selected-notes.tool.js.map +1 -1
  171. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.d.ts +1 -2
  172. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.js +2 -4
  173. package/dist/mcp/primitives/gui/tools/gui-show-answer.tool.js.map +1 -1
  174. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.d.ts +1 -2
  175. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.js +2 -4
  176. package/dist/mcp/primitives/gui/tools/gui-show-question.tool.js.map +1 -1
  177. package/dist/mcp/primitives/gui/tools/gui-undo.tool.d.ts +1 -2
  178. package/dist/mcp/primitives/gui/tools/gui-undo.tool.js +2 -4
  179. package/dist/mcp/primitives/gui/tools/gui-undo.tool.js.map +1 -1
  180. package/dist/services/ngrok.service.d.ts +1 -0
  181. package/dist/services/ngrok.service.js +5 -3
  182. package/dist/services/ngrok.service.js.map +1 -1
  183. package/dist/test-fixtures/mock-data.d.ts +8 -0
  184. package/dist/test-fixtures/mock-data.js +8 -0
  185. package/dist/test-fixtures/mock-data.js.map +1 -1
  186. package/dist/tunnel/commands/index.d.ts +3 -0
  187. package/dist/tunnel/commands/index.js +10 -0
  188. package/dist/tunnel/commands/index.js.map +1 -0
  189. package/dist/tunnel/commands/login.command.d.ts +2 -0
  190. package/dist/tunnel/commands/login.command.js +29 -0
  191. package/dist/tunnel/commands/login.command.js.map +1 -0
  192. package/dist/tunnel/commands/logout.command.d.ts +2 -0
  193. package/dist/tunnel/commands/logout.command.js +25 -0
  194. package/dist/tunnel/commands/logout.command.js.map +1 -0
  195. package/dist/tunnel/commands/perform-login.d.ts +9 -0
  196. package/dist/tunnel/commands/perform-login.js +72 -0
  197. package/dist/tunnel/commands/perform-login.js.map +1 -0
  198. package/dist/tunnel/commands/tunnel.command.d.ts +3 -0
  199. package/dist/tunnel/commands/tunnel.command.js +225 -0
  200. package/dist/tunnel/commands/tunnel.command.js.map +1 -0
  201. package/dist/tunnel/credentials.service.d.ts +23 -0
  202. package/dist/tunnel/credentials.service.js +152 -0
  203. package/dist/tunnel/credentials.service.js.map +1 -0
  204. package/dist/tunnel/device-flow.service.d.ts +46 -0
  205. package/dist/tunnel/device-flow.service.js +230 -0
  206. package/dist/tunnel/device-flow.service.js.map +1 -0
  207. package/dist/tunnel/in-memory.transport.d.ts +14 -0
  208. package/dist/tunnel/in-memory.transport.js +63 -0
  209. package/dist/tunnel/in-memory.transport.js.map +1 -0
  210. package/dist/tunnel/index.d.ts +6 -0
  211. package/dist/tunnel/index.js +31 -0
  212. package/dist/tunnel/index.js.map +1 -0
  213. package/dist/tunnel/tunnel-mcp.service.d.ts +15 -0
  214. package/dist/tunnel/tunnel-mcp.service.js +100 -0
  215. package/dist/tunnel/tunnel-mcp.service.js.map +1 -0
  216. package/dist/tunnel/tunnel.client.d.ts +60 -0
  217. package/dist/tunnel/tunnel.client.js +386 -0
  218. package/dist/tunnel/tunnel.client.js.map +1 -0
  219. package/dist/tunnel/tunnel.protocol.d.ts +67 -0
  220. package/dist/tunnel/tunnel.protocol.js +25 -0
  221. package/dist/tunnel/tunnel.protocol.js.map +1 -0
  222. package/dist/version.d.ts +2 -0
  223. package/dist/version.js +21 -0
  224. package/dist/version.js.map +1 -0
  225. package/package.json +31 -22
  226. package/dist/anki-config.service.d.ts +0 -11
  227. package/dist/anki-config.service.js +0 -46
  228. package/dist/anki-config.service.js.map +0 -1
  229. package/dist/cli.d.ts +0 -10
  230. package/dist/cli.js.map +0 -1
  231. package/dist/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deriveDashboardUrl = deriveDashboardUrl;
4
+ exports.handleTunnel = handleTunnel;
5
+ const core_1 = require("@nestjs/core");
6
+ const common_1 = require("@nestjs/common");
7
+ const app_module_1 = require("../../app.module");
8
+ const tunnel_1 = require("..");
9
+ const tunnel_mcp_service_1 = require("../tunnel-mcp.service");
10
+ const app_config_service_1 = require("../../app-config.service");
11
+ const config_1 = require("../../config");
12
+ const spinner_1 = require("../../cli/spinner");
13
+ const bootstrap_1 = require("../../bootstrap");
14
+ const perform_login_1 = require("./perform-login");
15
+ function displayBox(cli, title, url) {
16
+ cli.box(title, url);
17
+ }
18
+ function deriveDashboardUrl(tunnelUrl) {
19
+ const url = new URL(tunnelUrl);
20
+ url.hostname = url.hostname.replace(/^tunnel\./, "web.");
21
+ return url.origin;
22
+ }
23
+ function formatConnectionError(error, tunnelUrl) {
24
+ if (error instanceof tunnel_1.TunnelClientError && error.originalError) {
25
+ const origError = error.originalError;
26
+ if (origError.code === "ECONNREFUSED") {
27
+ return `Cannot connect to tunnel server at ${tunnelUrl}
28
+ Make sure the tunnel server is running.`;
29
+ }
30
+ }
31
+ if (error instanceof Error) {
32
+ if (error.message.includes("ECONNREFUSED") ||
33
+ error.message.includes("connect ECONNREFUSED")) {
34
+ return `Cannot connect to tunnel server at ${tunnelUrl}
35
+ Make sure the tunnel server is running.`;
36
+ }
37
+ if (error.message.includes("timeout") ||
38
+ error.message.includes("Connection timeout")) {
39
+ return `Connection timeout to ${tunnelUrl}
40
+ The tunnel server may be unavailable or slow to respond.`;
41
+ }
42
+ if (error.message.includes("Unauthorized") ||
43
+ error.message.includes("401")) {
44
+ return `Authentication failed
45
+ Your credentials may be invalid. Try: ankimcp --logout && ankimcp --login`;
46
+ }
47
+ }
48
+ const message = error instanceof Error ? error.message : String(error);
49
+ return `Failed to connect: ${message}`;
50
+ }
51
+ async function ensureCredentials(cli, credentialsService, deviceFlowService) {
52
+ const existing = await credentialsService.loadCredentials();
53
+ if (existing) {
54
+ return existing;
55
+ }
56
+ if (!process.stdout.isTTY) {
57
+ cli.error("Not logged in and running non-interactively. Run: ankimcp --login first.");
58
+ process.exit(1);
59
+ }
60
+ cli.info("Not logged in — starting authentication flow...");
61
+ cli.blank();
62
+ try {
63
+ const credentials = await (0, perform_login_1.performLogin)({
64
+ credentialsService,
65
+ deviceFlowService,
66
+ cli,
67
+ });
68
+ cli.info("Continuing to tunnel...");
69
+ cli.blank();
70
+ return credentials;
71
+ }
72
+ catch (error) {
73
+ cli.blank();
74
+ if (error instanceof tunnel_1.DeviceFlowError) {
75
+ cli.error((0, perform_login_1.translateDeviceFlowError)(error));
76
+ }
77
+ else {
78
+ cli.error(`Login failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
79
+ }
80
+ cli.blank();
81
+ process.exit(1);
82
+ }
83
+ }
84
+ async function handleTunnel(cli, tunnelUrl, debug, readOnly) {
85
+ const credentialsService = new tunnel_1.CredentialsService();
86
+ const validatedConfig = (0, config_1.loadValidatedConfig)({
87
+ debug,
88
+ readOnly,
89
+ tunnel: tunnelUrl,
90
+ });
91
+ const appConfigService = new app_config_service_1.AppConfigService(validatedConfig);
92
+ const deviceFlowService = new tunnel_1.DeviceFlowService(appConfigService);
93
+ let app;
94
+ let tunnelClient;
95
+ let shuttingDown = false;
96
+ const gracefulExit = async (code, message) => {
97
+ if (shuttingDown) {
98
+ process.exit(code);
99
+ }
100
+ shuttingDown = true;
101
+ try {
102
+ if (message) {
103
+ cli.info(message);
104
+ }
105
+ tunnelClient?.disconnect();
106
+ if (app) {
107
+ await app.close();
108
+ }
109
+ }
110
+ catch (err) {
111
+ cli.error(`Cleanup error: ${err instanceof Error ? err.message : String(err)}`);
112
+ }
113
+ process.exit(code);
114
+ };
115
+ cli.blank();
116
+ try {
117
+ const credentials = await ensureCredentials(cli, credentialsService, deviceFlowService);
118
+ const stopSpinner = (0, spinner_1.startSpinner)("Starting MCP service...");
119
+ let tunnelMcpService;
120
+ const logLevel = debug ? "debug" : "info";
121
+ const pinoLogger = (0, bootstrap_1.createPinoLogger)(bootstrap_1.LOG_DESTINATION.STDERR, logLevel);
122
+ const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger);
123
+ if (debug) {
124
+ common_1.Logger.overrideLogger(["log", "error", "warn", "debug", "verbose"]);
125
+ }
126
+ common_1.Logger.overrideLogger(loggerService);
127
+ try {
128
+ app = await core_1.NestFactory.createApplicationContext(app_module_1.AppModule.forTunnel({ debug, readOnly }), {
129
+ logger: loggerService,
130
+ });
131
+ tunnelMcpService = app.get(tunnel_mcp_service_1.TunnelMcpService);
132
+ stopSpinner();
133
+ cli.success("MCP service ready");
134
+ }
135
+ catch (error) {
136
+ stopSpinner();
137
+ cli.error(`Failed to start MCP service: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
138
+ cli.blank();
139
+ return await gracefulExit(1);
140
+ }
141
+ cli.blank();
142
+ const mcpHandler = {
143
+ async handle(request) {
144
+ const responseBody = await tunnelMcpService.handleRequest(request.body);
145
+ return {
146
+ status: 200,
147
+ headers: { "content-type": "application/json" },
148
+ body: responseBody,
149
+ };
150
+ },
151
+ };
152
+ const effectiveTunnelUrl = tunnelUrl ?? validatedConfig.tunnel.serverUrl;
153
+ tunnelClient = new tunnel_1.TunnelClient(mcpHandler, credentialsService, deviceFlowService, effectiveTunnelUrl);
154
+ tunnelClient.on("error", (error) => {
155
+ if (error instanceof tunnel_1.TunnelClientError &&
156
+ error.code === "session_expired") {
157
+ cli.blank();
158
+ cli.error(error.message);
159
+ void gracefulExit(1);
160
+ return;
161
+ }
162
+ if (tunnelClient?.isConnected()) {
163
+ cli.error(`Tunnel error: ${error.message}`, error);
164
+ }
165
+ });
166
+ const connectSpinner = (0, spinner_1.startSpinner)("Connecting to tunnel service...");
167
+ let publicUrl;
168
+ try {
169
+ publicUrl = await tunnelClient.connect(credentials);
170
+ connectSpinner();
171
+ cli.success("Tunnel established");
172
+ cli.blank();
173
+ }
174
+ catch (error) {
175
+ connectSpinner();
176
+ if (error instanceof tunnel_1.TunnelClientError &&
177
+ error.code === "session_expired") {
178
+ cli.blank();
179
+ cli.error(error.message);
180
+ return await gracefulExit(1);
181
+ }
182
+ const errorMessage = formatConnectionError(error, effectiveTunnelUrl);
183
+ cli.error(errorMessage, error instanceof Error ? error : undefined);
184
+ cli.blank();
185
+ return await gracefulExit(1);
186
+ }
187
+ displayBox(cli, "🚇 Tunnel URL", publicUrl);
188
+ cli.blank();
189
+ displayBox(cli, "🌐 Dashboard", deriveDashboardUrl(publicUrl));
190
+ cli.blank();
191
+ cli.info("Tunnel is active. Press Ctrl+C to disconnect.");
192
+ cli.blank();
193
+ const logger = new common_1.Logger("TunnelCommand");
194
+ tunnelClient.on("request", (requestId, request) => {
195
+ logger.log(`Request ${requestId}: ${request.method} ${request.path}`);
196
+ });
197
+ tunnelClient.on("url_changed", (oldUrl, newUrl) => {
198
+ cli.blank();
199
+ cli.info(`🔄 Tunnel URL changed:`);
200
+ cli.info(` Old: ${oldUrl}`);
201
+ cli.info(` New: ${newUrl}`);
202
+ cli.blank();
203
+ });
204
+ tunnelClient.on("disconnected", (code, reason) => {
205
+ cli.blank();
206
+ cli.error(`Tunnel disconnected (code ${code}): ${reason}`);
207
+ cli.blank();
208
+ });
209
+ process.on("SIGINT", () => {
210
+ cli.blank();
211
+ void gracefulExit(0, "Shutting down...");
212
+ });
213
+ process.on("SIGTERM", () => {
214
+ cli.blank();
215
+ void gracefulExit(0, "Shutting down...");
216
+ });
217
+ await new Promise(() => { });
218
+ }
219
+ catch (error) {
220
+ cli.error(`Tunnel failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
221
+ cli.blank();
222
+ await gracefulExit(1);
223
+ }
224
+ }
225
+ //# sourceMappingURL=tunnel.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.command.js","sourceRoot":"","sources":["../../../src/tunnel/commands/tunnel.command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface TunnelCredentials {
2
+ access_token: string;
3
+ refresh_token: string;
4
+ expires_at: string;
5
+ user: {
6
+ id: string;
7
+ email: string;
8
+ tier: "free" | "paid";
9
+ };
10
+ }
11
+ export declare class CredentialsService {
12
+ private readonly logger;
13
+ private static readonly CREDENTIALS_DIR;
14
+ private static readonly CREDENTIALS_FILE;
15
+ getCredentialsPath(): string;
16
+ saveCredentials(credentials: TunnelCredentials): Promise<void>;
17
+ loadCredentials(): Promise<TunnelCredentials | null>;
18
+ clearCredentials(): Promise<void>;
19
+ hasCredentials(): Promise<boolean>;
20
+ isTokenExpired(credentials: TunnelCredentials): boolean;
21
+ private ensureCredentialsDirectory;
22
+ private validateCredentials;
23
+ }
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CredentialsService = void 0;
4
+ const promises_1 = require("fs/promises");
5
+ const path_1 = require("path");
6
+ const os_1 = require("os");
7
+ const fs_1 = require("fs");
8
+ const common_1 = require("@nestjs/common");
9
+ class CredentialsService {
10
+ logger = new common_1.Logger(CredentialsService.name);
11
+ static CREDENTIALS_DIR = (0, path_1.join)((0, os_1.homedir)(), ".ankimcp");
12
+ static CREDENTIALS_FILE = (0, path_1.join)(CredentialsService.CREDENTIALS_DIR, "credentials.json");
13
+ getCredentialsPath() {
14
+ return CredentialsService.CREDENTIALS_FILE;
15
+ }
16
+ async saveCredentials(credentials) {
17
+ try {
18
+ await this.ensureCredentialsDirectory();
19
+ const content = JSON.stringify(credentials, null, 2);
20
+ await (0, promises_1.writeFile)(CredentialsService.CREDENTIALS_FILE, content, {
21
+ encoding: "utf-8",
22
+ mode: 0o600,
23
+ });
24
+ await (0, promises_1.chmod)(CredentialsService.CREDENTIALS_FILE, 0o600);
25
+ }
26
+ catch (error) {
27
+ throw new Error(`Failed to save credentials to ${CredentialsService.CREDENTIALS_FILE}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
28
+ }
29
+ }
30
+ async loadCredentials() {
31
+ try {
32
+ await (0, promises_1.access)(CredentialsService.CREDENTIALS_FILE, fs_1.constants.F_OK | fs_1.constants.R_OK);
33
+ const content = await (0, promises_1.readFile)(CredentialsService.CREDENTIALS_FILE, {
34
+ encoding: "utf-8",
35
+ });
36
+ const credentials = JSON.parse(content);
37
+ const validation = this.validateCredentials(credentials);
38
+ if (!validation.valid) {
39
+ this.logger.warn(`Corrupted credentials file at ${CredentialsService.CREDENTIALS_FILE}:`);
40
+ validation.errors.forEach((error) => {
41
+ this.logger.warn(` - ${error}`);
42
+ });
43
+ return null;
44
+ }
45
+ return credentials;
46
+ }
47
+ catch (error) {
48
+ if (error.code === "ENOENT") {
49
+ return null;
50
+ }
51
+ this.logger.warn(`Failed to load credentials from ${CredentialsService.CREDENTIALS_FILE}: ${error instanceof Error ? error.message : String(error)}`);
52
+ return null;
53
+ }
54
+ }
55
+ async clearCredentials() {
56
+ try {
57
+ await (0, promises_1.unlink)(CredentialsService.CREDENTIALS_FILE);
58
+ }
59
+ catch (error) {
60
+ if (error.code !== "ENOENT") {
61
+ throw new Error(`Failed to delete credentials file: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
62
+ }
63
+ }
64
+ }
65
+ async hasCredentials() {
66
+ try {
67
+ await (0, promises_1.access)(CredentialsService.CREDENTIALS_FILE, fs_1.constants.F_OK);
68
+ return true;
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ isTokenExpired(credentials) {
75
+ const expiresAt = new Date(credentials.expires_at).getTime();
76
+ const now = Date.now();
77
+ const bufferMs = 60 * 1000;
78
+ return now >= expiresAt - bufferMs;
79
+ }
80
+ async ensureCredentialsDirectory() {
81
+ try {
82
+ await (0, promises_1.access)(CredentialsService.CREDENTIALS_DIR, fs_1.constants.F_OK);
83
+ }
84
+ catch (error) {
85
+ if (error.code === "ENOENT") {
86
+ await (0, promises_1.mkdir)(CredentialsService.CREDENTIALS_DIR, {
87
+ recursive: true,
88
+ mode: 0o700,
89
+ });
90
+ }
91
+ else {
92
+ throw error;
93
+ }
94
+ }
95
+ }
96
+ validateCredentials(obj) {
97
+ const errors = [];
98
+ if (!obj || typeof obj !== "object") {
99
+ errors.push("Credentials must be an object");
100
+ return { valid: false, errors };
101
+ }
102
+ const creds = obj;
103
+ if (!("access_token" in creds)) {
104
+ errors.push("Missing field: access_token");
105
+ }
106
+ else if (typeof creds.access_token !== "string") {
107
+ errors.push(`Invalid type for access_token: expected string, got ${typeof creds.access_token}`);
108
+ }
109
+ if (!("refresh_token" in creds)) {
110
+ errors.push("Missing field: refresh_token");
111
+ }
112
+ else if (typeof creds.refresh_token !== "string") {
113
+ errors.push(`Invalid type for refresh_token: expected string, got ${typeof creds.refresh_token}`);
114
+ }
115
+ if (!("expires_at" in creds)) {
116
+ errors.push("Missing field: expires_at");
117
+ }
118
+ else if (typeof creds.expires_at !== "string") {
119
+ errors.push(`Invalid type for expires_at: expected string, got ${typeof creds.expires_at}`);
120
+ }
121
+ if (!("user" in creds)) {
122
+ errors.push("Missing field: user");
123
+ }
124
+ else if (!creds.user || typeof creds.user !== "object") {
125
+ errors.push(`Invalid type for user: expected object, got ${typeof creds.user}`);
126
+ }
127
+ else {
128
+ const user = creds.user;
129
+ if (!("id" in user)) {
130
+ errors.push("Missing field: user.id");
131
+ }
132
+ else if (typeof user.id !== "string") {
133
+ errors.push(`Invalid type for user.id: expected string, got ${typeof user.id}`);
134
+ }
135
+ if (!("email" in user)) {
136
+ errors.push("Missing field: user.email");
137
+ }
138
+ else if (typeof user.email !== "string") {
139
+ errors.push(`Invalid type for user.email: expected string, got ${typeof user.email}`);
140
+ }
141
+ if (!("tier" in user)) {
142
+ errors.push("Missing field: user.tier");
143
+ }
144
+ else if (user.tier !== "free" && user.tier !== "paid") {
145
+ errors.push(`Invalid tier value: expected 'free' or 'paid', got '${String(user.tier)}'`);
146
+ }
147
+ }
148
+ return { valid: errors.length === 0, errors };
149
+ }
150
+ }
151
+ exports.CredentialsService = CredentialsService;
152
+ //# sourceMappingURL=credentials.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.service.js","sourceRoot":"","sources":["../../src/tunnel/credentials.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { AppConfigService } from "../app-config.service";
2
+ export interface DeviceCodeResponse {
3
+ device_code: string;
4
+ user_code: string;
5
+ verification_uri: string;
6
+ verification_uri_complete?: string;
7
+ expires_in: number;
8
+ interval: number;
9
+ }
10
+ export interface TokenResponse {
11
+ access_token: string;
12
+ token_type: string;
13
+ expires_in: number;
14
+ refresh_token: string;
15
+ user: {
16
+ id: string;
17
+ email: string;
18
+ tier: "free" | "paid";
19
+ };
20
+ }
21
+ export interface DeviceFlowErrorResponse {
22
+ error: "authorization_pending" | "slow_down" | "expired_token" | "access_denied" | string;
23
+ error_description?: string;
24
+ }
25
+ export declare class DeviceFlowError extends Error {
26
+ readonly code: string;
27
+ readonly description?: string | undefined;
28
+ constructor(message: string, code: string, description?: string | undefined);
29
+ }
30
+ export declare class DeviceFlowService {
31
+ private readonly config;
32
+ private readonly client;
33
+ private readonly logger;
34
+ private readonly deviceEndpoint;
35
+ private readonly tokenEndpoint;
36
+ constructor(config: AppConfigService);
37
+ requestDeviceCode(): Promise<DeviceCodeResponse>;
38
+ pollForToken(deviceCode: string, interval: number, expiresIn: number): Promise<TokenResponse>;
39
+ refreshToken(refreshToken: string): Promise<TokenResponse>;
40
+ private sleep;
41
+ private handleError;
42
+ getConfig(): {
43
+ tunnelUrl: string;
44
+ clientId: string;
45
+ };
46
+ }