@egain/egain-mcp-server 1.0.6 → 1.0.12

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 (36) hide show
  1. package/README.md +22 -0
  2. package/bin/mcp-server.js +201 -171
  3. package/bin/mcp-server.js.map +9 -9
  4. package/esm/src/funcs/getPortals.d.ts +48 -7
  5. package/esm/src/funcs/getPortals.d.ts.map +1 -1
  6. package/esm/src/funcs/getPortals.js +48 -7
  7. package/esm/src/funcs/getPortals.js.map +1 -1
  8. package/esm/src/hooks/auth-hook.d.ts +6 -1
  9. package/esm/src/hooks/auth-hook.d.ts.map +1 -1
  10. package/esm/src/hooks/auth-hook.js +189 -197
  11. package/esm/src/hooks/auth-hook.js.map +1 -1
  12. package/esm/src/hooks/tooltip-images.d.ts +10 -0
  13. package/esm/src/hooks/tooltip-images.d.ts.map +1 -0
  14. package/esm/src/hooks/tooltip-images.js +12 -0
  15. package/esm/src/hooks/tooltip-images.js.map +1 -0
  16. package/esm/src/lib/config.d.ts +2 -2
  17. package/esm/src/lib/config.js +2 -2
  18. package/esm/src/lib/config.js.map +1 -1
  19. package/esm/src/mcp-server/mcp-server.js +1 -1
  20. package/esm/src/mcp-server/mcp-server.js.map +1 -1
  21. package/esm/src/mcp-server/server.js +1 -1
  22. package/esm/src/mcp-server/server.js.map +1 -1
  23. package/esm/src/mcp-server/tools/getPortals.d.ts.map +1 -1
  24. package/esm/src/mcp-server/tools/getPortals.js +48 -7
  25. package/esm/src/mcp-server/tools/getPortals.js.map +1 -1
  26. package/esm/src/models/getmyportalsop.d.ts +1 -1
  27. package/esm/src/models/getmyportalsop.d.ts.map +1 -1
  28. package/manifest.json +2 -2
  29. package/package.json +1 -1
  30. package/src/funcs/getPortals.ts +48 -7
  31. package/src/hooks/auth-hook.ts +200 -224
  32. package/src/lib/config.ts +2 -2
  33. package/src/mcp-server/mcp-server.ts +1 -1
  34. package/src/mcp-server/server.ts +1 -1
  35. package/src/mcp-server/tools/getPortals.ts +48 -7
  36. package/src/models/getmyportalsop.ts +1 -1
@@ -10,14 +10,55 @@ import { Result } from "../types/fp.js";
10
10
  * Get All Portals Accessible To User
11
11
  *
12
12
  * @remarks
13
+ * Get All Portals Accessible to User
14
+ *
13
15
  * ## Overview
14
- * The Get All Portals Accessible to User API allows a user to fetch all portals accessible to user across all department.
15
- * * If no access tags are specified for a portal, then any user can access the portal.
16
- * * If access tags are specified for a portal, users with a user profile that allows access have access to the portal. For users with multiple user profiles, the user profile that allows access does not need to be the active user profile.
17
- * * All the global users(partition) cannot be assigned user profiles; their access is limited to portals without access restrictions.
18
- * * The only articles returned are associated to an Article type when the parameter, “Include in browse on portals” is set to "Yes".
19
- * * When the "shortUrlTemplate" query parameter is provided, the API filters accessible portals according to the specified language and template name. Portal Short URL specific to to the "shortUrlTemplate" query parameter value is returned in the response.
20
- * * When there is no short URL available for a specific language, the API returns a portal object with an empty "shortURL" field.
16
+ * The Get All Portals Accessible to User API allows a user to fetch all portals accessible to the user across all departments.
17
+ * - If no access tags are specified for a portal, any user can access the portal.
18
+ * - If access tags are specified for a portal, users with a user profile that allows access can access the portal. For users with multiple user profiles, the user profile that allows access does not need to be the active user profile.
19
+ * - Global users (partition) cannot be assigned user profiles; their access is limited to portals without access restrictions.
20
+ * - The only articles returned are associated to an Article type when the parameter “Include in browse on portals” is set to "Yes".
21
+ * - When the `shortUrlTemplate` query parameter is provided, the API filters accessible portals according to the specified language and template name. A portal short URL specific to the `shortUrlTemplate` value is returned in the response when available. If there is no short URL for a language, the portal object returns an empty `shortURL` field.
22
+ *
23
+ * ## Pagination behavior (CRITICAL for AI assistants)
24
+ *
25
+ * **IMPORTANT**: This endpoint is paginated. When searching for a portal by name or listing portals, you MUST automatically fetch ALL pages before concluding that a portal doesn't exist.
26
+ *
27
+ * ### Automatic pagination is REQUIRED when:
28
+ * - User asks to find a portal by name (e.g., "business portal", "Master portal")
29
+ * - User requests to list or see all portals
30
+ * - You need to resolve a natural portal name to its ID
31
+ *
32
+ * ### How to detect more pages exist:
33
+ * The response includes `paginationInfo` with:
34
+ * - `count`: Total number of items across all pages
35
+ * - `pagenum`: Current page number
36
+ * - `pagesize`: Items per page (default: 25)
37
+ *
38
+ * **Check for more pages if ANY of these are true:**
39
+ * 1. The number of portals returned equals `pagesize` (e.g., exactly 25 portals returned)
40
+ * 2. `paginationInfo.count > (pagenum * pagesize)` - there are more items beyond this page
41
+ * 3. The response includes a `link` array with a `next` relation
42
+ *
43
+ * ### Required pagination workflow:
44
+ * 1. Start with `$pagenum=1` and `$pagesize=25` (default)
45
+ * 2. After receiving the response, check `paginationInfo`
46
+ * 3. **If more pages exist** (using the checks above), automatically call this endpoint again with `$pagenum=2`, then `$pagenum=3`, etc.
47
+ * 4. Continue incrementing `$pagenum` until:
48
+ * - A page returns fewer portals than `pagesize` (indicating the last page)
49
+ * - A page returns zero portals
50
+ * - `pagenum * pagesize >= paginationInfo.count` (if count represents total items)
51
+ * 5. Merge all portals from all pages by unique portal ID
52
+ * 6. Only then search through the complete merged list or report results to the user
53
+ *
54
+ * ### Example scenario:
55
+ * If you search for "business portal" and the first page returns 25 portals but none match:
56
+ * - DO NOT immediately tell the user the portal doesn't exist
57
+ * - Check `paginationInfo.count` - if it's > 25, automatically fetch page 2
58
+ * - Continue fetching until all pages are retrieved
59
+ * - Search the complete merged list before concluding the portal doesn't exist
60
+ *
61
+ * This ensures reliable portal name-to-ID resolution and prevents false "not found" errors.
21
62
  */
