@lanonasis/memory-client 1.0.0 → 2.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.
package/dist/index.js CHANGED
@@ -1,22 +1,30 @@
1
1
  'use strict';
2
2
 
3
- var child_process = require('child_process');
4
- var util = require('util');
5
3
  var zod = require('zod');
6
4
 
7
5
  /**
8
- * Memory Client class for interacting with the Memory as a Service API
6
+ * Core Memory Client - Pure Browser-Safe Implementation
7
+ *
8
+ * NO Node.js dependencies, NO CLI code, NO child_process
9
+ * Works in: Browser, React Native, Cloudflare Workers, Edge Functions, Deno, Bun
10
+ *
11
+ * Bundle size: ~15KB gzipped
12
+ */
13
+ /**
14
+ * Core Memory Client class for interacting with the Memory as a Service API
15
+ *
16
+ * This is a pure browser-safe client with zero Node.js dependencies.
17
+ * It uses only standard web APIs (fetch, AbortController, etc.)
9
18
  */
10
- class MemoryClient {
19
+ class CoreMemoryClient {
11
20
  constructor(config) {
12
21
  this.config = {
13
22
  timeout: 30000,
14
- useGateway: true,
15
23
  ...config
16
24
  };
17
25
  this.baseHeaders = {
18
26
  'Content-Type': 'application/json',
19
- 'User-Agent': '@lanonasis/memory-client/1.0.0',
27
+ 'User-Agent': '@lanonasis/memory-client/2.0.0',
20
28
  ...config.headers
21
29
  };
22
30
  // Set authentication headers
@@ -26,11 +34,46 @@ class MemoryClient {
26
34
  else if (config.apiKey) {
27
35
  this.baseHeaders['X-API-Key'] = config.apiKey;
28
36
  }
37
+ // Add organization ID header if provided
38
+ if (config.organizationId) {
39
+ this.baseHeaders['X-Organization-ID'] = config.organizationId;
40
+ }
41
+ }
42
+ /**
43
+ * Enrich request body with organization context if configured
44
+ * This ensures the API has the organization_id even if not in auth token
45
+ */
46
+ enrichWithOrgContext(body) {
47
+ // If organizationId is configured, include it in the request body
48
+ if (this.config.organizationId && !body.organization_id) {
49
+ return {
50
+ ...body,
51
+ organization_id: this.config.organizationId
52
+ };
53
+ }
54
+ // Fallback to userId if no organizationId configured
55
+ if (!this.config.organizationId && this.config.userId && !body.organization_id) {
56
+ return {
57
+ ...body,
58
+ organization_id: this.config.userId
59
+ };
60
+ }
61
+ return body;
29
62
  }
30
63
  /**
31
64
  * Make an HTTP request to the API
32
65
  */
33
66
  async request(endpoint, options = {}) {
67
+ const startTime = Date.now();
68
+ // Call onRequest hook if provided
69
+ if (this.config.onRequest) {
70
+ try {
71
+ this.config.onRequest(endpoint);
72
+ }
73
+ catch (error) {
74
+ console.warn('onRequest hook error:', error);
75
+ }
76
+ }
34
77
  // Handle gateway vs direct API URL formatting
35
78
  const baseUrl = this.config.apiUrl.includes('/api')
36
79
  ? this.config.apiUrl.replace('/api', '')
@@ -54,16 +97,63 @@ class MemoryClient {
54
97
  data = await response.text();
55
98
  }
56
99
  if (!response.ok) {
57
- return {
58
- error: data?.error || `HTTP ${response.status}: ${response.statusText}`
100
+ const error = {
101
+ message: data?.error || `HTTP ${response.status}: ${response.statusText}`,
102
+ statusCode: response.status,
103
+ code: 'API_ERROR'
59
104
  };
105
+ // Call onError hook if provided
106
+ if (this.config.onError) {
107
+ try {
108
+ this.config.onError(error);
109
+ }
110
+ catch (hookError) {
111
+ console.warn('onError hook error:', hookError);
112
+ }
113
+ }
114
+ return { error: error.message };
115
+ }
116
+ // Call onResponse hook if provided
117
+ if (this.config.onResponse) {
118
+ try {
119
+ const duration = Date.now() - startTime;
120
+ this.config.onResponse(endpoint, duration);
121
+ }
122
+ catch (error) {
123
+ console.warn('onResponse hook error:', error);
124
+ }
60
125
  }
61
126
  return { data };
62
127
  }
63
128
  catch (error) {
64
129
  if (error instanceof Error && error.name === 'AbortError') {
130
+ const timeoutError = {
131
+ message: 'Request timeout',
132
+ code: 'TIMEOUT_ERROR',
133
+ statusCode: 408
134
+ };
135
+ if (this.config.onError) {
136
+ try {
137
+ this.config.onError(timeoutError);
138
+ }
139
+ catch (hookError) {
140
+ console.warn('onError hook error:', hookError);
141
+ }
142
+ }
65
143
  return { error: 'Request timeout' };
66
144
  }
145
+ const networkError = {
146
+ message: error instanceof Error ? error.message : 'Network error',
147
+ code: 'NETWORK_ERROR'
148
+ };
149
+ if (this.config.onError) {
150
+ try {
151
+ this.config.onError(networkError);
152
+ }
153
+ catch (hookError) {
154
+ console.warn('onError hook error:', hookError);
155
+ }
156
+ }
67
157
  return {
68
158
  error: error instanceof Error ? error.message : 'Network error'
69
159
  };
@@ -80,9 +170,10 @@ class MemoryClient {
80
170
  * Create a new memory
81
171
  */
82
172
  async createMemory(memory) {
173
+ const enrichedMemory = this.enrichWithOrgContext(memory);
83
174
  return this.request('/memory', {
84
175
  method: 'POST',
85
- body: JSON.stringify(memory)
176
+ body: JSON.stringify(enrichedMemory)
86
177
  });
87
178
  }
88
179
  /**
@@ -131,18 +222,20 @@ class MemoryClient {
131
222
  * Search memories using semantic search
132
223
  */
133
224
  async searchMemories(request) {
225
+ const enrichedRequest = this.enrichWithOrgContext(request);
134
226
  return this.request('/memory/search', {
135
227
  method: 'POST',
136
- body: JSON.stringify(request)
228
+ body: JSON.stringify(enrichedRequest)
137
229
  });
138
230
  }
139
231
  /**
140
232
  * Bulk delete multiple memories
141
233
  */
142
234
  async bulkDeleteMemories(memoryIds) {
235
+ const enrichedRequest = this.enrichWithOrgContext({ memory_ids: memoryIds });
143
236
  return this.request('/memory/bulk/delete', {
144
237
  method: 'POST',
145
- body: JSON.stringify({ memory_ids: memoryIds })
238
+ body: JSON.stringify(enrichedRequest)
146
239
  });
147
240
  }
148
241
  // Topic Operations
@@ -150,9 +243,10 @@ class MemoryClient {
150
243
  * Create a new topic
151
244
  */
152
245
  async createTopic(topic) {
246
+ const enrichedTopic = this.enrichWithOrgContext(topic);
153
247
  return this.request('/topics', {
154
248
  method: 'POST',
155
- body: JSON.stringify(topic)
249
+ body: JSON.stringify(enrichedTopic)
156
250
  });
157
251
  }
158
252
  /**
@@ -231,719 +325,10 @@ class MemoryClient {
231
325
  }
232
326
  }
233
327
  /**
234
- * Factory function to create a new Memory Client instance
328
+ * Factory function to create a new Core Memory Client instance
235
329
  */
236
330
  function createMemoryClient(config) {
237
- return new MemoryClient(config);
238
- }
239
-
240
- /**
241
- * CLI Integration Module for Memory Client SDK
242
- *
243
- * Provides intelligent CLI detection and MCP channel utilization
244
- * when @lanonasis/cli v1.5.2+ is available in the environment
245
- */
246
- const execAsync = util.promisify(child_process.exec);
247
- /**
248
- * CLI Detection and Integration Service
249
- */
250
- class CLIIntegration {
251
- constructor() {
252
- this.cliInfo = null;
253
- this.detectionPromise = null;
254
- }
255
- /**
256
- * Detect if CLI is available and get its capabilities
257
- */
258
- async detectCLI() {
259
- // Return cached result if already detected
260
- if (this.cliInfo) {
261
- return this.cliInfo;
262
- }
263
- // Return existing promise if detection is in progress
264
- if (this.detectionPromise) {
265
- return this.detectionPromise;
266
- }
267
- // Start new detection
268
- this.detectionPromise = this.performDetection();
269
- this.cliInfo = await this.detectionPromise;
270
- return this.cliInfo;
271
- }
272
- async performDetection() {
273
- try {
274
- // Check if onasis/lanonasis CLI is available
275
- let versionOutput = '';
276
- try {
277
- const { stdout } = await execAsync('onasis --version 2>/dev/null', { timeout: 5000 });
278
- versionOutput = stdout;
279
- }
280
- catch {
281
- // Try lanonasis if onasis fails
282
- const { stdout } = await execAsync('lanonasis --version 2>/dev/null', { timeout: 5000 });
283
- versionOutput = stdout;
284
- }
285
- const version = versionOutput.trim();
286
- // Verify it's v1.5.2 or higher for Golden Contract support
287
- const versionMatch = version.match(/(\d+)\.(\d+)\.(\d+)/);
288
- if (!versionMatch) {
289
- return { available: false };
290
- }
291
- const [, major, minor, patch] = versionMatch.map(Number);
292
- const isCompatible = major > 1 || (major === 1 && minor > 5) || (major === 1 && minor === 5 && patch >= 2);
293
- if (!isCompatible) {
294
- return {
295
- available: true,
296
- version,
297
- mcpAvailable: false,
298
- authenticated: false
299
- };
300
- }
301
- // Check MCP availability
302
- let mcpAvailable = false;
303
- try {
304
- await execAsync('onasis mcp status --output json 2>/dev/null || lanonasis mcp status --output json 2>/dev/null', {
305
- timeout: 3000
306
- });
307
- mcpAvailable = true;
308
- }
309
- catch {
310
- // MCP not available or not configured
311
- }
312
- // Check authentication status
313
- let authenticated = false;
314
- try {
315
- const { stdout: authOutput } = await execAsync('onasis auth status --output json 2>/dev/null || lanonasis auth status --output json 2>/dev/null', {
316
- timeout: 3000
317
- });
318
- const authStatus = JSON.parse(authOutput);
319
- authenticated = authStatus.authenticated === true;
320
- }
321
- catch {
322
- // Authentication check failed
323
- }
324
- return {
325
- available: true,
326
- version,
327
- mcpAvailable,
328
- authenticated
329
- };
330
- }
331
- catch {
332
- return { available: false };
333
- }
334
- }
335
- /**
336
- * Execute CLI command and return parsed JSON result
337
- */
338
- async executeCLICommand(command, options = {}) {
339
- const cliInfo = await this.detectCLI();
340
- if (!cliInfo.available) {
341
- return { error: 'CLI not available' };
342
- }
343
- if (!cliInfo.authenticated) {
344
- return { error: 'CLI not authenticated. Run: onasis login' };
345
- }
346
- try {
347
- const timeout = options.timeout || 30000;
348
- const outputFormat = options.outputFormat || 'json';
349
- const verbose = options.verbose ? '--verbose' : '';
350
- // Determine which CLI command to use (prefer onasis for Golden Contract)
351
- const cliCmd = await this.getPreferredCLICommand();
352
- const fullCommand = `${cliCmd} ${command} --output ${outputFormat} ${verbose}`.trim();
353
- const { stdout, stderr } = await execAsync(fullCommand, {
354
- timeout,
355
- maxBuffer: 1024 * 1024 // 1MB buffer
356
- });
357
- if (stderr && stderr.trim()) {
358
- console.warn('CLI warning:', stderr);
359
- }
360
- if (outputFormat === 'json') {
361
- try {
362
- const result = JSON.parse(stdout);
363
- return { data: result };
364
- }
365
- catch (parseError) {
366
- return { error: `Failed to parse CLI JSON output: ${parseError instanceof Error ? parseError.message : 'Unknown error'}` };
367
- }
368
- }
369
- return { data: stdout };
370
- }
371
- catch (error) {
372
- if (error instanceof Error && error.message.includes('timeout')) {
373
- return { error: 'CLI command timeout' };
374
- }
375
- return {
376
- error: error instanceof Error ? error.message : 'CLI command failed'
377
- };
378
- }
379
- }
380
- /**
381
- * Get preferred CLI command (onasis for Golden Contract, fallback to lanonasis)
382
- */
383
- async getPreferredCLICommand() {
384
- try {
385
- child_process.execSync('which onasis', { stdio: 'ignore', timeout: 1000 });
386
- return 'onasis';
387
- }
388
- catch {
389
- return 'lanonasis';
390
- }
391
- }
392
- /**
393
- * Memory operations via CLI
394
- */
395
- async createMemoryViaCLI(title, content, options = {}) {
396
- const { memoryType = 'context', tags = [], topicId } = options;
397
- let command = `memory create --title "${title}" --content "${content}" --memory-type ${memoryType}`;
398
- if (tags.length > 0) {
399
- command += ` --tags "${tags.join(',')}"`;
400
- }
401
- if (topicId) {
402
- command += ` --topic-id "${topicId}"`;
403
- }
404
- return this.executeCLICommand(command);
405
- }
406
- async listMemoriesViaCLI(options = {}) {
407
- let command = 'memory list';
408
- if (options.limit) {
409
- command += ` --limit ${options.limit}`;
410
- }
411
- if (options.memoryType) {
412
- command += ` --memory-type ${options.memoryType}`;
413
- }
414
- if (options.tags && options.tags.length > 0) {
415
- command += ` --tags "${options.tags.join(',')}"`;
416
- }
417
- if (options.sortBy) {
418
- command += ` --sort-by ${options.sortBy}`;
419
- }
420
- return this.executeCLICommand(command);
421
- }
422
- async searchMemoriesViaCLI(query, options = {}) {
423
- let command = `memory search "${query}"`;
424
- if (options.limit) {
425
- command += ` --limit ${options.limit}`;
426
- }
427
- if (options.memoryTypes && options.memoryTypes.length > 0) {
428
- command += ` --memory-types "${options.memoryTypes.join(',')}"`;
429
- }
430
- return this.executeCLICommand(command);
431
- }
432
- /**
433
- * Health check via CLI
434
- */
435
- async healthCheckViaCLI() {
436
- return this.executeCLICommand('health');
437
- }
438
- /**
439
- * MCP-specific operations
440
- */
441
- async getMCPStatus() {
442
- const cliInfo = await this.detectCLI();
443
- if (!cliInfo.mcpAvailable) {
444
- return { error: 'MCP not available via CLI' };
445
- }
446
- return this.executeCLICommand('mcp status');
447
- }
448
- async listMCPTools() {
449
- const cliInfo = await this.detectCLI();
450
- if (!cliInfo.mcpAvailable) {
451
- return { error: 'MCP not available via CLI' };
452
- }
453
- return this.executeCLICommand('mcp tools');
454
- }
455
- /**
456
- * Authentication operations
457
- */
458
- async getAuthStatus() {
459
- return this.executeCLICommand('auth status');
460
- }
461
- /**
462
- * Check if specific CLI features are available
463
- */
464
- async getCapabilities() {
465
- const cliInfo = await this.detectCLI();
466
- return {
467
- cliAvailable: cliInfo.available,
468
- version: cliInfo.version,
469
- mcpSupport: cliInfo.mcpAvailable || false,
470
- authenticated: cliInfo.authenticated || false,
471
- goldenContract: cliInfo.available && this.isGoldenContractCompliant(cliInfo.version)
472
- };
473
- }
474
- isGoldenContractCompliant(version) {
475
- if (!version)
476
- return false;
477
- const versionMatch = version.match(/(\d+)\.(\d+)\.(\d+)/);
478
- if (!versionMatch)
479
- return false;
480
- const [, major, minor, patch] = versionMatch.map(Number);
481
- return major > 1 || (major === 1 && minor > 5) || (major === 1 && minor === 5 && patch >= 2);
482
- }
483
- /**
484
- * Force refresh CLI detection
485
- */
486
- async refresh() {
487
- this.cliInfo = null;
488
- this.detectionPromise = null;
489
- return this.detectCLI();
490
- }
491
- /**
492
- * Get cached CLI info without re-detection
493
- */
494
- getCachedInfo() {
495
- return this.cliInfo;
496
- }
497
- }
498
-
499
- /**
500
- * Enhanced Memory Client with CLI Integration
501
- *
502
- * Intelligently routes requests through CLI v1.5.2+ when available,
503
- * with fallback to direct API for maximum compatibility and performance
504
- */
505
- /**
506
- * Enhanced Memory Client with intelligent CLI/API routing
507
- */
508
- class EnhancedMemoryClient {
509
- createDefaultCapabilities() {
510
- return {
511
- cliAvailable: false,
512
- mcpSupport: false,
513
- authenticated: false,
514
- goldenContract: false
515
- };
516
- }
517
- constructor(config) {
518
- this.capabilities = null;
519
- this.config = {
520
- preferCLI: true,
521
- enableMCP: true,
522
- cliDetectionTimeout: 5000,
523
- fallbackToAPI: true,
524
- minCLIVersion: '1.5.2',
525
- verbose: false,
526
- timeout: 30000,
527
- useGateway: true,
528
- apiKey: config.apiKey || process.env.LANONASIS_API_KEY || '',
529
- authToken: config.authToken || '',
530
- headers: config.headers || {},
531
- ...config
532
- };
533
- this.directClient = new MemoryClient(config);
534
- this.cliIntegration = new CLIIntegration();
535
- }
536
- /**
537
- * Initialize the client and detect capabilities
538
- */
539
- async initialize() {
540
- try {
541
- const detectionPromise = this.cliIntegration.getCapabilities();
542
- const capabilities = this.config.cliDetectionTimeout > 0
543
- ? await Promise.race([
544
- detectionPromise,
545
- new Promise((resolve) => {
546
- setTimeout(() => resolve(null), this.config.cliDetectionTimeout);
547
- })
548
- ])
549
- : await detectionPromise;
550
- if (capabilities) {
551
- this.capabilities = capabilities;
552
- if (this.config.verbose && capabilities.cliAvailable && !capabilities.authenticated) {
553
- const suggestedCommand = capabilities.goldenContract ? 'onasis login' : 'lanonasis login';
554
- console.warn(`CLI detected but not authenticated. Run '${suggestedCommand}' to enable enhanced SDK features.`);
555
- }
556
- }
557
- else {
558
- this.capabilities = this.createDefaultCapabilities();
559
- if (this.config.verbose) {
560
- console.warn(`CLI detection timed out after ${this.config.cliDetectionTimeout}ms. Falling back to API mode.`);
561
- }
562
- }
563
- }
564
- catch (error) {
565
- if (this.config.verbose) {
566
- console.warn('CLI detection failed:', error);
567
- }
568
- this.capabilities = this.createDefaultCapabilities();
569
- }
570
- }
571
- /**
572
- * Get current capabilities
573
- */
574
- async getCapabilities() {
575
- if (!this.capabilities) {
576
- await this.initialize();
577
- }
578
- return this.capabilities;
579
- }
580
- /**
581
- * Determine if operation should use CLI
582
- */
583
- async shouldUseCLI() {
584
- const capabilities = await this.getCapabilities();
585
- return (this.config.preferCLI &&
586
- capabilities.cliAvailable &&
587
- capabilities.authenticated &&
588
- capabilities.goldenContract);
589
- }
590
- /**
591
- * Execute operation with intelligent routing
592
- */
593
- async executeOperation(operation, cliOperation, apiOperation) {
594
- const useCLI = await this.shouldUseCLI();
595
- const capabilities = await this.getCapabilities();
596
- if (useCLI) {
597
- try {
598
- const result = await cliOperation();
599
- if (result.error && this.config.fallbackToAPI) {
600
- console.warn(`CLI ${operation} failed, falling back to API:`, result.error);
601
- const apiResult = await apiOperation();
602
- return {
603
- ...apiResult,
604
- source: 'api',
605
- mcpUsed: false
606
- };
607
- }
608
- return {
609
- ...result,
610
- source: 'cli',
611
- mcpUsed: capabilities.mcpSupport
612
- };
613
- }
614
- catch (error) {
615
- if (this.config.fallbackToAPI) {
616
- console.warn(`CLI ${operation} error, falling back to API:`, error);
617
- const apiResult = await apiOperation();
618
- return {
619
- ...apiResult,
620
- source: 'api',
621
- mcpUsed: false
622
- };
623
- }
624
- return {
625
- error: error instanceof Error ? error.message : `CLI ${operation} failed`,
626
- source: 'cli',
627
- mcpUsed: false
628
- };
629
- }
630
- }
631
- else {
632
- const result = await apiOperation();
633
- return {
634
- ...result,
635
- source: 'api',
636
- mcpUsed: false
637
- };
638
- }
639
- }
640
- // Enhanced API Methods
641
- /**
642
- * Health check with intelligent routing
643
- */
644
- async healthCheck() {
645
- return this.executeOperation('health check', () => this.cliIntegration.healthCheckViaCLI(), () => this.directClient.healthCheck());
646
- }
647
- /**
648
- * Create memory with CLI/API routing
649
- */
650
- async createMemory(memory) {
651
- return this.executeOperation('create memory', () => this.cliIntegration.createMemoryViaCLI(memory.title, memory.content, {
652
- memoryType: memory.memory_type,
653
- tags: memory.tags,
654
- topicId: memory.topic_id
655
- }), () => this.directClient.createMemory(memory));
656
- }
657
- /**
658
- * List memories with intelligent routing
659
- */
660
- async listMemories(options = {}) {
661
- return this.executeOperation('list memories', () => this.cliIntegration.listMemoriesViaCLI({
662
- limit: options.limit,
663
- memoryType: options.memory_type,
664
- tags: options.tags,
665
- sortBy: options.sort
666
- }), () => this.directClient.listMemories(options));
667
- }
668
- /**
669
- * Search memories with MCP enhancement when available
670
- */
671
- async searchMemories(request) {
672
- return this.executeOperation('search memories', () => this.cliIntegration.searchMemoriesViaCLI(request.query, {
673
- limit: request.limit,
674
- memoryTypes: request.memory_types
675
- }), () => this.directClient.searchMemories(request));
676
- }
677
- /**
678
- * Get memory by ID (API only for now)
679
- */
680
- async getMemory(id) {
681
- // CLI doesn't have get by ID yet, use API
682
- const result = await this.directClient.getMemory(id);
683
- return {
684
- ...result,
685
- source: 'api',
686
- mcpUsed: false
687
- };
688
- }
689
- /**
690
- * Update memory (API only for now)
691
- */
692
- async updateMemory(id, updates) {
693
- // CLI doesn't have update yet, use API
694
- const result = await this.directClient.updateMemory(id, updates);
695
- return {
696
- ...result,
697
- source: 'api',
698
- mcpUsed: false
699
- };
700
- }
701
- /**
702
- * Delete memory (API only for now)
703
- */
704
- async deleteMemory(id) {
705
- // CLI doesn't have delete yet, use API
706
- const result = await this.directClient.deleteMemory(id);
707
- return {
708
- ...result,
709
- source: 'api',
710
- mcpUsed: false
711
- };
712
- }
713
- // Topic Operations (API only for now)
714
- async createTopic(topic) {
715
- const result = await this.directClient.createTopic(topic);
716
- return { ...result, source: 'api', mcpUsed: false };
717
- }
718
- async getTopics() {
719
- const result = await this.directClient.getTopics();
720
- return { ...result, source: 'api', mcpUsed: false };
721
- }
722
- async getTopic(id) {
723
- const result = await this.directClient.getTopic(id);
724
- return { ...result, source: 'api', mcpUsed: false };
725
- }
726
- async updateTopic(id, updates) {
727
- const result = await this.directClient.updateTopic(id, updates);
728
- return { ...result, source: 'api', mcpUsed: false };
729
- }
730
- async deleteTopic(id) {
731
- const result = await this.directClient.deleteTopic(id);
732
- return { ...result, source: 'api', mcpUsed: false };
733
- }
734
- /**
735
- * Get memory statistics
736
- */
737
- async getMemoryStats() {
738
- const result = await this.directClient.getMemoryStats();
739
- return { ...result, source: 'api', mcpUsed: false };
740
- }
741
- // Utility Methods
742
- /**
743
- * Force CLI re-detection
744
- */
745
- async refreshCLIDetection() {
746
- this.capabilities = null;
747
- await this.cliIntegration.refresh();
748
- await this.initialize();
749
- }
750
- /**
751
- * Get authentication status from CLI
752
- */
753
- async getAuthStatus() {
754
- try {
755
- const result = await this.cliIntegration.getAuthStatus();
756
- return { ...result, source: 'cli', mcpUsed: false };
757
- }
758
- catch (error) {
759
- return {
760
- error: error instanceof Error ? error.message : 'Auth status check failed',
761
- source: 'cli',
762
- mcpUsed: false
763
- };
764
- }
765
- }
766
- /**
767
- * Get MCP status when available
768
- */
769
- async getMCPStatus() {
770
- const capabilities = await this.getCapabilities();
771
- if (!capabilities.mcpSupport) {
772
- return {
773
- error: 'MCP not available',
774
- source: 'cli',
775
- mcpUsed: false
776
- };
777
- }
778
- try {
779
- const result = await this.cliIntegration.getMCPStatus();
780
- return { ...result, source: 'cli', mcpUsed: true };
781
- }
782
- catch (error) {
783
- return {
784
- error: error instanceof Error ? error.message : 'MCP status check failed',
785
- source: 'cli',
786
- mcpUsed: false
787
- };
788
- }
789
- }
790
- /**
791
- * Update authentication for both CLI and API client
792
- */
793
- setAuthToken(token) {
794
- this.directClient.setAuthToken(token);
795
- }
796
- setApiKey(apiKey) {
797
- this.directClient.setApiKey(apiKey);
798
- }
799
- clearAuth() {
800
- this.directClient.clearAuth();
801
- }
802
- /**
803
- * Update configuration
804
- */
805
- updateConfig(updates) {
806
- this.config = { ...this.config, ...updates };
807
- this.directClient.updateConfig(updates);
808
- }
809
- /**
810
- * Get configuration summary
811
- */
812
- getConfigSummary() {
813
- return {
814
- apiUrl: this.config.apiUrl,
815
- preferCLI: this.config.preferCLI,
816
- enableMCP: this.config.enableMCP,
817
- capabilities: this.capabilities || undefined
818
- };
819
- }
820
- }
821
- /**
822
- * Factory function to create an enhanced memory client
823
- */
824
- async function createEnhancedMemoryClient(config) {
825
- const client = new EnhancedMemoryClient(config);
826
- await client.initialize();
827
- return client;
828
- }
829
-
830
- /**
831
- * Configuration utilities for Memory Client SDK
832
- * Provides smart defaults and environment detection for CLI/MCP integration
833
- */
834
- /**
835
- * Environment detection utilities
836
- */
837
- const Environment = {
838
- isNode: typeof globalThis !== 'undefined' && 'process' in globalThis && globalThis.process?.versions?.node,
839
- isBrowser: typeof window !== 'undefined',
840
- isVSCode: typeof globalThis !== 'undefined' && 'vscode' in globalThis,
841
- isCursor: typeof globalThis !== 'undefined' && 'cursor' in globalThis,
842
- isWindsurf: typeof globalThis !== 'undefined' && 'windsurf' in globalThis,
843
- get isIDE() {
844
- return this.isVSCode || this.isCursor || this.isWindsurf;
845
- },
846
- get supportsCLI() {
847
- return Boolean(this.isNode && !this.isBrowser);
848
- }
849
- };
850
- /**
851
- * Create smart configuration with environment-aware defaults
852
- */
853
- function createSmartConfig(baseConfig, options = {}) {
854
- const defaults = {
855
- preferCLI: Environment.supportsCLI,
856
- minCLIVersion: '1.5.2',
857
- enableMCP: true,
858
- cliDetectionTimeout: 3000,
859
- verbose: false
860
- };
861
- const config = { ...defaults, ...options };
862
- return {
863
- ...baseConfig,
864
- preferCLI: config.preferCLI,
865
- minCLIVersion: config.minCLIVersion,
866
- enableMCP: config.enableMCP,
867
- cliDetectionTimeout: config.cliDetectionTimeout,
868
- verbose: config.verbose,
869
- // Smart API configuration with environment detection
870
- apiUrl: baseConfig.apiUrl || (process?.env?.NODE_ENV === 'development'
871
- ? 'http://localhost:3001'
872
- : 'https://api.lanonasis.com'),
873
- // Default timeout based on environment
874
- timeout: baseConfig.timeout || (Environment.isIDE ? 10000 : 15000)
875
- };
876
- }
877
- /**
878
- * Preset configurations for common scenarios
879
- */
880
- const ConfigPresets = {
881
- /**
882
- * Development configuration with local API and CLI preference
883
- */
884
- development: (apiKey) => createSmartConfig({
885
- apiUrl: 'http://localhost:3001',
886
- apiKey,
887
- timeout: 30000
888
- }, {
889
- preferCLI: true,
890
- verbose: true
891
- }),
892
- /**
893
- * Production configuration optimized for performance
894
- */
895
- production: (apiKey) => createSmartConfig({
896
- apiUrl: 'https://api.lanonasis.com',
897
- apiKey,
898
- timeout: 15000
899
- }, {
900
- preferCLI: Environment.supportsCLI,
901
- verbose: false
902
- }),
903
- /**
904
- * IDE extension configuration with MCP prioritization
905
- */
906
- ideExtension: (apiKey) => createSmartConfig({
907
- apiUrl: 'https://api.lanonasis.com',
908
- apiKey,
909
- timeout: 10000
910
- }, {
911
- preferCLI: true,
912
- enableMCP: true,
913
- cliDetectionTimeout: 2000
914
- }),
915
- /**
916
- * Browser-only configuration (no CLI support)
917
- */
918
- browserOnly: (apiKey) => createSmartConfig({
919
- apiUrl: 'https://api.lanonasis.com',
920
- apiKey,
921
- timeout: 15000
922
- }, {
923
- preferCLI: false,
924
- enableMCP: false
925
- }),
926
- /**
927
- * CLI-first configuration for server environments
928
- */
929
- serverCLI: (apiKey) => createSmartConfig({
930
- apiUrl: 'https://api.lanonasis.com',
931
- apiKey,
932
- timeout: 20000
933
- }, {
934
- preferCLI: true,
935
- enableMCP: true,
936
- verbose: false
937
- })
938
- };
939
- /**
940
- * Migration helper for existing MemoryClient users
941
- */
942
- function migrateToEnhanced(existingConfig, enhancementOptions = {}) {
943
- return createSmartConfig(existingConfig, {
944
- preferCLI: Environment.supportsCLI,
945
- ...enhancementOptions
946
- });
331
+ return new CoreMemoryClient(config);
947
332
  }
948
333
 
949
334
  /**
@@ -965,7 +350,7 @@ const createMemorySchema = zod.z.object({
965
350
  topic_id: zod.z.string().uuid().optional(),
966
351
  project_ref: zod.z.string().max(100).optional(),
967
352
  tags: zod.z.array(zod.z.string().min(1).max(50)).max(20).default([]),
968
- metadata: zod.z.record(zod.z.unknown()).optional()
353
+ metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
969
354
  });
970
355
  const updateMemorySchema = zod.z.object({
971
356
  title: zod.z.string().min(1).max(500).optional(),
@@ -976,7 +361,7 @@ const updateMemorySchema = zod.z.object({
976
361
  topic_id: zod.z.string().uuid().nullable().optional(),
977
362
  project_ref: zod.z.string().max(100).nullable().optional(),
978
363
  tags: zod.z.array(zod.z.string().min(1).max(50)).max(20).optional(),
979
- metadata: zod.z.record(zod.z.unknown()).optional()
364
+ metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
980
365
  });
981
366
  const searchMemorySchema = zod.z.object({
982
367
  query: zod.z.string().min(1).max(1000),
@@ -996,57 +381,257 @@ const createTopicSchema = zod.z.object({
996
381
  parent_topic_id: zod.z.string().uuid().optional()
997
382
  });
998
383
 
384
+ /**
385
+ * Error handling for Memory Client
386
+ * Browser-safe, no Node.js dependencies
387
+ */
388
+ /**
389
+ * Base error class for Memory Client errors
390
+ */
391
+ class MemoryClientError extends Error {
392
+ constructor(message, code, statusCode, details) {
393
+ super(message);
394
+ this.code = code;
395
+ this.statusCode = statusCode;
396
+ this.details = details;
397
+ this.name = 'MemoryClientError';
398
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
399
+ if (Error.captureStackTrace) {
400
+ Error.captureStackTrace(this, MemoryClientError);
401
+ }
402
+ }
403
+ }
404
+ /**
405
+ * Network/API error
406
+ */
407
+ class ApiError extends MemoryClientError {
408
+ constructor(message, statusCode, details) {
409
+ super(message, 'API_ERROR', statusCode, details);
410
+ this.name = 'ApiError';
411
+ }
412
+ }
413
+ /**
414
+ * Authentication error
415
+ */
416
+ class AuthenticationError extends MemoryClientError {
417
+ constructor(message = 'Authentication required') {
418
+ super(message, 'AUTH_ERROR', 401);
419
+ this.name = 'AuthenticationError';
420
+ }
421
+ }
422
+ /**
423
+ * Validation error
424
+ */
425
+ class ValidationError extends MemoryClientError {
426
+ constructor(message, details) {
427
+ super(message, 'VALIDATION_ERROR', 400, details);
428
+ this.name = 'ValidationError';
429
+ }
430
+ }
431
+ /**
432
+ * Timeout error
433
+ */
434
+ class TimeoutError extends MemoryClientError {
435
+ constructor(message = 'Request timeout') {
436
+ super(message, 'TIMEOUT_ERROR', 408);
437
+ this.name = 'TimeoutError';
438
+ }
439
+ }
440
+ /**
441
+ * Rate limit error
442
+ */
443
+ class RateLimitError extends MemoryClientError {
444
+ constructor(message = 'Rate limit exceeded') {
445
+ super(message, 'RATE_LIMIT_ERROR', 429);
446
+ this.name = 'RateLimitError';
447
+ }
448
+ }
449
+ /**
450
+ * Not found error
451
+ */
452
+ class NotFoundError extends MemoryClientError {
453
+ constructor(resource) {
454
+ super(`${resource} not found`, 'NOT_FOUND', 404);
455
+ this.name = 'NotFoundError';
456
+ }
457
+ }
458
+
999
459
  /**
1000
460
  * @lanonasis/memory-client
1001
461
  *
1002
- * Memory as a Service (MaaS) Client SDK for Lanonasis
462
+ * Universal Memory as a Service (MaaS) Client SDK for Lanonasis
1003
463
  * Intelligent memory management with semantic search capabilities
464
+ *
465
+ * v2.0.0 - Universal SDK Redesign
466
+ * "Drop In and Sleep" Architecture - Works everywhere with zero configuration
467
+ *
468
+ * @example Browser/Web App
469
+ * ```ts
470
+ * import { createMemoryClient } from '@lanonasis/memory-client/core';
471
+ * const client = createMemoryClient({ apiKey: 'your-key' });
472
+ * ```
473
+ *
474
+ * @example Node.js
475
+ * ```ts
476
+ * import { createNodeMemoryClient } from '@lanonasis/memory-client/node';
477
+ * const client = await createNodeMemoryClient({ apiKey: process.env.KEY });
478
+ * ```
479
+ *
480
+ * @example React
481
+ * ```tsx
482
+ * import { MemoryProvider, useMemories } from '@lanonasis/memory-client/react';
483
+ * ```
484
+ *
485
+ * @example Vue
486
+ * ```ts
487
+ * import { createMemoryPlugin, useMemories } from '@lanonasis/memory-client/vue';
488
+ * ```
1004
489
  */
1005
- // Main client
490
+ // ========================================
491
+ // Core Exports (Browser-Safe)
492
+ // ========================================
493
+ // ========================================
1006
494
  // Constants
1007
- const VERSION = '1.0.0';
495
+ // ========================================
496
+ const VERSION = '2.0.0';
1008
497
  const CLIENT_NAME = '@lanonasis/memory-client';
1009
- // Environment detection
498
+ // ========================================
499
+ // Environment Detection
500
+ // ========================================
1010
501
  const isBrowser = typeof window !== 'undefined';
1011
502
  const isNode = typeof globalThis !== 'undefined' && 'process' in globalThis && globalThis.process?.versions?.node;
1012
- // Default configurations for different environments
503
+ // ========================================
504
+ // Default Configurations
505
+ // ========================================
1013
506
  const defaultConfigs = {
1014
507
  development: {
1015
508
  apiUrl: 'http://localhost:3001',
1016
509
  timeout: 30000,
1017
- useGateway: false
1018
510
  },
1019
511
  production: {
1020
512
  apiUrl: 'https://api.lanonasis.com',
1021
513
  timeout: 15000,
1022
- useGateway: true
1023
514
  },
1024
- gateway: {
515
+ edge: {
1025
516
  apiUrl: 'https://api.lanonasis.com',
1026
- timeout: 10000,
1027
- useGateway: true
517
+ timeout: 5000,
1028
518
  }
1029
519
  };
1030
- // Utility functions will be added in a future version to avoid circular imports
520
+ // Note: Enhanced client requires Node.js, so we don't export it from main entry
521
+ // Users should import from '@lanonasis/memory-client/node' instead
522
+ // ========================================
523
+ // Usage Instructions
524
+ // ========================================
525
+ /**
526
+ * # @lanonasis/memory-client v2.0
527
+ *
528
+ * ## Quick Start
529
+ *
530
+ * ### Browser / Web App
531
+ * ```bash
532
+ * npm install @lanonasis/memory-client
533
+ * ```
534
+ * ```typescript
535
+ * import { createMemoryClient } from '@lanonasis/memory-client/core';
536
+ *
537
+ * const client = createMemoryClient({
538
+ * apiUrl: 'https://api.lanonasis.com',
539
+ * apiKey: 'your-key-here'
540
+ * });
541
+ *
542
+ * const memories = await client.listMemories();
543
+ * ```
544
+ *
545
+ * ### Node.js with CLI Support
546
+ * ```typescript
547
+ * import { createNodeMemoryClient } from '@lanonasis/memory-client/node';
548
+ *
549
+ * const client = await createNodeMemoryClient({
550
+ * apiKey: process.env.LANONASIS_KEY,
551
+ * preferCLI: true // Automatically uses CLI if available
552
+ * });
553
+ *
554
+ * const result = await client.listMemories();
555
+ * console.log(`Using: ${result.source}`); // 'cli' or 'api'
556
+ * ```
557
+ *
558
+ * ### React
559
+ * ```tsx
560
+ * import { MemoryProvider, useMemories } from '@lanonasis/memory-client/react';
561
+ *
562
+ * function App() {
563
+ * return (
564
+ * <MemoryProvider apiKey="your-key">
565
+ * <MemoryList />
566
+ * </MemoryProvider>
567
+ * );
568
+ * }
569
+ *
570
+ * function MemoryList() {
571
+ * const { memories, loading } = useMemories();
572
+ * if (loading) return <div>Loading...</div>;
573
+ * return <div>{memories.map(m => <div key={m.id}>{m.title}</div>)}</div>;
574
+ * }
575
+ * ```
576
+ *
577
+ * ### Vue 3
578
+ * ```typescript
579
+ * import { createMemoryPlugin, useMemories } from '@lanonasis/memory-client/vue';
580
+ *
581
+ * const app = createApp(App);
582
+ * app.use(createMemoryPlugin({ apiKey: 'your-key' }));
583
+ * ```
584
+ *
585
+ * ### Edge Functions (Cloudflare Workers, Vercel Edge)
586
+ * ```typescript
587
+ * import { createMemoryClient } from '@lanonasis/memory-client/core';
588
+ * import { edgePreset } from '@lanonasis/memory-client/presets';
589
+ *
590
+ * export default {
591
+ * async fetch(request: Request, env: Env) {
592
+ * const client = createMemoryClient(edgePreset({
593
+ * apiKey: env.LANONASIS_KEY
594
+ * }));
595
+ * const memories = await client.searchMemories({ query: 'test' });
596
+ * return Response.json(memories.data);
597
+ * }
598
+ * };
599
+ * ```
600
+ *
601
+ * ## Bundle Sizes
602
+ *
603
+ * - **Core** (browser): ~15KB gzipped
604
+ * - **Node** (with CLI): ~35KB gzipped
605
+ * - **React**: ~18KB gzipped (+ React)
606
+ * - **Vue**: ~17KB gzipped (+ Vue)
607
+ * - **Presets**: ~2KB gzipped
608
+ *
609
+ * ## Documentation
610
+ *
611
+ * - Full docs: https://docs.lanonasis.com/sdk
612
+ * - API reference: https://docs.lanonasis.com/api
613
+ * - Examples: https://github.com/lanonasis/examples
614
+ */
1031
615
 
616
+ exports.ApiErrorClass = ApiError;
617
+ exports.AuthenticationError = AuthenticationError;
1032
618
  exports.CLIENT_NAME = CLIENT_NAME;
1033
- exports.CLIIntegration = CLIIntegration;
1034
- exports.ConfigPresets = ConfigPresets;
1035
- exports.EnhancedMemoryClient = EnhancedMemoryClient;
1036
- exports.Environment = Environment;
619
+ exports.CoreMemoryClient = CoreMemoryClient;
1037
620
  exports.MEMORY_STATUSES = MEMORY_STATUSES;
1038
621
  exports.MEMORY_TYPES = MEMORY_TYPES;
1039
- exports.MemoryClient = MemoryClient;
622
+ exports.MemoryClient = CoreMemoryClient;
623
+ exports.MemoryClientError = MemoryClientError;
624
+ exports.NotFoundError = NotFoundError;
625
+ exports.RateLimitError = RateLimitError;
626
+ exports.TimeoutError = TimeoutError;
1040
627
  exports.VERSION = VERSION;
1041
- exports.createEnhancedMemoryClient = createEnhancedMemoryClient;
628
+ exports.ValidationError = ValidationError;
1042
629
  exports.createMemoryClient = createMemoryClient;
1043
630
  exports.createMemorySchema = createMemorySchema;
1044
- exports.createSmartConfig = createSmartConfig;
1045
631
  exports.createTopicSchema = createTopicSchema;
1046
632
  exports.defaultConfigs = defaultConfigs;
1047
633
  exports.isBrowser = isBrowser;
1048
634
  exports.isNode = isNode;
1049
- exports.migrateToEnhanced = migrateToEnhanced;
1050
635
  exports.searchMemorySchema = searchMemorySchema;
1051
636
  exports.updateMemorySchema = updateMemorySchema;
1052
637
  //# sourceMappingURL=index.js.map