appium-mcp 1.24.2 → 1.26.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 (53) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -0
  3. package/dist/server.d.ts.map +1 -1
  4. package/dist/server.js +7 -9
  5. package/dist/server.js.map +1 -1
  6. package/dist/session-store.d.ts +18 -4
  7. package/dist/session-store.d.ts.map +1 -1
  8. package/dist/session-store.js +129 -27
  9. package/dist/session-store.js.map +1 -1
  10. package/dist/tests/session-store.test.d.ts +2 -0
  11. package/dist/tests/session-store.test.d.ts.map +1 -0
  12. package/dist/tests/session-store.test.js +394 -0
  13. package/dist/tests/session-store.test.js.map +1 -0
  14. package/dist/tools/context/get-contexts.d.ts.map +1 -1
  15. package/dist/tools/context/get-contexts.js +5 -2
  16. package/dist/tools/context/get-contexts.js.map +1 -1
  17. package/dist/tools/context/switch-context.d.ts.map +1 -1
  18. package/dist/tools/context/switch-context.js +3 -2
  19. package/dist/tools/context/switch-context.js.map +1 -1
  20. package/dist/tools/index.d.ts.map +1 -1
  21. package/dist/tools/index.js +6 -0
  22. package/dist/tools/index.js.map +1 -1
  23. package/dist/tools/interactions/pinch.d.ts +3 -0
  24. package/dist/tools/interactions/pinch.d.ts.map +1 -0
  25. package/dist/tools/interactions/pinch.js +152 -0
  26. package/dist/tools/interactions/pinch.js.map +1 -0
  27. package/dist/tools/session/create-session.d.ts.map +1 -1
  28. package/dist/tools/session/create-session.js +13 -15
  29. package/dist/tools/session/create-session.js.map +1 -1
  30. package/dist/tools/session/delete-session.d.ts.map +1 -1
  31. package/dist/tools/session/delete-session.js +15 -6
  32. package/dist/tools/session/delete-session.js.map +1 -1
  33. package/dist/tools/session/list-sessions.d.ts +2 -0
  34. package/dist/tools/session/list-sessions.d.ts.map +1 -0
  35. package/dist/tools/session/list-sessions.js +43 -0
  36. package/dist/tools/session/list-sessions.js.map +1 -0
  37. package/dist/tools/session/select-session.d.ts +2 -0
  38. package/dist/tools/session/select-session.d.ts.map +1 -0
  39. package/dist/tools/session/select-session.js +38 -0
  40. package/dist/tools/session/select-session.js.map +1 -0
  41. package/package.json +1 -1
  42. package/server.json +2 -2
  43. package/src/server.ts +11 -9
  44. package/src/session-store.ts +181 -28
  45. package/src/tests/session-store.test.ts +498 -0
  46. package/src/tools/context/get-contexts.ts +10 -2
  47. package/src/tools/context/switch-context.ts +7 -2
  48. package/src/tools/index.ts +6 -0
  49. package/src/tools/interactions/pinch.ts +172 -0
  50. package/src/tools/session/create-session.ts +14 -21
  51. package/src/tools/session/delete-session.ts +18 -6
  52. package/src/tools/session/list-sessions.ts +47 -0
  53. package/src/tools/session/select-session.ts +41 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [1.26.0](https://github.com/appium/appium-mcp/compare/v1.25.0...v1.26.0) (2026-03-11)
2
+
3
+ ### Features
4
+
5
+ * handle multiple sessions ([#195](https://github.com/appium/appium-mcp/issues/195)) ([2b967dc](https://github.com/appium/appium-mcp/commit/2b967dc199c1540784e367a63a1540cb0224d57c))
6
+
7
+ ## [1.25.0](https://github.com/appium/appium-mcp/compare/v1.24.2...v1.25.0) (2026-03-11)
8
+
9
+ ### Features
10
+
11
+ * add `appium_pinch` gesture tool for iOS and Android ([#203](https://github.com/appium/appium-mcp/issues/203)) ([ee0896e](https://github.com/appium/appium-mcp/commit/ee0896eb0d9a5dac6002c59683bee1aeee9d2b82))
12
+
1
13
  ## [1.24.2](https://github.com/appium/appium-mcp/compare/v1.24.1...v1.24.2) (2026-03-10)
2
14
 
3
15
  ### Bug Fixes
package/README.md CHANGED
@@ -263,6 +263,7 @@ MCP Appium provides a comprehensive set of tools organized into the following ca
263
263
  | `appium_double_tap` | Perform double tap on an element |
264
264
  | `appium_long_press` | Perform a long press (press and hold) gesture on an element |
265
265
  | `appium_drag_and_drop` | Perform a drag and drop gesture from a source location to a target location (supports element-to-element, element-to-coordinates, coordinates-to-element, and coordinates-to-coordinates) |
266
+ | `appium_pinch` | Perform a pinch gesture to zoom in (scale > 1) or zoom out (scale < 1) on an element or the whole screen. Works on both iOS and Android. |
266
267
  | `appium_set_value` | Enter text into an input field |
267
268
  | `appium_get_text` | Get text content from an element |
268
269
  | `appium_handle_alert` | Accept or dismiss system/permission alerts, or click a dialog button by label |
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAMlC,QAAA,MAAM,MAAM,+CAKV,CAAC;AA4BH,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAMlC,QAAA,MAAM,MAAM,+CAKV,CAAC;AA8BH,eAAe,MAAM,CAAC"}
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FastMCP } from 'fastmcp';
2
2
  import registerTools from './tools/index.js';
3
3
  import registerResources from './resources/index.js';
4
- import { hasActiveSession, safeDeleteSession } from './session-store.js';
4
+ import { listSessions, safeDeleteAllSessions } from './session-store.js';
5
5
  import log from './logger.js';
6
6
  const server = new FastMCP({
7
7
  name: 'MCP Appium',
@@ -16,21 +16,19 @@ server.on('connect', (event) => {
16
16
  });
17
17
  server.on('disconnect', async (event) => {
18
18
  log.info('Client disconnected:', event.session);
19
- // Only try to clean up if there's an active session
20
- if (hasActiveSession()) {
19
+ const sessions = listSessions();
20
+ if (sessions.length > 0) {
21
21
  try {
22
- log.info('Active session detected on disconnect, cleaning up...');
23
- const deleted = await safeDeleteSession();
24
- if (deleted) {
25
- log.info('Session cleaned up successfully on disconnect.');
26
- }
22
+ log.info(`${sessions.length} active session(s) detected on disconnect, cleaning up...`);
23
+ const deletedCount = await safeDeleteAllSessions();
24
+ log.info(`${deletedCount} session(s) cleaned up successfully on disconnect.`);
27
25
  }
28
26
  catch (error) {
29
27
  log.error('Error cleaning up session on disconnect:', error);
30
28
  }
31
29
  }
32
30
  else {
33
- log.info('No active session to clean up on disconnect.');
31
+ log.info('No active sessions to clean up on disconnect.');
34
32
  }
35
33
  });
36
34
  export default server;
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,iBAAiB,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,GAAG,MAAM,aAAa,CAAC;AAE9B,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;IACzB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,OAAO;IAChB,YAAY,EACV,+GAA+G;CAClH,CAAC,CAAC;AAEH,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtB,oDAAoD;AACpD,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;IAC7B,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IACtC,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAChD,oDAAoD;IACpD,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;YAClE,MAAM,OAAO,GAAG,MAAM,iBAAiB,EAAE,CAAC;YAC1C,IAAI,OAAO,EAAE,CAAC;gBACZ,GAAG,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,iBAAiB,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,GAAG,MAAM,aAAa,CAAC;AAE9B,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;IACzB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,OAAO;IAChB,YAAY,EACV,+GAA+G;CAClH,CAAC,CAAC;AAEH,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtB,oDAAoD;AACpD,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;IAC7B,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IACtC,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CACN,GAAG,QAAQ,CAAC,MAAM,2DAA2D,CAC9E,CAAC;YACF,MAAM,YAAY,GAAG,MAAM,qBAAqB,EAAE,CAAC;YACnD,GAAG,CAAC,IAAI,CACN,GAAG,YAAY,oDAAoD,CACpE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -3,6 +3,7 @@ import { XCUITestDriver } from 'appium-xcuitest-driver';
3
3
  import type { Client } from 'webdriver';
4
4
  export type DriverInstance = Client | AndroidUiautomator2Driver | XCUITestDriver;
5
5
  export type NullableDriverInstance = DriverInstance | null;
6
+ export type SessionCapabilities = Record<string, any>;
6
7
  export declare const PLATFORM: {
7
8
  android: string;
8
9
  ios: string;
@@ -42,11 +43,24 @@ export declare function isAndroidUiautomator2DriverSession(driver: NullableDrive
42
43
  * @returns `true` if `driver` is an `XCUITestDriver`.
43
44
  */
44
45
  export declare function isXCUITestDriverSession(driver: NullableDriverInstance): driver is XCUITestDriver;
45
- export declare function setSession(d: DriverInstance, id: string | null): void;
46
- export declare function getDriver(): NullableDriverInstance;
46
+ export declare function setSession(d: DriverInstance, id: string | null, capabilities?: SessionCapabilities): void;
47
+ export declare function getDriver(sessionId?: string): NullableDriverInstance;
47
48
  export declare function getSessionId(): string | null;
48
- export declare function isDeletingSessionInProgress(): boolean;
49
+ export declare function listSessions(): Array<{
50
+ sessionId: string;
51
+ currentContext: string | null;
52
+ isActive: boolean;
53
+ platform: string | null;
54
+ automationName: string | null;
55
+ deviceName: string | null;
56
+ capabilities: SessionCapabilities;
57
+ }>;
58
+ export declare function setActiveSession(sessionId: string): boolean;
59
+ export declare function setCurrentContext(context: string, sessionId?: string): boolean;
60
+ export declare function getCurrentContext(sessionId?: string): string | null;
61
+ export declare function isDeletingSessionInProgress(sessionId?: string): boolean;
49
62
  export declare function hasActiveSession(): boolean;
50
- export declare function safeDeleteSession(): Promise<boolean>;
63
+ export declare function safeDeleteSession(sessionId?: string): Promise<boolean>;
64
+ export declare function safeDeleteAllSessions(): Promise<number>;
51
65
  export declare const getPlatformName: (driver: any) => string;
52
66
  //# sourceMappingURL=session-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAQxC,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,yBAAyB,GACzB,cAAc,CAAC;AACnB,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG,IAAI,CAAC;AAE3D,eAAO,MAAM,QAAQ;;;CAGpB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAQ7E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,sBAAsB,GAC7B,MAAM,IAAI,yBAAyB,CAErC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,IAAI,cAAc,CAE1B;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,QAO9D;AAED,wBAAgB,SAAS,IAAI,sBAAsB,CAElD;AAED,wBAAgB,YAAY,kBAE3B;AAED,wBAAgB,2BAA2B,YAE1C;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAiC1D;AAED,eAAO,MAAM,eAAe,GAAI,QAAQ,GAAG,KAAG,MAe7C,CAAC"}
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAIxC,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,yBAAyB,GACzB,cAAc,CAAC;AACnB,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG,IAAI,CAAC;AAC3D,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AA0BtD,eAAO,MAAM,QAAQ;;;CAGpB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAQ7E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,sBAAsB,GAC7B,MAAM,IAAI,yBAAyB,CAErC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,IAAI,cAAc,CAE1B;AAED,wBAAgB,UAAU,CACxB,CAAC,EAAE,cAAc,EACjB,EAAE,EAAE,MAAM,GAAG,IAAI,EACjB,YAAY,GAAE,mBAAwB,QA6BvC;AAED,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,sBAAsB,CAMpE;AAED,wBAAgB,YAAY,kBAE3B;AAED,wBAAgB,YAAY,IAAI,KAAK,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,mBAAmB,CAAC;CACnC,CAAC,CAUD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAM3D;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAaT;AAED,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMnE;AAED,wBAAgB,2BAA2B,CAAC,SAAS,CAAC,EAAE,MAAM,WAM7D;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAM1C;AAaD,wBAAsB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA6C5E;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CAgB7D;AAED,eAAO,MAAM,eAAe,GAAI,QAAQ,GAAG,KAAG,MAe7C,CAAC"}
@@ -1,9 +1,14 @@
1
1
  import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver';
2
2
  import { XCUITestDriver } from 'appium-xcuitest-driver';
3
3
  import log from './logger.js';
4
- let driver = null;
5
- let sessionId = null;
6
- let isDeletingSession = false; // Lock to prevent concurrent deletion
4
+ /**
5
+ * In-memory store for active Appium sessions and their associated drivers.
6
+ */
7
+ const sessions = new Map();
8
+ /**
9
+ * The ID of the currently active session, or `null` if no session is active.
10
+ */
11
+ let activeSessionId = null;
7
12
  export const PLATFORM = {
8
13
  android: 'Android',
9
14
  ios: 'iOS',
@@ -53,46 +58,124 @@ export function isAndroidUiautomator2DriverSession(driver) {
53
58
  export function isXCUITestDriverSession(driver) {
54
59
  return driver instanceof XCUITestDriver;
55
60
  }
56
- export function setSession(d, id) {
57
- driver = d;
58
- sessionId = id;
59
- // Reset deletion flag when setting a new session
60
- if (d && id) {
61
- isDeletingSession = false;
61
+ export function setSession(d, id, capabilities = {}) {
62
+ if (!id) {
63
+ activeSessionId = null;
64
+ return;
62
65
  }
66
+ const metadata = {
67
+ platform: capabilities.platformName ??
68
+ capabilities['appium:platformName'] ??
69
+ null,
70
+ automationName: capabilities['appium:automationName'] ?? null,
71
+ deviceName: capabilities['appium:deviceName'] ??
72
+ capabilities.deviceName ??
73
+ null,
74
+ capabilities,
75
+ };
76
+ sessions.set(id, {
77
+ driver: d,
78
+ sessionId: id,
79
+ currentContext: 'NATIVE_APP',
80
+ isDeletingSession: false,
81
+ metadata,
82
+ });
83
+ activeSessionId = id;
63
84
  }
64
- export function getDriver() {
65
- return driver;
85
+ export function getDriver(sessionId) {
86
+ const id = sessionId ?? activeSessionId;
87
+ if (!id) {
88
+ return null;
89
+ }
90
+ return sessions.get(id)?.driver ?? null;
66
91
  }
67
92
  export function getSessionId() {
68
- return sessionId;
93
+ return activeSessionId;
94
+ }
95
+ export function listSessions() {
96
+ return Array.from(sessions.values()).map((session) => ({
97
+ sessionId: session.sessionId,
98
+ currentContext: session.currentContext,
99
+ isActive: session.sessionId === activeSessionId,
100
+ platform: session.metadata.platform,
101
+ automationName: session.metadata.automationName,
102
+ deviceName: session.metadata.deviceName,
103
+ capabilities: session.metadata.capabilities,
104
+ }));
105
+ }
106
+ export function setActiveSession(sessionId) {
107
+ if (!sessions.has(sessionId)) {
108
+ return false;
109
+ }
110
+ activeSessionId = sessionId;
111
+ return true;
112
+ }
113
+ export function setCurrentContext(context, sessionId) {
114
+ const id = sessionId ?? activeSessionId;
115
+ if (!id) {
116
+ return false;
117
+ }
118
+ const session = sessions.get(id);
119
+ if (!session) {
120
+ return false;
121
+ }
122
+ session.currentContext = context;
123
+ return true;
69
124
  }
70
- export function isDeletingSessionInProgress() {
71
- return isDeletingSession;
125
+ export function getCurrentContext(sessionId) {
126
+ const id = sessionId ?? activeSessionId;
127
+ if (!id) {
128
+ return null;
129
+ }
130
+ return sessions.get(id)?.currentContext ?? null;
131
+ }
132
+ export function isDeletingSessionInProgress(sessionId) {
133
+ const id = sessionId ?? activeSessionId;
134
+ if (!id) {
135
+ return false;
136
+ }
137
+ return sessions.get(id)?.isDeletingSession ?? false;
72
138
  }
73
139
  export function hasActiveSession() {
74
- return driver !== null && sessionId !== null && !isDeletingSession;
140
+ if (!activeSessionId) {
141
+ return false;
142
+ }
143
+ const session = sessions.get(activeSessionId);
144
+ return !!session && !session.isDeletingSession;
75
145
  }
76
- export async function safeDeleteSession() {
77
- // Check if there's no session to delete
78
- if (!driver || !sessionId) {
146
+ function selectNextActiveSessionId(deletedSessionId) {
147
+ if (activeSessionId !== deletedSessionId) {
148
+ return activeSessionId;
149
+ }
150
+ const nextSession = Array.from(sessions.keys()).find((id) => id !== deletedSessionId);
151
+ return nextSession ?? null;
152
+ }
153
+ export async function safeDeleteSession(sessionId) {
154
+ const id = sessionId ?? activeSessionId;
155
+ if (!id) {
79
156
  log.info('No active session to delete.');
80
157
  return false;
81
158
  }
159
+ const session = sessions.get(id);
160
+ // Check if there's no session to delete
161
+ if (!session) {
162
+ log.info(`Session ${id} not found.`);
163
+ return false;
164
+ }
82
165
  // Check if deletion is already in progress
83
- if (isDeletingSession) {
84
- log.info('Session deletion already in progress, skipping...');
166
+ if (session.isDeletingSession) {
167
+ log.info(`Session ${id} deletion already in progress, skipping...`);
85
168
  return false;
86
169
  }
87
170
  // Set lock
88
- isDeletingSession = true;
171
+ session.isDeletingSession = true;
89
172
  try {
90
- log.info('Deleting current session');
91
- await driver.deleteSession();
173
+ log.info(`Deleting session ${id}`);
174
+ await session.driver.deleteSession();
92
175
  // Clear the session from store
93
- driver = null;
94
- sessionId = null;
95
- log.info('Session deleted successfully.');
176
+ sessions.delete(id);
177
+ activeSessionId = selectNextActiveSessionId(id);
178
+ log.info(`Session ${id} deleted successfully.`);
96
179
  return true;
97
180
  }
98
181
  catch (error) {
@@ -101,8 +184,27 @@ export async function safeDeleteSession() {
101
184
  }
102
185
  finally {
103
186
  // Always release lock
104
- isDeletingSession = false;
187
+ const existingSession = sessions.get(id);
188
+ if (existingSession) {
189
+ existingSession.isDeletingSession = false;
190
+ }
191
+ }
192
+ }
193
+ export async function safeDeleteAllSessions() {
194
+ let deletedCount = 0;
195
+ const sessionIds = Array.from(sessions.keys());
196
+ for (const sessionId of sessionIds) {
197
+ try {
198
+ const deleted = await safeDeleteSession(sessionId);
199
+ if (deleted) {
200
+ deletedCount += 1;
201
+ }
202
+ }
203
+ catch (error) {
204
+ log.error(`Error deleting session ${sessionId}:`, error);
205
+ }
105
206
  }
207
+ return deletedCount;
106
208
  }
107
209
  export const getPlatformName = (driver) => {
108
210
  if (driver instanceof AndroidUiautomator2Driver) {
@@ -1 +1 @@
1
- {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,GAAG,MAAM,aAAa,CAAC;AAE9B,IAAI,MAAM,GAAQ,IAAI,CAAC;AACvB,IAAI,SAAS,GAAkB,IAAI,CAAC;AACpC,IAAI,iBAAiB,GAAG,KAAK,CAAC,CAAC,sCAAsC;AASrE,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,KAAK;CACX,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAA8B;IAClE,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CACL,CAAC,CAAC,MAAM,YAAY,yBAAyB,CAAC;YAC9C,CAAC,CAAC,MAAM,YAAY,cAAc,CAAC,CACpC,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kCAAkC,CAChD,MAA8B;IAE9B,OAAO,MAAM,YAAY,yBAAyB,CAAC;AACrD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAA8B;IAE9B,OAAO,MAAM,YAAY,cAAc,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAiB,EAAE,EAAiB;IAC7D,MAAM,GAAG,CAAC,CAAC;IACX,SAAS,GAAG,EAAE,CAAC;IACf,iDAAiD;IACjD,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACZ,iBAAiB,GAAG,KAAK,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,MAAM,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,IAAI,CAAC,iBAAiB,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,wCAAwC;IACxC,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAC1B,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,2CAA2C;IAC3C,IAAI,iBAAiB,EAAE,CAAC;QACtB,GAAG,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QAC9D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,WAAW;IACX,iBAAiB,GAAG,IAAI,CAAC;IAEzB,IAAI,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACrC,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QAE7B,+BAA+B;QAC/B,MAAM,GAAG,IAAI,CAAC;QACd,SAAS,GAAG,IAAI,CAAC;QAEjB,GAAG,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,sBAAsB;QACtB,iBAAiB,GAAG,KAAK,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAW,EAAU,EAAE;IACrD,IAAI,MAAM,YAAY,yBAAyB,EAAE,CAAC;QAChD,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC1B,CAAC;IACD,IAAI,MAAM,YAAY,cAAc,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC,GAAG,CAAC;IACtB,CAAC;IAED,IAAK,MAAiB,CAAC,SAAS,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC1B,CAAC;SAAM,IAAK,MAAiB,CAAC,KAAK,EAAE,CAAC;QACpC,OAAO,QAAQ,CAAC,GAAG,CAAC;IACtB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;AACzC,CAAC,CAAC"}
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=session-store.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.test.d.ts","sourceRoot":"","sources":["../../src/tests/session-store.test.ts"],"names":[],"mappings":""}