22
63
  export declare function getPortals(client$: EgainMcpCore, request: GetMyPortalsRequest, options?: RequestOptions): APIPromise<Result<GetMyPortalsResponse, APIError | SDKValidationError | UnexpectedClientError | InvalidRequestError | RequestAbortedError | RequestTimeoutError | ConnectionError>>;
23
64
  //# sourceMappingURL=getPortals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getPortals.d.ts","sourceRoot":"","sources":["../../../src/funcs/getPortals.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK1C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACL,mBAAmB,EAEnB,oBAAoB,EAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAW,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,cAAc,GACvB,UAAU,CACX,MAAM,CACJ,oBAAoB,EAClB,QAAQ,GACR,kBAAkB,GAClB,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,GACnB,mBAAmB,GACnB,eAAe,CAClB,CACF,CAMA"}
1
+ {"version":3,"file":"getPortals.d.ts","sourceRoot":"","sources":["../../../src/funcs/getPortals.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK1C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACL,mBAAmB,EAEnB,oBAAoB,EAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAW,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,cAAc,GACvB,UAAU,CACX,MAAM,CACJ,oBAAoB,EAClB,QAAQ,GACR,kBAAkB,GAClB,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,GACnB,mBAAmB,GACnB,eAAe,CAClB,CACF,CAMA"}
@@ -13,14 +13,55 @@ import { APIPromise } from "../types/async.js";
13
13
  * Get All Portals Accessible To User
14
14
  *
15
15
  * @remarks
16
+ * Get All Portals Accessible to User
17
+ *
16
18
  * ## Overview
17
- * The Get All Portals Accessible to User API allows a user to fetch all portals accessible to user across all department.
18
- * * If no access tags are specified for a portal, then any user can access the portal.
19
- * * If access tags are specified for a portal, users with a user profile that allows access have access to the portal. For users with multiple user profiles, the user profile that allows access does not need to be the active user profile.
20
- * * All the global users(partition) cannot be assigned user profiles; their access is limited to portals without access restrictions.
21
- * * The only articles returned are associated to an Article type when the parameter, “Include in browse on portals” is set to "Yes".
22
- * * When the "shortUrlTemplate" query parameter is provided, the API filters accessible portals according to the specified language and template name. Portal Short URL specific to to the "shortUrlTemplate" query parameter value is returned in the response.
23
- * * When there is no short URL available for a specific language, the API returns a portal object with an empty "shortURL" field.
19
+ * The Get All Portals Accessible to User API allows a user to fetch all portals accessible to the user across all departments.
20
+ * - If no access tags are specified for a portal, any user can access the portal.
21
+ * - If access tags are specified for a portal, users with a user profile that allows access can access the portal. For users with multiple user profiles, the user profile that allows access does not need to be the active user profile.
22
+ * - Global users (partition) cannot be assigned user profiles; their access is limited to portals without access restrictions.
23
+ * - The only articles returned are associated to an Article type when the parameter “Include in browse on portals” is set to "Yes".
24
+ * - When the `shortUrlTemplate` query parameter is provided, the API filters accessible portals according to the specified language and template name. A portal short URL specific to the `shortUrlTemplate` value is returned in the response when available. If there is no short URL for a language, the portal object returns an empty `shortURL` field.
25
+ *
26
+ * ## Pagination behavior (CRITICAL for AI assistants)
27
+ *
28
+ * **IMPORTANT**: This endpoint is paginated. When searching for a portal by name or listing portals, you MUST automatically fetch ALL pages before concluding that a portal doesn't exist.
29
+ *
30
+ * ### Automatic pagination is REQUIRED when:
31
+ * - User asks to find a portal by name (e.g., "business portal", "Master portal")
32
+ * - User requests to list or see all portals
33
+ * - You need to resolve a natural portal name to its ID
34
+ *
35
+ * ### How to detect more pages exist:
36
+ * The response includes `paginationInfo` with:
37
+ * - `count`: Total number of items across all pages
38
+ * - `pagenum`: Current page number
39
+ * - `pagesize`: Items per page (default: 25)
40
+ *
41
+ * **Check for more pages if ANY of these are true:**
42
+ * 1. The number of portals returned equals `pagesize` (e.g., exactly 25 portals returned)
43
+ * 2. `paginationInfo.count > (pagenum * pagesize)` - there are more items beyond this page
44
+ * 3. The response includes a `link` array with a `next` relation
45
+ *
46
+ * ### Required pagination workflow:
47
+ * 1. Start with `$pagenum=1` and `$pagesize=25` (default)
48
+ * 2. After receiving the response, check `paginationInfo`
49
+ * 3. **If more pages exist** (using the checks above), automatically call this endpoint again with `$pagenum=2`, then `$pagenum=3`, etc.
50
+ * 4. Continue incrementing `$pagenum` until:
51
+ * - A page returns fewer portals than `pagesize` (indicating the last page)
52
+ * - A page returns zero portals
53
+ * - `pagenum * pagesize >= paginationInfo.count` (if count represents total items)
54
+ * 5. Merge all portals from all pages by unique portal ID
55
+ * 6. Only then search through the complete merged list or report results to the user
56
+ *
57
+ * ### Example scenario:
58
+ * If you search for "business portal" and the first page returns 25 portals but none match:
59
+ * - DO NOT immediately tell the user the portal doesn't exist
60
+ * - Check `paginationInfo.count` - if it's > 25, automatically fetch page 2
61
+ * - Continue fetching until all pages are retrieved
62
+ * - Search the complete merged list before concluding the portal doesn't exist
63
+ *
64
+ * This ensures reliable portal name-to-ID resolution and prevents false "not found" errors.
24
65
  */
25
66
  export function getPortals(client$, request, options) {
26
67
  return new APIPromise($do(client$, request, options));
@@ -1 +1 @@
1
- {"version":3,"file":"getPortals.js","sourceRoot":"","sources":["../../../src/funcs/getPortals.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"getPortals.js","sourceRoot":"","sources":["../../../src/funcs/getPortals.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,CAAC,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAU3C,OAAO,EAEL,6BAA6B,EAE7B,8BAA8B,GAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAW,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,UAAU,UAAU,CACxB,OAAqB,EACrB,OAA4B,EAC5B,OAAwB;IAaxB,OAAO,IAAI,UAAU,CAAC,GAAG,CACvB,OAAO,EACP,OAAO,EACP,OAAO,CACR,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,GAAG,CAChB,OAAqB,EACrB,OAA4B,EAC5B,OAAwB;IAgBxB,MAAM,OAAO,GAAG,SAAS,CACvB,OAAO,EACP,CAAC,MAAM,EAAE,EAAE,CAAC,6BAA6B,CAAC,KAAK,CAAC,MAAM,CAAC,EACvD,yBAAyB,CAC1B,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC;IACnB,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,eAAe,CAAC;QAC7B,OAAO,EAAE,QAAQ,CAAC,WAAW;QAC7B,QAAQ,EAAE,QAAQ,CAAC,YAAY;QAC/B,UAAU,EAAE,QAAQ,CAAC,cAAc;QACnC,WAAW,EAAE,QAAQ,CAAC,eAAe;QACrC,OAAO,EAAE,QAAQ,CAAC,WAAW;QAC7B,YAAY,EAAE,QAAQ,CAAC,UAAU;QACjC,YAAY,EAAE,QAAQ,CAAC,UAAU;QACjC,kBAAkB,EAAE,QAAQ,CAAC,gBAAgB;KAC9C,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC;QACtC,MAAM,EAAE,kBAAkB;QAC1B,iBAAiB,EAAE,YAAY,CAC7B,iBAAiB,EACjB,QAAQ,CAAC,cAAc,EACvB,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,CACzC;KACF,CAAC,CAAC,CAAC;IACJ,MAAM,aAAa,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvE,MAAM,eAAe,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAE7D,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,OAAO,CAAC,QAAQ;QACzB,OAAO,EAAE,OAAO,EAAE,SAAS,IAAI,OAAO,CAAC,QAAQ,IAAI,EAAE;QACrD,WAAW,EAAE,cAAc;QAC3B,YAAY,EAAE,IAAI;QAClB,gBAAgB,EAAE,eAAe;QACjC,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ;QACzC,WAAW,EAAE,OAAO,EAAE,OAAO;eACxB,OAAO,CAAC,QAAQ,CAAC,WAAW;eAC5B,EAAE,QAAQ,EAAE,MAAM,EAAE;QACzB,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI;YACjC,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;YACL,KAAK;SACN;KACF,CAAC;IAEF,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE;QACjD,QAAQ,EAAE,eAAe;QACzB,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,OAAO,EAAE,SAAS;QAC3B,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,KAAK;QACX,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;QACrC,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS;eACtD,CAAC,CAAC;KACR,EAAE,OAAO,CAAC,CAAC;IACZ,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC;IAE9B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE;QACvC,OAAO;QACP,UAAU,EAAE,EAAE;QACd,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC;IAChC,MAAM,eAAe,GAAG;QACtB,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;KAChD,CAAC;IAEF,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAU7B,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,8BAA8B,EAAE;QAC1C,GAAG,EAAE,sBAAsB;KAC5B,CAAC,EACF,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,8BAA8B,CAAC,EAC1C,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,8BAA8B,EAAE;QAChE,GAAG,EAAE,eAAe;KACrB,CAAC,EACF,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,8BAA8B,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,CACtE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;IAEpD,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;AACpE,CAAC"}
@@ -61,7 +61,6 @@ export declare class AuthenticationHook implements SDKInitHook, BeforeRequestHoo
61
61
  * Monitor browser window for authorization code in URL
62
62
  * Works with ANY redirect URL - detects when URL contains code= parameter
63
63
  */
64
- private monitorBrowserForAuthCode;
65
64
  private getUserAccessToken;
66
65
  private saveToken;
67
66
  /**
@@ -84,6 +83,12 @@ export declare class AuthenticationHook implements SDKInitHook, BeforeRequestHoo
84
83
  * Start the configuration HTTP server
85
84
  */
86
85
  private startConfigServer;
86
+ /**
87
+ * Monitor browser for authorization code with retry on OAuth errors
88
+ * This method will continue monitoring even after OAuth errors (like wrong password)
89
+ * to allow users to retry authentication
90
+ */
91
+ private monitorBrowserWithRetry;
87
92
  /**
88
93
  * Stop the configuration HTTP server
89
94
  */
@@ -1 +1 @@
1
- {"version":3,"file":"auth-hook.d.ts","sourceRoot":"","sources":["../../../src/hooks/auth-hook.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAgrC9C,qBAAa,kBAAmB,YAAW,WAAW,EAAE,iBAAiB;IACvE,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,eAAe,CAAC,CAAM;IAC9B,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,oBAAoB,CAAkB;IAG9C;;;OAGG;IACH,OAAO,CAAC,kBAAkB;gBAuBd,eAAe,CAAC,EAAE,GAAG;IAUjC;;OAEG;YACW,oBAAoB;IA2BlC;;OAEG;YACW,kBAAkB;IA+EhC;;OAEG;YACW,oBAAoB;IAkFlC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAyBxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;OAEG;IACH,OAAO,CAAC,cAAc;IA2GtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,YAAY;IAgEpB;;;OAGG;YACW,yBAAyB;YAoKzB,kBAAkB;YA2GlB,SAAS;IAmBvB;;;;OAIG;YACW,uBAAuB;IA2BrC;;;OAGG;IACH,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACI,UAAU,IAAI,IAAI;IAwBzB;;OAEG;YACW,iBAAiB;IAka/B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;YACW,iBAAiB;IA0IlB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IA2FtC,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IA8B9E,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU;IAoCrC,OAAO,CAAC,eAAe;CAiCxB"}
1
+ {"version":3,"file":"auth-hook.d.ts","sourceRoot":"","sources":["../../../src/hooks/auth-hook.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAgrC9C,qBAAa,kBAAmB,YAAW,WAAW,EAAE,iBAAiB;IACvE,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,eAAe,CAAC,CAAM;IAC9B,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,oBAAoB,CAAkB;IAG9C;;;OAGG;IACH,OAAO,CAAC,kBAAkB;gBAuBd,eAAe,CAAC,EAAE,GAAG;IAUjC;;OAEG;YACW,oBAAoB;IA2BlC;;OAEG;YACW,kBAAkB;IA+EhC;;OAEG;YACW,oBAAoB;IAkFlC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAyBxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;OAEG;IACH,OAAO,CAAC,cAAc;IA2GtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,YAAY;IAgEpB;;;OAGG;YACW,kBAAkB;YA2GlB,SAAS;IAmBvB;;;;OAIG;YACW,uBAAuB;IA2BrC;;;OAGG;IACH,OAAO,CAAC,YAAY;IA8CpB,OAAO,CAAC,iBAAiB;IA6BzB;;OAEG;IACI,UAAU,IAAI,IAAI;IAwBzB;;OAEG;YACW,iBAAiB;IAoX/B;;;;OAIG;YACW,uBAAuB;IAqJrC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;YACW,iBAAiB;IA0IlB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IA6FtC,aAAa,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IA8B9E,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU;IAoCrC,OAAO,CAAC,eAAe;CAiCxB"}
@@ -1657,149 +1657,6 @@ export class AuthenticationHook {
1657
1657
  * Monitor browser window for authorization code in URL
1658
1658
  * Works with ANY redirect URL - detects when URL contains code= parameter
1659
1659
  */
1660
- async monitorBrowserForAuthCode() {
1661
- const platform = process.platform;
1662
- const timeout = 120; // 2 minutes
1663
- const startTime = Date.now();
1664
- if (platform === 'darwin') {
1665
- // macOS - Monitor using AppleScript
1666
- console.error(`🔍 Monitoring ${this.detectedBrowser} for authorization code...`);
1667
- let lastUrl = '';
1668
- while ((Date.now() - startTime) < timeout * 1000) {
1669
- try {
1670
- // Get URL from browser using AppleScript
1671
- const script = `
1672
- tell application "${this.detectedBrowser}"
1673
- try
1674
- set currentURL to URL of active tab of front window
1675
- return currentURL
1676
- on error
1677
- return ""
1678
- end try
1679
- end tell
1680
- `;
1681
- const { stdout } = await execAsync(`osascript -e '${script}'`);
1682
- const currentUrl = stdout.trim();
1683
- if (currentUrl && currentUrl !== lastUrl) {
1684
- lastUrl = currentUrl;
1685
- console.error(`🔍 Current URL: ${currentUrl}`);
1686
- }
1687
- // Check if URL contains code= parameter (regardless of domain)
1688
- if (currentUrl && currentUrl.includes('code=')) {
1689
- console.error('✅ Found authorization code in URL!');
1690
- // Extract the code from the URL
1691
- const codeMatch = currentUrl.match(/[?&]code=([^&]+)/);
1692
- if (codeMatch && codeMatch[1]) {
1693
- const code = decodeURIComponent(codeMatch[1]);
1694
- console.error(`🔑 Extracted authorization code (first 20 chars): ${code.substring(0, 20)}...`);
1695
- console.error(` Code length: ${code.length} characters`);
1696
- // Close the browser window immediately (non-blocking - fire and forget)
1697
- setImmediate(async () => {
1698
- try {
1699
- await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to close front window'`);
1700
- console.error('✅ Browser window closed');
1701
- }
1702
- catch (closeError) {
1703
- console.error('⚠️ Could not close browser window:', closeError);
1704
- }
1705
- });
1706
- // Return code immediately without waiting for window close
1707
- return code;
1708
- }
1709
- }
1710
- // Also check for error parameters
1711
- if (currentUrl && currentUrl.includes('error=')) {
1712
- const errorMatch = currentUrl.match(/[?&]error=([^&]+)/);
1713
- const errorDescMatch = currentUrl.match(/error_description=([^&]+)/);
1714
- const error = errorMatch && errorMatch[1] ? decodeURIComponent(errorMatch[1]) : 'unknown_error';
1715
- const errorDesc = errorDescMatch && errorDescMatch[1] ? decodeURIComponent(errorDescMatch[1]) : 'No description';
1716
- // Throw OAuth error - this will stop monitoring but window stays open so user can see the error
1717
- throw new Error(`OAuth error: ${error} - ${errorDesc}`);
1718
- }
1719
- }
1720
- catch (error) {
1721
- // Re-throw OAuth errors (they should stop monitoring but window stays open)
1722
- if (error instanceof Error && error.message.includes('OAuth error:')) {
1723
- throw error;
1724
- }
1725
- // Ignore AppleScript errors and continue monitoring
1726
- }
1727
- // Wait 500ms before checking again
1728
- await new Promise(resolve => setTimeout(resolve, 500));
1729
- }
1730
- throw new Error('Authentication timeout. Please try again.');
1731
- }
1732
- else if (platform === 'win32') {
1733
- // Windows - Monitor browser window title (contains URL in most browsers)
1734
- console.error(`🔍 Monitoring ${this.detectedBrowser} for authorization code...`);
1735
- let lastTitle = '';
1736
- while ((Date.now() - startTime) < timeout * 1000) {
1737
- try {
1738
- // PowerShell script to get browser window title
1739
- // Window titles often contain the URL or page title
1740
- const browserProcessName = this.detectedBrowser.replace('.exe', '');
1741
- const psScript = `
1742
- $process = Get-Process -Name "${browserProcessName}" -ErrorAction SilentlyContinue |
1743
- Where-Object { $_.MainWindowHandle -ne 0 } |
1744
- Select-Object -First 1
1745
- if ($process) {
1746
- $process.MainWindowTitle
1747
- }
1748
- `.replace(/\n\s+/g, ' ');
1749
- const { stdout } = await execAsync(`powershell -Command "${psScript}"`);
1750
- const windowTitle = stdout.trim();
1751
- if (windowTitle && windowTitle !== lastTitle) {
1752
- lastTitle = windowTitle;
1753
- console.error(`🔍 Browser window: ${windowTitle.substring(0, 100)}...`);
1754
- // Check if title or URL contains the code parameter
1755
- // Most browsers show URL in the title or we can detect redirect completion
1756
- if (windowTitle.includes('code=') || windowTitle.includes('localhost:3333')) {
1757
- console.error('✅ Detected OAuth callback!');
1758
- // Try to extract code from title if visible
1759
- const codeMatch = windowTitle.match(/code=([^&\s]+)/);
1760
- if (codeMatch && codeMatch[1]) {
1761
- const code = decodeURIComponent(codeMatch[1]);
1762
- console.error(`🔑 Extracted authorization code (first 20 chars): ${code.substring(0, 20)}...`);
1763
- console.error(` Code length: ${code.length} characters`);
1764
- // Close browser window immediately (non-blocking - fire and forget)
1765
- setImmediate(async () => {
1766
- try {
1767
- await execAsync(`powershell -Command "Stop-Process -Name '${browserProcessName}' -Force"`);
1768
- console.error('✅ Browser window closed');
1769
- }
1770
- catch (closeError) {
1771
- console.error('⚠️ Could not close browser window:', closeError);
1772
- }
1773
- });
1774
- // Return code immediately without waiting for window close
1775
- return code;
1776
- }
1777
- }
1778
- // Check for OAuth error in title
1779
- if (windowTitle.includes('error=')) {
1780
- const errorMatch = windowTitle.match(/error=([^&\s]+)/);
1781
- const error = errorMatch && errorMatch[1] ? decodeURIComponent(errorMatch[1]) : 'unknown_error';
1782
- // Throw OAuth error - this will stop monitoring but window stays open so user can see the error
1783
- throw new Error(`OAuth error: ${error}`);
1784
- }
1785
- }
1786
- }
1787
- catch (error) {
1788
- // Re-throw OAuth errors (they should stop monitoring but window stays open)
1789
- if (error instanceof Error && error.message.includes('OAuth error:')) {
1790
- throw error;
1791
- }
1792
- // Ignore other errors and continue monitoring
1793
- }
1794
- // Wait 500ms before checking again
1795
- await new Promise(resolve => setTimeout(resolve, 500));
1796
- }
1797
- throw new Error('Authentication timeout. The browser window title did not show the authorization code. Please ensure your redirect URL is http://localhost:3333/callback for automatic detection on Windows.');
1798
- }
1799
- else {
1800
- throw new Error('Linux is not supported. Use macOS or Windows for automatic authentication.');
1801
- }
1802
- }
1803
1660
  async getUserAccessToken(code) {
1804
1661
  const { clientId, clientSecret, redirectUri, accessUrl } = this.authConfig;
1805
1662
  console.error('🔄 Starting token exchange...');
@@ -1963,6 +1820,24 @@ export class AuthenticationHook {
1963
1820
  }
1964
1821
  else {
1965
1822
  console.error(`⏰ AUTH: Token expires in ${Math.round(timeUntilExpiry / 1000)} seconds - treating as expired`);
1823
+ // Delete expired token files to prevent reuse
1824
+ const projectRoot = getProjectRoot();
1825
+ const tokenPath = path.join(projectRoot, '.bearer_token');
1826
+ try {
1827
+ if (fs.existsSync(tokenPath)) {
1828
+ fs.unlinkSync(tokenPath);
1829
+ console.error('🗑️ Deleted expired bearer token file');
1830
+ }
1831
+ if (fs.existsSync(metadataPath)) {
1832
+ fs.unlinkSync(metadataPath);
1833
+ console.error('🗑️ Deleted expired bearer token metadata file');
1834
+ }
1835
+ }
1836
+ catch (error) {
1837
+ console.error('⚠️ Failed to delete expired token files:', error);
1838
+ }
1839
+ // Clear in-memory token to prevent reuse
1840
+ this.token = null;
1966
1841
  return false;
1967
1842
  }
1968
1843
  }
@@ -1985,9 +1860,20 @@ export class AuthenticationHook {
1985
1860
  return token;
1986
1861
  }
1987
1862
  }
1863
+ else {
1864
+ // Token file doesn't exist, clear in-memory token if it was set
1865
+ if (this.token) {
1866
+ console.error('🗑️ Token file deleted, clearing in-memory token');
1867
+ this.token = null;
1868
+ }
1869
+ }
1988
1870
  }
1989
1871
  catch (error) {
1990
1872
  console.error('Could not load existing token:', error);
1873
+ // Clear in-memory token on error as well
1874
+ if (this.token) {
1875
+ this.token = null;
1876
+ }
1991
1877
  }
1992
1878
  return null;
1993
1879
  }
@@ -2117,31 +2003,7 @@ export class AuthenticationHook {
2117
2003
  // Start monitoring browser in background (for ANY redirect URL)
2118
2004
  console.error('🔍 Starting browser URL monitoring for authorization code...');
2119
2005
  setImmediate(async () => {
2120
- try {
2121
- const code = await this.monitorBrowserForAuthCode();
2122
- console.error('✅ Authorization code detected:', code.substring(0, 10) + '...');
2123
- const accessToken = await this.getUserAccessToken(code);
2124
- console.error('✅ Access token received');
2125
- this.token = accessToken;
2126
- // Trigger cache initialization if available
2127
- if (this.portalCacheHook) {
2128
- try {
2129
- const fakeRequest = new Request(this.authConfig.environmentUrl, {
2130
- headers: { 'Authorization': `Bearer ${accessToken}` }
2131
- });
2132
- await this.portalCacheHook.ensureCacheInitialized(fakeRequest);
2133
- }
2134
- catch (error) {
2135
- // Cache init failure is non-fatal
2136
- }
2137
- }
2138
- console.error('🎉 Authentication complete! Stopping config server...');
2139
- this.stopConfigServer();
2140
- }
2141
- catch (authError) {
2142
- console.error('❌ Authentication monitoring error:', authError);
2143
- this.stopConfigServer();
2144
- }
2006
+ await this.monitorBrowserWithRetry();
2145
2007
  });
2146
2008
  }
2147
2009
  catch (error) {
@@ -2230,33 +2092,7 @@ export class AuthenticationHook {
2230
2092
  // Start monitoring browser in background (for ANY redirect URL)
2231
2093
  console.error('🔍 Starting browser URL monitoring for authorization code...');
2232
2094
  setImmediate(async () => {
2233
- try {
2234
- const code = await this.monitorBrowserForAuthCode();
2235
- console.error('✅ Authorization code detected:', code.substring(0, 10) + '...');
2236
- const accessToken = await this.getUserAccessToken(code);
2237
- console.error('✅ Access token received');
2238
- this.token = accessToken;
2239
- // Trigger cache initialization if available
2240
- if (this.portalCacheHook) {
2241
- console.error('🔄 Triggering cache initialization...');
2242
- try {
2243
- const fakeRequest = new Request(this.authConfig.environmentUrl, {
2244
- headers: { 'Authorization': `Bearer ${accessToken}` }
2245
- });
2246
- await this.portalCacheHook.ensureCacheInitialized(fakeRequest);
2247
- console.error('✅ Cache initialization completed');
2248
- }
2249
- catch (error) {
2250
- console.error('⚠️ Cache initialization failed:', error);
2251
- }
2252
- }
2253
- console.error('🎉 Authentication complete! Stopping config server...');
2254
- this.stopConfigServer();
2255
- }
2256
- catch (authError) {
2257
- console.error('❌ Authentication monitoring error:', authError);
2258
- this.stopConfigServer();
2259
- }
2095
+ await this.monitorBrowserWithRetry();
2260
2096
  });
2261
2097
  }
2262
2098
  catch (error) {
@@ -2322,8 +2158,18 @@ export class AuthenticationHook {
2322
2158
  this.stopConfigServer();
2323
2159
  }
2324
2160
  catch (authError) {
2325
- console.error('❌ Token exchange error:', authError);
2326
- this.stopConfigServer();
2161
+ // Check if this is an OAuth error (like wrong username/password)
2162
+ const isOAuthError = authError instanceof Error && authError.message.includes('OAuth error:');
2163
+ if (isOAuthError) {
2164
+ // For OAuth errors, don't stop the server - allow user to try again
2165
+ console.error('❌ OAuth authentication error:', authError.message);
2166
+ console.error('💡 The configuration server will remain running. Please try again with correct credentials.');
2167
+ }
2168
+ else {
2169
+ // For other token exchange errors, stop the server
2170
+ console.error('❌ Token exchange error:', authError);
2171
+ this.stopConfigServer();
2172
+ }
2327
2173
  }
2328
2174
  });
2329
2175
  // Send success page to browser
@@ -2397,6 +2243,150 @@ export class AuthenticationHook {
2397
2243
  });
2398
2244
  });
2399
2245
  }
