lex-microsoft_teams 0.6.23 → 0.6.25

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc24206d1c97c648d8c3cf0b5ab0acac653195153903e901e1d89e89445b6618
4
- data.tar.gz: 5768ef9650b4bc861d193c8477e80f2e96962501c11246aaf1178b00c43f1432
3
+ metadata.gz: 42353a2d92e77ba3659f2ab93c24339efca2e869a4ae18d30621b5fb3e3cd947
4
+ data.tar.gz: 4420f02e9d66c85c673e6411203b06fa49862d9a5a16ef78cf7b55a366da3a8d
5
5
  SHA512:
6
- metadata.gz: eb531084dcff80d75c9e624ab02f2db647d18758cf7621f7ee3ea8f79be593b5db2d4297aef2ac716aba394a76945e766ee13015b4558ed50b57dacc401d4fff
7
- data.tar.gz: f7e5df0a0e9b251043b14e1dac114c24c797b23fc8097402508bfacf326f6903f125ffcbd6df474b9927542b2ba4fd123d8aabf9355ac3b302a1b47cb2510694
6
+ metadata.gz: b165c26eca6e63b1d181a0aee9a2bfadd72039e2cda558bc33fc08e49a1ba1730af044012dcb6936848c03b02ca7d30c00be6678c5e4e9665070f2811b24ec4a
7
+ data.tar.gz: bdae821120daca1fcd888c57cc2a2996aced5b8270e88332235dc4c2ee71fe1a0f4533f6b5a28df6761f78f3bb233e7aafb4f92db4c33fec518cf1d39d78584e
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.6.25] - 2026-03-28
6
+
7
+ ### Fixed
8
+ - `Hooks::Auth` — migrated from v2.0 `Routes::Hooks` pattern to v3.0 `LexDispatch` pattern: replaced instance `route`/`runner_class` overrides with a class-level `self.runner_class`; hook now registers as `POST /api/extensions/microsoft_teams/hooks/auth/handle` (was `/api/hooks/lex/microsoft_teams/auth/callback`)
9
+ - `Runners::Auth` — added `handle` alias for `auth_callback` so LexDispatch's default `:handle` routing resolves correctly
10
+ - `Helpers::BrowserAuth` — updated all three references to the hook redirect URI and probe path from the stale v2.0 path to `/api/extensions/microsoft_teams/hooks/auth/handle`
11
+
12
+ ## [0.6.24] - 2026-03-28
13
+
14
+ ### Added
15
+ - `Actors::AbsorbMeeting` — Subscription actor that listens on `lex.microsoft_teams.absorbers.meeting.absorb` and delegates to `Absorbers::Meeting#absorb`
16
+ - `Helpers::GraphClient` — mixin module wrapping `Helpers::Client#graph_connection` with `graph_get`, `graph_post`, `graph_paginate`, and an inline `GraphError` class for responses other than 200, 201, 204, or 404; 401/403 raise with descriptive messages including the Graph error body when available
17
+
5
18
  ### Fixed
6
19
  - `Absorbers::Meeting#graph_token` — rescue now captures the exception as `=> e` and logs a warning, satisfying the rescue-logging lint rule
7
20
 
data/CLAUDE.md CHANGED
@@ -10,7 +10,7 @@ Legion Extension that connects LegionIO to Microsoft Teams via Graph API and Bot
10
10
 
11
11
  **GitHub**: https://github.com/LegionIO/lex-microsoft_teams
12
12
  **License**: MIT
13
- **Version**: 0.6.23
13
+ **Version**: 0.6.24
14
14
 
15
15
  ## Architecture
16
16
 
@@ -64,7 +64,7 @@ Legion::Extensions::MicrosoftTeams
64
64
  │ ├── TraceRetriever # Retrieves memory traces from the shared store for bot context (2000-token budget, strength-ranked dedup)
65
65
  │ └── TransformDefinitions # lex-transformer definitions for conversation extraction and person summary
66
66
  ├── Hooks/
67
- │ └── Auth # OAuth callback hook (mount '/callback') → /api/hooks/lex/microsoft_teams/auth/callback
67
+ │ └── Auth # OAuth callback hook (mount '/callback') → /api/extensions/microsoft_teams/hooks/auth/handle
68
68
  ├── CLI/
69
69
  │ └── Auth # CLI module for `legion lex exec teams auth login/status`
70
70
  └── Client # Standalone client (includes all runners)
@@ -74,10 +74,10 @@ Legion::Extensions::MicrosoftTeams
74
74
 
75
75
  Opt-in browser-based OAuth for delegated Microsoft Graph permissions. Two flows:
76
76
 
