mcp-twake-mail 0.1.0 → 1.0.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 (69) hide show
  1. package/README.md +77 -48
  2. package/build/cli/commands/setup.js +54 -12
  3. package/build/cli/commands/setup.js.map +1 -1
  4. package/build/cli/prompts/setup-wizard.d.ts +33 -1
  5. package/build/cli/prompts/setup-wizard.js +134 -2
  6. package/build/cli/prompts/setup-wizard.js.map +1 -1
  7. package/build/cli/prompts/setup-wizard.test.d.ts +1 -0
  8. package/build/cli/prompts/setup-wizard.test.js +161 -0
  9. package/build/cli/prompts/setup-wizard.test.js.map +1 -0
  10. package/build/config/schema.d.ts +2 -0
  11. package/build/config/schema.js +3 -0
  12. package/build/config/schema.js.map +1 -1
  13. package/build/discovery/dns-srv.d.ts +18 -0
  14. package/build/discovery/dns-srv.js +60 -0
  15. package/build/discovery/dns-srv.js.map +1 -0
  16. package/build/discovery/dns-srv.test.d.ts +4 -0
  17. package/build/discovery/dns-srv.test.js +79 -0
  18. package/build/discovery/dns-srv.test.js.map +1 -0
  19. package/build/discovery/index.d.ts +9 -0
  20. package/build/discovery/index.js +13 -0
  21. package/build/discovery/index.js.map +1 -0
  22. package/build/discovery/oauth-discovery.d.ts +34 -0
  23. package/build/discovery/oauth-discovery.js +160 -0
  24. package/build/discovery/oauth-discovery.js.map +1 -0
  25. package/build/discovery/oauth-discovery.test.d.ts +1 -0
  26. package/build/discovery/oauth-discovery.test.js +198 -0
  27. package/build/discovery/oauth-discovery.test.js.map +1 -0
  28. package/build/discovery/orchestrator.d.ts +31 -0
  29. package/build/discovery/orchestrator.js +87 -0
  30. package/build/discovery/orchestrator.js.map +1 -0
  31. package/build/discovery/orchestrator.test.d.ts +4 -0
  32. package/build/discovery/orchestrator.test.js +242 -0
  33. package/build/discovery/orchestrator.test.js.map +1 -0
  34. package/build/discovery/types.d.ts +18 -0
  35. package/build/discovery/types.js +15 -0
  36. package/build/discovery/types.js.map +1 -0
  37. package/build/discovery/well-known.d.ts +21 -0
  38. package/build/discovery/well-known.js +52 -0
  39. package/build/discovery/well-known.js.map +1 -0
  40. package/build/discovery/well-known.test.d.ts +4 -0
  41. package/build/discovery/well-known.test.js +120 -0
  42. package/build/discovery/well-known.test.js.map +1 -0
  43. package/build/mcp/server.d.ts +5 -3
  44. package/build/mcp/server.js +11 -5
  45. package/build/mcp/server.js.map +1 -1
  46. package/build/mcp/tools/email-sending.d.ts +10 -1
  47. package/build/mcp/tools/email-sending.js +60 -15
  48. package/build/mcp/tools/email-sending.js.map +1 -1
  49. package/build/mcp/tools/index.d.ts +10 -1
  50. package/build/mcp/tools/index.js +4 -3
  51. package/build/mcp/tools/index.js.map +1 -1
  52. package/build/signature/converter.d.ts +2 -0
  53. package/build/signature/converter.js +23 -0
  54. package/build/signature/converter.js.map +1 -0
  55. package/build/signature/converter.test.d.ts +1 -0
  56. package/build/signature/converter.test.js +84 -0
  57. package/build/signature/converter.test.js.map +1 -0
  58. package/build/signature/index.d.ts +2 -0
  59. package/build/signature/index.js +3 -0
  60. package/build/signature/index.js.map +1 -0
  61. package/build/signature/loader.d.ts +6 -0
  62. package/build/signature/loader.js +31 -0
  63. package/build/signature/loader.js.map +1 -0
  64. package/build/signature/loader.test.d.ts +1 -0
  65. package/build/signature/loader.test.js +85 -0
  66. package/build/signature/loader.test.js.map +1 -0
  67. package/docs/auto-discovery.md +210 -0
  68. package/docs/oidc-configuration.md +261 -0
  69. package/package.json +3 -1
