@onchaindb/sdk 0.4.5 → 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.
Files changed (97) hide show
  1. package/.claude/settings.local.json +10 -2
  2. package/README.md +422 -355
  3. package/dist/batch.d.ts +1 -10
  4. package/dist/batch.d.ts.map +1 -1
  5. package/dist/batch.js +4 -26
  6. package/dist/batch.js.map +1 -1
  7. package/dist/client.d.ts +29 -43
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +198 -323
  10. package/dist/client.js.map +1 -1
  11. package/dist/database.d.ts +14 -131
  12. package/dist/database.d.ts.map +1 -1
  13. package/dist/database.js +35 -131
  14. package/dist/database.js.map +1 -1
  15. package/dist/index.d.ts +6 -9
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -15
  18. package/dist/index.js.map +1 -1
  19. package/dist/query-sdk/ConditionBuilder.d.ts +3 -11
  20. package/dist/query-sdk/ConditionBuilder.d.ts.map +1 -1
  21. package/dist/query-sdk/ConditionBuilder.js +10 -48
  22. package/dist/query-sdk/ConditionBuilder.js.map +1 -1
  23. package/dist/query-sdk/NestedBuilders.d.ts +33 -30
  24. package/dist/query-sdk/NestedBuilders.d.ts.map +1 -1
  25. package/dist/query-sdk/NestedBuilders.js +46 -43
  26. package/dist/query-sdk/NestedBuilders.js.map +1 -1
  27. package/dist/query-sdk/QueryBuilder.d.ts +4 -2
  28. package/dist/query-sdk/QueryBuilder.d.ts.map +1 -1
  29. package/dist/query-sdk/QueryBuilder.js +47 -169
  30. package/dist/query-sdk/QueryBuilder.js.map +1 -1
  31. package/dist/query-sdk/QueryResult.d.ts +0 -38
  32. package/dist/query-sdk/QueryResult.d.ts.map +1 -1
  33. package/dist/query-sdk/QueryResult.js +1 -227
  34. package/dist/query-sdk/QueryResult.js.map +1 -1
  35. package/dist/query-sdk/index.d.ts +1 -1
  36. package/dist/query-sdk/index.d.ts.map +1 -1
  37. package/dist/query-sdk/index.js.map +1 -1
  38. package/dist/query-sdk/operators.d.ts +32 -28
  39. package/dist/query-sdk/operators.d.ts.map +1 -1
  40. package/dist/query-sdk/operators.js +45 -155
  41. package/dist/query-sdk/operators.js.map +1 -1
  42. package/dist/types.d.ts +153 -1
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/types.js.map +1 -1
  45. package/jest.config.js +4 -0
  46. package/package.json +1 -1
  47. package/skills.md +0 -1
  48. package/src/client.ts +242 -745
  49. package/src/database.ts +70 -493
  50. package/src/index.ts +40 -193
  51. package/src/query-sdk/ConditionBuilder.ts +37 -89
  52. package/src/query-sdk/NestedBuilders.ts +90 -92
  53. package/src/query-sdk/QueryBuilder.ts +59 -218
  54. package/src/query-sdk/QueryResult.ts +4 -330
  55. package/src/query-sdk/README.md +214 -583
  56. package/src/query-sdk/index.ts +1 -1
  57. package/src/query-sdk/operators.ts +91 -200
  58. package/src/query-sdk/tests/FieldConditionBuilder.test.ts +70 -71
  59. package/src/query-sdk/tests/LogicalOperator.test.ts +43 -82
  60. package/src/query-sdk/tests/NestedBuilders.test.ts +229 -309
  61. package/src/query-sdk/tests/QueryBuilder.test.ts +5 -5
  62. package/src/query-sdk/tests/QueryResult.test.ts +41 -435
  63. package/src/query-sdk/tests/comprehensive.test.ts +4 -185
  64. package/src/tests/client-requests.test.ts +280 -0
  65. package/src/tests/client-validation.test.ts +80 -0
  66. package/src/types.ts +229 -8
  67. package/src/batch.ts +0 -257
  68. package/src/query-sdk/dist/ConditionBuilder.d.ts +0 -22
  69. package/src/query-sdk/dist/ConditionBuilder.js +0 -90
  70. package/src/query-sdk/dist/FieldConditionBuilder.d.ts +0 -1
  71. package/src/query-sdk/dist/FieldConditionBuilder.js +0 -6
  72. package/src/query-sdk/dist/NestedBuilders.d.ts +0 -43
  73. package/src/query-sdk/dist/NestedBuilders.js +0 -144
  74. package/src/query-sdk/dist/OnChainDB.d.ts +0 -19
  75. package/src/query-sdk/dist/OnChainDB.js +0 -123
  76. package/src/query-sdk/dist/QueryBuilder.d.ts +0 -70
  77. package/src/query-sdk/dist/QueryBuilder.js +0 -295
  78. package/src/query-sdk/dist/QueryResult.d.ts +0 -52
  79. package/src/query-sdk/dist/QueryResult.js +0 -293
  80. package/src/query-sdk/dist/SelectionBuilder.d.ts +0 -20
  81. package/src/query-sdk/dist/SelectionBuilder.js +0 -80
  82. package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +0 -27
  83. package/src/query-sdk/dist/adapters/HttpClientAdapter.js +0 -170
  84. package/src/query-sdk/dist/index.d.ts +0 -36
  85. package/src/query-sdk/dist/index.js +0 -27
  86. package/src/query-sdk/dist/operators.d.ts +0 -56
  87. package/src/query-sdk/dist/operators.js +0 -289
  88. package/src/query-sdk/dist/tests/setup.d.ts +0 -15
  89. package/src/query-sdk/dist/tests/setup.js +0 -46
  90. package/src/query-sdk/jest.config.js +0 -25
  91. package/src/query-sdk/package.json +0 -46
  92. package/src/query-sdk/tests/aggregations.test.ts +0 -653
  93. package/src/query-sdk/tests/integration.test.ts +0 -608
  94. package/src/query-sdk/tests/operators.test.ts +0 -327
  95. package/src/query-sdk/tests/unit.test.ts +0 -794
  96. package/src/query-sdk/tsconfig.json +0 -26
  97. 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