2246
+ /**
2247
+ * Monitor browser for authorization code with retry on OAuth errors
2248
+ * This method will continue monitoring even after OAuth errors (like wrong password)
2249
+ * to allow users to retry authentication
2250
+ */
2251
+ async monitorBrowserWithRetry() {
2252
+ const platform = process.platform;
2253
+ const timeout = 120; // 2 minutes
2254
+ const startTime = Date.now();
2255
+ let oAuthErrorLogged = false;
2256
+ let lastUrl = '';
2257
+ let lastErrorUrl = null;
2258
+ // Log monitoring start only once
2259
+ if (platform === 'darwin') {
2260
+ console.error(`🔍 Monitoring ${this.detectedBrowser} for authorization code...`);
2261
+ }
2262
+ else if (platform === 'win32') {
2263
+ console.error(`🔍 Monitoring ${this.detectedBrowser} for authorization code...`);
2264
+ }
2265
+ while (true) {
2266
+ try {
2267
+ // Check timeout
2268
+ if ((Date.now() - startTime) >= timeout * 1000) {
2269
+ throw new Error('Authentication timeout. Please try again.');
2270
+ }
2271
+ let currentUrl = '';
2272
+ if (platform === 'darwin') {
2273
+ // macOS - Get URL from browser using AppleScript
2274
+ const script = `
2275
+ tell application "${this.detectedBrowser}"
2276
+ try
2277
+ set currentURL to URL of active tab of front window
2278
+ return currentURL
2279
+ on error
2280
+ return ""
2281
+ end try
2282
+ end tell
2283
+ `;
2284
+ const { stdout } = await execAsync(`osascript -e '${script}'`);
2285
+ currentUrl = stdout.trim();
2286
+ }
2287
+ else if (platform === 'win32') {
2288
+ // Windows - Get browser window title
2289
+ const browserProcessName = this.detectedBrowser.replace('.exe', '');
2290
+ const psScript = `
2291
+ $process = Get-Process -Name "${browserProcessName}" -ErrorAction SilentlyContinue |
2292
+ Where-Object { $_.MainWindowHandle -ne 0 } |
2293
+ Select-Object -First 1
2294
+ if ($process) {
2295
+ $process.MainWindowTitle
2296
+ }
2297
+ `.replace(/\n\s+/g, ' ');
2298
+ const { stdout } = await execAsync(`powershell -Command "${psScript}"`);
2299
+ currentUrl = stdout.trim();
2300
+ }
2301
+ // Only log URL when it changes
2302
+ if (currentUrl && currentUrl !== lastUrl) {
2303
+ lastUrl = currentUrl;
2304
+ console.error(`🔍 Current URL: ${currentUrl}`);
2305
+ }
2306
+ // Check if URL contains code= parameter
2307
+ if (currentUrl && currentUrl.includes('code=')) {
2308
+ const codeMatch = currentUrl.match(/[?&]code=([^&]+)/);
2309
+ if (codeMatch && codeMatch[1]) {
2310
+ const code = decodeURIComponent(codeMatch[1]);
2311
+ console.error('✅ Found authorization code in URL!');
2312
+ console.error(`🔑 Extracted authorization code (first 20 chars): ${code.substring(0, 20)}...`);
2313
+ // Close browser window (non-blocking)
2314
+ setImmediate(async () => {
2315
+ try {
2316
+ if (platform === 'darwin') {
2317
+ await execAsync(`osascript -e 'tell application "${this.detectedBrowser}" to close front window'`);
2318
+ }
2319
+ else if (platform === 'win32') {
2320
+ const browserProcessName = this.detectedBrowser.replace('.exe', '');
2321
+ await execAsync(`powershell -Command "Stop-Process -Name '${browserProcessName}' -Force"`);
2322
+ }
2323
+ }
2324
+ catch (closeError) {
2325
+ // Ignore close errors
2326
+ }
2327
+ });
2328
+ console.error('✅ Authorization code detected:', code.substring(0, 10) + '...');
2329
+ const accessToken = await this.getUserAccessToken(code);
2330
+ console.error('✅ Access token received');
2331
+ this.token = accessToken;
2332
+ // Trigger cache initialization if available
2333
+ if (this.portalCacheHook) {
2334
+ try {
2335
+ const fakeRequest = new Request(this.authConfig.environmentUrl, {
2336
+ headers: { 'Authorization': `Bearer ${accessToken}` }
2337
+ });
2338
+ await this.portalCacheHook.ensureCacheInitialized(fakeRequest);
2339
+ console.error('✅ Cache initialization completed');
2340
+ }
2341
+ catch (error) {
2342
+ console.error('⚠️ Cache initialization failed:', error);
2343
+ }
2344
+ }
2345
+ console.error('🎉 Authentication complete! Stopping config server...');
2346
+ this.stopConfigServer();
2347
+ return; // Success - exit the loop
2348
+ }
2349
+ }
2350
+ // Check for error parameters - only throw if this is a new error URL
2351
+ if (currentUrl && currentUrl.includes('error=')) {
2352
+ if (currentUrl !== lastErrorUrl) {
2353
+ lastErrorUrl = currentUrl;
2354
+ const errorMatch = currentUrl.match(/[?&]error=([^&]+)/);
2355
+ const errorDescMatch = currentUrl.match(/error_description=([^&]+)/);
2356
+ const error = errorMatch && errorMatch[1] ? decodeURIComponent(errorMatch[1]) : 'unknown_error';
2357
+ const errorDesc = errorDescMatch && errorDescMatch[1] ? decodeURIComponent(errorDescMatch[1]) : 'No description';
2358
+ // Log error only once
2359
+ if (!oAuthErrorLogged) {
2360
+ console.error('❌ OAuth authentication error:', `${error} - ${errorDesc}`);
2361
+ console.error('💡 The configuration server will remain running. Please try again with correct credentials.');
2362
+ console.error('🔍 Continuing to monitor browser for authorization code...');
2363
+ oAuthErrorLogged = true;
2364
+ }
2365
+ // Continue monitoring silently - don't throw, just keep checking
2366
+ }
2367
+ // If it's the same error URL, continue monitoring silently
2368
+ }
2369
+ else {
2370
+ // Reset error tracking if URL no longer contains error
2371
+ if (lastErrorUrl !== null) {
2372
+ lastErrorUrl = null;
2373
+ oAuthErrorLogged = false; // Reset so we can log new errors
2374
+ }
2375
+ }
2376
+ // Wait before checking again
2377
+ await new Promise(resolve => setTimeout(resolve, 500));
2378
+ }
2379
+ catch (error) {
2380
+ // Only handle non-OAuth errors here (OAuth errors are handled above)
2381
+ if (!(error instanceof Error && error.message.includes('OAuth error:'))) {
2382
+ console.error('❌ Authentication monitoring error:', error);
2383
+ this.stopConfigServer();
2384
+ return; // Exit the loop
2385
+ }
2386
+ // OAuth errors are handled in the main loop above
2387
+ }
2388
+ }
2389
+ }
2400
2390
  /**
2401
2391
  * Stop the configuration HTTP server
2402
2392
  */
@@ -2572,6 +2562,8 @@ export class AuthenticationHook {
2572
2562
  }
2573
2563
  else {
2574
2564
  console.error('⏰ Existing token is expired or not found, proceeding with fresh login...');
2565
+ // Clear in-memory token to ensure fresh authentication
2566
+ this.token = null;
2575
2567
  }
2576
2568
  // Check if we have configuration (from .env or file)
2577
2569
  const hasConfig = this.authConfig.environmentUrl && this.authConfig.clientId &&