oblien 1.3.0 → 2.0.1

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 (187) hide show
  1. package/README.md +482 -422
  2. package/dist/client.d.ts +31 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +33 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/error.d.ts +29 -0
  7. package/dist/error.d.ts.map +1 -0
  8. package/dist/error.js +52 -0
  9. package/dist/error.js.map +1 -0
  10. package/dist/http.d.ts +20 -0
  11. package/dist/http.d.ts.map +1 -0
  12. package/dist/http.js +108 -0
  13. package/dist/http.js.map +1 -0
  14. package/dist/index.d.ts +8 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +10 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/resources/api-access.d.ts +21 -0
  19. package/dist/resources/api-access.d.ts.map +1 -0
  20. package/dist/resources/api-access.js +32 -0
  21. package/dist/resources/api-access.js.map +1 -0
  22. package/dist/resources/base.d.ts +17 -0
  23. package/dist/resources/base.d.ts.map +1 -0
  24. package/dist/resources/base.js +21 -0
  25. package/dist/resources/base.js.map +1 -0
  26. package/dist/resources/images.d.ts +11 -0
  27. package/dist/resources/images.d.ts.map +1 -0
  28. package/dist/resources/images.js +16 -0
  29. package/dist/resources/images.js.map +1 -0
  30. package/dist/resources/lifecycle.d.ts +23 -0
  31. package/dist/resources/lifecycle.d.ts.map +1 -0
  32. package/dist/resources/lifecycle.js +32 -0
  33. package/dist/resources/lifecycle.js.map +1 -0
  34. package/dist/resources/logs.d.ts +25 -0
  35. package/dist/resources/logs.d.ts.map +1 -0
  36. package/dist/resources/logs.js +51 -0
  37. package/dist/resources/logs.js.map +1 -0
  38. package/dist/resources/metadata.d.ts +15 -0
  39. package/dist/resources/metadata.d.ts.map +1 -0
  40. package/dist/resources/metadata.js +20 -0
  41. package/dist/resources/metadata.js.map +1 -0
  42. package/dist/resources/metrics.d.ts +17 -0
  43. package/dist/resources/metrics.d.ts.map +1 -0
  44. package/dist/resources/metrics.js +27 -0
  45. package/dist/resources/metrics.js.map +1 -0
  46. package/dist/resources/network.d.ts +17 -0
  47. package/dist/resources/network.d.ts.map +1 -0
  48. package/dist/resources/network.js +20 -0
  49. package/dist/resources/network.js.map +1 -0
  50. package/dist/resources/public-access.d.ts +15 -0
  51. package/dist/resources/public-access.d.ts.map +1 -0
  52. package/dist/resources/public-access.js +21 -0
  53. package/dist/resources/public-access.js.map +1 -0
  54. package/dist/resources/resources.d.ts +15 -0
  55. package/dist/resources/resources.d.ts.map +1 -0
  56. package/dist/resources/resources.js +20 -0
  57. package/dist/resources/resources.js.map +1 -0
  58. package/dist/resources/snapshots.d.ts +27 -0
  59. package/dist/resources/snapshots.d.ts.map +1 -0
  60. package/dist/resources/snapshots.js +45 -0
  61. package/dist/resources/snapshots.js.map +1 -0
  62. package/dist/resources/ssh.d.ts +19 -0
  63. package/dist/resources/ssh.d.ts.map +1 -0
  64. package/dist/resources/ssh.js +28 -0
  65. package/dist/resources/ssh.js.map +1 -0
  66. package/dist/resources/usage.d.ts +25 -0
  67. package/dist/resources/usage.d.ts.map +1 -0
  68. package/dist/resources/usage.js +44 -0
  69. package/dist/resources/usage.js.map +1 -0
  70. package/dist/resources/workloads.d.ts +39 -0
  71. package/dist/resources/workloads.d.ts.map +1 -0
  72. package/dist/resources/workloads.js +83 -0
  73. package/dist/resources/workloads.js.map +1 -0
  74. package/dist/runtime/exec.d.ts +71 -0
  75. package/dist/runtime/exec.d.ts.map +1 -0
  76. package/dist/runtime/exec.js +163 -0
  77. package/dist/runtime/exec.js.map +1 -0
  78. package/dist/runtime/files.d.ts +39 -0
  79. package/dist/runtime/files.d.ts.map +1 -0
  80. package/dist/runtime/files.js +143 -0
  81. package/dist/runtime/files.js.map +1 -0
  82. package/dist/runtime/search.d.ts +23 -0
  83. package/dist/runtime/search.d.ts.map +1 -0
  84. package/dist/runtime/search.js +65 -0
  85. package/dist/runtime/search.js.map +1 -0
  86. package/dist/runtime/terminal.d.ts +29 -0
  87. package/dist/runtime/terminal.d.ts.map +1 -0
  88. package/dist/runtime/terminal.js +58 -0
  89. package/dist/runtime/terminal.js.map +1 -0
  90. package/dist/runtime/watcher.d.ts +27 -0
  91. package/dist/runtime/watcher.d.ts.map +1 -0
  92. package/dist/runtime/watcher.js +53 -0
  93. package/dist/runtime/watcher.js.map +1 -0
  94. package/dist/runtime/ws.d.ts +92 -0
  95. package/dist/runtime/ws.d.ts.map +1 -0
  96. package/dist/runtime/ws.js +228 -0
  97. package/dist/runtime/ws.js.map +1 -0
  98. package/dist/runtime-http.d.ts +35 -0
  99. package/dist/runtime-http.d.ts.map +1 -0
  100. package/dist/runtime-http.js +99 -0
  101. package/dist/runtime-http.js.map +1 -0
  102. package/dist/runtime.d.ts +77 -0
  103. package/dist/runtime.d.ts.map +1 -0
  104. package/dist/runtime.js +97 -0
  105. package/dist/runtime.js.map +1 -0
  106. package/dist/types/client.d.ts +7 -0
  107. package/dist/types/client.d.ts.map +1 -0
  108. package/dist/types/client.js +3 -0
  109. package/dist/types/client.js.map +1 -0
  110. package/dist/types/common.d.ts +13 -0
  111. package/dist/types/common.d.ts.map +1 -0
  112. package/dist/types/common.js +3 -0
  113. package/dist/types/common.js.map +1 -0
  114. package/dist/types/index.d.ts +8 -0
  115. package/dist/types/index.d.ts.map +1 -0
  116. package/dist/types/index.js +2 -0
  117. package/dist/types/index.js.map +1 -0
  118. package/dist/types/network.d.ts +15 -0
  119. package/dist/types/network.d.ts.map +1 -0
  120. package/dist/types/network.js +3 -0
  121. package/dist/types/network.js.map +1 -0
  122. package/dist/types/resources.d.ts +10 -0
  123. package/dist/types/resources.d.ts.map +1 -0
  124. package/dist/types/resources.js +3 -0
  125. package/dist/types/resources.js.map +1 -0
  126. package/dist/types/runtime.d.ts +302 -0
  127. package/dist/types/runtime.d.ts.map +1 -0
  128. package/dist/types/runtime.js +3 -0
  129. package/dist/types/runtime.js.map +1 -0
  130. package/dist/types/workspace-resources.d.ts +186 -0
  131. package/dist/types/workspace-resources.d.ts.map +1 -0
  132. package/dist/types/workspace-resources.js +3 -0
  133. package/dist/types/workspace-resources.js.map +1 -0
  134. package/dist/types/workspace.d.ts +41 -0
  135. package/dist/types/workspace.d.ts.map +1 -0
  136. package/dist/types/workspace.js +3 -0
  137. package/dist/types/workspace.js.map +1 -0
  138. package/dist/workspace.d.ts +135 -0
  139. package/dist/workspace.d.ts.map +1 -0
  140. package/dist/workspace.js +194 -0
  141. package/dist/workspace.js.map +1 -0
  142. package/package.json +30 -69
  143. package/LICENSE +0 -21
  144. package/agents.js +0 -14
  145. package/browser.js +0 -6
  146. package/cdn.js +0 -6
  147. package/chat.js +0 -21
  148. package/credits.js +0 -11
  149. package/icons.js +0 -11
  150. package/index.d.ts +0 -986
  151. package/index.js +0 -63
  152. package/namespaces.js +0 -12
  153. package/sandbox.js +0 -12
  154. package/search.js +0 -11
  155. package/src/agents/agent.js +0 -229
  156. package/src/agents/index.js +0 -227
  157. package/src/agents/settings.js +0 -100
  158. package/src/agents/tools.js +0 -155
  159. package/src/browser/index.js +0 -474
  160. package/src/cdn/index.js +0 -769
  161. package/src/chat/index.js +0 -724
  162. package/src/chat/session.js +0 -93
  163. package/src/client.js +0 -175
  164. package/src/credits/index.js +0 -492
  165. package/src/icons/index.js +0 -185
  166. package/src/namespaces/index.js +0 -236
  167. package/src/namespaces/namespace.js +0 -274
  168. package/src/sandbox/core/api/base.js +0 -89
  169. package/src/sandbox/core/api/database.js +0 -340
  170. package/src/sandbox/core/api/files.js +0 -141
  171. package/src/sandbox/core/api/git.js +0 -174
  172. package/src/sandbox/core/api/search.js +0 -29
  173. package/src/sandbox/core/api/snapshots.js +0 -132
  174. package/src/sandbox/core/api/terminal.js +0 -20
  175. package/src/sandbox/core/auth.js +0 -256
  176. package/src/sandbox/core/client.js +0 -197
  177. package/src/sandbox/core/index.js +0 -22
  178. package/src/sandbox/core/managers/terminal.js +0 -453
  179. package/src/sandbox/core/managers/watcher.js +0 -197
  180. package/src/sandbox/core/types.js +0 -92
  181. package/src/sandbox/core/utils/http.js +0 -89
  182. package/src/sandbox/core/websocket/connection.js +0 -479
  183. package/src/sandbox/index.d.ts +0 -542
  184. package/src/sandbox/index.js +0 -234
  185. package/src/sandbox/sandbox.js +0 -313
  186. package/src/search/index.js +0 -206
  187. package/src/utils/guest-manager.js +0 -454