- if (!this._database || this._database['appId'] !== appId) {
48
- this._database = (0, database_1.createDatabaseManager)(this.http, this.config.endpoint, appId, this.config.apiKey);
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 && taskInfo.result.results && taskInfo.result.results.length > 0) {
119
- const firstResult = taskInfo.result.results[0];
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 && taskInfo.result.results && taskInfo.result.results.length > 0) {
169
- const firstResult = taskInfo.result.results[0];
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 && serverResult.results[0];
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) {
@@ -252,60 +213,6 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
252
213
  throw dbError;
253
214
  }
254
215
  }
255
- async storeAndConfirm(request) {
256
- return this.store(request, undefined, true);
257
- }
258
- async waitForConfirmation(transactionHash, maxWaitTime = 300000) {
259
- const startTime = Date.now();
260
- const pollInterval = 3000;
261
- console.log(`🔄 Waiting for transaction ${transactionHash} confirmation...`);
262
- while (Date.now() - startTime < maxWaitTime) {
263
- try {
264
- const rpcUrl = 'https://celestia-mocha-rpc.publicnode.com:443';
265
- const txUrl = `${rpcUrl}/tx?hash=0x${transactionHash}`;
266
- console.log(`🔍 Checking transaction status: attempt ${Math.floor((Date.now() - startTime) / pollInterval) + 1}`);
267
- const response = await axios_1.default.get(txUrl);
268
- if (response.data?.result && response.data.result !== null) {
269
- const txResult = response.data.result;
270
- const height = parseInt(txResult.height);
271
- if (height > 0) {
272
- console.log(`✅ Transaction ${transactionHash} confirmed at height ${height}`);
273
- const confirmedTx = {
274
- id: transactionHash,
275
- namespace: '',
276
- block_height: height,
277
- transaction_hash: transactionHash,
278
- celestia_height: height,
279
- confirmed: true
280
- };
281
- this.emit('transaction:confirmed', {
282
- id: transactionHash,
283
- status: 'confirmed',
284
- block_height: height,
285
- transaction_hash: transactionHash
286
- });
287
- return confirmedTx;
288
- }
289
- }
290
- console.log(`⏳ Transaction still pending, waiting ${pollInterval}ms...`);
291
- this.emit('transaction:pending', {
292
- id: transactionHash,
293
- status: 'pending',
294
- block_height: 0,
295
- transaction_hash: transactionHash
296
- });
297
- await this.sleep(pollInterval);
298
- }
299
- catch (error) {
300
- if (Date.now() - startTime >= maxWaitTime) {
301
- throw new types_1.TransactionError(`Transaction confirmation timeout after ${maxWaitTime}ms`, transactionHash);
302
- }
303
- console.log(`⚠️ Error checking transaction (will retry): ${error}`);
304
- await this.sleep(pollInterval);
305
- }
306
- }
307
- throw new types_1.TransactionError(`Transaction confirmation timeout after ${maxWaitTime}ms`, transactionHash);
308
- }
309
216
  async createIndex(request) {
310
217
  try {
311
218
  const appId = this.config.appId || 'default';
@@ -391,18 +298,6 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
391
298
  success: true,
392
299
  errors: []
393
300
  };
394
- let existingIndexes = [];
395
- try {
396
- const response = await this.http.get(`/api/apps/${appId}/collections/${schema.name}/indexes`);
397
- existingIndexes = response.data?.indexes || response.data || [];
398
- }
399
- catch (error) {
400
- existingIndexes = [];
401
- }
402
- const existingByField = new Map();
403
- for (const idx of existingIndexes) {
404
- existingByField.set(idx.field_name, { type: idx.index_type, name: idx.name });
405
- }
406
301
  const allFields = {};
407
302
  if (schema.useBaseFields !== false) {
408
303
  Object.assign(allFields, OnChainDBClient.BASE_FIELDS);
@@ -415,7 +310,7 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
415
310
  }
416
311
  }