77
- - **Authorization Code + PKCE** (primary): Opens browser for Entra ID login. When the Legion API is running, uses the hook URL (`/api/hooks/lex/microsoft_teams/auth/callback`) with `Legion::Events` for callback notification; otherwise falls back to an ephemeral local port via `CallbackServer`
77
+ - **Authorization Code + PKCE** (primary): Opens browser for Entra ID login. When the Legion API is running, uses the hook URL (`/api/extensions/microsoft_teams/hooks/auth/handle`) with `Legion::Events` for callback notification; otherwise falls back to an ephemeral local port via `CallbackServer`
78
78
  - **Device Code** (fallback): Auto-selected in headless/SSH environments (no `DISPLAY`/`WAYLAND_DISPLAY`)
79
79
 
80
- Tokens stored in Vault at a per-user path (`{USER}/microsoft_teams/delegated_token`, where `{USER}` is the system username) with configurable pre-expiry silent refresh. CLI command: `legion auth teams`. Hook route: `GET|POST /api/hooks/lex/microsoft_teams/auth/callback` for daemon re-auth (routed through Ingress for RBAC/audit).
80
+ Tokens stored in Vault at a per-user path (`{USER}/microsoft_teams/delegated_token`, where `{USER}` is the system username) with configurable pre-expiry silent refresh. CLI command: `legion auth teams`. Hook route: `POST /api/extensions/microsoft_teams/hooks/auth/handle` for daemon re-auth (routed through LexDispatch for RBAC/audit).
81
81
 
82
82
  Key files: `Helpers::BrowserAuth` (orchestrator), `Helpers::CallbackServer` (ephemeral TCP), `Runners::Auth` (authorize_url, exchange_code, refresh_delegated_token, auth_callback), `Helpers::TokenCache` (delegated slot), `Hooks::Auth` (hook class with mount path).
83
83
 
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module MicrosoftTeams
6
+ module Actor
7
+ class AbsorbMeeting < Legion::Extensions::Actors::Subscription
8
+ def runner_class = 'Legion::Extensions::MicrosoftTeams::Absorbers::Meeting'
9
+ def runner_function = 'absorb'
10
+ def check_subtask? = false
11
+ def generate_task? = false
12
+
13
+ def enabled?
14
+ defined?(Legion::Extensions::Absorbers::Base) &&
15
+ defined?(Legion::Extensions::MicrosoftTeams::Absorbers::Meeting)
16
+ rescue StandardError => e
17
+ log.debug("AbsorbMeeting#enabled?: #{e.message}")
18
+ false
19
+ end
20
+
21
+ def work(payload)
22
+ parsed = parse_payload(payload)
23
+ absorber = Absorbers::Meeting.new
24
+ result = absorber.absorb(
25
+ url: parsed[:url],
26
+ metadata: parsed[:metadata] || {},
27
+ context: parsed[:context] || {}
28
+ )
29
+ if result.respond_to?(:[]) && result.key?(:success)
30
+ if result[:success]
31
+ ack!
32
+ else
33
+ log.error("AbsorbMeeting actor absorb failed: #{result.inspect}")
34
+ reject!(requeue: false)
35
+ end
36
+ else
37
+ ack!
38
+ end
39
+ result
40
+ rescue StandardError => e
41
+ log.error("AbsorbMeeting actor error: #{e.message}")
42
+ reject!(requeue: false)
43
+ end
44
+
45
+ private
46
+
47
+ def parse_payload(payload)
48
+ data = payload.is_a?(String) ? json_load(payload) : payload
49
+ return {} unless data.is_a?(Hash)
50
+
51
+ data.transform_keys(&:to_sym)
52
+ rescue StandardError => e
53
+ log.debug("AbsorbMeeting#parse_payload: #{e.message}")
54
+ {}
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -72,7 +72,7 @@ module Legion
72
72
  else
73
73
  4567
74
74
  end
75
- "http://127.0.0.1:#{port}/api/hooks/lex/microsoft_teams/auth/callback"
75
+ "http://127.0.0.1:#{port}/api/extensions/microsoft_teams/hooks/auth/handle"
76
76
  end
77
77
 
78
78
  def generate_pkce
@@ -121,9 +121,9 @@ module Legion
121
121
  def hook_route_registered?
122
122
  return false unless defined?(Legion::API)
123
123
 
124
- log.debug("Probing hook route at http://127.0.0.1:#{api_port}/api/hooks/lex/microsoft_teams/auth/callback")
124
+ log.debug("Probing hook route at http://127.0.0.1:#{api_port}/api/extensions/microsoft_teams/hooks/auth/handle")
125
125
  conn = Faraday.new(url: "http://127.0.0.1:#{api_port}")
126
- resp = conn.head('/api/hooks/lex/microsoft_teams/auth/callback')
126
+ resp = conn.head('/api/extensions/microsoft_teams/hooks/auth/handle')
127
127
  registered = resp.status != 404
128
128
  log.debug("Hook route probe returned #{resp.status} (registered=#{registered})")