@@ -1,206 +0,0 @@
1
- /**
2
- * Search Module
3
- * Web search, content extraction, and research crawling
4
- */
5
-
6
- import { OblienClient } from '../client.js';
7
-
8
- export class OblienSearch {
9
- /**
10
- * @param {import('../client.js').OblienClient|Object} clientOrConfig - Oblien client instance or config
11
- * @param {string} [clientOrConfig.clientId] - Client ID (if not using client instance)
12
- * @param {string} [clientOrConfig.clientSecret] - Client Secret (if not using client instance)
13
- * @param {string} [clientOrConfig.baseURL] - Base URL (optional)
14
- */
15
- constructor(clientOrConfig) {
16
- if (!clientOrConfig) {
17
- throw new Error('Oblien client or credentials are required');
18
- }
19
-
20
- // If it's already a client instance
21
- if (clientOrConfig.clientId && clientOrConfig.clientSecret && typeof clientOrConfig.get === 'function') {
22
- this.client = clientOrConfig;
23
- }
24
- // If credentials provided, create client
25
- else if (clientOrConfig.clientId && clientOrConfig.clientSecret) {
26
- this.client = new OblienClient(clientOrConfig);
27
- }
28
- else {
29
- throw new Error('Either provide OblienClient instance or { clientId, clientSecret }');
30
- }
31
- }
32
-
33
- /**
34
- * Search the web with multiple queries
35
- * @param {Object} options - Search options
36
- * @param {Array<string>} options.queries - Array of search queries (required)
37
- * @param {boolean} [options.includeAnswers=false] - Include AI-generated answers
38
- * @param {Object} [options.options] - Additional search options
39
- * @param {number} [options.options.maxResults] - Max results per query
40
- * @param {string} [options.options.region] - Search region
41
- * @param {string} [options.options.timeRange] - Time range filter
42
- * @returns {Promise<Array>} Search results
43
- */
44
- async search(options) {
45
- const { queries, includeAnswers = false, options: searchOptions = {} } = options;
46
-
47
- if (!queries || !Array.isArray(queries) || queries.length === 0) {
48
- throw new Error('Queries array is required and must not be empty');
49
- }
50
-
51
- const response = await this.client.post('search', {
52
- queries,
53
- includeAnswers,
54
- options: searchOptions
55
- });
56
-
57
- return response;
58
- }
59
-
60
- /**
61
- * Extract and summarize content from web pages
62
- * @param {Object} options - Extract options
63
- * @param {Array<Object>} options.pages - Array of pages to extract (required)
64
- * @param {string} options.pages[].url - Page URL (required)
65
- * @param {Array<string>} options.pages[].details - Details to extract (required)
66
- * @param {string} [options.pages[].summaryLevel='medium'] - Summary level: 'brief' | 'medium' | 'detailed'
67
- * @param {Object} [options.options] - Additional extraction options
68
- * @returns {Promise<Object>} Extracted content
69
- */
70
- async extract(options) {
71
- const { pages, options: extractOptions = {} } = options;
72
-
73
- if (!pages || !Array.isArray(pages) || pages.length === 0) {
74
- throw new Error('Pages array is required and must not be empty');
75
- }
76
-
77
- // Validate pages
78
- pages.forEach((page, index) => {
79
- if (!page.url) {
80
- throw new Error(`Page at index ${index} is missing 'url'`);
81
- }
82
- if (!page.details || !Array.isArray(page.details) || page.details.length === 0) {
83
- throw new Error(`Page at index ${index} is missing 'details' array`);
84
- }
85
- });
86
-
87
- const response = await this.client.post('search/extract', {
88
- pages,
89
- options: extractOptions
90
- });
91
-
92
- return response;
93
- }
94
-
95
- /**
96
- * Create deep research report with AI crawling
97
- * @param {Object} options - Crawl options
98
- * @param {string} options.instructions - Research instructions (required)
99
- * @param {Object} [options.options] - Additional crawl options
100
- * @param {boolean} [options.options.thinking] - Enable thinking mode
101
- * @param {boolean} [options.options.allow_thinking_callback] - Allow thinking callbacks
102
- * @param {boolean} [options.options.stream_text] - Stream text responses
103
- * @param {string} [options.reportType='pdf'] - Report type: 'pdf' | 'markdown' | 'html'
104
- * @param {Function} [options.onProgress] - Callback for progress updates (streaming)
105
- * @returns {Promise<Object>} Research report result
106
- */
107
- async crawl(options) {
108
- const {
109
- instructions,
110
- options: crawlOptions = {},
111
- reportType = 'pdf',
112
- onProgress = null
113
- } = options;
114
-
115
- if (!instructions || typeof instructions !== 'string') {
116
- throw new Error('Instructions string is required');
117
- }
118
-
119
- // If onProgress is provided, we need to handle streaming
120
- if (onProgress && typeof onProgress === 'function') {
121
- return this._crawlWithStreaming({
122
- instructions,
123
- options: crawlOptions,
124
- reportType,
125
- onProgress
126
- });
127
- }
128
-
129
- // Standard JSON response
130
- const response = await this.client.post('search/crawl', {
131
- instructions,
132
- options: crawlOptions,
133
- responseType: 'json',
134
- reportType
135
- });
136
-
137
- return response;
138
- }
139
-
140
- /**
141
- * Handle streaming crawl with progress callbacks
142
- * @private
143
- */
144
- async _crawlWithStreaming({ instructions, options, reportType, onProgress }) {
145
- const url = this.client._buildURL('search/crawl');
146
- const headers = this.client.getAuthHeaders();
147
-
148
- const response = await fetch(url, {
149
- method: 'POST',
150
- headers,
151
- body: JSON.stringify({
152
- instructions,
153
- options,
154
- responseType: 'stream',
155
- reportType
156
- })
157
- });
158
-
159
- if (!response.ok) {
160
- const error = await response.json();
161
- throw new Error(error.message || error.error || 'Crawl request failed');
162
- }
163
-
164
- // Handle streaming response
165
- const reader = response.body.getReader();
166
- const decoder = new TextDecoder();
167
- let buffer = '';
168
- let finalResult = null;
169
-
170
- while (true) {
171
- const { done, value } = await reader.read();
172
-
173
- if (done) break;
174
-
175
- buffer += decoder.decode(value, { stream: true });
176
-
177
- // Process complete SSE messages
178
- const lines = buffer.split('\n\n');
179
- buffer = lines.pop() || ''; // Keep incomplete message in buffer
180
-
181
- for (const line of lines) {
182
- if (line.startsWith('data: ')) {
183
- try {
184
- const data = JSON.parse(line.slice(6));
185
-
186
- if (data.type === 'crawl_end') {
187
- finalResult = data.data;
188
- } else if (data.type === 'error') {
189
- throw new Error(data.error);
190
- } else {
191
- // Progress update
192
- onProgress(data);
193
- }
194
- } catch (error) {
195
- console.error('Error parsing SSE data:', error);
196
- }
197
- }
198
- }
199
- }
200
-
201
- return finalResult || { success: true };
202
- }
203
- }
204
-
205
- export default OblienSearch;
206
-
@@ -1,454 +0,0 @@
1
- /**
2
- * Guest Manager
3
- * Manages guest users based on IP addresses or custom identifiers
4
- */
5
-
6
- import crypto from 'crypto';
7
- import NodeCache from 'node-cache';
8
-
9
- export class GuestManager {
10
- /**
11
- * @param {Object} options - Configuration options
12
- * @param {Object} [options.storage] - Custom storage adapter (must implement get, set, delete)
13
- * @param {number} [options.ttl] - Time to live for guest sessions in seconds (default: 24 hours)
14
- * @param {Function} [options.onGuestCreated] - Callback when a new guest is created
15
- */
16
- constructor(options = {}) {
17
- this.storage = options.storage || new NodeCacheStorage(options.ttl);
18
- this.ttl = options.ttl || 24 * 60 * 60; // 24 hours
19
- this.onGuestCreated = options.onGuestCreated;
20
- }
21
-
22
- /**
23
- * Generate guest ID from IP address
24
- * @param {string} ip - IP address
25
- * @returns {string} Guest ID
26
- */
27
- generateGuestId(ip) {
28
- // Hash IP to create consistent guest ID
29
- const hash = crypto.createHash('sha256').update(ip).digest('hex');
30
- return `guest_${hash.substring(0, 16)}`;
31
- }
32
-
33
- /**
34
- * Find existing guest by fingerprint or IP (dual-layer identification)
35
- * @param {string} fingerprint - Client fingerprint
36
- * @param {string} ip - IP address
37
- * @returns {Promise<Object|null>} Guest object or null
38
- */
39
- async findExistingGuest(fingerprint, ip) {
40
- // Layer 1: Try to find by fingerprint first
41
- const guestIdByFingerprint = await this.storage.get(`fingerprint:${fingerprint}`);
42
- if (guestIdByFingerprint) {
43
- const guest = await this.getGuest(guestIdByFingerprint);
44
- if (guest) {
45
- // Update IP mapping if it changed
46
- if (guest.metadata?.ip !== ip) {
47
- await this._updateMappings(guest.id, fingerprint, ip);
48
- await this.updateGuest(guest.id, {
49
- ip: this._maskIP(ip),
50
- metadata: {
51
- ...guest.metadata,
52
- ip,
53
- previousIps: [...(guest.metadata?.previousIps || []), guest.metadata?.ip].filter(Boolean),
54
- },
55
- });
56
- }
57
- return guest;
58
- }
59
- }
60
-
61
- // Layer 2: Fallback to IP if fingerprint didn't match
62
- const guestIdByIp = await this.storage.get(`ip:${ip}`);
63
- if (guestIdByIp) {
64
- const guest = await this.getGuest(guestIdByIp);
65
- if (guest) {
66
- // Update fingerprint mapping
67
- await this._updateMappings(guest.id, fingerprint, ip);
68
- await this.updateGuest(guest.id, {
69
- metadata: {
70
- ...guest.metadata,
71
- fingerprint,
72
- previousFingerprints: [...(guest.metadata?.previousFingerprints || []), guest.metadata?.fingerprint].filter(Boolean),
73
- },
74
- });
75
- return guest;
76
- }
77
- }
78
-
79
- return null;
80
- }
81
-
82
- /**
83
- * Update fingerprint and IP mappings
84
- * @private
85
- */
86
- async _updateMappings(guestId, fingerprint, ip) {
87
- await this.storage.set(`fingerprint:${fingerprint}`, guestId, this.ttl);
88
- await this.storage.set(`ip:${ip}`, guestId, this.ttl);
89
- }
90
-
91
- /**
92
- * Get or create guest user by IP and fingerprint (dual-layer identification)
93
- * Supports both old signature: getOrCreateGuest(ip, metadata)
94
- * and new signature: getOrCreateGuest(ip, fingerprint, metadata)
95
- * @param {string} ip - IP address
96
- * @param {string|Object} fingerprintOrMetadata - Client fingerprint (string) or metadata (object)
97
- * @param {Object} [metadata] - Additional metadata to store (only if fingerprint is provided)
98
- * @returns {Promise<Object>} Guest user object
99
- */
100
- async getOrCreateGuest(ip, fingerprintOrMetadata = null, metadata = {}) {
101
- // Handle backward compatibility: detect if second param is metadata (object) or fingerprint (string)
102
- let fingerprint = null;
103
- let finalMetadata = {};
104
-
105
- if (fingerprintOrMetadata === null || fingerprintOrMetadata === undefined) {
106
- // No second parameter
107
- finalMetadata = metadata || {};
108
- } else if (typeof fingerprintOrMetadata === 'string') {
109
- // New signature: (ip, fingerprint, metadata)
110
- fingerprint = fingerprintOrMetadata;
111
- finalMetadata = metadata || {};
112
- } else if (typeof fingerprintOrMetadata === 'object') {
113
- // Old signature: (ip, metadata) - fingerprint is in metadata
114
- finalMetadata = fingerprintOrMetadata;
115
- fingerprint = finalMetadata.fingerprint || null;
116
- }
117
-
118
- // Try to find existing guest by fingerprint or IP
119
- if (fingerprint) {
120
- const existingGuest = await this.findExistingGuest(fingerprint, ip);
121
- if (existingGuest) {
122
- // Update last seen
123
- existingGuest.lastSeen = new Date().toISOString();
124
- await this.storage.set(`guest:${existingGuest.id}`, existingGuest, this.ttl);
125
- return existingGuest;
126
- }
127
- } else {
128
- // Try to find by IP only
129
- const guestIdByIp = await this.storage.get(`ip:${ip}`);
130
- if (guestIdByIp) {
131
- const guest = await this.getGuest(guestIdByIp);
132
- if (guest) {
133
- guest.lastSeen = new Date().toISOString();
134
- await this.storage.set(`guest:${guest.id}`, guest, this.ttl);
135
- return guest;
136
- }
137
- }
138
- }
139
-
140
- // Create new guest
141
- const guestId = this.generateGuestId(ip);
142
- const guest = {
143
- id: guestId,
144
- namespace: guestId, // For rate limiting
145
- ip: this._maskIP(ip), // Store masked IP for privacy
146
- isGuest: true,
147
- createdAt: new Date().toISOString(),
148
- lastSeen: new Date().toISOString(),
149
- metadata: {
150
- ...finalMetadata,
151
- ip,
152
- fingerprint,
153
- },
154
- sessions: [],
155
- };
156
-
157
- await this.storage.set(`guest:${guestId}`, guest, this.ttl);
158
-
159
- // Store mappings
160
- if (fingerprint) {
161
- await this._updateMappings(guestId, fingerprint, ip);
162
- } else {
163
- // Fallback: just store IP mapping if no fingerprint
164
- await this.storage.set(`ip:${ip}`, guestId, this.ttl);
165
- }
166
-
167
- // Call callback if provided
168
- if (this.onGuestCreated) {
169
- this.onGuestCreated(guest);
170
- }
171
-
172
- return guest;
173
- }
174
-
175
- /**
176
- * Get guest by ID
177
- * @param {string} guestId - Guest ID
178
- * @returns {Promise<Object|null>} Guest object or null
179
- */
180
- async getGuest(guestId) {
181
- try {
182
- return await this.storage.get(`guest:${guestId}`);
183
- } catch (error) {
184
- return null;
185
- }
186
- }
187
-
188
- /**
189
- * Update guest metadata
190
- * @param {string} guestId - Guest ID
191
- * @param {Object} updates - Fields to update
192
- * @returns {Promise<Object>} Updated guest object
193
- */
194
- async updateGuest(guestId, updates) {
195
- const guest = await this.storage.get(`guest:${guestId}`);
196
-
197
- if (!guest) {
198
- throw new Error(`Guest not found: ${guestId}`);
199
- }
200
-
201
- const updated = {
202
- ...guest,
203
- ...updates,
204
- lastSeen: new Date().toISOString(),
205
- };
206
-
207
- await this.storage.set(`guest:${guestId}`, updated, this.ttl);
208
- return updated;
209
- }
210
-
211
- /**
212
- * Add session to guest
213
- * @param {string} guestId - Guest ID
214
- * @param {string} sessionId - Session ID
215
- * @returns {Promise<Object>} Updated guest object
216
- */
217
- async addSession(guestId, sessionId) {
218
- const guest = await this.storage.get(`guest:${guestId}`);
219
-
220
- if (!guest) {
221
- throw new Error(`Guest not found: ${guestId}`);
222
- }
223
-
224
- if (!guest.sessions.includes(sessionId)) {
225
- guest.sessions.push(sessionId);
226
- }
227
-
228
- guest.lastSeen = new Date().toISOString();
229
- await this.storage.set(`guest:${guestId}`, guest, this.ttl);
230
-
231
- return guest;
232
- }
233
-
234
- /**
235
- * Delete guest
236
- * @param {string} guestId - Guest ID
237
- * @returns {Promise<boolean>} Success status
238
- */
239
- async deleteGuest(guestId) {
240
- return await this.storage.delete(`guest:${guestId}`);
241
- }
242
-
243
- /**
244
- * Mask IP address for privacy (keep first 2 octets)
245
- * @private
246
- */
247
- _maskIP(ip) {
248
- if (!ip) return 'unknown';
249
-
250
- // IPv4
251
- if (ip.includes('.')) {
252
- const parts = ip.split('.');
253
- return `${parts[0]}.${parts[1]}.xxx.xxx`;
254
- }
255
-
256
- // IPv6 - keep first 4 groups
257
- if (ip.includes(':')) {
258
- const parts = ip.split(':');
259
- return `${parts.slice(0, 4).join(':')}:xxxx:xxxx:xxxx:xxxx`;
260
- }
261
-
262
- return 'unknown';
263
- }
264
-
265
- /**
266
- * Get all active guests (for admin/monitoring)
267
- * @returns {Promise<Array>} Array of guest objects
268
- */
269
- async getAllGuests() {
270
- return await this.storage.getAll('guest:*');
271
- }
272
-
273
- /**
274
- * Clean up expired guests
275
- * @returns {Promise<number>} Number of cleaned guests
276
- */
277
- async cleanup() {
278
- const guests = await this.getAllGuests();
279
- const now = Date.now();
280
- let cleaned = 0;
281
-
282
- for (const guest of guests) {
283
- const lastSeen = new Date(guest.lastSeen).getTime();
284
- const age = now - lastSeen;
285
-
286
- if (age > this.ttl * 1000) {
287
- await this.deleteGuest(guest.id);
288
- cleaned++;
289
- }
290
- }
291
-
292
- return cleaned;
293
- }
294
- }
295
-
296
- /**
297
- * NodeCache Storage Adapter (Default)
298
- * Uses node-cache for automatic expiration and memory management
299
- */
300
- class NodeCacheStorage {
301
- constructor(ttl = 24 * 60 * 60) {
302
- this.cache = new NodeCache({
303
- stdTTL: ttl,
304
- checkperiod: 600, // Check for expired keys every 10 minutes
305
- useClones: false, // Better performance
306
- maxKeys: 100000, // Limit memory usage
307
- });
308
- }
309
-
310
- async get(key) {
311
- return this.cache.get(key) || null;
312
- }
313
-
314
- async set(key, value, ttl) {
315
- return this.cache.set(key, value, ttl || undefined);
316
- }
317
-
318
- async delete(key) {
319
- return this.cache.del(key) > 0;
320
- }
321
-
322
- async getAll(pattern) {
323
- const prefix = pattern.replace('*', '');
324
- const keys = this.cache.keys();
325
- const results = [];
326
-
327
- for (const key of keys) {
328
- if (key.startsWith(prefix)) {
329
- const value = this.cache.get(key);
330
- if (value) results.push(value);
331
- }
332
- }
333
-
334
- return results;
335
- }
336
-
337
- /**
338
- * Get cache statistics
339
- */
340
- getStats() {
341
- return this.cache.getStats();
342
- }
343
-
344
- /**
345
- * Clear all cache
346
- */
347
- clear() {
348
- this.cache.flushAll();
349
- }
350
- }
351
-
352
- /**
353
- * Simple In-Memory Storage (Fallback)
354
- * Use NodeCacheStorage or RedisStorage for production
355
- */
356
- export class InMemoryStorage {
357
- constructor() {
358
- this.store = new Map();
359
- this.expirations = new Map();
360
- }
361
-
362
- async get(key) {
363
- // Check if expired
364
- const expiry = this.expirations.get(key);
365
- if (expiry && Date.now() > expiry) {
366
- this.store.delete(key);
367
- this.expirations.delete(key);
368
- return null;
369
- }
370
-
371
- return this.store.get(key) || null;
372
- }
373
-
374
- async set(key, value, ttl) {
375
- this.store.set(key, value);
376
-
377
- if (ttl) {
378
- this.expirations.set(key, Date.now() + (ttl * 1000));
379
- }
380
-
381
- return true;
382
- }
383
-
384
- async delete(key) {
385
- this.expirations.delete(key);
386
- return this.store.delete(key);
387
- }
388
-
389
- async getAll(pattern) {
390
- const results = [];
391
- const prefix = pattern.replace('*', '');
392
-
393
- for (const [key, value] of this.store.entries()) {
394
- if (key.startsWith(prefix)) {
395
- // Check expiration
396
- const expiry = this.expirations.get(key);
397
- if (!expiry || Date.now() <= expiry) {
398
- results.push(value);
399
- }
400
- }
401
- }
402
-
403
- return results;
404
- }
405
- }
406
-
407
- /**
408
- * Redis Storage Adapter
409
- * For production use with Redis
410
- * Requires 'redis' package: npm install redis
411
- */
412
- export class RedisStorage {
413
- constructor(redisClient) {
414
- if (!redisClient) {
415
- throw new Error('Redis client is required');
416
- }
417
- this.redis = redisClient;
418
- }
419
-
420
- async get(key) {
421
- const data = await this.redis.get(key);
422
- return data ? JSON.parse(data) : null;
423
- }
424
-
425
- async set(key, value, ttl) {
426
- const data = JSON.stringify(value);
427
- if (ttl) {
428
- await this.redis.setex(key, ttl, data);
429
- } else {
430
- await this.redis.set(key, data);
431
- }
432
- return true;
433
- }
434
-
435
- async delete(key) {
436
- await this.redis.del(key);
437
- return true;
438
- }
439
-
440
- async getAll(pattern) {
441
- const keys = await this.redis.keys(pattern);
442
- const results = [];
443
-
444
- for (const key of keys) {
445
- const data = await this.get(key);
446
- if (data) results.push(data);
447
- }
448
-
449
- return results;
450
- }
451
- }
452
-
453
- export { NodeCacheStorage };
454
- export default GuestManager;