417
312
  for (const fieldName of desiredIndexedFields) {
418
- if (!existingByField.has(fieldName)) {
313
+ {
419
314
  const fieldDef = allFields[fieldName];
420
315
  const indexType = fieldDef.indexType || this.getDefaultIndexType(fieldDef.type);
421
316
  try {
@@ -449,232 +344,237 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
449
344
  }
450
345
  }
451
346
  }
452
- for (const [fieldName, existing] of existingByField) {
453
- if (!desiredIndexedFields.has(fieldName)) {
454
- try {
455
- const indexId = `${schema.name}_${fieldName}_index`;
456
- await this.http.delete(`/api/apps/${appId}/indexes/${indexId}`);
457
- result.removed.push({
458
- field: fieldName,
459
- type: existing.type
460
- });
461
- }
462
- catch (error) {
463
- const errorMsg = error instanceof Error ? error.message : String(error);
464
- result.errors.push(`Failed to remove index on ${fieldName}: ${errorMsg}`);
465
- result.success = false;
466
- }
347
+ if (schema.sharding) {
348
+ try {
349
+ await this.setupSharding(schema.name, schema.sharding);
350
+ result.sharding_configured = true;
467
351
  }
468
- }
469
- for (const [fieldName, existing] of existingByField) {
470
- if (desiredIndexedFields.has(fieldName)) {
471
- result.unchanged.push({
472
- field: fieldName,
473
- type: existing.type
474
- });
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;
475
356
  }
476
357
  }
477
358
  return result;
478
359
  }
479
- async getCollectionInfo(collection) {
360
+ async setupSharding(collection, sharding) {
480
361
  const appId = this.config.appId;
481
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)
482
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;
483
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');
484
390
  try {
485
- const response = await this.http.get(`/api/apps/${appId}/collections/${collection}`);
391
+ const response = await this.http.patch(`/api/apps/${appId}/collections/${collection}`, updates);
486
392
  return response.data;
487
393
  }
488
394
  catch (error) {
489
395
  throw error instanceof types_1.OnChainDBError ? error :
490
- new types_1.OnChainDBError('Failed to get collection info', 'COLLECTION_ERROR');
396
+ new types_1.OnChainDBError('Failed to update collection', 'COLLECTION_ERROR');
491
397
  }
492
398
  }
493
- async createRelation(request) {
399
+ async getRetention(collection) {
400
+ const appId = this.config.appId;
401
+ if (!appId)
402
+ throw new types_1.ValidationError('appId must be configured');
494
403
  try {
495
- const appId = this.config.appId || 'default';
496
- const response = await this.http.post(`/api/apps/${appId}/relations`, request);
404
+ const response = await this.http.get(`/api/apps/${appId}/collections/${collection}/retention`);
497
405
  return response.data;
498
406
  }
499
407
  catch (error) {
500
408
  throw error instanceof types_1.OnChainDBError ? error :
501
- new types_1.OnChainDBError('Failed to create relation', 'RELATION_ERROR');
409
+ new types_1.OnChainDBError('Failed to get retention config', 'RETENTION_ERROR');
502
410
  }
503
411
  }
504
- async health() {
412
+ async setRetention(collection, request) {
413
+ const appId = this.config.appId;
414
+ if (!appId)
415
+ throw new types_1.ValidationError('appId must be configured');
505
416
  try {
506
- const response = await this.http.get('/');
417
+ const response = await this.http.post(`/api/apps/${appId}/collections/${collection}/retention`, request);
507
418
  return response.data;
508
419
  }
509
420
  catch (error) {
510
- throw new types_1.OnChainDBError('Health check failed', 'HEALTH_ERROR');
421
+ throw error instanceof types_1.OnChainDBError ? error :
422
+ new types_1.OnChainDBError('Failed to set retention config', 'RETENTION_ERROR');
511
423
  }
512
424
  }
513
- async getPricingQuote(request) {
425
+ async getRetentionCost() {
426
+ const appId = this.config.appId;
427
+ if (!appId)
428
+ throw new types_1.ValidationError('appId must be configured');
514
429
  try {
515
- const response = await this.http.post('/api/pricing/quote', request);
430
+ const response = await this.http.get(`/api/apps/${appId}/retention/cost`);
516
431
  return response.data;
517
432
  }
518
433
  catch (error) {
519
434
  throw error instanceof types_1.OnChainDBError ? error :
520
- new types_1.OnChainDBError('Failed to get pricing quote', 'PRICING_QUOTE_ERROR');
435
+ new types_1.OnChainDBError('Failed to get retention cost', 'RETENTION_ERROR');
521
436
  }
522
437
  }
523
- async query(request) {
438
+ async sql(query, options) {
524
439
  try {
525
- const queryBuilder = this.queryBuilder();
526
- const root = this.resolveRoot(request);
527
- if (request.filters) {
528
- queryBuilder.find(builder => {
529
- const conditions = Object.entries(request.filters).map(([field, value]) => query_sdk_1.LogicalOperator.Condition(builder.field(field).equals(value)));
530
- return conditions.length === 1 ? conditions[0] : query_sdk_1.LogicalOperator.And(conditions);
531
- });
532
- }
533
- if (request.limit) {
534
- queryBuilder.limit(request.limit);
535
- }
536
- if (request.offset) {
537
- queryBuilder.offset(request.offset);
538
- }
539
- 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;
540
445
  }
541
446
  catch (error) {
542
447
  throw error instanceof types_1.OnChainDBError ? error :
543
- new types_1.OnChainDBError('Failed to execute query', 'QUERY_ERROR');
448
+ new types_1.OnChainDBError('SQL query failed', 'SQL_ERROR');
544
449
  }
545
450
  }
546
- queryBuilder() {
547
- const { AxiosHttpClient } = require('./query-sdk/adapters/HttpClientAdapter');
548
- const httpClient = new AxiosHttpClient(this.http);
549
- return new query_sdk_1.QueryBuilder(httpClient, this.config.endpoint, this.config.appId);
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
+ }
550
461
  }
551
- batch() {
552
- const { BatchOperations } = require('./batch');
553
- return new BatchOperations(this);
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
+ }
554
474
  }
555
- async findUnique(collection, where) {
475
+ async createQuery(request) {
476
+ const appId = this.config.appId;
477
+ if (!appId)
478
+ throw new types_1.ValidationError('appId must be configured');
556
479
  try {
557
- let queryBuilder = this.queryBuilder().collection(collection);
558
- for (const [field, value] of Object.entries(where)) {
559
- queryBuilder = queryBuilder.whereField(field).equals(value);
560
- }
561
- return await queryBuilder.selectAll().executeUnique();
480
+ const response = await this.http.post(`/apps/${appId}/queries`, request);
481
+ return response.data;
562
482
  }
563
483
  catch (error) {
564
- console.error(`findUnique error for ${collection}:`, error);
565
- return null;
484
+ throw error instanceof types_1.OnChainDBError ? error :
485
+ new types_1.OnChainDBError('Failed to create predefined query', 'QUERY_ERROR');
566
486
  }
567
487
  }
568
- async findMany(collection, where = {}, options = {}) {
488
+ async getQuery(name) {
489
+ const appId = this.config.appId;
490
+ if (!appId)
491
+ throw new types_1.ValidationError('appId must be configured');
569
492
  try {
570
- let queryBuilder = this.queryBuilder().collection(collection);
571
- for (const [field, value] of Object.entries(where)) {
572
- queryBuilder = queryBuilder.whereField(field).equals(value);
573
- }
574
- if (options.limit) {
575
- queryBuilder = queryBuilder.limit(options.limit);
576
- }
577
- if (options.offset) {
578
- queryBuilder = queryBuilder.offset(options.offset);
579
- }
580
- const result = await queryBuilder.selectAll().execute();
581
- if (!result.records) {
582
- return [];
583
- }
584
- let records = result.records;
585
- if (options.sort) {
586
- records = records.sort((a, b) => {
587
- const aVal = a[options.sort.field];
588
- const bVal = b[options.sort.field];
589
- if (options.sort.order === 'asc') {
590
- return aVal > bVal ? 1 : -1;
591
- }
592
- else {
593
- return aVal < bVal ? 1 : -1;
594
- }
595
- });
596
- }
597
- return records;
493
+ const response = await this.http.get(`/apps/${appId}/queries/${name}`);
494
+ return response.data;
598
495
  }
599
496
  catch (error) {
600
- console.error(`findMany error for ${collection}:`, error);
601
- return [];
497
+ throw error instanceof types_1.OnChainDBError ? error :
498
+ new types_1.OnChainDBError('Failed to get predefined query', 'QUERY_ERROR');
602
499
  }
603
500
  }
604
- async createDocument(collection, data, paymentCallback, options) {
605
- const document = {
606
- id: options?.idGenerator ? options.idGenerator() : this.generateId(),
607
- ...data,
608
- createdAt: new Date().toISOString(),
609
- updatedAt: new Date().toISOString(),
610
- };
611
- await this.store({
612
- collection,
613
- data: [document],
614
- }, paymentCallback);
615
- return document;
616
- }
617
- async updateDocument(collection, where, data, paymentCallback) {
618
- const current = await this.findUnique(collection, where);
619
- if (!current) {
620
- return null;
621
- }
622
- const updated = {
623
- ...current,
624
- ...data,
625
- updatedAt: new Date().toISOString(),
626
- };
627
- await this.store({
628
- collection,
629
- data: [updated],
630
- }, paymentCallback);
631
- 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
+ }
632
513
  }
633
- async upsertDocument(collection, where, create, update, paymentCallback, options) {
634
- const existing = await this.findUnique(collection, where);
635
- if (existing) {
636
- return (await this.updateDocument(collection, where, update, paymentCallback));
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;
637
524
  }
638
- else {
639
- return await this.createDocument(collection, create, paymentCallback, options);
525
+ catch (error) {
526
+ throw error instanceof types_1.OnChainDBError ? error :
527
+ new types_1.OnChainDBError('Failed to execute predefined query', 'QUERY_ERROR');
640
528
  }
641
529
  }
642
- async deleteDocument(collection, where, paymentCallback) {
643
- const existing = await this.findUnique(collection, where);
644
- if (!existing) {
645
- return false;
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');
646
542
  }
647
- const deleted = {
648
- ...existing,
649
- deleted: true,
650
- updatedAt: new Date().toISOString(),
651
- };
652
- await this.store({
653
- collection,
654
- data: [deleted],
655
- }, paymentCallback);
656
- return true;
657
543
  }
658
- async countDocuments(collection, where = {}) {
544
+ async createRelation(request) {
659
545
  try {
660
- let queryBuilder = this.queryBuilder().collection(collection);
661
- for (const [field, value] of Object.entries(where)) {
662
- queryBuilder = queryBuilder.whereField(field).equals(value);
663
- }
664
- 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;
665
549
  }
666
550
  catch (error) {
667
- console.error(`countDocuments error for ${collection}:`, error);
668
- return 0;
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');
669
562
  }
670
563
  }
671
- generateId() {
672
- const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
673
- let id = '';
674
- for (let i = 0; i < 24; i++) {
675
- id += chars[Math.floor(Math.random() * chars.length)];
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');
676
572
  }
677
- return id;
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);
678
578
  }
679
579
  async getTaskStatus(ticketId) {
680
580
  try {
@@ -742,13 +642,7 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
742
642
  formData.append('metadata', JSON.stringify(request.metadata));
743
643
  }
744
644
  const uploadWithHeaders = async (headers = {}) => {
745
- return await this.http.post(`/api/apps/${appId}/blobs/${request.collection}`, formData, {
746
- headers: {
747
- 'Content-Type': 'multipart/form-data',
748
- 'X-App-Key': this.config.appKey,
749
- ...headers
750
- }
751
- });
645
+ return await this.http.post(`/api/apps/${appId}/blobs/${request.collection}`, formData, { headers: { 'Content-Type': 'multipart/form-data', ...headers } });
752
646
  };
753
647
  try {
754
648
  const response = await uploadWithHeaders();
@@ -786,12 +680,7 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
786
680
  if (!appId) {
787
681
  throw new types_1.ValidationError('appId must be configured to retrieve blobs');
788
682
  }
789
- const response = await this.http.get(`/api/apps/${appId}/blobs/${request.collection}/${request.blob_id}`, {
790
- responseType: 'arraybuffer',
791
- headers: {
792
- 'X-App-Key': this.config.appKey
793
- }
794
- });
683
+ const response = await this.http.get(`/api/apps/${appId}/blobs/${request.collection}/${request.blob_id}`, { responseType: 'arraybuffer' });
795
684
  if (typeof global.window !== 'undefined' && typeof Blob !== 'undefined') {
796
685
  const contentType = response.headers['content-type'] || 'application/octet-stream';
797
686
  return new Blob([response.data], { type: contentType });
@@ -805,9 +694,6 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
805
694
  new types_1.OnChainDBError('Failed to retrieve blob', 'BLOB_RETRIEVAL_ERROR');
806
695
  }
807
696
  }
808
- async queryBlobMetadata(collection, where = {}) {
809
- return await this.findMany(collection, where);
810
- }
811
697
  getDefaultIndexType(fieldType) {
812
698
  switch (fieldType) {
813
699
  case 'string':
@@ -822,6 +708,16 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
822
708
  return 'string';
823
709
  }
824
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
+ }
825
721
  validateStoreRequest(request) {
826
722
  if (!request.root && !request.collection) {
827
723
  throw new types_1.ValidationError('Either root or collection must be provided');
@@ -848,36 +744,15 @@ class OnChainDBClient extends eventemitter3_1.EventEmitter {
848
744
  throw new types_1.ValidationError('Total data size exceeds 5MB limit');
849
745
  }
850
746
  }
851
- handleHttpError(error) {
852
- console.error(error);
853
- if (error.response) {
854
- const statusCode = error.response.status;
855
- const message = error.response.data?.error || error.message;
856
- if (statusCode >= 400 && statusCode < 500) {
857
- return new types_1.ValidationError(message, error.response.data);
858
- }
859
- return new types_1.OnChainDBError(message, 'HTTP_ERROR', statusCode, error.response.data);
860
- }
861
- if (error.request) {
862
- return new types_1.OnChainDBError('Network error - could not reach OnChainDB service', 'NETWORK_ERROR');
863
- }
864
- return new types_1.OnChainDBError(error.message, 'UNKNOWN_ERROR');
865
- }
866
747
  sleep(ms) {
867
748
  return new Promise(resolve => setTimeout(resolve, ms));
868
749
  }
869
- buildRoot(collection) {
870
- if (!this.config.appId) {
871
- return collection;
872
- }
873
- return `${this.config.appId}::${collection}`;
874
- }
875
750
  resolveRoot(request) {
876
751
  if (request.root) {
877
752
  return request.root;
878
753
  }
879
754
  if (request.collection) {
880
- return this.buildRoot(request.collection);
755
+ return this.config.appId ? `${this.config.appId}::${request.collection}` : request.collection;
881
756
  }
882
757
  throw new types_1.ValidationError('Either root or collection must be provided');
883
758
  }