@cmdoss/memwal-sdk 0.6.2 → 0.8.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/ARCHITECTURE.md +547 -547
- package/BENCHMARKS.md +238 -238
- package/README.md +310 -181
- package/dist/ai-sdk/tools.d.ts +2 -2
- package/dist/ai-sdk/tools.js +2 -2
- package/dist/client/ClientMemoryManager.js +2 -2
- package/dist/client/ClientMemoryManager.js.map +1 -1
- package/dist/client/PersonalDataWallet.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.d.ts +29 -1
- package/dist/client/SimplePDWClient.d.ts.map +1 -1
- package/dist/client/SimplePDWClient.js +45 -13
- package/dist/client/SimplePDWClient.js.map +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.d.ts +1 -1
- package/dist/client/namespaces/EmbeddingsNamespace.js +1 -1
- package/dist/client/namespaces/MemoryNamespace.d.ts +31 -0
- package/dist/client/namespaces/MemoryNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/MemoryNamespace.js +272 -39
- package/dist/client/namespaces/MemoryNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/AINamespace.d.ts +2 -2
- package/dist/client/namespaces/consolidated/AINamespace.js +2 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts +12 -2
- package/dist/client/namespaces/consolidated/BlockchainNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js +62 -4
- package/dist/client/namespaces/consolidated/BlockchainNamespace.js.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts +67 -2
- package/dist/client/namespaces/consolidated/StorageNamespace.d.ts.map +1 -1
- package/dist/client/namespaces/consolidated/StorageNamespace.js +549 -16
- package/dist/client/namespaces/consolidated/StorageNamespace.js.map +1 -1
- package/dist/config/ConfigurationHelper.js +61 -61
- package/dist/config/defaults.js +2 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/graph/GraphService.js +21 -21
- package/dist/graph/GraphService.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.d.ts +9 -5
- package/dist/infrastructure/seal/EncryptionService.d.ts.map +1 -1
- package/dist/infrastructure/seal/EncryptionService.js +37 -15
- package/dist/infrastructure/seal/EncryptionService.js.map +1 -1
- package/dist/infrastructure/seal/SealService.d.ts +13 -5
- package/dist/infrastructure/seal/SealService.d.ts.map +1 -1
- package/dist/infrastructure/seal/SealService.js +36 -34
- package/dist/infrastructure/seal/SealService.js.map +1 -1
- package/dist/langchain/createPDWRAG.js +30 -30
- package/dist/retrieval/MemoryDecryptionPipeline.d.ts.map +1 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js +2 -1
- package/dist/retrieval/MemoryDecryptionPipeline.js.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.d.ts +31 -0
- package/dist/retrieval/MemoryRetrievalService.d.ts.map +1 -1
- package/dist/retrieval/MemoryRetrievalService.js +44 -4
- package/dist/retrieval/MemoryRetrievalService.js.map +1 -1
- package/dist/services/CapabilityService.d.ts.map +1 -1
- package/dist/services/CapabilityService.js +30 -14
- package/dist/services/CapabilityService.js.map +1 -1
- package/dist/services/CrossContextPermissionService.d.ts.map +1 -1
- package/dist/services/CrossContextPermissionService.js +9 -7
- package/dist/services/CrossContextPermissionService.js.map +1 -1
- package/dist/services/EmbeddingService.d.ts +28 -1
- package/dist/services/EmbeddingService.d.ts.map +1 -1
- package/dist/services/EmbeddingService.js +54 -0
- package/dist/services/EmbeddingService.js.map +1 -1
- package/dist/services/EncryptionService.d.ts.map +1 -1
- package/dist/services/EncryptionService.js +6 -5
- package/dist/services/EncryptionService.js.map +1 -1
- package/dist/services/GeminiAIService.js +309 -309
- package/dist/services/IndexManager.d.ts +5 -1
- package/dist/services/IndexManager.d.ts.map +1 -1
- package/dist/services/IndexManager.js +17 -40
- package/dist/services/IndexManager.js.map +1 -1
- package/dist/services/QueryService.js +1 -1
- package/dist/services/QueryService.js.map +1 -1
- package/dist/services/StorageService.d.ts +11 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/dist/services/StorageService.js +73 -10
- package/dist/services/StorageService.js.map +1 -1
- package/dist/services/TransactionService.d.ts +20 -0
- package/dist/services/TransactionService.d.ts.map +1 -1
- package/dist/services/TransactionService.js +43 -0
- package/dist/services/TransactionService.js.map +1 -1
- package/dist/services/ViewService.js +2 -2
- package/dist/services/ViewService.js.map +1 -1
- package/dist/services/storage/QuiltBatchManager.d.ts +101 -1
- package/dist/services/storage/QuiltBatchManager.d.ts.map +1 -1
- package/dist/services/storage/QuiltBatchManager.js +410 -20
- package/dist/services/storage/QuiltBatchManager.js.map +1 -1
- package/dist/services/storage/index.d.ts +1 -1
- package/dist/services/storage/index.d.ts.map +1 -1
- package/dist/services/storage/index.js.map +1 -1
- package/dist/utils/LRUCache.d.ts +106 -0
- package/dist/utils/LRUCache.d.ts.map +1 -0
- package/dist/utils/LRUCache.js +281 -0
- package/dist/utils/LRUCache.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/memoryIndexOnChain.d.ts +212 -0
- package/dist/utils/memoryIndexOnChain.d.ts.map +1 -0
- package/dist/utils/memoryIndexOnChain.js +312 -0
- package/dist/utils/memoryIndexOnChain.js.map +1 -0
- package/dist/utils/rebuildIndexNode.d.ts +29 -0
- package/dist/utils/rebuildIndexNode.d.ts.map +1 -1
- package/dist/utils/rebuildIndexNode.js +366 -98
- package/dist/utils/rebuildIndexNode.js.map +1 -1
- package/dist/vector/HnswWasmService.d.ts +20 -5
- package/dist/vector/HnswWasmService.d.ts.map +1 -1
- package/dist/vector/HnswWasmService.js +73 -40
- package/dist/vector/HnswWasmService.js.map +1 -1
- package/dist/vector/IHnswService.d.ts +10 -1
- package/dist/vector/IHnswService.d.ts.map +1 -1
- package/dist/vector/IHnswService.js.map +1 -1
- package/dist/vector/NodeHnswService.d.ts +16 -0
- package/dist/vector/NodeHnswService.d.ts.map +1 -1
- package/dist/vector/NodeHnswService.js +84 -5
- package/dist/vector/NodeHnswService.js.map +1 -1
- package/dist/vector/createHnswService.d.ts +1 -1
- package/dist/vector/createHnswService.js +1 -1
- package/dist/vector/index.d.ts +1 -1
- package/dist/vector/index.js +1 -1
- package/package.json +157 -157
- package/src/access/PermissionService.ts +635 -635
- package/src/aggregation/AggregationService.ts +389 -389
- package/src/ai-sdk/PDWVectorStore.ts +715 -715
- package/src/ai-sdk/index.ts +65 -65
- package/src/ai-sdk/tools.ts +460 -460
- package/src/ai-sdk/types.ts +404 -404
- package/src/batch/BatchManager.ts +597 -597
- package/src/batch/BatchingService.ts +429 -429
- package/src/batch/MemoryProcessingCache.ts +492 -492
- package/src/batch/index.ts +30 -30
- package/src/browser.ts +200 -200
- package/src/client/ClientMemoryManager.ts +987 -987
- package/src/client/PersonalDataWallet.ts +345 -345
- package/src/client/SimplePDWClient.ts +1289 -1222
- package/src/client/factory.ts +154 -154
- package/src/client/namespaces/AnalyticsNamespace.ts +377 -377
- package/src/client/namespaces/BatchNamespace.ts +356 -356
- package/src/client/namespaces/CacheNamespace.ts +123 -123
- package/src/client/namespaces/CapabilityNamespace.ts +217 -217
- package/src/client/namespaces/ClassifyNamespace.ts +169 -169
- package/src/client/namespaces/ContextNamespace.ts +297 -297
- package/src/client/namespaces/EmbeddingsNamespace.ts +99 -99
- package/src/client/namespaces/EncryptionNamespace.ts +221 -221
- package/src/client/namespaces/GraphNamespace.ts +468 -468
- package/src/client/namespaces/IndexNamespace.ts +361 -361
- package/src/client/namespaces/MemoryNamespace.ts +1422 -1135
- package/src/client/namespaces/PermissionsNamespace.ts +254 -254
- package/src/client/namespaces/PipelineNamespace.ts +220 -220
- package/src/client/namespaces/SearchNamespace.ts +1049 -1049
- package/src/client/namespaces/StorageNamespace.ts +458 -458
- package/src/client/namespaces/TxNamespace.ts +260 -260
- package/src/client/namespaces/WalletNamespace.ts +243 -243
- package/src/client/namespaces/consolidated/AINamespace.ts +449 -449
- package/src/client/namespaces/consolidated/BlockchainNamespace.ts +607 -546
- package/src/client/namespaces/consolidated/SecurityNamespace.ts +648 -648
- package/src/client/namespaces/consolidated/StorageNamespace.ts +1141 -497
- package/src/client/namespaces/consolidated/index.ts +39 -39
- package/src/client/signers/KeypairSigner.ts +108 -108
- package/src/client/signers/UnifiedSigner.ts +110 -110
- package/src/client/signers/WalletAdapterSigner.ts +159 -159
- package/src/client/signers/index.ts +26 -26
- package/src/config/ConfigurationHelper.ts +412 -412
- package/src/config/defaults.ts +51 -51
- package/src/config/index.ts +8 -8
- package/src/config/validation.ts +70 -70
- package/src/core/index.ts +14 -14
- package/src/core/interfaces/IService.ts +307 -307
- package/src/core/interfaces/index.ts +8 -8
- package/src/core/types/capability.ts +297 -297
- package/src/core/types/index.ts +870 -870
- package/src/core/types/wallet.ts +270 -270
- package/src/core/types.ts +9 -9
- package/src/core/wallet.ts +222 -222
- package/src/embedding/index.ts +19 -19
- package/src/embedding/types.ts +357 -357
- package/src/errors/index.ts +602 -602
- package/src/errors/recovery.ts +461 -461
- package/src/errors/validation.ts +567 -567
- package/src/generated/pdw/capability.ts +319 -319
- package/src/graph/GraphService.ts +887 -887
- package/src/graph/KnowledgeGraphManager.ts +728 -728
- package/src/graph/index.ts +25 -25
- package/src/index.ts +498 -474
- package/src/infrastructure/index.ts +22 -22
- package/src/infrastructure/seal/EncryptionService.ts +628 -603
- package/src/infrastructure/seal/SealService.ts +613 -615
- package/src/infrastructure/seal/index.ts +9 -9
- package/src/infrastructure/sui/BlockchainManager.ts +627 -627
- package/src/infrastructure/sui/SuiService.ts +888 -888
- package/src/infrastructure/sui/index.ts +9 -9
- package/src/infrastructure/walrus/StorageManager.ts +604 -604
- package/src/infrastructure/walrus/WalrusStorageService.ts +612 -612
- package/src/infrastructure/walrus/index.ts +9 -9
- package/src/langchain/PDWEmbeddings.ts +145 -145
- package/src/langchain/PDWVectorStore.ts +456 -456
- package/src/langchain/createPDWRAG.ts +303 -303
- package/src/langchain/index.ts +47 -47
- package/src/permissions/ConsentRepository.browser.ts +249 -249
- package/src/permissions/ConsentRepository.ts +364 -364
- package/src/pipeline/MemoryPipeline.ts +862 -862
- package/src/pipeline/PipelineManager.ts +683 -683
- package/src/pipeline/index.ts +26 -26
- package/src/retrieval/AdvancedSearchService.ts +629 -629
- package/src/retrieval/MemoryAnalyticsService.ts +711 -711
- package/src/retrieval/MemoryDecryptionPipeline.ts +825 -824
- package/src/retrieval/MemoryRetrievalService.ts +904 -830
- package/src/retrieval/index.ts +42 -42
- package/src/services/BatchService.ts +352 -352
- package/src/services/CapabilityService.ts +464 -448
- package/src/services/ClassifierService.ts +465 -465
- package/src/services/CrossContextPermissionService.ts +486 -484
- package/src/services/EmbeddingService.ts +771 -706
- package/src/services/EncryptionService.ts +712 -711
- package/src/services/GeminiAIService.ts +753 -753
- package/src/services/IndexManager.ts +977 -1004
- package/src/services/MemoryIndexService.ts +1003 -1003
- package/src/services/MemoryService.ts +369 -369
- package/src/services/QueryService.ts +890 -890
- package/src/services/StorageService.ts +1182 -1111
- package/src/services/TransactionService.ts +838 -790
- package/src/services/VectorService.ts +462 -462
- package/src/services/ViewService.ts +484 -484
- package/src/services/index.ts +25 -25
- package/src/services/storage/BlobAttributesManager.ts +333 -333
- package/src/services/storage/KnowledgeGraphManager.ts +425 -425
- package/src/services/storage/MemorySearchManager.ts +387 -387
- package/src/services/storage/QuiltBatchManager.ts +1130 -660
- package/src/services/storage/WalrusMetadataManager.ts +268 -268
- package/src/services/storage/WalrusStorageManager.ts +287 -287
- package/src/services/storage/index.ts +57 -52
- package/src/types/index.ts +13 -13
- package/src/utils/LRUCache.ts +378 -0
- package/src/utils/index.ts +76 -68
- package/src/utils/memoryIndexOnChain.ts +507 -0
- package/src/utils/rebuildIndex.ts +290 -290
- package/src/utils/rebuildIndexNode.ts +771 -424
- package/src/vector/BrowserHnswIndexService.ts +758 -758
- package/src/vector/HnswWasmService.ts +731 -679
- package/src/vector/IHnswService.ts +233 -224
- package/src/vector/NodeHnswService.ts +833 -735
- package/src/vector/VectorManager.ts +478 -478
- package/src/vector/createHnswService.ts +135 -135
- package/src/vector/index.ts +56 -56
- package/src/wallet/ContextWalletService.ts +656 -656
- package/src/wallet/MainWalletService.ts +317 -317
|
@@ -1,485 +1,485 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ViewService - Read-only blockchain query methods
|
|
3
|
-
*
|
|
4
|
-
* Provides methods for querying blockchain state without creating transactions.
|
|
5
|
-
* Follows MystenLabs patterns for view/query operations.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { SuiClient } from '@mysten/sui/client';
|
|
9
|
-
import type { PDWConfig, ClientWithCoreApi } from '../types';
|
|
10
|
-
|
|
11
|
-
// View query result types
|
|
12
|
-
export interface MemoryRecord {
|
|
13
|
-
id: string;
|
|
14
|
-
owner: string;
|
|
15
|
-
category: string;
|
|
16
|
-
vectorId: number;
|
|
17
|
-
blobId: string;
|
|
18
|
-
contentType: string;
|
|
19
|
-
contentSize: number;
|
|
20
|
-
contentHash: string;
|
|
21
|
-
topic: string;
|
|
22
|
-
importance: number;
|
|
23
|
-
embeddingBlobId: string;
|
|
24
|
-
createdAt: number;
|
|
25
|
-
updatedAt: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface MemoryIndex {
|
|
29
|
-
id: string;
|
|
30
|
-
owner: string;
|
|
31
|
-
version: number;
|
|
32
|
-
indexBlobId: string;
|
|
33
|
-
graphBlobId: string;
|
|
34
|
-
memoryCount: number;
|
|
35
|
-
lastUpdated: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface MemoryStats {
|
|
39
|
-
totalMemories: number;
|
|
40
|
-
categoryCounts: Record<string, number>;
|
|
41
|
-
totalSize: number;
|
|
42
|
-
averageImportance: number;
|
|
43
|
-
lastActivityTime: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface AccessPermission {
|
|
47
|
-
id: string;
|
|
48
|
-
grantor: string;
|
|
49
|
-
grantee: string;
|
|
50
|
-
contentId: string;
|
|
51
|
-
permissionType: string;
|
|
52
|
-
expiresAt?: number;
|
|
53
|
-
createdAt: number;
|
|
54
|
-
isActive: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface ContentRegistry {
|
|
58
|
-
id: string;
|
|
59
|
-
owner: string;
|
|
60
|
-
contentHash: string;
|
|
61
|
-
encryptionInfo: string;
|
|
62
|
-
accessCount: number;
|
|
63
|
-
createdAt: number;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export class ViewService {
|
|
67
|
-
private static readonly MAX_QUERY_LIMIT = 50;
|
|
68
|
-
private static readonly MAX_RETRIES = 3;
|
|
69
|
-
private static readonly RETRY_DELAY_MS = 1000;
|
|
70
|
-
private client: SuiClient;
|
|
71
|
-
private config: PDWConfig;
|
|
72
|
-
|
|
73
|
-
constructor(client: ClientWithCoreApi, config: PDWConfig) {
|
|
74
|
-
// Extract SuiClient from the core API wrapper
|
|
75
|
-
this.client = (client as any).client || client;
|
|
76
|
-
this.config = config;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Retry wrapper with exponential backoff for network operations
|
|
81
|
-
*/
|
|
82
|
-
private async withRetry<T>(
|
|
83
|
-
operation: () => Promise<T>,
|
|
84
|
-
operationName: string
|
|
85
|
-
): Promise<T> {
|
|
86
|
-
let lastError: Error | null = null;
|
|
87
|
-
|
|
88
|
-
for (let attempt = 1; attempt <= ViewService.MAX_RETRIES; attempt++) {
|
|
89
|
-
try {
|
|
90
|
-
return await operation();
|
|
91
|
-
} catch (error: any) {
|
|
92
|
-
lastError = error;
|
|
93
|
-
const isNetworkError = error.message?.includes('fetch failed') ||
|
|
94
|
-
error.message?.includes('ECONNREFUSED') ||
|
|
95
|
-
error.message?.includes('ETIMEDOUT') ||
|
|
96
|
-
error.code === 'ENOTFOUND';
|
|
97
|
-
|
|
98
|
-
if (!isNetworkError || attempt === ViewService.MAX_RETRIES) {
|
|
99
|
-
throw error;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const delay = ViewService.RETRY_DELAY_MS * Math.pow(2, attempt - 1);
|
|
103
|
-
console.warn(`[ViewService] ${operationName} failed (attempt ${attempt}/${ViewService.MAX_RETRIES}), retrying in ${delay}ms...`);
|
|
104
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
throw lastError;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ==================== MEMORY QUERIES ====================
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Get all memories owned by a user
|
|
115
|
-
*/
|
|
116
|
-
async getUserMemories(userAddress: string, options?: {
|
|
117
|
-
limit?: number;
|
|
118
|
-
cursor?: string;
|
|
119
|
-
category?: string;
|
|
120
|
-
}): Promise<{
|
|
121
|
-
data: MemoryRecord[];
|
|
122
|
-
nextCursor?: string;
|
|
123
|
-
hasMore: boolean;
|
|
124
|
-
}> {
|
|
125
|
-
try {
|
|
126
|
-
const response = await this.withRetry(
|
|
127
|
-
() => this.client.getOwnedObjects({
|
|
128
|
-
owner: userAddress,
|
|
129
|
-
filter: {
|
|
130
|
-
StructType: `${this.config.packageId}::memory::Memory`,
|
|
131
|
-
},
|
|
132
|
-
options: {
|
|
133
|
-
showContent: true,
|
|
134
|
-
showType: true,
|
|
135
|
-
},
|
|
136
|
-
limit: options?.limit || 50,
|
|
137
|
-
cursor: options?.cursor,
|
|
138
|
-
}),
|
|
139
|
-
'getUserMemories'
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
const memories: MemoryRecord[] = [];
|
|
143
|
-
|
|
144
|
-
for (const obj of response.data) {
|
|
145
|
-
if (obj.data?.content && 'fields' in obj.data.content) {
|
|
146
|
-
const fields = obj.data.content.fields as any;
|
|
147
|
-
const metadata = fields.metadata?.fields || fields.metadata || {};
|
|
148
|
-
|
|
149
|
-
// Filter by category if specified
|
|
150
|
-
if (options?.category && fields.category !== options.category) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
memories.push({
|
|
155
|
-
id: obj.data.objectId,
|
|
156
|
-
owner: fields.owner,
|
|
157
|
-
category: fields.category,
|
|
158
|
-
vectorId: parseInt(fields.vector_id),
|
|
159
|
-
blobId: fields.blob_id,
|
|
160
|
-
contentType: metadata.content_type || '',
|
|
161
|
-
contentSize: parseInt(metadata.content_size || '0'),
|
|
162
|
-
contentHash: metadata.content_hash || '',
|
|
163
|
-
topic: metadata.topic || '',
|
|
164
|
-
importance: parseInt(metadata.importance || '5'),
|
|
165
|
-
embeddingBlobId: metadata.embedding_blob_id || '',
|
|
166
|
-
createdAt: parseInt(metadata.created_timestamp || '0'),
|
|
167
|
-
updatedAt: parseInt(metadata.updated_timestamp || '0'),
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return {
|
|
173
|
-
data: memories,
|
|
174
|
-
nextCursor: response.nextCursor || undefined,
|
|
175
|
-
hasMore: response.hasNextPage,
|
|
176
|
-
};
|
|
177
|
-
} catch (error) {
|
|
178
|
-
throw new Error(`Failed to get user memories: ${error}`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Get a specific memory by ID
|
|
184
|
-
*/
|
|
185
|
-
async getMemory(memoryId: string): Promise<MemoryRecord | null> {
|
|
186
|
-
try {
|
|
187
|
-
const response = await this.withRetry(
|
|
188
|
-
() => this.client.getObject({
|
|
189
|
-
id: memoryId,
|
|
190
|
-
options: {
|
|
191
|
-
showContent: true,
|
|
192
|
-
showType: true,
|
|
193
|
-
},
|
|
194
|
-
}),
|
|
195
|
-
'getMemory'
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
if (!response.data?.content || !('fields' in response.data.content)) {
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const fields = response.data.content.fields as any;
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
id: response.data.objectId,
|
|
206
|
-
owner: fields.owner,
|
|
207
|
-
category: fields.category,
|
|
208
|
-
vectorId: parseInt(fields.vector_id),
|
|
209
|
-
blobId: fields.blob_id,
|
|
210
|
-
contentType: fields.content_type,
|
|
211
|
-
contentSize: parseInt(fields.content_size),
|
|
212
|
-
contentHash: fields.content_hash,
|
|
213
|
-
topic: fields.topic,
|
|
214
|
-
importance: parseInt(fields.importance),
|
|
215
|
-
embeddingBlobId: fields.embedding_blob_id,
|
|
216
|
-
createdAt: parseInt(fields.created_at || '0'),
|
|
217
|
-
updatedAt: parseInt(fields.updated_at || '0'),
|
|
218
|
-
};
|
|
219
|
-
} catch (error) {
|
|
220
|
-
throw new Error(`Failed to get memory: ${error}`);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Get memory index for a user
|
|
226
|
-
*/
|
|
227
|
-
async getMemoryIndex(userAddress: string): Promise<MemoryIndex | null> {
|
|
228
|
-
try {
|
|
229
|
-
const response = await this.withRetry(
|
|
230
|
-
() => this.client.getOwnedObjects({
|
|
231
|
-
owner: userAddress,
|
|
232
|
-
filter: {
|
|
233
|
-
StructType: `${this.config.packageId}::memory::MemoryIndex`,
|
|
234
|
-
},
|
|
235
|
-
options: {
|
|
236
|
-
showContent: true,
|
|
237
|
-
showType: true,
|
|
238
|
-
},
|
|
239
|
-
limit: 1,
|
|
240
|
-
}),
|
|
241
|
-
'getMemoryIndex'
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
if (response.data.length === 0) {
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const obj = response.data[0];
|
|
249
|
-
if (!obj.data?.content || !('fields' in obj.data.content)) {
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const fields = obj.data.content.fields as any;
|
|
254
|
-
|
|
255
|
-
return {
|
|
256
|
-
id: obj.data.objectId,
|
|
257
|
-
owner: fields.owner,
|
|
258
|
-
version: parseInt(fields.version),
|
|
259
|
-
indexBlobId: fields.index_blob_id,
|
|
260
|
-
graphBlobId: fields.graph_blob_id,
|
|
261
|
-
memoryCount: parseInt(fields.memory_count || '0'),
|
|
262
|
-
lastUpdated: parseInt(fields.last_updated || '0'),
|
|
263
|
-
};
|
|
264
|
-
} catch (error) {
|
|
265
|
-
throw new Error(`Failed to get memory index: ${error}`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Get memory statistics for a user
|
|
271
|
-
*/
|
|
272
|
-
async getMemoryStats(userAddress: string): Promise<MemoryStats> {
|
|
273
|
-
try {
|
|
274
|
-
const memories = await this.getUserMemories(userAddress, { limit: ViewService.MAX_QUERY_LIMIT });
|
|
275
|
-
|
|
276
|
-
const categoryCounts: Record<string, number> = {};
|
|
277
|
-
let totalSize = 0;
|
|
278
|
-
let totalImportance = 0;
|
|
279
|
-
let lastActivityTime = 0;
|
|
280
|
-
|
|
281
|
-
for (const memory of memories.data) {
|
|
282
|
-
// Count categories
|
|
283
|
-
categoryCounts[memory.category] = (categoryCounts[memory.category] || 0) + 1;
|
|
284
|
-
|
|
285
|
-
// Sum sizes
|
|
286
|
-
totalSize += memory.contentSize;
|
|
287
|
-
|
|
288
|
-
// Sum importance for average
|
|
289
|
-
totalImportance += memory.importance;
|
|
290
|
-
|
|
291
|
-
// Track latest activity
|
|
292
|
-
if (memory.updatedAt > lastActivityTime) {
|
|
293
|
-
lastActivityTime = memory.updatedAt;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return {
|
|
298
|
-
totalMemories: memories.data.length,
|
|
299
|
-
categoryCounts,
|
|
300
|
-
totalSize,
|
|
301
|
-
averageImportance: memories.data.length > 0 ? totalImportance / memories.data.length : 0,
|
|
302
|
-
lastActivityTime,
|
|
303
|
-
};
|
|
304
|
-
} catch (error) {
|
|
305
|
-
throw new Error(`Failed to get memory stats: ${error}`);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// ==================== ACCESS CONTROL QUERIES ====================
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Get access permissions for a user
|
|
313
|
-
*/
|
|
314
|
-
async getAccessPermissions(userAddress: string, options?: {
|
|
315
|
-
asGrantor?: boolean;
|
|
316
|
-
asGrantee?: boolean;
|
|
317
|
-
activeOnly?: boolean;
|
|
318
|
-
}): Promise<AccessPermission[]> {
|
|
319
|
-
try {
|
|
320
|
-
const permissions: AccessPermission[] = [];
|
|
321
|
-
|
|
322
|
-
// Query as grantor (permissions granted by user)
|
|
323
|
-
if (options?.asGrantor !== false) {
|
|
324
|
-
const grantorResponse = await this.client.getOwnedObjects({
|
|
325
|
-
owner: userAddress,
|
|
326
|
-
filter: {
|
|
327
|
-
StructType: `${this.config.packageId}::
|
|
328
|
-
},
|
|
329
|
-
options: {
|
|
330
|
-
showContent: true,
|
|
331
|
-
showType: true,
|
|
332
|
-
},
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
for (const obj of grantorResponse.data) {
|
|
336
|
-
if (obj.data?.content && 'fields' in obj.data.content) {
|
|
337
|
-
const fields = obj.data.content.fields as any;
|
|
338
|
-
const expiresAt = fields.expires_at ? parseInt(fields.expires_at) : undefined;
|
|
339
|
-
const isActive = !expiresAt || expiresAt > Date.now();
|
|
340
|
-
|
|
341
|
-
if (!options?.activeOnly || isActive) {
|
|
342
|
-
permissions.push({
|
|
343
|
-
id: obj.data.objectId,
|
|
344
|
-
grantor: fields.grantor,
|
|
345
|
-
grantee: fields.grantee,
|
|
346
|
-
contentId: fields.content_id,
|
|
347
|
-
permissionType: fields.permission_type,
|
|
348
|
-
expiresAt,
|
|
349
|
-
createdAt: parseInt(fields.created_at),
|
|
350
|
-
isActive,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Query as grantee (permissions granted to user) - would need events or indexing
|
|
358
|
-
if (options?.asGrantee !== false) {
|
|
359
|
-
// Note: In a real implementation, this would require event querying
|
|
360
|
-
// or a secondary index to find permissions where user is the grantee
|
|
361
|
-
// For now, we'll note this limitation
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
return permissions;
|
|
365
|
-
} catch (error) {
|
|
366
|
-
throw new Error(`Failed to get access permissions: ${error}`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Get content registry entries
|
|
372
|
-
*/
|
|
373
|
-
async getContentRegistry(options?: {
|
|
374
|
-
owner?: string;
|
|
375
|
-
limit?: number;
|
|
376
|
-
cursor?: string;
|
|
377
|
-
}): Promise<{
|
|
378
|
-
data: ContentRegistry[];
|
|
379
|
-
nextCursor?: string;
|
|
380
|
-
hasMore: boolean;
|
|
381
|
-
}> {
|
|
382
|
-
try {
|
|
383
|
-
const queryOptions: any = {
|
|
384
|
-
filter: {
|
|
385
|
-
StructType: `${this.config.packageId}::
|
|
386
|
-
},
|
|
387
|
-
options: {
|
|
388
|
-
showContent: true,
|
|
389
|
-
showType: true,
|
|
390
|
-
},
|
|
391
|
-
limit: options?.limit || 50,
|
|
392
|
-
cursor: options?.cursor,
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
// If owner specified, query owned objects
|
|
396
|
-
if (options?.owner) {
|
|
397
|
-
queryOptions.owner = options.owner;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Query objects - for non-owned queries, we'll use a different approach
|
|
401
|
-
let response;
|
|
402
|
-
if (options?.owner) {
|
|
403
|
-
response = await this.client.getOwnedObjects(queryOptions);
|
|
404
|
-
} else {
|
|
405
|
-
// For general queries without owner, we'll need to use events or other indexing
|
|
406
|
-
// For now, return empty result as this requires additional infrastructure
|
|
407
|
-
response = { data: [], nextCursor: null, hasNextPage: false };
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const registries: ContentRegistry[] = [];
|
|
411
|
-
|
|
412
|
-
for (const obj of response.data) {
|
|
413
|
-
if (obj.data?.content && 'fields' in obj.data.content) {
|
|
414
|
-
const fields = obj.data.content.fields as any;
|
|
415
|
-
|
|
416
|
-
registries.push({
|
|
417
|
-
id: obj.data.objectId,
|
|
418
|
-
owner: fields.owner,
|
|
419
|
-
contentHash: fields.content_hash,
|
|
420
|
-
encryptionInfo: fields.encryption_info,
|
|
421
|
-
accessCount: parseInt(fields.access_count || '0'),
|
|
422
|
-
createdAt: parseInt(fields.created_at),
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
return {
|
|
428
|
-
data: registries,
|
|
429
|
-
nextCursor: response.nextCursor || undefined,
|
|
430
|
-
hasMore: response.hasNextPage,
|
|
431
|
-
};
|
|
432
|
-
} catch (error) {
|
|
433
|
-
throw new Error(`Failed to get content registry: ${error}`);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// ==================== UTILITY QUERIES ====================
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Check if an object exists and is accessible
|
|
441
|
-
*/
|
|
442
|
-
async objectExists(objectId: string): Promise<boolean> {
|
|
443
|
-
try {
|
|
444
|
-
const response = await this.client.getObject({
|
|
445
|
-
id: objectId,
|
|
446
|
-
options: { showType: true },
|
|
447
|
-
});
|
|
448
|
-
return response.data !== null;
|
|
449
|
-
} catch (error) {
|
|
450
|
-
return false;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Get object type information
|
|
456
|
-
*/
|
|
457
|
-
async getObjectType(objectId: string): Promise<string | null> {
|
|
458
|
-
try {
|
|
459
|
-
const response = await this.client.getObject({
|
|
460
|
-
id: objectId,
|
|
461
|
-
options: { showType: true },
|
|
462
|
-
});
|
|
463
|
-
return response.data?.type || null;
|
|
464
|
-
} catch (error) {
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Search memories by content hash
|
|
471
|
-
* Note: This requires event-based indexing or a search service in production
|
|
472
|
-
*/
|
|
473
|
-
async findMemoryByContentHash(contentHash: string): Promise<MemoryRecord[]> {
|
|
474
|
-
try {
|
|
475
|
-
// Note: This would typically require an event-based search or indexing service
|
|
476
|
-
// For now, we'll return empty as this requires additional infrastructure
|
|
477
|
-
// In a real implementation, this would use event queries or an indexing service
|
|
478
|
-
|
|
479
|
-
console.debug('findMemoryByContentHash: This method requires event indexing infrastructure');
|
|
480
|
-
return [];
|
|
481
|
-
} catch (error) {
|
|
482
|
-
throw new Error(`Failed to find memory by content hash: ${error}`);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* ViewService - Read-only blockchain query methods
|
|
3
|
+
*
|
|
4
|
+
* Provides methods for querying blockchain state without creating transactions.
|
|
5
|
+
* Follows MystenLabs patterns for view/query operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { SuiClient } from '@mysten/sui/client';
|
|
9
|
+
import type { PDWConfig, ClientWithCoreApi } from '../types';
|
|
10
|
+
|
|
11
|
+
// View query result types
|
|
12
|
+
export interface MemoryRecord {
|
|
13
|
+
id: string;
|
|
14
|
+
owner: string;
|
|
15
|
+
category: string;
|
|
16
|
+
vectorId: number;
|
|
17
|
+
blobId: string;
|
|
18
|
+
contentType: string;
|
|
19
|
+
contentSize: number;
|
|
20
|
+
contentHash: string;
|
|
21
|
+
topic: string;
|
|
22
|
+
importance: number;
|
|
23
|
+
embeddingBlobId: string;
|
|
24
|
+
createdAt: number;
|
|
25
|
+
updatedAt: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface MemoryIndex {
|
|
29
|
+
id: string;
|
|
30
|
+
owner: string;
|
|
31
|
+
version: number;
|
|
32
|
+
indexBlobId: string;
|
|
33
|
+
graphBlobId: string;
|
|
34
|
+
memoryCount: number;
|
|
35
|
+
lastUpdated: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface MemoryStats {
|
|
39
|
+
totalMemories: number;
|
|
40
|
+
categoryCounts: Record<string, number>;
|
|
41
|
+
totalSize: number;
|
|
42
|
+
averageImportance: number;
|
|
43
|
+
lastActivityTime: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface AccessPermission {
|
|
47
|
+
id: string;
|
|
48
|
+
grantor: string;
|
|
49
|
+
grantee: string;
|
|
50
|
+
contentId: string;
|
|
51
|
+
permissionType: string;
|
|
52
|
+
expiresAt?: number;
|
|
53
|
+
createdAt: number;
|
|
54
|
+
isActive: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ContentRegistry {
|
|
58
|
+
id: string;
|
|
59
|
+
owner: string;
|
|
60
|
+
contentHash: string;
|
|
61
|
+
encryptionInfo: string;
|
|
62
|
+
accessCount: number;
|
|
63
|
+
createdAt: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class ViewService {
|
|
67
|
+
private static readonly MAX_QUERY_LIMIT = 50;
|
|
68
|
+
private static readonly MAX_RETRIES = 3;
|
|
69
|
+
private static readonly RETRY_DELAY_MS = 1000;
|
|
70
|
+
private client: SuiClient;
|
|
71
|
+
private config: PDWConfig;
|
|
72
|
+
|
|
73
|
+
constructor(client: ClientWithCoreApi, config: PDWConfig) {
|
|
74
|
+
// Extract SuiClient from the core API wrapper
|
|
75
|
+
this.client = (client as any).client || client;
|
|
76
|
+
this.config = config;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Retry wrapper with exponential backoff for network operations
|
|
81
|
+
*/
|
|
82
|
+
private async withRetry<T>(
|
|
83
|
+
operation: () => Promise<T>,
|
|
84
|
+
operationName: string
|
|
85
|
+
): Promise<T> {
|
|
86
|
+
let lastError: Error | null = null;
|
|
87
|
+
|
|
88
|
+
for (let attempt = 1; attempt <= ViewService.MAX_RETRIES; attempt++) {
|
|
89
|
+
try {
|
|
90
|
+
return await operation();
|
|
91
|
+
} catch (error: any) {
|
|
92
|
+
lastError = error;
|
|
93
|
+
const isNetworkError = error.message?.includes('fetch failed') ||
|
|
94
|
+
error.message?.includes('ECONNREFUSED') ||
|
|
95
|
+
error.message?.includes('ETIMEDOUT') ||
|
|
96
|
+
error.code === 'ENOTFOUND';
|
|
97
|
+
|
|
98
|
+
if (!isNetworkError || attempt === ViewService.MAX_RETRIES) {
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const delay = ViewService.RETRY_DELAY_MS * Math.pow(2, attempt - 1);
|
|
103
|
+
console.warn(`[ViewService] ${operationName} failed (attempt ${attempt}/${ViewService.MAX_RETRIES}), retrying in ${delay}ms...`);
|
|
104
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
throw lastError;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ==================== MEMORY QUERIES ====================
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get all memories owned by a user
|
|
115
|
+
*/
|
|
116
|
+
async getUserMemories(userAddress: string, options?: {
|
|
117
|
+
limit?: number;
|
|
118
|
+
cursor?: string;
|
|
119
|
+
category?: string;
|
|
120
|
+
}): Promise<{
|
|
121
|
+
data: MemoryRecord[];
|
|
122
|
+
nextCursor?: string;
|
|
123
|
+
hasMore: boolean;
|
|
124
|
+
}> {
|
|
125
|
+
try {
|
|
126
|
+
const response = await this.withRetry(
|
|
127
|
+
() => this.client.getOwnedObjects({
|
|
128
|
+
owner: userAddress,
|
|
129
|
+
filter: {
|
|
130
|
+
StructType: `${this.config.packageId}::memory::Memory`,
|
|
131
|
+
},
|
|
132
|
+
options: {
|
|
133
|
+
showContent: true,
|
|
134
|
+
showType: true,
|
|
135
|
+
},
|
|
136
|
+
limit: options?.limit || 50,
|
|
137
|
+
cursor: options?.cursor,
|
|
138
|
+
}),
|
|
139
|
+
'getUserMemories'
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const memories: MemoryRecord[] = [];
|
|
143
|
+
|
|
144
|
+
for (const obj of response.data) {
|
|
145
|
+
if (obj.data?.content && 'fields' in obj.data.content) {
|
|
146
|
+
const fields = obj.data.content.fields as any;
|
|
147
|
+
const metadata = fields.metadata?.fields || fields.metadata || {};
|
|
148
|
+
|
|
149
|
+
// Filter by category if specified
|
|
150
|
+
if (options?.category && fields.category !== options.category) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
memories.push({
|
|
155
|
+
id: obj.data.objectId,
|
|
156
|
+
owner: fields.owner,
|
|
157
|
+
category: fields.category,
|
|
158
|
+
vectorId: parseInt(fields.vector_id),
|
|
159
|
+
blobId: fields.blob_id,
|
|
160
|
+
contentType: metadata.content_type || '',
|
|
161
|
+
contentSize: parseInt(metadata.content_size || '0'),
|
|
162
|
+
contentHash: metadata.content_hash || '',
|
|
163
|
+
topic: metadata.topic || '',
|
|
164
|
+
importance: parseInt(metadata.importance || '5'),
|
|
165
|
+
embeddingBlobId: metadata.embedding_blob_id || '',
|
|
166
|
+
createdAt: parseInt(metadata.created_timestamp || '0'),
|
|
167
|
+
updatedAt: parseInt(metadata.updated_timestamp || '0'),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
data: memories,
|
|
174
|
+
nextCursor: response.nextCursor || undefined,
|
|
175
|
+
hasMore: response.hasNextPage,
|
|
176
|
+
};
|
|
177
|
+
} catch (error) {
|
|
178
|
+
throw new Error(`Failed to get user memories: ${error}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get a specific memory by ID
|
|
184
|
+
*/
|
|
185
|
+
async getMemory(memoryId: string): Promise<MemoryRecord | null> {
|
|
186
|
+
try {
|
|
187
|
+
const response = await this.withRetry(
|
|
188
|
+
() => this.client.getObject({
|
|
189
|
+
id: memoryId,
|
|
190
|
+
options: {
|
|
191
|
+
showContent: true,
|
|
192
|
+
showType: true,
|
|
193
|
+
},
|
|
194
|
+
}),
|
|
195
|
+
'getMemory'
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
if (!response.data?.content || !('fields' in response.data.content)) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const fields = response.data.content.fields as any;
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
id: response.data.objectId,
|
|
206
|
+
owner: fields.owner,
|
|
207
|
+
category: fields.category,
|
|
208
|
+
vectorId: parseInt(fields.vector_id),
|
|
209
|
+
blobId: fields.blob_id,
|
|
210
|
+
contentType: fields.content_type,
|
|
211
|
+
contentSize: parseInt(fields.content_size),
|
|
212
|
+
contentHash: fields.content_hash,
|
|
213
|
+
topic: fields.topic,
|
|
214
|
+
importance: parseInt(fields.importance),
|
|
215
|
+
embeddingBlobId: fields.embedding_blob_id,
|
|
216
|
+
createdAt: parseInt(fields.created_at || '0'),
|
|
217
|
+
updatedAt: parseInt(fields.updated_at || '0'),
|
|
218
|
+
};
|
|
219
|
+
} catch (error) {
|
|
220
|
+
throw new Error(`Failed to get memory: ${error}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get memory index for a user
|
|
226
|
+
*/
|
|
227
|
+
async getMemoryIndex(userAddress: string): Promise<MemoryIndex | null> {
|
|
228
|
+
try {
|
|
229
|
+
const response = await this.withRetry(
|
|
230
|
+
() => this.client.getOwnedObjects({
|
|
231
|
+
owner: userAddress,
|
|
232
|
+
filter: {
|
|
233
|
+
StructType: `${this.config.packageId}::memory::MemoryIndex`,
|
|
234
|
+
},
|
|
235
|
+
options: {
|
|
236
|
+
showContent: true,
|
|
237
|
+
showType: true,
|
|
238
|
+
},
|
|
239
|
+
limit: 1,
|
|
240
|
+
}),
|
|
241
|
+
'getMemoryIndex'
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
if (response.data.length === 0) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const obj = response.data[0];
|
|
249
|
+
if (!obj.data?.content || !('fields' in obj.data.content)) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const fields = obj.data.content.fields as any;
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
id: obj.data.objectId,
|
|
257
|
+
owner: fields.owner,
|
|
258
|
+
version: parseInt(fields.version),
|
|
259
|
+
indexBlobId: fields.index_blob_id,
|
|
260
|
+
graphBlobId: fields.graph_blob_id,
|
|
261
|
+
memoryCount: parseInt(fields.memory_count || '0'),
|
|
262
|
+
lastUpdated: parseInt(fields.last_updated || '0'),
|
|
263
|
+
};
|
|
264
|
+
} catch (error) {
|
|
265
|
+
throw new Error(`Failed to get memory index: ${error}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Get memory statistics for a user
|
|
271
|
+
*/
|
|
272
|
+
async getMemoryStats(userAddress: string): Promise<MemoryStats> {
|
|
273
|
+
try {
|
|
274
|
+
const memories = await this.getUserMemories(userAddress, { limit: ViewService.MAX_QUERY_LIMIT });
|
|
275
|
+
|
|
276
|
+
const categoryCounts: Record<string, number> = {};
|
|
277
|
+
let totalSize = 0;
|
|
278
|
+
let totalImportance = 0;
|
|
279
|
+
let lastActivityTime = 0;
|
|
280
|
+
|
|
281
|
+
for (const memory of memories.data) {
|
|
282
|
+
// Count categories
|
|
283
|
+
categoryCounts[memory.category] = (categoryCounts[memory.category] || 0) + 1;
|
|
284
|
+
|
|
285
|
+
// Sum sizes
|
|
286
|
+
totalSize += memory.contentSize;
|
|
287
|
+
|
|
288
|
+
// Sum importance for average
|
|
289
|
+
totalImportance += memory.importance;
|
|
290
|
+
|
|
291
|
+
// Track latest activity
|
|
292
|
+
if (memory.updatedAt > lastActivityTime) {
|
|
293
|
+
lastActivityTime = memory.updatedAt;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
totalMemories: memories.data.length,
|
|
299
|
+
categoryCounts,
|
|
300
|
+
totalSize,
|
|
301
|
+
averageImportance: memories.data.length > 0 ? totalImportance / memories.data.length : 0,
|
|
302
|
+
lastActivityTime,
|
|
303
|
+
};
|
|
304
|
+
} catch (error) {
|
|
305
|
+
throw new Error(`Failed to get memory stats: ${error}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ==================== ACCESS CONTROL QUERIES ====================
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get access permissions for a user
|
|
313
|
+
*/
|
|
314
|
+
async getAccessPermissions(userAddress: string, options?: {
|
|
315
|
+
asGrantor?: boolean;
|
|
316
|
+
asGrantee?: boolean;
|
|
317
|
+
activeOnly?: boolean;
|
|
318
|
+
}): Promise<AccessPermission[]> {
|
|
319
|
+
try {
|
|
320
|
+
const permissions: AccessPermission[] = [];
|
|
321
|
+
|
|
322
|
+
// Query as grantor (permissions granted by user)
|
|
323
|
+
if (options?.asGrantor !== false) {
|
|
324
|
+
const grantorResponse = await this.client.getOwnedObjects({
|
|
325
|
+
owner: userAddress,
|
|
326
|
+
filter: {
|
|
327
|
+
StructType: `${this.config.packageId}::capability::AccessPermission`,
|
|
328
|
+
},
|
|
329
|
+
options: {
|
|
330
|
+
showContent: true,
|
|
331
|
+
showType: true,
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
for (const obj of grantorResponse.data) {
|
|
336
|
+
if (obj.data?.content && 'fields' in obj.data.content) {
|
|
337
|
+
const fields = obj.data.content.fields as any;
|
|
338
|
+
const expiresAt = fields.expires_at ? parseInt(fields.expires_at) : undefined;
|
|
339
|
+
const isActive = !expiresAt || expiresAt > Date.now();
|
|
340
|
+
|
|
341
|
+
if (!options?.activeOnly || isActive) {
|
|
342
|
+
permissions.push({
|
|
343
|
+
id: obj.data.objectId,
|
|
344
|
+
grantor: fields.grantor,
|
|
345
|
+
grantee: fields.grantee,
|
|
346
|
+
contentId: fields.content_id,
|
|
347
|
+
permissionType: fields.permission_type,
|
|
348
|
+
expiresAt,
|
|
349
|
+
createdAt: parseInt(fields.created_at),
|
|
350
|
+
isActive,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Query as grantee (permissions granted to user) - would need events or indexing
|
|
358
|
+
if (options?.asGrantee !== false) {
|
|
359
|
+
// Note: In a real implementation, this would require event querying
|
|
360
|
+
// or a secondary index to find permissions where user is the grantee
|
|
361
|
+
// For now, we'll note this limitation
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return permissions;
|
|
365
|
+
} catch (error) {
|
|
366
|
+
throw new Error(`Failed to get access permissions: ${error}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Get content registry entries
|
|
372
|
+
*/
|
|
373
|
+
async getContentRegistry(options?: {
|
|
374
|
+
owner?: string;
|
|
375
|
+
limit?: number;
|
|
376
|
+
cursor?: string;
|
|
377
|
+
}): Promise<{
|
|
378
|
+
data: ContentRegistry[];
|
|
379
|
+
nextCursor?: string;
|
|
380
|
+
hasMore: boolean;
|
|
381
|
+
}> {
|
|
382
|
+
try {
|
|
383
|
+
const queryOptions: any = {
|
|
384
|
+
filter: {
|
|
385
|
+
StructType: `${this.config.packageId}::capability::ContentRegistry`,
|
|
386
|
+
},
|
|
387
|
+
options: {
|
|
388
|
+
showContent: true,
|
|
389
|
+
showType: true,
|
|
390
|
+
},
|
|
391
|
+
limit: options?.limit || 50,
|
|
392
|
+
cursor: options?.cursor,
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// If owner specified, query owned objects
|
|
396
|
+
if (options?.owner) {
|
|
397
|
+
queryOptions.owner = options.owner;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Query objects - for non-owned queries, we'll use a different approach
|
|
401
|
+
let response;
|
|
402
|
+
if (options?.owner) {
|
|
403
|
+
response = await this.client.getOwnedObjects(queryOptions);
|
|
404
|
+
} else {
|
|
405
|
+
// For general queries without owner, we'll need to use events or other indexing
|
|
406
|
+
// For now, return empty result as this requires additional infrastructure
|
|
407
|
+
response = { data: [], nextCursor: null, hasNextPage: false };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const registries: ContentRegistry[] = [];
|
|
411
|
+
|
|
412
|
+
for (const obj of response.data) {
|
|
413
|
+
if (obj.data?.content && 'fields' in obj.data.content) {
|
|
414
|
+
const fields = obj.data.content.fields as any;
|
|
415
|
+
|
|
416
|
+
registries.push({
|
|
417
|
+
id: obj.data.objectId,
|
|
418
|
+
owner: fields.owner,
|
|
419
|
+
contentHash: fields.content_hash,
|
|
420
|
+
encryptionInfo: fields.encryption_info,
|
|
421
|
+
accessCount: parseInt(fields.access_count || '0'),
|
|
422
|
+
createdAt: parseInt(fields.created_at),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
data: registries,
|
|
429
|
+
nextCursor: response.nextCursor || undefined,
|
|
430
|
+
hasMore: response.hasNextPage,
|
|
431
|
+
};
|
|
432
|
+
} catch (error) {
|
|
433
|
+
throw new Error(`Failed to get content registry: ${error}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ==================== UTILITY QUERIES ====================
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Check if an object exists and is accessible
|
|
441
|
+
*/
|
|
442
|
+
async objectExists(objectId: string): Promise<boolean> {
|
|
443
|
+
try {
|
|
444
|
+
const response = await this.client.getObject({
|
|
445
|
+
id: objectId,
|
|
446
|
+
options: { showType: true },
|
|
447
|
+
});
|
|
448
|
+
return response.data !== null;
|
|
449
|
+
} catch (error) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Get object type information
|
|
456
|
+
*/
|
|
457
|
+
async getObjectType(objectId: string): Promise<string | null> {
|
|
458
|
+
try {
|
|
459
|
+
const response = await this.client.getObject({
|
|
460
|
+
id: objectId,
|
|
461
|
+
options: { showType: true },
|
|
462
|
+
});
|
|
463
|
+
return response.data?.type || null;
|
|
464
|
+
} catch (error) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Search memories by content hash
|
|
471
|
+
* Note: This requires event-based indexing or a search service in production
|
|
472
|
+
*/
|
|
473
|
+
async findMemoryByContentHash(contentHash: string): Promise<MemoryRecord[]> {
|
|
474
|
+
try {
|
|
475
|
+
// Note: This would typically require an event-based search or indexing service
|
|
476
|
+
// For now, we'll return empty as this requires additional infrastructure
|
|
477
|
+
// In a real implementation, this would use event queries or an indexing service
|
|
478
|
+
|
|
479
|
+
console.debug('findMemoryByContentHash: This method requires event indexing infrastructure');
|
|
480
|
+
return [];
|
|
481
|
+
} catch (error) {
|
|
482
|
+
throw new Error(`Failed to find memory by content hash: ${error}`);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
485
|
}
|