129
129
  registered
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module MicrosoftTeams
6
+ module Helpers
7
+ module GraphClient
8
+ class GraphError < StandardError; end
9
+
10
+ def graph_get(path, token:, params: {})
11
+ connection = graph_connection(token: token)
12
+ response = connection.get(path, params)
13
+ handle_graph_response(response, path)
14
+ end
15
+
16
+ def graph_paginate(path, token:, params: {}, max_pages: 10)
17
+ results = []
18
+ next_link = nil
19
+ page = 0
20
+
21
+ loop do
22
+ current_path = next_link || path
23
+ data = graph_get(current_path, token: token, params: page.zero? ? params : {})
24
+ break if data.nil?
25
+
26
+ items = data['value'] || data[:value]
27
+ results.concat(Array(items)) if items
28
+
29
+ next_link = data['@odata.nextLink'] || data[:'@odata.nextLink']
30
+ page += 1
31
+ break if next_link.nil? || page >= max_pages
32
+ end
33
+
34
+ results
35
+ end
36
+
37
+ def graph_post(path, token:, body: {})
38
+ connection = graph_connection(token: token)
39
+ response = connection.post(path) do |req|
40
+ req.body = body
41
+ end
42
+ handle_graph_response(response, path)
43
+ end
44
+
45
+ private
46
+
47
+ def handle_graph_response(response, path)
48
+ error_message =
49
+ if response.body.respond_to?(:dig)
50
+ response.body.dig('error', 'message') ||
51
+ response.body.dig(:error, :message)
52
+ end
53
+
54
+ case response.status
55
+ when 200, 201
56
+ response.body
57
+ when 204, 404
58
+ nil
59
+ when 401
60
+ detail = error_message || 'Access token is missing, expired, or invalid.'
61
+ raise GraphError, "Graph API 401 Unauthorized on #{path}: #{detail}"
62
+ when 403
63
+ detail = error_message || 'Caller does not have sufficient permissions to perform this action.'
64
+ raise GraphError, "Graph API 403 Forbidden on #{path}: #{detail}"
65
+ else
66
+ base_message = "Graph API #{response.status} on #{path}"
67
+ base_message = "#{base_message}: #{error_message}" if error_message
68
+ raise GraphError, base_message
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -7,11 +7,7 @@ module Legion
7
7
  class Auth < Legion::Extensions::Hooks::Base
8
8
  mount '/callback'
9
9
 
10
- def route(_headers, _payload)
11
- :auth_callback
12
- end
13
-
14
- def runner_class
10
+ def self.runner_class
15
11
  'Legion::Extensions::MicrosoftTeams::Runners::Auth'
16
12
  end
17
13
  end
@@ -124,6 +124,7 @@ module Legion
124
124
  body: callback_success_html }
125
125
  }
126
126
  end
127
+ alias handle auth_callback
127
128
 
128
129
  private
129
130
 
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module MicrosoftTeams
6
- VERSION = '0.6.23'
6
+ VERSION = '0.6.25'
7
7
  end
8
8
  end
9
9
  end
@@ -33,6 +33,7 @@ require 'legion/extensions/microsoft_teams/helpers/callback_server'
33
33
  require 'legion/extensions/microsoft_teams/helpers/browser_auth'
34
34
  require 'legion/extensions/microsoft_teams/helpers/permission_guard'
35
35
  require 'legion/extensions/microsoft_teams/helpers/transform_definitions'
36
+ require 'legion/extensions/microsoft_teams/helpers/graph_client'
36
37
 
37
38
  # Transport
38
39
  if defined?(Legion::Transport)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-microsoft_teams
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.23
4
+ version: 0.6.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -176,6 +176,7 @@ files:
176
176
  - lex-microsoft_teams.gemspec
177
177
  - lib/legion/extensions/microsoft_teams.rb
178
178
  - lib/legion/extensions/microsoft_teams/absorbers/meeting.rb
179
+ - lib/legion/extensions/microsoft_teams/actors/absorb_meeting.rb
179
180
  - lib/legion/extensions/microsoft_teams/actors/api_ingest.rb
180
181
  - lib/legion/extensions/microsoft_teams/actors/auth_validator.rb
181
182
  - lib/legion/extensions/microsoft_teams/actors/cache_bulk_ingest.rb
@@ -194,6 +195,7 @@ files:
194
195
  - lib/legion/extensions/microsoft_teams/helpers/browser_auth.rb
195
196
  - lib/legion/extensions/microsoft_teams/helpers/callback_server.rb
196
197
  - lib/legion/extensions/microsoft_teams/helpers/client.rb
198
+ - lib/legion/extensions/microsoft_teams/helpers/graph_client.rb
197
199
  - lib/legion/extensions/microsoft_teams/helpers/high_water_mark.rb
198
200
  - lib/legion/extensions/microsoft_teams/helpers/permission_guard.rb
199
201
  - lib/legion/extensions/microsoft_teams/helpers/prompt_resolver.rb