@onchaindb/sdk 0.4.4 → 1.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/.claude/settings.local.json +10 -2
- package/README.md +422 -355
- package/dist/batch.d.ts +1 -10
- package/dist/batch.d.ts.map +1 -1
- package/dist/batch.js +4 -26
- package/dist/batch.js.map +1 -1
- package/dist/client.d.ts +29 -43
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +199 -323
- package/dist/client.js.map +1 -1
- package/dist/database.d.ts +14 -131
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +35 -131
- package/dist/database.js.map +1 -1
- package/dist/index.d.ts +6 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -15
- package/dist/index.js.map +1 -1
- package/dist/query-sdk/ConditionBuilder.d.ts +3 -11
- package/dist/query-sdk/ConditionBuilder.d.ts.map +1 -1
- package/dist/query-sdk/ConditionBuilder.js +10 -48
- package/dist/query-sdk/ConditionBuilder.js.map +1 -1
- package/dist/query-sdk/NestedBuilders.d.ts +33 -30
- package/dist/query-sdk/NestedBuilders.d.ts.map +1 -1
- package/dist/query-sdk/NestedBuilders.js +46 -43
- package/dist/query-sdk/NestedBuilders.js.map +1 -1
- package/dist/query-sdk/QueryBuilder.d.ts +4 -2
- package/dist/query-sdk/QueryBuilder.d.ts.map +1 -1
- package/dist/query-sdk/QueryBuilder.js +47 -169
- package/dist/query-sdk/QueryBuilder.js.map +1 -1
- package/dist/query-sdk/QueryResult.d.ts +0 -38
- package/dist/query-sdk/QueryResult.d.ts.map +1 -1
- package/dist/query-sdk/QueryResult.js +1 -227
- package/dist/query-sdk/QueryResult.js.map +1 -1
- package/dist/query-sdk/index.d.ts +1 -1
- package/dist/query-sdk/index.d.ts.map +1 -1
- package/dist/query-sdk/index.js.map +1 -1
- package/dist/query-sdk/operators.d.ts +32 -28
- package/dist/query-sdk/operators.d.ts.map +1 -1
- package/dist/query-sdk/operators.js +45 -155
- package/dist/query-sdk/operators.js.map +1 -1
- package/dist/types.d.ts +153 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/jest.config.js +4 -0
- package/package.json +1 -1
- package/skills.md +0 -1
- package/src/client.ts +243 -745
- package/src/database.ts +70 -493
- package/src/index.ts +40 -193
- package/src/query-sdk/ConditionBuilder.ts +37 -89
- package/src/query-sdk/NestedBuilders.ts +90 -92
- package/src/query-sdk/QueryBuilder.ts +59 -218
- package/src/query-sdk/QueryResult.ts +4 -330
- package/src/query-sdk/README.md +214 -583
- package/src/query-sdk/index.ts +1 -1
- package/src/query-sdk/operators.ts +91 -200
- package/src/query-sdk/tests/FieldConditionBuilder.test.ts +70 -71
- package/src/query-sdk/tests/LogicalOperator.test.ts +43 -82
- package/src/query-sdk/tests/NestedBuilders.test.ts +229 -309
- package/src/query-sdk/tests/QueryBuilder.test.ts +5 -5
- package/src/query-sdk/tests/QueryResult.test.ts +41 -435
- package/src/query-sdk/tests/comprehensive.test.ts +4 -185
- package/src/tests/client-requests.test.ts +280 -0
- package/src/tests/client-validation.test.ts +80 -0
- package/src/types.ts +229 -8
- package/src/batch.ts +0 -257
- package/src/query-sdk/dist/ConditionBuilder.d.ts +0 -22
- package/src/query-sdk/dist/ConditionBuilder.js +0 -90
- package/src/query-sdk/dist/FieldConditionBuilder.d.ts +0 -1
- package/src/query-sdk/dist/FieldConditionBuilder.js +0 -6
- package/src/query-sdk/dist/NestedBuilders.d.ts +0 -43
- package/src/query-sdk/dist/NestedBuilders.js +0 -144
- package/src/query-sdk/dist/OnChainDB.d.ts +0 -19
- package/src/query-sdk/dist/OnChainDB.js +0 -123
- package/src/query-sdk/dist/QueryBuilder.d.ts +0 -70
- package/src/query-sdk/dist/QueryBuilder.js +0 -295
- package/src/query-sdk/dist/QueryResult.d.ts +0 -52
- package/src/query-sdk/dist/QueryResult.js +0 -293
- package/src/query-sdk/dist/SelectionBuilder.d.ts +0 -20
- package/src/query-sdk/dist/SelectionBuilder.js +0 -80
- package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +0 -27
- package/src/query-sdk/dist/adapters/HttpClientAdapter.js +0 -170
- package/src/query-sdk/dist/index.d.ts +0 -36
- package/src/query-sdk/dist/index.js +0 -27
- package/src/query-sdk/dist/operators.d.ts +0 -56
- package/src/query-sdk/dist/operators.js +0 -289
- package/src/query-sdk/dist/tests/setup.d.ts +0 -15
- package/src/query-sdk/dist/tests/setup.js +0 -46
- package/src/query-sdk/jest.config.js +0 -25
- package/src/query-sdk/package.json +0 -46
- package/src/query-sdk/tests/aggregations.test.ts +0 -653
- package/src/query-sdk/tests/integration.test.ts +0 -608
- package/src/query-sdk/tests/operators.test.ts +0 -327
- package/src/query-sdk/tests/unit.test.ts +0 -794
- package/src/query-sdk/tsconfig.json +0 -26
- package/src/query-sdk/yarn.lock +0 -3092
package/dist/client.js
CHANGED
|
@@ -15,11 +15,13 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
15
15
|
super();
|
|
16
16
|
const appKey = config.appKey || '';
|
|
17
17
|
const userKey = config.userKey || '';
|
|
18
|
+
const agentKey = config.agentKey || '';
|
|
18
19
|
this.config = {
|
|
19
20
|
endpoint: config.endpoint,
|
|
20
21
|
apiKey: config.apiKey || "",
|
|
21
22
|
appKey: appKey,
|
|
22
23
|
userKey: userKey,
|
|
24
|
+
agentKey: agentKey,
|
|
23
25
|
appId: config.appId || undefined,
|
|
24
26
|
timeout: config.timeout || 30000,
|
|
25
27
|
retryCount: config.retryCount || 3,
|
|
@@ -37,6 +39,9 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
37
39
|
if (userKey) {
|
|
38
40
|
headers['X-User-Key'] = userKey;
|
|
39
41
|
}
|
|
42
|
+
if (agentKey) {
|
|
43
|
+
headers['X-Agent-Key'] = agentKey;
|
|
44
|
+
}
|
|
40
45
|
this.http = axios_1.default.create({
|
|
41
46
|
baseURL: this.config.endpoint,
|
|
42
47
|
timeout: this.config.timeout,
|
|
@@ -44,8 +49,12 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
44
49
|
});
|
|
45
50
|
}
|
|
46
51
|
database(appId) {
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
const resolvedAppId = appId || this.config.appId;
|
|
53
|
+
if (!resolvedAppId) {
|
|
54
|
+
throw new types_1.ValidationError('appId must be provided either in config or as an argument to database()');
|
|
55
|
+
}
|
|
56
|
+
if (!this._database || this._database['appId'] !== resolvedAppId) {
|
|
57
|
+
this._database = (0, database_1.createDatabaseManager)(this.http, resolvedAppId, this.config.apiKey);
|
|
49
58
|
}
|
|
50
59
|
return this._database;
|
|
51
60
|
}
|
|
@@ -115,28 +124,12 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
115
124
|
if (serverResult.ticket_id) {
|
|
116
125
|
if (waitForConfirmation) {
|
|
117
126
|
const taskInfo = await this.waitForTaskCompletion(serverResult.ticket_id);
|
|
118
|
-
if (taskInfo.result
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
id: firstResult.id,
|
|
122
|
-
block_height: firstResult.celestia_height || 0,
|
|
123
|
-
transaction_hash: firstResult.blob_id || '',
|
|
124
|
-
celestia_height: firstResult.celestia_height || 0,
|
|
125
|
-
namespace: firstResult.namespace || '',
|
|
126
|
-
confirmed: firstResult.celestia_height > 0
|
|
127
|
-
};
|
|
127
|
+
if (taskInfo.result?.results?.length > 0) {
|
|
128
|
+
return this.buildStoreResult(taskInfo.result.results[0]);
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
else {
|
|
131
|
-
return {
|
|
132
|
-
id: serverResult.ticket_id,
|
|
133
|
-
block_height: 0,
|
|
134
|
-
transaction_hash: '',
|
|
135
|
-
celestia_height: 0,
|
|
136
|
-
namespace: '',
|
|
137
|
-
confirmed: false,
|
|
138
|
-
ticket_id: serverResult.ticket_id
|
|
139
|
-
};
|
|
132
|
+
return { id: serverResult.ticket_id, block_height: 0, transaction_hash: '', celestia_height: 0, namespace: '', confirmed: false, ticket_id: serverResult.ticket_id };
|
|
140
133
|
}
|
|
141
134
|
}
|
|
142
135
|
throw new types_1.OnChainDBError('No ticket_id in response after payment', 'STORE_ERROR');
|
|
@@ -150,12 +143,6 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
150
143
|
try {
|
|
151
144
|
delete resolvedRequest.collection;
|
|
152
145
|
const response = await this.http.post('/store', resolvedRequest);
|
|
153
|
-
if (response.status === 402 && response.data) {
|
|
154
|
-
const v = await this.handleX402(response, paymentCallback, resolvedRequest, waitForConfirmation);
|
|
155
|
-
if (v) {
|
|
156
|
-
return v;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
146
|
const serverResult = response.data;
|
|
160
147
|
if (serverResult.ticket_id) {
|
|
161
148
|
this.emit('transaction:queued', {
|
|
@@ -165,16 +152,8 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
165
152
|
});
|
|
166
153
|
if (waitForConfirmation) {
|
|
167
154
|
const taskInfo = await this.waitForTaskCompletion(serverResult.ticket_id);
|
|
168
|
-
if (taskInfo.result
|
|
169
|
-
const
|
|
170
|
-
const result = {
|
|
171
|
-
id: firstResult.id,
|
|
172
|
-
block_height: firstResult.celestia_height || 0,
|
|
173
|
-
transaction_hash: firstResult.blob_id || '',
|
|
174
|
-
celestia_height: firstResult.celestia_height || 0,
|
|
175
|
-
namespace: firstResult.namespace || '',
|
|
176
|
-
confirmed: firstResult.celestia_height > 0
|
|
177
|
-
};
|
|
155
|
+
if (taskInfo.result?.results?.length > 0) {
|
|
156
|
+
const result = this.buildStoreResult(taskInfo.result.results[0]);
|
|
178
157
|
this.emit('transaction:confirmed', {
|
|
179
158
|
id: result.id,
|
|
180
159
|
status: 'confirmed',
|
|
@@ -189,29 +168,14 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
189
168
|
}
|
|
190
169
|
}
|
|
191
170
|
else {
|
|
192
|
-
return {
|
|
193
|
-
id: serverResult.ticket_id,
|
|
194
|
-
block_height: 0,
|
|
195
|
-
transaction_hash: '',
|
|
196
|
-
celestia_height: 0,
|
|
197
|
-
namespace: '',
|
|
198
|
-
confirmed: false,
|
|
199
|
-
ticket_id: serverResult.ticket_id
|
|
200
|
-
};
|
|
171
|
+
return { id: serverResult.ticket_id, block_height: 0, transaction_hash: '', celestia_height: 0, namespace: '', confirmed: false, ticket_id: serverResult.ticket_id };
|
|
201
172
|
}
|
|
202
173
|
}
|
|
203
|
-
const firstResult = serverResult.results
|
|
174
|
+
const firstResult = serverResult.results?.[0];
|
|
204
175
|
if (!firstResult) {
|
|
205
176
|
throw new types_1.OnChainDBError('No results returned from server', 'STORE_ERROR');
|
|
206
177
|
}
|
|
207
|
-
const result =
|
|
208
|
-
id: firstResult.id,
|
|
209
|
-
block_height: firstResult.celestia_height || 0,
|
|
210
|
-
transaction_hash: firstResult.blob_id || '',
|
|
211
|
-
celestia_height: firstResult.celestia_height || 0,
|
|
212
|
-
namespace: firstResult.namespace || '',
|
|
213
|
-
confirmed: firstResult.celestia_height > 0
|
|
214
|
-
};
|
|
178
|
+
const result = this.buildStoreResult(firstResult);
|
|
215
179
|
if (result.block_height === 0) {
|
|
216
180
|
this.emit('transaction:pending', {
|
|
217
181
|
id: result.id,
|
|
@@ -229,9 +193,6 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
229
193
|
celestia_height: result.celestia_height
|
|
230
194
|
});
|
|
231
195
|
}
|
|
232
|
-
if (waitForConfirmation && result.block_height === 0) {
|
|
233
|
-
return await this.waitForConfirmation(result.transaction_hash);
|
|
234
|
-
}
|
|
235
196
|
return result;
|
|
236
197
|
}
|
|
237
198
|
catch (error) {
|
|
@@ -245,66 +206,13 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
245
206
|
}
|
|
246
207
|
throw new types_1.OnChainDBError(JSON.stringify(err.response?.data), 'STORE_ERROR');
|
|
247
208
|
}
|
|
209
|
+
console.error(error);
|
|
248
210
|
const dbError = error instanceof types_1.OnChainDBError ? error :
|
|
249
211
|
new types_1.OnChainDBError(error.message, 'STORE_ERROR');
|
|
250
212
|
this.emit('error', dbError);
|
|
251
213
|
throw dbError;
|
|
252
214
|
}
|
|
253
215
|
}
|
|
254
|
-
async storeAndConfirm(request) {
|
|
255
|
-
return this.store(request, undefined, true);
|
|
256
|
-
}
|
|
257
|
-
async waitForConfirmation(transactionHash, maxWaitTime = 300000) {
|
|
258
|
-
const startTime = Date.now();
|
|
259
|
-
const pollInterval = 3000;
|
|
260
|
-
console.log(`🔄 Waiting for transaction ${transactionHash} confirmation...`);
|
|
261
|
-
while (Date.now() - startTime < maxWaitTime) {
|
|
262
|
-
try {
|
|
263
|
-
const rpcUrl = 'https://celestia-mocha-rpc.publicnode.com:443';
|
|
264
|
-
const txUrl = `${rpcUrl}/tx?hash=0x${transactionHash}`;
|
|
265
|
-
console.log(`🔍 Checking transaction status: attempt ${Math.floor((Date.now() - startTime) / pollInterval) + 1}`);
|
|
266
|
-
const response = await axios_1.default.get(txUrl);
|
|
267
|
-
if (response.data?.result && response.data.result !== null) {
|
|
268
|
-
const txResult = response.data.result;
|
|
269
|
-
const height = parseInt(txResult.height);
|
|
270
|
-
if (height > 0) {
|
|
271
|
-
console.log(`✅ Transaction ${transactionHash} confirmed at height ${height}`);
|
|
272
|
-
const confirmedTx = {
|
|
273
|
-
id: transactionHash,
|
|
274
|
-
namespace: '',
|
|
275
|
-
block_height: height,
|
|
276
|
-
transaction_hash: transactionHash,
|
|
277
|
-
celestia_height: height,
|
|
278
|
-
confirmed: true
|
|
279
|
-
};
|
|
280
|
-
this.emit('transaction:confirmed', {
|
|
281
|
-
id: transactionHash,
|
|
282
|
-
status: 'confirmed',
|
|
283
|
-
block_height: height,
|
|
284
|
-
transaction_hash: transactionHash
|
|
285
|
-
});
|
|
286
|
-
return confirmedTx;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
console.log(`⏳ Transaction still pending, waiting ${pollInterval}ms...`);
|
|
290
|
-
this.emit('transaction:pending', {
|
|
291
|
-
id: transactionHash,
|
|
292
|
-
status: 'pending',
|
|
293
|
-
block_height: 0,
|
|
294
|
-
transaction_hash: transactionHash
|
|
295
|
-
});
|
|
296
|
-
await this.sleep(pollInterval);
|
|
297
|
-
}
|
|
298
|
-
catch (error) {
|
|
299
|
-
if (Date.now() - startTime >= maxWaitTime) {
|
|
300
|
-
throw new types_1.TransactionError(`Transaction confirmation timeout after ${maxWaitTime}ms`, transactionHash);
|
|
301
|
-
}
|
|
302
|
-
console.log(`⚠️ Error checking transaction (will retry): ${error}`);
|
|
303
|
-
await this.sleep(pollInterval);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
throw new types_1.TransactionError(`Transaction confirmation timeout after ${maxWaitTime}ms`, transactionHash);
|
|
307
|
-
}
|
|
308
216
|
async createIndex(request) {
|
|
309
217
|
try {
|
|
310
218
|
const appId = this.config.appId || 'default';
|
|
@@ -390,18 +298,6 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
390
298
|
success: true,
|
|
391
299
|
errors: []
|
|
392
300
|
};
|
|
393
|
-
let existingIndexes = [];
|
|
394
|
-
try {
|
|
395
|
-
const response = await this.http.get(`/api/apps/${appId}/collections/${schema.name}/indexes`);
|
|
396
|
-
existingIndexes = response.data?.indexes || response.data || [];
|
|
397
|
-
}
|
|
398
|
-
catch (error) {
|
|
399
|
-
existingIndexes = [];
|
|
400
|
-
}
|
|
401
|
-
const existingByField = new Map();
|
|
402
|
-
for (const idx of existingIndexes) {
|
|
403
|
-
existingByField.set(idx.field_name, { type: idx.index_type, name: idx.name });
|
|
404
|
-
}
|
|
405
301
|
const allFields = {};
|
|
406
302
|
if (schema.useBaseFields !== false) {
|
|
407
303
|
Object.assign(allFields, OnChainDBClient.BASE_FIELDS);
|
|
@@ -414,7 +310,7 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
414
310
|
}
|
|
415
311
|
}
|
|
416
312
|
for (const fieldName of desiredIndexedFields) {
|
|
417
|
-
|
|
313
|
+
{
|
|
418
314
|
const fieldDef = allFields[fieldName];
|
|
419
315
|
const indexType = fieldDef.indexType || this.getDefaultIndexType(fieldDef.type);
|
|
420
316
|
try {
|
|
@@ -448,232 +344,237 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
448
344
|
}
|
|
449
345
|
}
|
|
450
346
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
await this.http.delete(`/api/apps/${appId}/indexes/${indexId}`);
|
|
456
|
-
result.removed.push({
|
|
457
|
-
field: fieldName,
|
|
458
|
-
type: existing.type
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
catch (error) {
|
|
462
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
463
|
-
result.errors.push(`Failed to remove index on ${fieldName}: ${errorMsg}`);
|
|
464
|
-
result.success = false;
|
|
465
|
-
}
|
|
347
|
+
if (schema.sharding) {
|
|
348
|
+
try {
|
|
349
|
+
await this.setupSharding(schema.name, schema.sharding);
|
|
350
|
+
result.sharding_configured = true;
|
|
466
351
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
result.
|
|
471
|
-
field: fieldName,
|
|
472
|
-
type: existing.type
|
|
473
|
-
});
|
|
352
|
+
catch (error) {
|
|
353
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
354
|
+
result.errors.push(`Failed to configure sharding: ${errorMsg}`);
|
|
355
|
+
result.success = false;
|
|
474
356
|
}
|
|
475
357
|
}
|
|
476
358
|
return result;
|
|
477
359
|
}
|
|
478
|
-
async
|
|
360
|
+
async setupSharding(collection, sharding) {
|
|
479
361
|
const appId = this.config.appId;
|
|
480
362
|
if (!appId) {
|
|
363
|
+
throw new types_1.ValidationError('appId must be configured to setup sharding');
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
await this.http.patch(`/api/apps/${appId}/collections/${collection}/sharding`, sharding);
|
|
367
|
+
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
370
|
+
new types_1.OnChainDBError('Failed to setup sharding', 'SHARDING_ERROR');
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
async deleteCollection(collection) {
|
|
374
|
+
const appId = this.config.appId;
|
|
375
|
+
if (!appId)
|
|
481
376
|
throw new types_1.ValidationError('appId must be configured');
|
|
377
|
+
try {
|
|
378
|
+
const response = await this.http.delete(`/api/apps/${appId}/collections/${collection}`);
|
|
379
|
+
return response.data;
|
|
482
380
|
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
383
|
+
new types_1.OnChainDBError('Failed to delete collection', 'COLLECTION_ERROR');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async updateCollection(collection, updates) {
|
|
387
|
+
const appId = this.config.appId;
|
|
388
|
+
if (!appId)
|
|
389
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
483
390
|
try {
|
|
484
|
-
const response = await this.http.
|
|
391
|
+
const response = await this.http.patch(`/api/apps/${appId}/collections/${collection}`, updates);
|
|
485
392
|
return response.data;
|
|
486
393
|
}
|
|
487
394
|
catch (error) {
|
|
488
395
|
throw error instanceof types_1.OnChainDBError ? error :
|
|
489
|
-
new types_1.OnChainDBError('Failed to
|
|
396
|
+
new types_1.OnChainDBError('Failed to update collection', 'COLLECTION_ERROR');
|
|
490
397
|
}
|
|
491
398
|
}
|
|
492
|
-
async
|
|
399
|
+
async getRetention(collection) {
|
|
400
|
+
const appId = this.config.appId;
|
|
401
|
+
if (!appId)
|
|
402
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
493
403
|
try {
|
|
494
|
-
const
|
|
495
|
-
const response = await this.http.post(`/api/apps/${appId}/relations`, request);
|
|
404
|
+
const response = await this.http.get(`/api/apps/${appId}/collections/${collection}/retention`);
|
|
496
405
|
return response.data;
|
|
497
406
|
}
|
|
498
407
|
catch (error) {
|
|
499
408
|
throw error instanceof types_1.OnChainDBError ? error :
|
|
500
|
-
new types_1.OnChainDBError('Failed to
|
|
409
|
+
new types_1.OnChainDBError('Failed to get retention config', 'RETENTION_ERROR');
|
|
501
410
|
}
|
|
502
411
|
}
|
|
503
|
-
async
|
|
412
|
+
async setRetention(collection, request) {
|
|
413
|
+
const appId = this.config.appId;
|
|
414
|
+
if (!appId)
|
|
415
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
504
416
|
try {
|
|
505
|
-
const response = await this.http.
|
|
417
|
+
const response = await this.http.post(`/api/apps/${appId}/collections/${collection}/retention`, request);
|
|
506
418
|
return response.data;
|
|
507
419
|
}
|
|
508
420
|
catch (error) {
|
|
509
|
-
throw
|
|
421
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
422
|
+
new types_1.OnChainDBError('Failed to set retention config', 'RETENTION_ERROR');
|
|
510
423
|
}
|
|
511
424
|
}
|
|
512
|
-
async
|
|
425
|
+
async getRetentionCost() {
|
|
426
|
+
const appId = this.config.appId;
|
|
427
|
+
if (!appId)
|
|
428
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
513
429
|
try {
|
|
514
|
-
const response = await this.http.
|
|
430
|
+
const response = await this.http.get(`/api/apps/${appId}/retention/cost`);
|
|
515
431
|
return response.data;
|
|
516
432
|
}
|
|
517
433
|
catch (error) {
|
|
518
434
|
throw error instanceof types_1.OnChainDBError ? error :
|
|
519
|
-
new types_1.OnChainDBError('Failed to get
|
|
435
|
+
new types_1.OnChainDBError('Failed to get retention cost', 'RETENTION_ERROR');
|
|
520
436
|
}
|
|
521
437
|
}
|
|
522
|
-
async query
|
|
438
|
+
async sql(query, options) {
|
|
523
439
|
try {
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
return conditions.length === 1 ? conditions[0] : query_sdk_1.LogicalOperator.And(conditions);
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
if (request.limit) {
|
|
533
|
-
queryBuilder.limit(request.limit);
|
|
534
|
-
}
|
|
535
|
-
if (request.offset) {
|
|
536
|
-
queryBuilder.offset(request.offset);
|
|
537
|
-
}
|
|
538
|
-
return await queryBuilder.execute();
|
|
440
|
+
const body = { sql: query };
|
|
441
|
+
if (options?.includeHistory !== undefined)
|
|
442
|
+
body.include_history = options.includeHistory;
|
|
443
|
+
const response = await this.http.post('/query/sql', body);
|
|
444
|
+
return response.data;
|
|
539
445
|
}
|
|
540
446
|
catch (error) {
|
|
541
447
|
throw error instanceof types_1.OnChainDBError ? error :
|
|
542
|
-
new types_1.OnChainDBError('
|
|
448
|
+
new types_1.OnChainDBError('SQL query failed', 'SQL_ERROR');
|
|
543
449
|
}
|
|
544
450
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
451
|
+
async sqlInsert(sql) {
|
|
452
|
+
try {
|
|
453
|
+
const body = { sql };
|
|
454
|
+
const response = await this.http.post('/insert/sql', body);
|
|
455
|
+
return response.data;
|
|
456
|
+
}
|
|
457
|
+
catch (error) {
|
|
458
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
459
|
+
new types_1.OnChainDBError('SQL insert failed', 'SQL_ERROR');
|
|
460
|
+
}
|
|
549
461
|
}
|
|
550
|
-
|
|
551
|
-
const
|
|
552
|
-
|
|
462
|
+
async listQueries() {
|
|
463
|
+
const appId = this.config.appId;
|
|
464
|
+
if (!appId)
|
|
465
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
466
|
+
try {
|
|
467
|
+
const response = await this.http.get(`/apps/${appId}/queries`);
|
|
468
|
+
return response.data.queries ?? response.data;
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
472
|
+
new types_1.OnChainDBError('Failed to list predefined queries', 'QUERY_ERROR');
|
|
473
|
+
}
|
|
553
474
|
}
|
|
554
|
-
async
|
|
475
|
+
async createQuery(request) {
|
|
476
|
+
const appId = this.config.appId;
|
|
477
|
+
if (!appId)
|
|
478
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
555
479
|
try {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
queryBuilder = queryBuilder.whereField(field).equals(value);
|
|
559
|
-
}
|
|
560
|
-
return await queryBuilder.selectAll().executeUnique();
|
|
480
|
+
const response = await this.http.post(`/apps/${appId}/queries`, request);
|
|
481
|
+
return response.data;
|
|
561
482
|
}
|
|
562
483
|
catch (error) {
|
|
563
|
-
|
|
564
|
-
|
|
484
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
485
|
+
new types_1.OnChainDBError('Failed to create predefined query', 'QUERY_ERROR');
|
|
565
486
|
}
|
|
566
487
|
}
|
|
567
|
-
async
|
|
488
|
+
async getQuery(name) {
|
|
489
|
+
const appId = this.config.appId;
|
|
490
|
+
if (!appId)
|
|
491
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
568
492
|
try {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
queryBuilder = queryBuilder.whereField(field).equals(value);
|
|
572
|
-
}
|
|
573
|
-
if (options.limit) {
|
|
574
|
-
queryBuilder = queryBuilder.limit(options.limit);
|
|
575
|
-
}
|
|
576
|
-
if (options.offset) {
|
|
577
|
-
queryBuilder = queryBuilder.offset(options.offset);
|
|
578
|
-
}
|
|
579
|
-
const result = await queryBuilder.selectAll().execute();
|
|
580
|
-
if (!result.records) {
|
|
581
|
-
return [];
|
|
582
|
-
}
|
|
583
|
-
let records = result.records;
|
|
584
|
-
if (options.sort) {
|
|
585
|
-
records = records.sort((a, b) => {
|
|
586
|
-
const aVal = a[options.sort.field];
|
|
587
|
-
const bVal = b[options.sort.field];
|
|
588
|
-
if (options.sort.order === 'asc') {
|
|
589
|
-
return aVal > bVal ? 1 : -1;
|
|
590
|
-
}
|
|
591
|
-
else {
|
|
592
|
-
return aVal < bVal ? 1 : -1;
|
|
593
|
-
}
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
return records;
|
|
493
|
+
const response = await this.http.get(`/apps/${appId}/queries/${name}`);
|
|
494
|
+
return response.data;
|
|
597
495
|
}
|
|
598
496
|
catch (error) {
|
|
599
|
-
|
|
600
|
-
|
|
497
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
498
|
+
new types_1.OnChainDBError('Failed to get predefined query', 'QUERY_ERROR');
|
|
601
499
|
}
|
|
602
500
|
}
|
|
603
|
-
async
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
}
|
|
616
|
-
async updateDocument(collection, where, data, paymentCallback) {
|
|
617
|
-
const current = await this.findUnique(collection, where);
|
|
618
|
-
if (!current) {
|
|
619
|
-
return null;
|
|
620
|
-
}
|
|
621
|
-
const updated = {
|
|
622
|
-
...current,
|
|
623
|
-
...data,
|
|
624
|
-
updatedAt: new Date().toISOString(),
|
|
625
|
-
};
|
|
626
|
-
await this.store({
|
|
627
|
-
collection,
|
|
628
|
-
data: [updated],
|
|
629
|
-
}, paymentCallback);
|
|
630
|
-
return updated;
|
|
501
|
+
async deleteQuery(name) {
|
|
502
|
+
const appId = this.config.appId;
|
|
503
|
+
if (!appId)
|
|
504
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
505
|
+
try {
|
|
506
|
+
const response = await this.http.delete(`/apps/${appId}/queries/${name}`);
|
|
507
|
+
return response.data;
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
511
|
+
new types_1.OnChainDBError('Failed to delete predefined query', 'QUERY_ERROR');
|
|
512
|
+
}
|
|
631
513
|
}
|
|
632
|
-
async
|
|
633
|
-
const
|
|
634
|
-
if (
|
|
635
|
-
|
|
514
|
+
async executeQuery(name, params, version) {
|
|
515
|
+
const appId = this.config.appId;
|
|
516
|
+
if (!appId)
|
|
517
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
518
|
+
try {
|
|
519
|
+
const queryParams = { ...params };
|
|
520
|
+
if (version !== undefined)
|
|
521
|
+
queryParams['v'] = version;
|
|
522
|
+
const response = await this.http.get(`/api/queries/${appId}/${name}/data`, { params: queryParams });
|
|
523
|
+
return response.data;
|
|
636
524
|
}
|
|
637
|
-
|
|
638
|
-
|
|
525
|
+
catch (error) {
|
|
526
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
527
|
+
new types_1.OnChainDBError('Failed to execute predefined query', 'QUERY_ERROR');
|
|
639
528
|
}
|
|
640
529
|
}
|
|
641
|
-
async
|
|
642
|
-
const
|
|
643
|
-
if (!
|
|
644
|
-
|
|
530
|
+
async getCollectionInfo(collectionId) {
|
|
531
|
+
const appId = this.config.appId;
|
|
532
|
+
if (!appId) {
|
|
533
|
+
throw new types_1.ValidationError('appId must be configured');
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
const response = await this.http.get(`/api/apps/${appId}/collections/${collectionId}`);
|
|
537
|
+
return response.data;
|
|
538
|
+
}
|
|
539
|
+
catch (error) {
|
|
540
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
541
|
+
new types_1.OnChainDBError('Failed to get collection info', 'COLLECTION_ERROR');
|
|
645
542
|
}
|
|
646
|
-
const deleted = {
|
|
647
|
-
...existing,
|
|
648
|
-
deleted: true,
|
|
649
|
-
updatedAt: new Date().toISOString(),
|
|
650
|
-
};
|
|
651
|
-
await this.store({
|
|
652
|
-
collection,
|
|
653
|
-
data: [deleted],
|
|
654
|
-
}, paymentCallback);
|
|
655
|
-
return true;
|
|
656
543
|
}
|
|
657
|
-
async
|
|
544
|
+
async createRelation(request) {
|
|
658
545
|
try {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
}
|
|
663
|
-
return await queryBuilder.count();
|
|
546
|
+
const appId = this.config.appId || 'default';
|
|
547
|
+
const response = await this.http.post(`/api/apps/${appId}/relations`, request);
|
|
548
|
+
return response.data;
|
|
664
549
|
}
|
|
665
550
|
catch (error) {
|
|
666
|
-
|
|
667
|
-
|
|
551
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
552
|
+
new types_1.OnChainDBError('Failed to create relation', 'RELATION_ERROR');
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
async health() {
|
|
556
|
+
try {
|
|
557
|
+
const response = await this.http.get('/');
|
|
558
|
+
return response.data;
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
throw new types_1.OnChainDBError('Health check failed', 'HEALTH_ERROR');
|
|
668
562
|
}
|
|
669
563
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
564
|
+
async getPricingQuote(request) {
|
|
565
|
+
try {
|
|
566
|
+
const response = await this.http.post('/api/pricing/quote', request);
|
|
567
|
+
return response.data;
|
|
568
|
+
}
|
|
569
|
+
catch (error) {
|
|
570
|
+
throw error instanceof types_1.OnChainDBError ? error :
|
|
571
|
+
new types_1.OnChainDBError('Failed to get pricing quote', 'PRICING_QUOTE_ERROR');
|
|
675
572
|
}
|
|
676
|
-
|
|
573
|
+
}
|
|
574
|
+
queryBuilder() {
|
|
575
|
+
const { AxiosHttpClient } = require('./query-sdk/adapters/HttpClientAdapter');
|
|
576
|
+
const httpClient = new AxiosHttpClient(this.http);
|
|
577
|
+
return new query_sdk_1.QueryBuilder(httpClient, this.config.endpoint, this.config.appId);
|
|
677
578
|
}
|
|
678
579
|
async getTaskStatus(ticketId) {
|
|
679
580
|
try {
|
|
@@ -741,13 +642,7 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
741
642
|
formData.append('metadata', JSON.stringify(request.metadata));
|
|
742
643
|
}
|
|
743
644
|
const uploadWithHeaders = async (headers = {}) => {
|
|
744
|
-
return await this.http.post(`/api/apps/${appId}/blobs/${request.collection}`, formData, {
|
|
745
|
-
headers: {
|
|
746
|
-
'Content-Type': 'multipart/form-data',
|
|
747
|
-
'X-App-Key': this.config.appKey,
|
|
748
|
-
...headers
|
|
749
|
-
}
|
|
750
|
-
});
|
|
645
|
+
return await this.http.post(`/api/apps/${appId}/blobs/${request.collection}`, formData, { headers: { 'Content-Type': 'multipart/form-data', ...headers } });
|
|
751
646
|
};
|
|
752
647
|
try {
|
|
753
648
|
const response = await uploadWithHeaders();
|
|
@@ -785,12 +680,7 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
785
680
|
if (!appId) {
|
|
786
681
|
throw new types_1.ValidationError('appId must be configured to retrieve blobs');
|
|
787
682
|
}
|
|
788
|
-
const response = await this.http.get(`/api/apps/${appId}/blobs/${request.collection}/${request.blob_id}`, {
|
|
789
|
-
responseType: 'arraybuffer',
|
|
790
|
-
headers: {
|
|
791
|
-
'X-App-Key': this.config.appKey
|
|
792
|
-
}
|
|
793
|
-
});
|
|
683
|
+
const response = await this.http.get(`/api/apps/${appId}/blobs/${request.collection}/${request.blob_id}`, { responseType: 'arraybuffer' });
|
|
794
684
|
if (typeof global.window !== 'undefined' && typeof Blob !== 'undefined') {
|
|
795
685
|
const contentType = response.headers['content-type'] || 'application/octet-stream';
|
|
796
686
|
return new Blob([response.data], { type: contentType });
|
|
@@ -804,9 +694,6 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
804
694
|
new types_1.OnChainDBError('Failed to retrieve blob', 'BLOB_RETRIEVAL_ERROR');
|
|
805
695
|
}
|
|
806
696
|
}
|
|
807
|
-
async queryBlobMetadata(collection, where = {}) {
|
|
808
|
-
return await this.findMany(collection, where);
|
|
809
|
-
}
|
|
810
697
|
getDefaultIndexType(fieldType) {
|
|
811
698
|
switch (fieldType) {
|
|
812
699
|
case 'string':
|
|
@@ -821,6 +708,16 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
821
708
|
return 'string';
|
|
822
709
|
}
|
|
823
710
|
}
|
|
711
|
+
buildStoreResult(raw) {
|
|
712
|
+
return {
|
|
713
|
+
id: raw.id,
|
|
714
|
+
block_height: raw.celestia_height || 0,
|
|
715
|
+
transaction_hash: raw.blob_id || '',
|
|
716
|
+
celestia_height: raw.celestia_height || 0,
|
|
717
|
+
namespace: raw.namespace || '',
|
|
718
|
+
confirmed: raw.celestia_height > 0
|
|
719
|
+
};
|
|
720
|
+
}
|
|
824
721
|
validateStoreRequest(request) {
|
|
825
722
|
if (!request.root && !request.collection) {
|
|
826
723
|
throw new types_1.ValidationError('Either root or collection must be provided');
|
|
@@ -847,36 +744,15 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
|
|
|
847
744
|
throw new types_1.ValidationError('Total data size exceeds 5MB limit');
|
|
848
745
|
}
|
|
849
746
|
}
|
|
850
|
-
handleHttpError(error) {
|
|
851
|
-
console.error(error);
|
|
852
|
-
if (error.response) {
|
|
853
|
-
const statusCode = error.response.status;
|
|
854
|
-
const message = error.response.data?.error || error.message;
|
|
855
|
-
if (statusCode >= 400 && statusCode < 500) {
|
|
856
|
-
return new types_1.ValidationError(message, error.response.data);
|
|
857
|
-
}
|
|
858
|
-
return new types_1.OnChainDBError(message, 'HTTP_ERROR', statusCode, error.response.data);
|
|
859
|
-
}
|
|
860
|
-
if (error.request) {
|
|
861
|
-
return new types_1.OnChainDBError('Network error - could not reach OnChainDB service', 'NETWORK_ERROR');
|
|
862
|
-
}
|
|
863
|
-
return new types_1.OnChainDBError(error.message, 'UNKNOWN_ERROR');
|
|
864
|
-
}
|
|
865
747
|
sleep(ms) {
|
|
866
748
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
867
749
|
}
|
|
868
|
-
buildRoot(collection) {
|
|
869
|
-
if (!this.config.appId) {
|
|
870
|
-
return collection;
|
|
871
|
-
}
|
|
872
|
-
return `${this.config.appId}::${collection}`;
|
|
873
|
-
}
|
|
874
750
|
resolveRoot(request) {
|
|
875
751
|
if (request.root) {
|
|
876
752
|
return request.root;
|
|
877
753
|
}
|
|
878
754
|
if (request.collection) {
|
|
879
|
-
return this.
|
|
755
|
+
return this.config.appId ? `${this.config.appId}::${request.collection}` : request.collection;
|
|
880
756
|
}
|
|
881
757
|
throw new types_1.ValidationError('Either root or collection must be provided');
|
|
882
758
|
}
|