@@ -0,0 +1,198 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { parseWwwAuthenticate, discoverOAuthFromResource, } from './oauth-discovery.js';
3
+ describe('parseWwwAuthenticate', () => {
4
+ it('should parse valid Bearer header with issuer', () => {
5
+ const header = 'Bearer issuer="https://auth.example.com"';
6
+ const result = parseWwwAuthenticate(header);
7
+ expect(result).toEqual({
8
+ issuer: 'https://auth.example.com',
9
+ });
10
+ });
11
+ it('should parse Bearer header with multiple parameters', () => {
12
+ const header = 'Bearer realm="example", scope="openid email", issuer="https://auth.example.com"';
13
+ const result = parseWwwAuthenticate(header);
14
+ expect(result).toEqual({
15
+ realm: 'example',
16
+ scope: 'openid email',
17
+ issuer: 'https://auth.example.com',
18
+ });
19
+ });
20
+ it('should be case-insensitive for Bearer scheme', () => {
21
+ const header = 'bearer issuer="https://auth.example.com"';
22
+ const result = parseWwwAuthenticate(header);
23
+ expect(result).toEqual({
24
+ issuer: 'https://auth.example.com',
25
+ });
26
+ });
27
+ it('should return null for non-Bearer header', () => {
28
+ const header = 'Basic realm="example"';
29
+ const result = parseWwwAuthenticate(header);
30
+ expect(result).toBeNull();
31
+ });
32
+ it('should return null for malformed header without parameters', () => {
33
+ const header = 'Bearer';
34
+ const result = parseWwwAuthenticate(header);
35
+ expect(result).toBeNull();
36
+ });
37
+ it('should ignore unknown parameters', () => {
38
+ const header = 'Bearer issuer="https://auth.example.com", unknown="value"';
39
+ const result = parseWwwAuthenticate(header);
40
+ expect(result).toEqual({
41
+ issuer: 'https://auth.example.com',
42
+ });
43
+ });
44
+ });
45
+ describe('discoverOAuthFromResource', () => {
46
+ const mockFetch = vi.fn();
47
+ beforeEach(() => {
48
+ global.fetch = mockFetch;
49
+ vi.clearAllMocks();
50
+ });
51
+ afterEach(() => {
52
+ vi.restoreAllMocks();
53
+ });
54
+ it('should discover issuer from protected-resource metadata', async () => {
55
+ mockFetch.mockResolvedValueOnce({
56
+ ok: true,
57
+ json: async () => ({
58
+ authorization_servers: ['https://auth.example.com'],
59
+ }),
60
+ });
61
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api');
62
+ expect(result).toEqual({
63
+ issuer: 'https://auth.example.com',
64
+ method: 'protected-resource',
65
+ });
66
+ expect(mockFetch).toHaveBeenCalledWith('https://jmap.example.com/.well-known/oauth-protected-resource', expect.objectContaining({ signal: expect.any(AbortSignal) }));
67
+ });
68
+ it('should fallback to WWW-Authenticate on 401 response', async () => {
69
+ // First call: protected-resource fails
70
+ mockFetch.mockResolvedValueOnce({
71
+ ok: false,
72
+ status: 404,
73
+ });
74
+ // Second call: JMAP URL returns 401 with WWW-Authenticate
75
+ mockFetch.mockResolvedValueOnce({
76
+ ok: false,
77
+ status: 401,
78
+ headers: {
79
+ get: (name) => {
80
+ if (name === 'WWW-Authenticate') {
81
+ return 'Bearer issuer="https://auth.example.com"';
82
+ }
83
+ return null;
84
+ },
85
+ },
86
+ });
87
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api');
88
+ expect(result).toEqual({
89
+ issuer: 'https://auth.example.com',
90
+ method: 'www-authenticate',
91
+ });
92
+ expect(mockFetch).toHaveBeenCalledTimes(2);
93
+ });
94
+ it('should return null when no OAuth info available', async () => {
95
+ // First call: protected-resource fails
96
+ mockFetch.mockResolvedValueOnce({
97
+ ok: false,
98
+ status: 404,
99
+ });
100
+ // Second call: JMAP URL returns 200 (no auth required)
101
+ mockFetch.mockResolvedValueOnce({
102
+ ok: true,
103
+ status: 200,
104
+ });
105
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api');
106
+ expect(result).toBeNull();
107
+ });
108
+ it('should return null when WWW-Authenticate has no issuer', async () => {
109
+ // First call: protected-resource fails
110
+ mockFetch.mockResolvedValueOnce({
111
+ ok: false,
112
+ status: 404,
113
+ });
114
+ // Second call: JMAP URL returns 401 with WWW-Authenticate but no issuer
115
+ mockFetch.mockResolvedValueOnce({
116
+ ok: false,
117
+ status: 401,
118
+ headers: {
119
+ get: (name) => {
120
+ if (name === 'WWW-Authenticate') {
121
+ return 'Bearer realm="example"';
122
+ }
123
+ return null;
124
+ },
125
+ },
126
+ });
127
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api');
128
+ expect(result).toBeNull();
129
+ });
130
+ it('should handle network errors gracefully', async () => {
131
+ mockFetch.mockRejectedValue(new Error('Network error'));
132
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api');
133
+ expect(result).toBeNull();
134
+ });
135
+ it('should handle invalid URL gracefully', async () => {
136
+ const result = await discoverOAuthFromResource('not-a-url');
137
+ expect(result).toBeNull();
138
+ expect(mockFetch).not.toHaveBeenCalled();
139
+ });
140
+ it('should respect custom timeout', async () => {
141
+ const abortError = new Error('Aborted');
142
+ abortError.name = 'AbortError';
143
+ mockFetch.mockRejectedValue(abortError);
144
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api', 100);
145
+ expect(result).toBeNull();
146
+ });
147
+ it('should handle protected-resource with empty authorization_servers', async () => {
148
+ mockFetch.mockResolvedValueOnce({
149
+ ok: true,
150
+ json: async () => ({
151
+ authorization_servers: [],
152
+ }),
153
+ });
154
+ // Second call: fallback to WWW-Authenticate
155
+ mockFetch.mockResolvedValueOnce({
156
+ ok: false,
157
+ status: 401,
158
+ headers: {
159
+ get: (name) => {
160
+ if (name === 'WWW-Authenticate') {
161
+ return 'Bearer issuer="https://auth.example.com"';
162
+ }
163
+ return null;
164
+ },
165
+ },
166
+ });
167
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api');
168
+ expect(result).toEqual({
169
+ issuer: 'https://auth.example.com',
170
+ method: 'www-authenticate',
171
+ });
172
+ });
173
+ it('should handle protected-resource with missing authorization_servers', async () => {
174
+ mockFetch.mockResolvedValueOnce({
175
+ ok: true,
176
+ json: async () => ({}),
177
+ });
178
+ // Second call: fallback to WWW-Authenticate
179
+ mockFetch.mockResolvedValueOnce({
180
+ ok: false,
181
+ status: 401,
182
+ headers: {
183
+ get: (name) => {
184
+ if (name === 'WWW-Authenticate') {
185
+ return 'Bearer issuer="https://auth.example.com"';
186
+ }
187
+ return null;
188
+ },
189
+ },
190
+ });
191
+ const result = await discoverOAuthFromResource('https://jmap.example.com/api');
192
+ expect(result).toEqual({
193
+ issuer: 'https://auth.example.com',
194
+ method: 'www-authenticate',
195
+ });
196
+ });
197
+ });
198
+ //# sourceMappingURL=oauth-discovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-discovery.test.js","sourceRoot":"","sources":["../../src/discovery/oauth-discovery.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Discovery orchestrator - chains DNS SRV, well-known, and OAuth discovery
3
+ * Provides high-level API to discover JMAP and OIDC settings from email address
4
+ */
5
+ import { JmapDiscoveryResult, OidcDiscoveryResult } from './types.js';
6
+ export interface FullDiscoveryResult {
7
+ jmap: JmapDiscoveryResult;
8
+ oidc?: OidcDiscoveryResult;
9
+ email: string;
10
+ domain: string;
11
+ }
12
+ /**
13
+ * Extract domain from email address.
14
+ * @throws Error if email format invalid
15
+ */
16
+ export declare function extractDomain(email: string): string;
17
+ /**
18
+ * Discover JMAP and OIDC settings from an email address.
19
+ *
20
+ * Discovery stages:
21
+ * 1. Extract domain from email
22
+ * 2. Try DNS SRV lookup for _jmap._tcp.{domain}
23
+ * 3. If SRV found, construct URL and verify it works
24
+ * 4. If SRV fails, try .well-known/jmap on domain
25
+ * 5. If JMAP found, attempt OAuth discovery on that URL
26
+ *
27
+ * @param email User's email address (e.g., "user@example.com")
28
+ * @returns Full discovery result with JMAP and optional OIDC settings
29
+ * @throws DiscoveryError if JMAP server cannot be discovered
30
+ */
31
+ export declare function discoverFromEmail(email: string): Promise<FullDiscoveryResult>;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Discovery orchestrator - chains DNS SRV, well-known, and OAuth discovery
3
+ * Provides high-level API to discover JMAP and OIDC settings from email address
4
+ */
5
+ import { resolveSrvRecord } from './dns-srv.js';
6
+ import { fetchWellKnownJmap, verifyJmapUrl } from './well-known.js';
7
+ import { discoverOAuthFromResource } from './oauth-discovery.js';
8
+ import { DiscoveryError, } from './types.js';
9
+ /**
10
+ * Extract domain from email address.
11
+ * @throws Error if email format invalid
12
+ */
13
+ export function extractDomain(email) {
14
+ // Split on '@' and take second part
15
+ const parts = email.split('@');
16
+ if (parts.length !== 2) {
17
+ throw new Error('Invalid email format');
18
+ }
19
+ const domain = parts[1];
20
+ // Validate domain has at least one '.'
21
+ if (!domain.includes('.')) {
22
+ throw new Error('Invalid email format');
23
+ }
24
+ return domain;
25
+ }
26
+ /**
27
+ * Discover JMAP and OIDC settings from an email address.
28
+ *
29
+ * Discovery stages:
30
+ * 1. Extract domain from email
31
+ * 2. Try DNS SRV lookup for _jmap._tcp.{domain}
32
+ * 3. If SRV found, construct URL and verify it works
33
+ * 4. If SRV fails, try .well-known/jmap on domain
34
+ * 5. If JMAP found, attempt OAuth discovery on that URL
35
+ *
36
+ * @param email User's email address (e.g., "user@example.com")
37
+ * @returns Full discovery result with JMAP and optional OIDC settings
38
+ * @throws DiscoveryError if JMAP server cannot be discovered
39
+ */
40
+ export async function discoverFromEmail(email) {
41
+ // Extract domain from email
42
+ const domain = extractDomain(email);
43
+ // Stage 1 - DNS SRV discovery
44
+ const srv = await resolveSrvRecord(domain);
45
+ if (srv) {
46
+ // Construct URL from SRV record
47
+ const url = srv.port === 443
48
+ ? `https://${srv.hostname}/.well-known/jmap`
49
+ : `https://${srv.hostname}:${srv.port}/.well-known/jmap`;
50
+ // Verify the URL works
51
+ const verified = await verifyJmapUrl(url);
52
+ if (verified) {
53
+ const jmap = {
54
+ sessionUrl: verified,
55
+ method: 'dns-srv',
56
+ };
57
+ // Stage 4 - OAuth discovery
58
+ const oidc = await discoverOAuthFromResource(verified);
59
+ return {
60
+ jmap,
61
+ oidc: oidc ?? undefined,
62
+ email,
63
+ domain,
64
+ };
65
+ }
66
+ }
67
+ // Stage 2 - Well-known fallback
68
+ const wellKnown = await fetchWellKnownJmap(domain);
69
+ if (wellKnown) {
70
+ const jmap = {
71
+ sessionUrl: wellKnown,
72
+ method: 'well-known-direct',
73
+ };
74
+ // Stage 4 - OAuth discovery
75
+ const oidc = await discoverOAuthFromResource(wellKnown);
76
+ return {
77
+ jmap,
78
+ oidc: oidc ?? undefined,
79
+ email,
80
+ domain,
81
+ };
82
+ }
83
+ // Stage 3 - Failure
84
+ throw new DiscoveryError(`Could not discover JMAP server for domain "${domain}". ` +
85
+ 'The domain does not have a JMAP SRV record or .well-known/jmap endpoint.', domain, 'well-known');
86
+ }
87
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/discovery/orchestrator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAGL,cAAc,GACf,MAAM,YAAY,CAAC;AASpB;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,oCAAoC;IACpC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAExB,uCAAuC;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa;IAEb,4BAA4B;IAC5B,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEpC,8BAA8B;IAC9B,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,GAAG,EAAE,CAAC;QACR,gCAAgC;QAChC,MAAM,GAAG,GACP,GAAG,CAAC,IAAI,KAAK,GAAG;YACd,CAAC,CAAC,WAAW,GAAG,CAAC,QAAQ,mBAAmB;YAC5C,CAAC,CAAC,WAAW,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI,mBAAmB,CAAC;QAE7D,uBAAuB;QACvB,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,IAAI,GAAwB;gBAChC,UAAU,EAAE,QAAQ;gBACpB,MAAM,EAAE,SAAS;aAClB,CAAC;YAEF,4BAA4B;YAC5B,MAAM,IAAI,GAAG,MAAM,yBAAyB,CAAC,QAAQ,CAAC,CAAC;YAEvD,OAAO;gBACL,IAAI;gBACJ,IAAI,EAAE,IAAI,IAAI,SAAS;gBACvB,KAAK;gBACL,MAAM;aACP,CAAC;QACJ,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,IAAI,GAAwB;YAChC,UAAU,EAAE,SAAS;YACrB,MAAM,EAAE,mBAAmB;SAC5B,CAAC;QAEF,4BAA4B;QAC5B,MAAM,IAAI,GAAG,MAAM,yBAAyB,CAAC,SAAS,CAAC,CAAC;QAExD,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,IAAI,IAAI,SAAS;YACvB,KAAK;YACL,MAAM;SACP,CAAC;IACJ,CAAC;IAED,oBAAoB;IACpB,MAAM,IAAI,cAAc,CACtB,8CAA8C,MAAM,KAAK;QACvD,0EAA0E,EAC5E,MAAM,EACN,YAAY,CACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tests for discovery orchestrator
3
+ */
4
+ export {};
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Tests for discovery orchestrator
3
+ */
4
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
5
+ import { discoverFromEmail, extractDomain } from './orchestrator.js';
6
+ import { DiscoveryError } from './types.js';
7
+ // Mock the discovery modules
8
+ vi.mock('./dns-srv.js');
9
+ vi.mock('./well-known.js');
10
+ vi.mock('./oauth-discovery.js');
11
+ import { resolveSrvRecord } from './dns-srv.js';
12
+ import { fetchWellKnownJmap, verifyJmapUrl } from './well-known.js';
13
+ import { discoverOAuthFromResource } from './oauth-discovery.js';
14
+ describe('extractDomain', () => {
15
+ it('extracts domain from valid email', () => {
16
+ expect(extractDomain('user@example.com')).toBe('example.com');
17
+ });
18
+ it('extracts domain from email with subdomain', () => {
19
+ expect(extractDomain('user@mail.example.com')).toBe('mail.example.com');
20
+ });
21
+ it('throws on email without @', () => {
22
+ expect(() => extractDomain('userexample.com')).toThrow('Invalid email format');
23
+ });
24
+ it('throws on domain without dot', () => {
25
+ expect(() => extractDomain('user@localhost')).toThrow('Invalid email format');
26
+ });
27
+ it('throws on multiple @ symbols', () => {
28
+ expect(() => extractDomain('user@test@example.com')).toThrow('Invalid email format');
29
+ });
30
+ it('throws on empty domain', () => {
31
+ expect(() => extractDomain('user@')).toThrow('Invalid email format');
32
+ });
33
+ });
34
+ describe('discoverFromEmail', () => {
35
+ beforeEach(() => {
36
+ vi.clearAllMocks();
37
+ });
38
+ describe('DNS SRV success path', () => {
39
+ it('discovers via DNS SRV with standard port', async () => {
40
+ // Mock DNS SRV success
41
+ vi.mocked(resolveSrvRecord).mockResolvedValue({
42
+ hostname: 'jmap.example.com',
43
+ port: 443,
44
+ });
45
+ // Mock URL verification
46
+ vi.mocked(verifyJmapUrl).mockResolvedValue('https://jmap.example.com/.well-known/jmap');
47
+ // Mock OAuth discovery
48
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue({
49
+ issuer: 'https://auth.example.com',
50
+ method: 'protected-resource',
51
+ });
52
+ const result = await discoverFromEmail('user@example.com');
53
+ expect(result).toEqual({
54
+ jmap: {
55
+ sessionUrl: 'https://jmap.example.com/.well-known/jmap',
56
+ method: 'dns-srv',
57
+ },
58
+ oidc: {
59
+ issuer: 'https://auth.example.com',
60
+ method: 'protected-resource',
61
+ },
62
+ email: 'user@example.com',
63
+ domain: 'example.com',
64
+ });
65
+ // Verify correct URL was constructed
66
+ expect(verifyJmapUrl).toHaveBeenCalledWith('https://jmap.example.com/.well-known/jmap');
67
+ });
68
+ it('discovers via DNS SRV with non-standard port', async () => {
69
+ // Mock DNS SRV success with non-standard port
70
+ vi.mocked(resolveSrvRecord).mockResolvedValue({
71
+ hostname: 'jmap.example.com',
72
+ port: 8443,
73
+ });
74
+ // Mock URL verification
75
+ vi.mocked(verifyJmapUrl).mockResolvedValue('https://jmap.example.com:8443/.well-known/jmap');
76
+ // Mock OAuth discovery (no OAuth info)
77
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue(null);
78
+ const result = await discoverFromEmail('user@example.com');
79
+ expect(result).toEqual({
80
+ jmap: {
81
+ sessionUrl: 'https://jmap.example.com:8443/.well-known/jmap',
82
+ method: 'dns-srv',
83
+ },
84
+ oidc: undefined,
85
+ email: 'user@example.com',
86
+ domain: 'example.com',
87
+ });
88
+ // Verify URL includes non-standard port
89
+ expect(verifyJmapUrl).toHaveBeenCalledWith('https://jmap.example.com:8443/.well-known/jmap');
90
+ });
91
+ it('discovers without OAuth info', async () => {
92
+ // Mock DNS SRV success
93
+ vi.mocked(resolveSrvRecord).mockResolvedValue({
94
+ hostname: 'jmap.example.com',
95
+ port: 443,
96
+ });
97
+ // Mock URL verification
98
+ vi.mocked(verifyJmapUrl).mockResolvedValue('https://jmap.example.com/.well-known/jmap');
99
+ // Mock OAuth discovery returning null
100
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue(null);
101
+ const result = await discoverFromEmail('user@example.com');
102
+ expect(result.oidc).toBeUndefined();
103
+ expect(result.jmap.sessionUrl).toBe('https://jmap.example.com/.well-known/jmap');
104
+ });
105
+ });
106
+ describe('Well-known fallback path', () => {
107
+ it('falls back to well-known when DNS SRV returns null', async () => {
108
+ // Mock DNS SRV failure
109
+ vi.mocked(resolveSrvRecord).mockResolvedValue(null);
110
+ // Mock well-known success
111
+ vi.mocked(fetchWellKnownJmap).mockResolvedValue('https://example.com/jmap/session');
112
+ // Mock OAuth discovery
113
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue({
114
+ issuer: 'https://auth.example.com',
115
+ method: 'www-authenticate',
116
+ });
117
+ const result = await discoverFromEmail('user@example.com');
118
+ expect(result).toEqual({
119
+ jmap: {
120
+ sessionUrl: 'https://example.com/jmap/session',
121
+ method: 'well-known-direct',
122
+ },
123
+ oidc: {
124
+ issuer: 'https://auth.example.com',
125
+ method: 'www-authenticate',
126
+ },
127
+ email: 'user@example.com',
128
+ domain: 'example.com',
129
+ });
130
+ // Verify DNS SRV was tried first
131
+ expect(resolveSrvRecord).toHaveBeenCalledWith('example.com');
132
+ // Verify well-known was called
133
+ expect(fetchWellKnownJmap).toHaveBeenCalledWith('example.com');
134
+ });
135
+ it('falls back to well-known when DNS SRV verification fails', async () => {
136
+ // Mock DNS SRV success but verification failure
137
+ vi.mocked(resolveSrvRecord).mockResolvedValue({
138
+ hostname: 'jmap.example.com',
139
+ port: 443,
140
+ });
141
+ vi.mocked(verifyJmapUrl).mockResolvedValue(null);
142
+ // Mock well-known success
143
+ vi.mocked(fetchWellKnownJmap).mockResolvedValue('https://example.com/.well-known/jmap');
144
+ // Mock no OAuth
145
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue(null);
146
+ const result = await discoverFromEmail('user@example.com');
147
+ expect(result.jmap.method).toBe('well-known-direct');
148
+ expect(result.jmap.sessionUrl).toBe('https://example.com/.well-known/jmap');
149
+ // Verify both were tried
150
+ expect(resolveSrvRecord).toHaveBeenCalled();
151
+ expect(fetchWellKnownJmap).toHaveBeenCalled();
152
+ });
153
+ });
154
+ describe('Complete failure path', () => {
155
+ it('throws DiscoveryError when all methods fail', async () => {
156
+ // Mock DNS SRV failure
157
+ vi.mocked(resolveSrvRecord).mockResolvedValue(null);
158
+ // Mock well-known failure
159
+ vi.mocked(fetchWellKnownJmap).mockResolvedValue(null);
160
+ await expect(discoverFromEmail('user@example.com')).rejects.toThrow(DiscoveryError);
161
+ await expect(discoverFromEmail('user@example.com')).rejects.toThrow('Could not discover JMAP server for domain "example.com"');
162
+ });
163
+ it('throws DiscoveryError with correct domain and stage', async () => {
164
+ // Mock all failures
165
+ vi.mocked(resolveSrvRecord).mockResolvedValue(null);
166
+ vi.mocked(fetchWellKnownJmap).mockResolvedValue(null);
167
+ try {
168
+ await discoverFromEmail('user@example.com');
169
+ expect.fail('Should have thrown DiscoveryError');
170
+ }
171
+ catch (error) {
172
+ expect(error).toBeInstanceOf(DiscoveryError);
173
+ if (error instanceof DiscoveryError) {
174
+ expect(error.domain).toBe('example.com');
175
+ expect(error.stage).toBe('well-known');
176
+ }
177
+ }
178
+ });
179
+ it('throws on invalid email format', async () => {
180
+ await expect(discoverFromEmail('not-an-email')).rejects.toThrow('Invalid email format');
181
+ // Verify no discovery methods were called
182
+ expect(resolveSrvRecord).not.toHaveBeenCalled();
183
+ expect(fetchWellKnownJmap).not.toHaveBeenCalled();
184
+ });
185
+ });
186
+ describe('OAuth discovery integration', () => {
187
+ it('includes OAuth info when discovered via protected-resource', async () => {
188
+ vi.mocked(resolveSrvRecord).mockResolvedValue({
189
+ hostname: 'jmap.example.com',
190
+ port: 443,
191
+ });
192
+ vi.mocked(verifyJmapUrl).mockResolvedValue('https://jmap.example.com/.well-known/jmap');
193
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue({
194
+ issuer: 'https://auth.example.com',
195
+ clientId: 'optional-client-id',
196
+ method: 'protected-resource',
197
+ });
198
+ const result = await discoverFromEmail('user@example.com');
199
+ expect(result.oidc).toEqual({
200
+ issuer: 'https://auth.example.com',
201
+ clientId: 'optional-client-id',
202
+ method: 'protected-resource',
203
+ });
204
+ });
205
+ it('includes OAuth info when discovered via www-authenticate', async () => {
206
+ vi.mocked(resolveSrvRecord).mockResolvedValue(null);
207
+ vi.mocked(fetchWellKnownJmap).mockResolvedValue('https://example.com/.well-known/jmap');
208
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue({
209
+ issuer: 'https://auth.example.com',
210
+ method: 'www-authenticate',
211
+ });
212
+ const result = await discoverFromEmail('user@example.com');
213
+ expect(result.oidc).toEqual({
214
+ issuer: 'https://auth.example.com',
215
+ method: 'www-authenticate',
216
+ });
217
+ });
218
+ it('handles OAuth discovery returning null gracefully', async () => {
219
+ vi.mocked(resolveSrvRecord).mockResolvedValue({
220
+ hostname: 'jmap.example.com',
221
+ port: 443,
222
+ });
223
+ vi.mocked(verifyJmapUrl).mockResolvedValue('https://jmap.example.com/.well-known/jmap');
224
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue(null);
225
+ const result = await discoverFromEmail('user@example.com');
226
+ expect(result.oidc).toBeUndefined();
227
+ expect(result.jmap).toBeDefined();
228
+ });
229
+ it('calls OAuth discovery with correct JMAP URL', async () => {
230
+ const jmapUrl = 'https://jmap.example.com/.well-known/jmap';
231
+ vi.mocked(resolveSrvRecord).mockResolvedValue({
232
+ hostname: 'jmap.example.com',
233
+ port: 443,
234
+ });
235
+ vi.mocked(verifyJmapUrl).mockResolvedValue(jmapUrl);
236
+ vi.mocked(discoverOAuthFromResource).mockResolvedValue(null);
237
+ await discoverFromEmail('user@example.com');
238
+ expect(discoverOAuthFromResource).toHaveBeenCalledWith(jmapUrl);
239
+ });
240
+ });
241
+ });
242
+ //# sourceMappingURL=orchestrator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.test.js","sourceRoot":"","sources":["../../src/discovery/orchestrator.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,6BAA6B;AAC7B,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AACxB,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC3B,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;AAEhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO,CAC1D,sBAAsB,CACvB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,uBAAuB;YACvB,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC;gBAC5C,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,GAAG;aACV,CAAC,CAAC;YAEH,wBAAwB;YACxB,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,iBAAiB,CACxC,2CAA2C,CAC5C,CAAC;YAEF,uBAAuB;YACvB,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC;gBACrD,MAAM,EAAE,0BAA0B;gBAClC,MAAM,EAAE,oBAAoB;aAC7B,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;gBACrB,IAAI,EAAE;oBACJ,UAAU,EAAE,2CAA2C;oBACvD,MAAM,EAAE,SAAS;iBAClB;gBACD,IAAI,EAAE;oBACJ,MAAM,EAAE,0BAA0B;oBAClC,MAAM,EAAE,oBAAoB;iBAC7B;gBACD,KAAK,EAAE,kBAAkB;gBACzB,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;YAEH,qCAAqC;YACrC,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CACxC,2CAA2C,CAC5C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,8CAA8C;YAC9C,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC;gBAC5C,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI;aACX,CAAC,CAAC;YAEH,wBAAwB;YACxB,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,iBAAiB,CACxC,gDAAgD,CACjD,CAAC;YAEF,uCAAuC;YACvC,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAE7D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;gBACrB,IAAI,EAAE;oBACJ,UAAU,EAAE,gDAAgD;oBAC5D,MAAM,EAAE,SAAS;iBAClB;gBACD,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,kBAAkB;gBACzB,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;YAEH,wCAAwC;YACxC,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CACxC,gDAAgD,CACjD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,uBAAuB;YACvB,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC;gBAC5C,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,GAAG;aACV,CAAC,CAAC;YAEH,wBAAwB;YACxB,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,iBAAiB,CACxC,2CAA2C,CAC5C,CAAC;YAEF,sCAAsC;YACtC,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAE7D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CACjC,2CAA2C,CAC5C,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAClE,uBAAuB;YACvB,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAEpD,0BAA0B;YAC1B,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,iBAAiB,CAC7C,kCAAkC,CACnC,CAAC;YAEF,uBAAuB;YACvB,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC;gBACrD,MAAM,EAAE,0BAA0B;gBAClC,MAAM,EAAE,kBAAkB;aAC3B,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;gBACrB,IAAI,EAAE;oBACJ,UAAU,EAAE,kCAAkC;oBAC9C,MAAM,EAAE,mBAAmB;iBAC5B;gBACD,IAAI,EAAE;oBACJ,MAAM,EAAE,0BAA0B;oBAClC,MAAM,EAAE,kBAAkB;iBAC3B;gBACD,KAAK,EAAE,kBAAkB;gBACzB,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;YAEH,iCAAiC;YACjC,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC;YAC7D,+BAA+B;YAC/B,MAAM,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;YACxE,gDAAgD;YAChD,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC;gBAC5C,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,GAAG;aACV,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAEjD,0BAA0B;YAC1B,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,iBAAiB,CAC7C,sCAAsC,CACvC,CAAC;YAEF,gBAAgB;YAChB,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAE7D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACrD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CACjC,sCAAsC,CACvC,CAAC;YAEF,yBAAyB;YACzB,MAAM,CAAC,gBAAgB,CAAC,CAAC,gBAAgB,EAAE,CAAC;YAC5C,MAAM,CAAC,kBAAkB,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,uBAAuB;YACvB,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAEpD,0BAA0B;YAC1B,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAEtD,MAAM,MAAM,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACjE,cAAc,CACf,CAAC;YAEF,MAAM,MAAM,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACjE,yDAAyD,CAC1D,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACnE,oBAAoB;YACpB,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YACpD,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAEtD,IAAI,CAAC;gBACH,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;gBAC5C,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;gBAC7C,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;oBACpC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;oBACzC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC7D,sBAAsB,CACvB,CAAC;YAEF,0CAA0C;YAC1C,MAAM,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YAChD,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;QAC3C,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;YAC1E,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC;gBAC5C,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,GAAG;aACV,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,iBAAiB,CACxC,2CAA2C,CAC5C,CAAC;YACF,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC;gBACrD,MAAM,EAAE,0BAA0B;gBAClC,QAAQ,EAAE,oBAAoB;gBAC9B,MAAM,EAAE,oBAAoB;aAC7B,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;gBAC1B,MAAM,EAAE,0BAA0B;gBAClC,QAAQ,EAAE,oBAAoB;gBAC9B,MAAM,EAAE,oBAAoB;aAC7B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;YACxE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YACpD,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,iBAAiB,CAC7C,sCAAsC,CACvC,CAAC;YACF,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC;gBACrD,MAAM,EAAE,0BAA0B;gBAClC,MAAM,EAAE,kBAAkB;aAC3B,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;gBAC1B,MAAM,EAAE,0BAA0B;gBAClC,MAAM,EAAE,kBAAkB;aAC3B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC;gBAC5C,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,GAAG;aACV,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,iBAAiB,CACxC,2CAA2C,CAC5C,CAAC;YACF,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAE7D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,OAAO,GAAG,2CAA2C,CAAC;YAC5D,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,iBAAiB,CAAC;gBAC5C,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,GAAG;aACV,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YACpD,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAE7D,MAAM,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE5C,MAAM,CAAC,yBAAyB,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * JMAP server discovery result types
3
+ * Supports DNS SRV, .well-known/jmap, and manual configuration
4
+ */
5
+ export interface JmapDiscoveryResult {
6
+ sessionUrl: string;
7
+ method: 'dns-srv' | 'well-known-direct' | 'manual';
8
+ }
9
+ export interface OidcDiscoveryResult {
10
+ issuer: string;
11
+ clientId?: string;
12
+ method: 'protected-resource' | 'www-authenticate' | 'well-known-oidc' | 'manual';
13
+ }
14
+ export declare class DiscoveryError extends Error {
15
+ readonly domain: string;
16
+ readonly stage: 'dns' | 'well-known' | 'verification';
17
+ constructor(message: string, domain: string, stage: 'dns' | 'well-known' | 'verification');
18
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * JMAP server discovery result types
3
+ * Supports DNS SRV, .well-known/jmap, and manual configuration
4
+ */
5
+ export class DiscoveryError extends Error {
6
+ domain;
7
+ stage;
8
+ constructor(message, domain, stage) {
9
+ super(message);
10
+ this.domain = domain;
11
+ this.stage = stage;
12
+ this.name = 'DiscoveryError';
13
+ }
14
+ }
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/discovery/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGrB;IACA;IAHlB,YACE,OAAe,EACC,MAAc,EACd,KAA4C;QAE5D,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAuC;QAG5D,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF"}