@fluxmail/core 0.19.0 → 0.20.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 (49) hide show
  1. package/dist/attachments.d.ts +9 -0
  2. package/dist/attachments.d.ts.map +1 -0
  3. package/dist/attachments.js +27 -0
  4. package/dist/attachments.js.map +1 -0
  5. package/dist/errors.d.ts +5 -0
  6. package/dist/errors.d.ts.map +1 -1
  7. package/dist/errors.js +16 -0
  8. package/dist/errors.js.map +1 -1
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp/clients.d.ts +16 -0
  14. package/dist/mcp/clients.d.ts.map +1 -0
  15. package/dist/mcp/clients.js +69 -0
  16. package/dist/mcp/clients.js.map +1 -0
  17. package/dist/mcp/index.d.ts +2 -0
  18. package/dist/mcp/index.d.ts.map +1 -1
  19. package/dist/mcp/index.js +2 -0
  20. package/dist/mcp/index.js.map +1 -1
  21. package/dist/mcp/pdf.d.ts +18 -0
  22. package/dist/mcp/pdf.d.ts.map +1 -0
  23. package/dist/mcp/pdf.js +97 -0
  24. package/dist/mcp/pdf.js.map +1 -0
  25. package/dist/mcp/results.d.ts +114 -0
  26. package/dist/mcp/results.d.ts.map +1 -0
  27. package/dist/mcp/results.js +165 -0
  28. package/dist/mcp/results.js.map +1 -0
  29. package/dist/mcp/tools.d.ts +7 -0
  30. package/dist/mcp/tools.d.ts.map +1 -1
  31. package/dist/mcp/tools.generated.d.ts +1 -0
  32. package/dist/mcp/tools.generated.d.ts.map +1 -1
  33. package/dist/mcp/tools.generated.js +1852 -0
  34. package/dist/mcp/tools.generated.js.map +1 -1
  35. package/dist/mcp/tools.js +2 -1
  36. package/dist/mcp/tools.js.map +1 -1
  37. package/dist/reply.d.ts +11 -1
  38. package/dist/reply.d.ts.map +1 -1
  39. package/dist/reply.js +43 -0
  40. package/dist/reply.js.map +1 -1
  41. package/dist/search.d.ts +8 -1
  42. package/dist/search.d.ts.map +1 -1
  43. package/dist/search.js +36 -0
  44. package/dist/search.js.map +1 -1
  45. package/dist/searchCursor.d.ts +35 -0
  46. package/dist/searchCursor.d.ts.map +1 -0
  47. package/dist/searchCursor.js +113 -0
  48. package/dist/searchCursor.js.map +1 -0
  49. package/package.json +9 -1
