@shin1ohno/sage 0.8.8 → 0.9.3

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 (110) hide show
  1. package/README.md +31 -0
  2. package/dist/cli/http-server-with-config.d.ts +2 -0
  3. package/dist/cli/http-server-with-config.d.ts.map +1 -1
  4. package/dist/cli/http-server-with-config.js +71 -0
  5. package/dist/cli/http-server-with-config.js.map +1 -1
  6. package/dist/cli/main-entry.d.ts.map +1 -1
  7. package/dist/cli/main-entry.js +1 -0
  8. package/dist/cli/main-entry.js.map +1 -1
  9. package/dist/cli/parser.d.ts +2 -0
  10. package/dist/cli/parser.d.ts.map +1 -1
  11. package/dist/cli/parser.js +7 -0
  12. package/dist/cli/parser.js.map +1 -1
  13. package/dist/config/validation.d.ts +721 -0
  14. package/dist/config/validation.d.ts.map +1 -1
  15. package/dist/config/validation.js +203 -0
  16. package/dist/config/validation.js.map +1 -1
  17. package/dist/index.js +11 -10
  18. package/dist/index.js.map +1 -1
  19. package/dist/integrations/apple-reminders.d.ts.map +1 -1
  20. package/dist/integrations/apple-reminders.js +6 -5
  21. package/dist/integrations/apple-reminders.js.map +1 -1
  22. package/dist/integrations/calendar-event-creator.d.ts.map +1 -1
  23. package/dist/integrations/calendar-event-creator.js +2 -1
  24. package/dist/integrations/calendar-event-creator.js.map +1 -1
  25. package/dist/integrations/calendar-event-deleter.d.ts.map +1 -1
  26. package/dist/integrations/calendar-event-deleter.js +2 -1
  27. package/dist/integrations/calendar-event-deleter.js.map +1 -1
  28. package/dist/integrations/calendar-event-response.d.ts.map +1 -1
  29. package/dist/integrations/calendar-event-response.js +4 -3
  30. package/dist/integrations/calendar-event-response.js.map +1 -1
  31. package/dist/integrations/calendar-service.d.ts +14 -0
  32. package/dist/integrations/calendar-service.d.ts.map +1 -1
  33. package/dist/integrations/calendar-service.js +6 -5
  34. package/dist/integrations/calendar-service.js.map +1 -1
  35. package/dist/integrations/calendar-source-manager.d.ts +86 -3
  36. package/dist/integrations/calendar-source-manager.d.ts.map +1 -1
  37. package/dist/integrations/calendar-source-manager.js +152 -20
  38. package/dist/integrations/calendar-source-manager.js.map +1 -1
  39. package/dist/integrations/google-calendar-service.d.ts +55 -3
  40. package/dist/integrations/google-calendar-service.d.ts.map +1 -1
  41. package/dist/integrations/google-calendar-service.js +215 -5
  42. package/dist/integrations/google-calendar-service.js.map +1 -1
  43. package/dist/integrations/notion-mcp.d.ts.map +1 -1
  44. package/dist/integrations/notion-mcp.js +5 -4
  45. package/dist/integrations/notion-mcp.js.map +1 -1
  46. package/dist/integrations/todo-list-manager.d.ts.map +1 -1
  47. package/dist/integrations/todo-list-manager.js +3 -2
  48. package/dist/integrations/todo-list-manager.js.map +1 -1
  49. package/dist/oauth/encryption-service.d.ts +104 -0
  50. package/dist/oauth/encryption-service.d.ts.map +1 -0
  51. package/dist/oauth/encryption-service.js +271 -0
  52. package/dist/oauth/encryption-service.js.map +1 -0
  53. package/dist/oauth/file-mutex.d.ts +68 -0
  54. package/dist/oauth/file-mutex.d.ts.map +1 -0
  55. package/dist/oauth/file-mutex.js +141 -0
  56. package/dist/oauth/file-mutex.js.map +1 -0
  57. package/dist/oauth/google-oauth-handler.d.ts +8 -9
  58. package/dist/oauth/google-oauth-handler.d.ts.map +1 -1
  59. package/dist/oauth/google-oauth-handler.js +30 -65
  60. package/dist/oauth/google-oauth-handler.js.map +1 -1
  61. package/dist/oauth/index.d.ts +1 -0
  62. package/dist/oauth/index.d.ts.map +1 -1
  63. package/dist/oauth/index.js +2 -0
  64. package/dist/oauth/index.js.map +1 -1
  65. package/dist/oauth/oauth-server.d.ts +61 -1
  66. package/dist/oauth/oauth-server.d.ts.map +1 -1
  67. package/dist/oauth/oauth-server.js +177 -40
  68. package/dist/oauth/oauth-server.js.map +1 -1
  69. package/dist/oauth/persistent-client-store.d.ts +58 -0
  70. package/dist/oauth/persistent-client-store.d.ts.map +1 -0
  71. package/dist/oauth/persistent-client-store.js +188 -0
  72. package/dist/oauth/persistent-client-store.js.map +1 -0
  73. package/dist/oauth/persistent-refresh-token-store.d.ts +77 -0
  74. package/dist/oauth/persistent-refresh-token-store.d.ts.map +1 -0
  75. package/dist/oauth/persistent-refresh-token-store.js +226 -0
  76. package/dist/oauth/persistent-refresh-token-store.js.map +1 -0
  77. package/dist/oauth/persistent-session-store.d.ts +69 -0
  78. package/dist/oauth/persistent-session-store.d.ts.map +1 -0
  79. package/dist/oauth/persistent-session-store.js +155 -0
  80. package/dist/oauth/persistent-session-store.js.map +1 -0
  81. package/dist/oauth/session-store.d.ts +31 -0
  82. package/dist/oauth/session-store.d.ts.map +1 -0
  83. package/dist/oauth/session-store.js +47 -0
  84. package/dist/oauth/session-store.js.map +1 -0
  85. package/dist/remote/cloud-config.d.ts.map +1 -1
  86. package/dist/remote/cloud-config.js +2 -1
  87. package/dist/remote/cloud-config.js.map +1 -1
  88. package/dist/services/container.d.ts.map +1 -1
  89. package/dist/services/container.js +3 -2
  90. package/dist/services/container.js.map +1 -1
  91. package/dist/services/working-cadence.d.ts +37 -1
  92. package/dist/services/working-cadence.d.ts.map +1 -1
  93. package/dist/services/working-cadence.js +152 -13
  94. package/dist/services/working-cadence.js.map +1 -1
  95. package/dist/tools/calendar/handlers.d.ts +82 -3
  96. package/dist/tools/calendar/handlers.d.ts.map +1 -1
  97. package/dist/tools/calendar/handlers.js +200 -16
  98. package/dist/tools/calendar/handlers.js.map +1 -1
  99. package/dist/types/google-calendar-types.d.ts +150 -3
  100. package/dist/types/google-calendar-types.d.ts.map +1 -1
  101. package/dist/types/google-calendar-types.js +79 -2
  102. package/dist/types/google-calendar-types.js.map +1 -1
  103. package/dist/types/task.d.ts +14 -0
  104. package/dist/types/task.d.ts.map +1 -1
  105. package/dist/utils/logger.d.ts +28 -0
  106. package/dist/utils/logger.d.ts.map +1 -0
  107. package/dist/utils/logger.js +61 -0
  108. package/dist/utils/logger.js.map +1 -0
  109. package/dist/version.js +1 -1
  110. package/package.json +4 -1
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Persistent Refresh Token Store
3
+ * Requirements: 21.6, 26.3, 26.8
4
+ *
5
+ * Extends InMemoryRefreshTokenStore with encrypted filesystem persistence.
6
+ * Maintains same interface but survives server restarts.
7
+ */
8
+ import { RefreshTokenStore, RefreshTokenStoreConfig, GenerateRefreshTokenOptions, RefreshTokenValidationResult } from './refresh-token-store.js';
9
+ import { EncryptionService } from './encryption-service.js';
10
+ /**
11
+ * Persistent Refresh Token Store Implementation
12
+ *
13
+ * Provides encrypted filesystem persistence for refresh tokens
14
+ * while maintaining in-memory cache for fast access.
15
+ */
16
+ export declare class PersistentRefreshTokenStore implements RefreshTokenStore {
17
+ private tokens;
18
+ private config;
19
+ private encryptionService;
20
+ private storagePath;
21
+ private saveDebounceTimer;
22
+ private saveDebounceMs;
23
+ constructor(config: RefreshTokenStoreConfig, encryptionService: EncryptionService, storagePath?: string);
24
+ /**
25
+ * Load tokens from encrypted file
26
+ */
27
+ loadFromStorage(): Promise<void>;
28
+ /**
29
+ * Save tokens to encrypted file immediately
30
+ */
31
+ saveToStorage(): Promise<void>;
32
+ /**
33
+ * Schedule save operation with debouncing
34
+ *
35
+ * Batches multiple writes within 1 second to reduce I/O operations.
36
+ */
37
+ private scheduleSave;
38
+ /**
39
+ * Generate new refresh token
40
+ */
41
+ generateToken(options: GenerateRefreshTokenOptions): Promise<string>;
42
+ /**
43
+ * Validate refresh token
44
+ */
45
+ validateToken(token: string, clientId: string): Promise<RefreshTokenValidationResult>;
46
+ /**
47
+ * Rotate refresh token
48
+ */
49
+ rotateToken(token: string, clientId: string): Promise<string | null>;
50
+ /**
51
+ * Revoke refresh token
52
+ */
53
+ revokeToken(token: string): Promise<void>;
54
+ /**
55
+ * Revoke all tokens for client
56
+ */
57
+ revokeAllForClient(clientId: string): Promise<void>;
58
+ /**
59
+ * Clean up expired and rotated tokens
60
+ */
61
+ cleanup(): Promise<number>;
62
+ /**
63
+ * Flush pending saves (call on server shutdown)
64
+ *
65
+ * Ensures all pending changes are written to disk before server shutdown.
66
+ */
67
+ flush(): Promise<void>;
68
+ /**
69
+ * Get metrics for monitoring
70
+ */
71
+ getMetrics(): {
72
+ count: number;
73
+ expiredCount: number;
74
+ rotatedCount: number;
75
+ };
76
+ }
77
+ //# sourceMappingURL=persistent-refresh-token-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistent-refresh-token-store.d.ts","sourceRoot":"","sources":["../../src/oauth/persistent-refresh-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAW5D;;;;;GAKG;AACH,qBAAa,2BAA4B,YAAW,iBAAiB;IACnE,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,cAAc,CAAQ;gBAG5B,MAAM,EAAE,uBAAuB,EAC/B,iBAAiB,EAAE,iBAAiB,EACpC,WAAW,CAAC,EAAE,MAAM;IAOtB;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BtC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAUpC;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAgBpB;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB1E;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,4BAA4B,CAAC;IA2B3F;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAsB1E;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/C;;OAEG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBhC;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;OAEG;IACH,UAAU,IAAI;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACtB;CAoBF"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Persistent Refresh Token Store
3
+ * Requirements: 21.6, 26.3, 26.8
4
+ *
5
+ * Extends InMemoryRefreshTokenStore with encrypted filesystem persistence.
6
+ * Maintains same interface but survives server restarts.
7
+ */
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ import { randomBytes } from 'crypto';
11
+ import { oauthLogger } from '../utils/logger.js';
12
+ /**
13
+ * Persistent Refresh Token Store Implementation
14
+ *
15
+ * Provides encrypted filesystem persistence for refresh tokens
16
+ * while maintaining in-memory cache for fast access.
17
+ */
18
+ export class PersistentRefreshTokenStore {
19
+ tokens = new Map();
20
+ config;
21
+ encryptionService;
22
+ storagePath;
23
+ saveDebounceTimer = null;
24
+ saveDebounceMs = 1000; // Batch saves within 1 second
25
+ constructor(config, encryptionService, storagePath) {
26
+ this.config = config;
27
+ this.encryptionService = encryptionService;
28
+ this.storagePath = storagePath || join(homedir(), '.sage', 'oauth_refresh_tokens.enc');
29
+ }
30
+ /**
31
+ * Load tokens from encrypted file
32
+ */
33
+ async loadFromStorage() {
34
+ const data = await this.encryptionService.decryptFromFile(this.storagePath);
35
+ if (!data) {
36
+ oauthLogger.info('No existing refresh tokens found, starting fresh');
37
+ return;
38
+ }
39
+ try {
40
+ const storage = JSON.parse(data);
41
+ // Load tokens and filter expired ones
42
+ const now = Date.now();
43
+ let loadedCount = 0;
44
+ let expiredCount = 0;
45
+ for (const token of storage.tokens) {
46
+ if (now < token.expires_at) {
47
+ this.tokens.set(token.token, token);
48
+ loadedCount++;
49
+ }
50
+ else {
51
+ expiredCount++;
52
+ }
53
+ }
54
+ oauthLogger.info({ loadedCount, expiredCount }, 'Loaded refresh tokens');
55
+ }
56
+ catch (error) {
57
+ oauthLogger.error({ err: error }, 'Failed to parse refresh token storage, starting fresh');
58
+ }
59
+ }
60
+ /**
61
+ * Save tokens to encrypted file immediately
62
+ */
63
+ async saveToStorage() {
64
+ const storage = {
65
+ version: 1,
66
+ tokens: Array.from(this.tokens.values()),
67
+ };
68
+ const data = JSON.stringify(storage, null, 2);
69
+ await this.encryptionService.encryptToFile(data, this.storagePath);
70
+ }
71
+ /**
72
+ * Schedule save operation with debouncing
73
+ *
74
+ * Batches multiple writes within 1 second to reduce I/O operations.
75
+ */
76
+ scheduleSave() {
77
+ // Clear existing timer
78
+ if (this.saveDebounceTimer) {
79
+ clearTimeout(this.saveDebounceTimer);
80
+ }
81
+ // Schedule save after debounce period
82
+ this.saveDebounceTimer = setTimeout(async () => {
83
+ try {
84
+ await this.saveToStorage();
85
+ }
86
+ catch (error) {
87
+ oauthLogger.error({ err: error }, 'Failed to save refresh tokens');
88
+ }
89
+ }, this.saveDebounceMs);
90
+ }
91
+ /**
92
+ * Generate new refresh token
93
+ */
94
+ async generateToken(options) {
95
+ // Generate secure random token
96
+ const token = randomBytes(32).toString('base64url');
97
+ const now = Date.now();
98
+ const expiresAt = now + this.config.expirySeconds * 1000;
99
+ const tokenData = {
100
+ token,
101
+ client_id: options.clientId,
102
+ user_id: options.userId,
103
+ scope: options.scope,
104
+ created_at: now,
105
+ expires_at: expiresAt,
106
+ rotated: false,
107
+ };
108
+ this.tokens.set(token, tokenData);
109
+ // Schedule debounced save
110
+ this.scheduleSave();
111
+ return token;
112
+ }
113
+ /**
114
+ * Validate refresh token
115
+ */
116
+ async validateToken(token, clientId) {
117
+ const tokenData = this.tokens.get(token);
118
+ if (!tokenData) {
119
+ return { valid: false, error: 'invalid_grant' };
120
+ }
121
+ // Check if token has been rotated
122
+ if (tokenData.rotated) {
123
+ return { valid: false, error: 'invalid_grant' };
124
+ }
125
+ // Check if token has expired
126
+ if (Date.now() > tokenData.expires_at) {
127
+ this.tokens.delete(token);
128
+ this.scheduleSave();
129
+ return { valid: false, error: 'invalid_grant' };
130
+ }
131
+ // Verify client_id matches
132
+ if (tokenData.client_id !== clientId) {
133
+ return { valid: false, error: 'invalid_grant' };
134
+ }
135
+ return { valid: true, tokenData };
136
+ }
137
+ /**
138
+ * Rotate refresh token
139
+ */
140
+ async rotateToken(token, clientId) {
141
+ const validationResult = await this.validateToken(token, clientId);
142
+ if (!validationResult.valid || !validationResult.tokenData) {
143
+ return null;
144
+ }
145
+ // Mark old token as rotated (Requirement 26.8)
146
+ const oldTokenData = this.tokens.get(token);
147
+ oldTokenData.rotated = true;
148
+ // Generate new token with same scope
149
+ const newToken = await this.generateToken({
150
+ clientId: validationResult.tokenData.client_id,
151
+ userId: validationResult.tokenData.user_id,
152
+ scope: validationResult.tokenData.scope,
153
+ });
154
+ // scheduleSave is already called in generateToken
155
+ return newToken;
156
+ }
157
+ /**
158
+ * Revoke refresh token
159
+ */
160
+ async revokeToken(token) {
161
+ this.tokens.delete(token);
162
+ this.scheduleSave();
163
+ }
164
+ /**
165
+ * Revoke all tokens for client
166
+ */
167
+ async revokeAllForClient(clientId) {
168
+ for (const [token, data] of this.tokens.entries()) {
169
+ if (data.client_id === clientId) {
170
+ this.tokens.delete(token);
171
+ }
172
+ }
173
+ this.scheduleSave();
174
+ }
175
+ /**
176
+ * Clean up expired and rotated tokens
177
+ */
178
+ async cleanup() {
179
+ const now = Date.now();
180
+ let cleanedCount = 0;
181
+ for (const [token, data] of this.tokens.entries()) {
182
+ if (data.expires_at < now || data.rotated) {
183
+ this.tokens.delete(token);
184
+ cleanedCount++;
185
+ }
186
+ }
187
+ if (cleanedCount > 0) {
188
+ this.scheduleSave();
189
+ }
190
+ return cleanedCount;
191
+ }
192
+ /**
193
+ * Flush pending saves (call on server shutdown)
194
+ *
195
+ * Ensures all pending changes are written to disk before server shutdown.
196
+ */
197
+ async flush() {
198
+ if (this.saveDebounceTimer) {
199
+ clearTimeout(this.saveDebounceTimer);
200
+ this.saveDebounceTimer = null;
201
+ }
202
+ await this.saveToStorage();
203
+ }
204
+ /**
205
+ * Get metrics for monitoring
206
+ */
207
+ getMetrics() {
208
+ const now = Date.now();
209
+ let expiredCount = 0;
210
+ let rotatedCount = 0;
211
+ for (const token of this.tokens.values()) {
212
+ if (token.expires_at < now) {
213
+ expiredCount++;
214
+ }
215
+ if (token.rotated) {
216
+ rotatedCount++;
217
+ }
218
+ }
219
+ return {
220
+ count: this.tokens.size,
221
+ expiredCount,
222
+ rotatedCount,
223
+ };
224
+ }
225
+ }
226
+ //# sourceMappingURL=persistent-refresh-token-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistent-refresh-token-store.js","sourceRoot":"","sources":["../../src/oauth/persistent-refresh-token-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Persistent Session Store
3
+ * Requirements: 26 (Session Management)
4
+ *
5
+ * Stores user sessions with encrypted filesystem persistence.
6
+ * Implements automatic cleanup of expired sessions and session limits.
7
+ */
8
+ import { UserSession } from './types.js';
9
+ import { EncryptionService } from './encryption-service.js';
10
+ import { SessionStore } from './session-store.js';
11
+ /**
12
+ * Persistent Session Store Implementation
13
+ *
14
+ * Extends SessionStore interface with encrypted filesystem persistence.
15
+ * Maintains in-memory cache for fast access while persisting to disk.
16
+ */
17
+ export declare class PersistentSessionStore implements SessionStore {
18
+ private sessions;
19
+ private sessionExpiryMs;
20
+ private maxSessions;
21
+ private encryptionService;
22
+ private storagePath;
23
+ constructor(encryptionService: EncryptionService, storagePath?: string);
24
+ /**
25
+ * Load sessions from encrypted file
26
+ *
27
+ * Filters out expired sessions during load.
28
+ * Logs loaded and expired session counts.
29
+ */
30
+ loadFromStorage(): Promise<void>;
31
+ /**
32
+ * Save sessions to encrypted file
33
+ *
34
+ * Enforces session limit by keeping only most recent 100 sessions.
35
+ */
36
+ private saveToStorage;
37
+ /**
38
+ * Create new session
39
+ *
40
+ * Saves asynchronously (fire and forget) to avoid blocking.
41
+ */
42
+ createSession(userId: string): UserSession;
43
+ /**
44
+ * Get session by ID
45
+ *
46
+ * Checks expiry and removes expired sessions automatically.
47
+ */
48
+ getSession(sessionId: string): UserSession | null;
49
+ /**
50
+ * Delete session
51
+ *
52
+ * Saves asynchronously after deletion.
53
+ */
54
+ deleteSession(sessionId: string): void;
55
+ /**
56
+ * Flush pending saves
57
+ *
58
+ * Call on server shutdown to ensure all data is persisted.
59
+ */
60
+ flush(): Promise<void>;
61
+ /**
62
+ * Get metrics for monitoring
63
+ */
64
+ getMetrics(): {
65
+ count: number;
66
+ expiredCount: number;
67
+ };
68
+ }
69
+ //# sourceMappingURL=persistent-session-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistent-session-store.d.ts","sourceRoot":"","sources":["../../src/oauth/persistent-session-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAWlD;;;;;GAKG;AACH,qBAAa,sBAAuB,YAAW,YAAY;IACzD,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,WAAW,CAAS;gBAEhB,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,CAAC,EAAE,MAAM;IAKtE;;;;;OAKG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IA8BtC;;;;OAIG;YACW,aAAa;IAuB3B;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW;IAmB1C;;;;OAIG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAgBjD;;;;OAIG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAOtC;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,UAAU,IAAI;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;KACtB;CAeF"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Persistent Session Store
3
+ * Requirements: 26 (Session Management)
4
+ *
5
+ * Stores user sessions with encrypted filesystem persistence.
6
+ * Implements automatic cleanup of expired sessions and session limits.
7
+ */
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ import { randomBytes } from 'crypto';
11
+ import { oauthLogger } from '../utils/logger.js';
12
+ /**
13
+ * Persistent Session Store Implementation
14
+ *
15
+ * Extends SessionStore interface with encrypted filesystem persistence.
16
+ * Maintains in-memory cache for fast access while persisting to disk.
17
+ */
18
+ export class PersistentSessionStore {
19
+ sessions = new Map();
20
+ sessionExpiryMs = 24 * 60 * 60 * 1000; // 24 hours
21
+ maxSessions = 100; // Limit to prevent unbounded growth
22
+ encryptionService;
23
+ storagePath;
24
+ constructor(encryptionService, storagePath) {
25
+ this.encryptionService = encryptionService;
26
+ this.storagePath = storagePath || join(homedir(), '.sage', 'oauth_sessions.enc');
27
+ }
28
+ /**
29
+ * Load sessions from encrypted file
30
+ *
31
+ * Filters out expired sessions during load.
32
+ * Logs loaded and expired session counts.
33
+ */
34
+ async loadFromStorage() {
35
+ const data = await this.encryptionService.decryptFromFile(this.storagePath);
36
+ if (!data) {
37
+ oauthLogger.info('No existing sessions found, starting fresh');
38
+ return;
39
+ }
40
+ try {
41
+ const storage = JSON.parse(data);
42
+ // Load sessions and filter expired ones
43
+ const now = Date.now();
44
+ let loadedCount = 0;
45
+ let expiredCount = 0;
46
+ for (const session of storage.sessions) {
47
+ if (now < session.expiresAt) {
48
+ this.sessions.set(session.sessionId, session);
49
+ loadedCount++;
50
+ }
51
+ else {
52
+ expiredCount++;
53
+ }
54
+ }
55
+ oauthLogger.info({ loadedCount, expiredCount }, 'Loaded sessions');
56
+ }
57
+ catch (error) {
58
+ oauthLogger.error({ err: error }, 'Failed to parse session storage, starting fresh');
59
+ }
60
+ }
61
+ /**
62
+ * Save sessions to encrypted file
63
+ *
64
+ * Enforces session limit by keeping only most recent 100 sessions.
65
+ */
66
+ async saveToStorage() {
67
+ // Enforce session limit by keeping only most recent sessions
68
+ let sessions = Array.from(this.sessions.values());
69
+ if (sessions.length > this.maxSessions) {
70
+ sessions.sort((a, b) => b.createdAt - a.createdAt);
71
+ sessions = sessions.slice(0, this.maxSessions);
72
+ // Update map to reflect limit
73
+ this.sessions.clear();
74
+ for (const session of sessions) {
75
+ this.sessions.set(session.sessionId, session);
76
+ }
77
+ }
78
+ const storage = {
79
+ version: 1,
80
+ sessions,
81
+ };
82
+ const data = JSON.stringify(storage, null, 2);
83
+ await this.encryptionService.encryptToFile(data, this.storagePath);
84
+ }
85
+ /**
86
+ * Create new session
87
+ *
88
+ * Saves asynchronously (fire and forget) to avoid blocking.
89
+ */
90
+ createSession(userId) {
91
+ const sessionId = randomBytes(32).toString('hex');
92
+ const now = Date.now();
93
+ const session = {
94
+ sessionId,
95
+ userId,
96
+ createdAt: now,
97
+ expiresAt: now + this.sessionExpiryMs,
98
+ };
99
+ this.sessions.set(sessionId, session);
100
+ // Save asynchronously (don't wait)
101
+ this.saveToStorage().catch((err) => oauthLogger.error({ err }, 'Failed to save session'));
102
+ return session;
103
+ }
104
+ /**
105
+ * Get session by ID
106
+ *
107
+ * Checks expiry and removes expired sessions automatically.
108
+ */
109
+ getSession(sessionId) {
110
+ const session = this.sessions.get(sessionId);
111
+ if (!session)
112
+ return null;
113
+ // Check expiry
114
+ if (Date.now() > session.expiresAt) {
115
+ this.sessions.delete(sessionId);
116
+ this.saveToStorage().catch((err) => oauthLogger.error({ err }, 'Failed to save after session expiry'));
117
+ return null;
118
+ }
119
+ return session;
120
+ }
121
+ /**
122
+ * Delete session
123
+ *
124
+ * Saves asynchronously after deletion.
125
+ */
126
+ deleteSession(sessionId) {
127
+ this.sessions.delete(sessionId);
128
+ this.saveToStorage().catch((err) => oauthLogger.error({ err }, 'Failed to save after session deletion'));
129
+ }
130
+ /**
131
+ * Flush pending saves
132
+ *
133
+ * Call on server shutdown to ensure all data is persisted.
134
+ */
135
+ async flush() {
136
+ await this.saveToStorage();
137
+ }
138
+ /**
139
+ * Get metrics for monitoring
140
+ */
141
+ getMetrics() {
142
+ const now = Date.now();
143
+ let expiredCount = 0;
144
+ for (const session of this.sessions.values()) {
145
+ if (session.expiresAt < now) {
146
+ expiredCount++;
147
+ }
148
+ }
149
+ return {
150
+ count: this.sessions.size,
151
+ expiredCount,
152
+ };
153
+ }
154
+ }
155
+ //# sourceMappingURL=persistent-session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistent-session-store.js","sourceRoot":"","sources":["../../src/oauth/persistent-session-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAIrC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUjD;;;;;GAKG;AACH,MAAM,OAAO,sBAAsB;IACzB,QAAQ,GAA6B,IAAI,GAAG,EAAE,CAAC;IAC/C,eAAe,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;IAClD,WAAW,GAAG,GAAG,CAAC,CAAC,oCAAoC;IACvD,iBAAiB,CAAoB;IACrC,WAAW,CAAS;IAE5B,YAAY,iBAAoC,EAAE,WAAoB;QACpE,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;IACnF,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC5E,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,WAAW,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAmB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAEjD,wCAAwC;YACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,IAAI,YAAY,GAAG,CAAC,CAAC;YAErB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACvC,IAAI,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;oBAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;oBAC9C,WAAW,EAAE,CAAC;gBAChB,CAAC;qBAAM,CAAC;oBACN,YAAY,EAAE,CAAC;gBACjB,CAAC;YACH,CAAC;YAED,WAAW,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,iBAAiB,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,iDAAiD,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,aAAa;QACzB,6DAA6D;QAC7D,IAAI,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAClD,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;YACvC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;YACnD,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YAE/C,8BAA8B;YAC9B,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACtB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAmB;YAC9B,OAAO,EAAE,CAAC;YACV,QAAQ;SACT,CAAC;QAEF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9C,MAAM,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACrE,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,MAAc;QAC1B,MAAM,SAAS,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,MAAM;YACN,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,eAAe;SACtC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAEtC,mCAAmC;QACnC,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACjC,WAAW,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CACrD,CAAC;QAEF,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,SAAiB;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAE1B,eAAe;QACf,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACjC,WAAW,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,qCAAqC,CAAC,CAClE,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,SAAiB;QAC7B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChC,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACjC,WAAW,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,uCAAuC,CAAC,CACpE,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,UAAU;QAIR,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,IAAI,OAAO,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;gBAC5B,YAAY,EAAE,CAAC;YACjB,CAAC;QACH,CAAC;QAED,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACzB,YAAY;SACb,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Session Store
3
+ * Requirements: 26 (Session Management)
4
+ *
5
+ * Manages user sessions for OAuth authentication flow.
6
+ * Sessions track authenticated users during the consent process.
7
+ */
8
+ import { UserSession } from './types.js';
9
+ /**
10
+ * Session Store Interface
11
+ */
12
+ export interface SessionStore {
13
+ createSession(userId: string): UserSession;
14
+ getSession(sessionId: string): UserSession | null;
15
+ deleteSession(sessionId: string): void;
16
+ }
17
+ /**
18
+ * In-memory Session Store Implementation
19
+ */
20
+ export declare class InMemorySessionStore implements SessionStore {
21
+ private sessions;
22
+ private sessionExpiryMs;
23
+ createSession(userId: string): UserSession;
24
+ getSession(sessionId: string): UserSession | null;
25
+ deleteSession(sessionId: string): void;
26
+ }
27
+ /**
28
+ * Create a Session Store instance
29
+ */
30
+ export declare function createSessionStore(): SessionStore;
31
+ //# sourceMappingURL=session-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/oauth/session-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAClD,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACvD,OAAO,CAAC,QAAQ,CAAuC;IACvD,OAAO,CAAC,eAAe,CAAuB;IAE9C,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW;IAa1C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAUjD,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAGvC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Session Store
3
+ * Requirements: 26 (Session Management)
4
+ *
5
+ * Manages user sessions for OAuth authentication flow.
6
+ * Sessions track authenticated users during the consent process.
7
+ */
8
+ import { randomBytes } from 'crypto';
9
+ /**
10
+ * In-memory Session Store Implementation
11
+ */
12
+ export class InMemorySessionStore {
13
+ sessions = new Map();
14
+ sessionExpiryMs = 24 * 60 * 60 * 1000; // 24 hours
15
+ createSession(userId) {
16
+ const sessionId = randomBytes(32).toString('hex');
17
+ const now = Date.now();
18
+ const session = {
19
+ sessionId,
20
+ userId,
21
+ createdAt: now,
22
+ expiresAt: now + this.sessionExpiryMs,
23
+ };
24
+ this.sessions.set(sessionId, session);
25
+ return session;
26
+ }
27
+ getSession(sessionId) {
28
+ const session = this.sessions.get(sessionId);
29
+ if (!session)
30
+ return null;
31
+ if (Date.now() > session.expiresAt) {
32
+ this.sessions.delete(sessionId);
33
+ return null;
34
+ }
35
+ return session;
36
+ }
37
+ deleteSession(sessionId) {
38
+ this.sessions.delete(sessionId);
39
+ }
40
+ }
41
+ /**
42
+ * Create a Session Store instance
43
+ */
44
+ export function createSessionStore() {
45
+ return new InMemorySessionStore();
46
+ }
47
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/oauth/session-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAYrC;;GAEG;AACH,MAAM,OAAO,oBAAoB;IACvB,QAAQ,GAA6B,IAAI,GAAG,EAAE,CAAC;IAC/C,eAAe,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;IAE1D,aAAa,CAAC,MAAc;QAC1B,MAAM,SAAS,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAgB;YAC3B,SAAS;YACT,MAAM;YACN,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,eAAe;SACtC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,aAAa,CAAC,SAAiB;QAC7B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,oBAAoB,EAAE,CAAC;AACpC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../../src/remote/cloud-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../../src/remote/cloud-config.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@
4
4
  * Requirements: 12.3, 12.6
5
5
  */
6
6
  import { createCipheriv, createDecipheriv, randomBytes, createHash } from 'crypto';
7
+ import { logger } from '../utils/logger.js';
7
8
  /**
8
9
  * Cloud Configuration Manager
9
10
  * Handles encrypted cloud sync of configurations
@@ -221,7 +222,7 @@ export class CloudConfigManager {
221
222
  return this.localConfig;
222
223
  }
223
224
  catch (error) {
224
- console.error('Failed to sync from cloud:', error);
225
+ logger.error({ err: error }, 'Failed to sync from cloud');
225
226
  return null;
226
227
  }
227
228
  }