@@ -0,0 +1,113 @@
1
+ import { createHash, createHmac, hkdfSync, timingSafeEqual } from 'node:crypto';
2
+ import { EmailError } from './errors.js';
3
+ const CURSOR_VERSION = 1;
4
+ const CURSOR_LIFETIME_MS = 60 * 60 * 1_000;
5
+ const MAX_CURSOR_BYTES = 16 * 1_024;
6
+ const HKDF_CONTEXT = 'fluxmail/search-page-token/v1';
7
+ function canonicalQuery(query) {
8
+ const entries = Object.entries(query)
9
+ .filter(([, value]) => value !== undefined)
10
+ .sort(([left], [right]) => left.localeCompare(right));
11
+ return JSON.stringify(Object.fromEntries(entries));
12
+ }
13
+ export function emailQueryHash(query) {
14
+ return createHash('sha256').update(canonicalQuery(query)).digest('base64url');
15
+ }
16
+ /**
17
+ * Node only, so it ships as `@fluxmail/core/search-cursor` instead of the root export.
18
+ *
19
+ * Wraps a provider's page token in a signed, expiring cursor bound to the account, query and
20
+ * page options, so a token can't be replayed against a different search.
21
+ */
22
+ export class SearchCursorCodec {
23
+ key;
24
+ invalidCursor;
25
+ constructor(secret, options = {}) {
26
+ this.key = Buffer.from(hkdfSync('sha256', secret, Buffer.alloc(0), HKDF_CONTEXT, 32));
27
+ this.invalidCursor =
28
+ options.invalidCursor ?? (() => new EmailError('invalid_request', 'Invalid or expired search page token.'));
29
+ }
30
+ encode(binding, now = Date.now()) {
31
+ const payload = {
32
+ v: CURSOR_VERSION,
33
+ accountId: binding.accountId,
34
+ provider: binding.provider,
35
+ queryHash: emailQueryHash(binding.query),
36
+ pageSize: binding.pageSize,
37
+ ...(binding.includeSnippet !== undefined ? { includeSnippet: binding.includeSnippet } : {}),
38
+ ...(binding.includeSearchContext ? { includeSearchContext: true } : {}),
39
+ providerToken: binding.providerToken,
40
+ issuedAt: now,
41
+ expiresAt: now + CURSOR_LIFETIME_MS,
42
+ };
43
+ const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64url');
44
+ const signature = createHmac('sha256', this.key).update(encodedPayload).digest('base64url');
45
+ const token = `${encodedPayload}.${signature}`;
46
+ if (Buffer.byteLength(token) > MAX_CURSOR_BYTES) {
47
+ throw new EmailError('invalid_request', 'The provider returned a search page token that is too large.');
48
+ }
49
+ return token;
50
+ }
51
+ decode(token, binding, now = Date.now()) {
52
+ if (Buffer.byteLength(token) > MAX_CURSOR_BYTES)
53
+ throw this.invalidCursor();
54
+ const parts = token.split('.');
55
+ if (parts.length !== 2 || !parts[0] || !parts[1])
56
+ throw this.invalidCursor();
57
+ const [encodedPayload, encodedSignature] = parts;
58
+ if (!/^[A-Za-z0-9_-]+$/.test(encodedPayload) || !/^[A-Za-z0-9_-]+$/.test(encodedSignature)) {
59
+ throw this.invalidCursor();
60
+ }
61
+ let suppliedSignature;
62
+ try {
63
+ suppliedSignature = Buffer.from(encodedSignature, 'base64url');
64
+ }
65
+ catch {
66
+ throw this.invalidCursor();
67
+ }
68
+ if (suppliedSignature.toString('base64url') !== encodedSignature)
69
+ throw this.invalidCursor();
70
+ const expectedSignature = createHmac('sha256', this.key).update(encodedPayload).digest();
71
+ if (suppliedSignature.length !== expectedSignature.length)
72
+ throw this.invalidCursor();
73
+ if (!timingSafeEqual(suppliedSignature, expectedSignature))
74
+ throw this.invalidCursor();
75
+ let payload;
76
+ try {
77
+ const bytes = Buffer.from(encodedPayload, 'base64url');
78
+ if (bytes.toString('base64url') !== encodedPayload)
79
+ throw new Error();
80
+ payload = JSON.parse(bytes.toString('utf8'));
81
+ }
82
+ catch {
83
+ throw this.invalidCursor();
84
+ }
85
+ if (!payload ||
86
+ payload.v !== CURSOR_VERSION ||
87
+ typeof payload.accountId !== 'string' ||
88
+ !['gmail', 'outlook', 'imap'].includes(payload.provider) ||
89
+ typeof payload.queryHash !== 'string' ||
90
+ !Number.isInteger(payload.pageSize) ||
91
+ (payload.includeSnippet !== undefined && typeof payload.includeSnippet !== 'boolean') ||
92
+ (payload.includeSearchContext !== undefined && typeof payload.includeSearchContext !== 'boolean') ||
93
+ typeof payload.providerToken !== 'string' ||
94
+ !payload.providerToken ||
95
+ !Number.isFinite(payload.issuedAt) ||
96
+ !Number.isFinite(payload.expiresAt) ||
97
+ payload.expiresAt !== payload.issuedAt + CURSOR_LIFETIME_MS ||
98
+ payload.issuedAt > now ||
99
+ payload.expiresAt <= now) {
100
+ throw this.invalidCursor();
101
+ }
102
+ if (payload.accountId !== binding.accountId ||
103
+ payload.provider !== binding.provider ||
104
+ payload.queryHash !== emailQueryHash(binding.query) ||
105
+ payload.pageSize !== binding.pageSize ||
106
+ payload.includeSnippet !== binding.includeSnippet ||
107
+ (payload.includeSearchContext ?? false) !== (binding.includeSearchContext ?? false)) {
108
+ throw this.invalidCursor();
109
+ }
110
+ return payload.providerToken;
111
+ }
112
+ }
113
+ //# sourceMappingURL=searchCursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchCursor.js","sourceRoot":"","sources":["../src/searchCursor.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluxmail/core",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "Unified email types and provider interface for Fluxmail",
5
5
  "license": "Elastic-2.0",
6
6
  "repository": {
@@ -19,6 +19,14 @@
19
19
  "./mcp": {
20
20
  "types": "./dist/mcp/index.d.ts",
21
21
  "default": "./dist/mcp/index.js"
22
+ },
23
+ "./mcp/pdf": {
24
+ "types": "./dist/mcp/pdf.d.ts",
25
+ "default": "./dist/mcp/pdf.js"
26
+ },
27
+ "./search-cursor": {
28
+ "types": "./dist/searchCursor.d.ts",
29
+ "default": "./dist/searchCursor.js"
22
30
  }
23
31
  },
24
32
  "files": [