@onchaindb/sdk 2.0.0 → 2.1.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 (44) hide show
  1. package/.claude/settings.local.json +5 -1
  2. package/.gitignore +1 -0
  3. package/README.md +8 -9
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +0 -5
  6. package/dist/client.js.map +1 -1
  7. package/dist/database.d.ts +46 -8
  8. package/dist/database.d.ts.map +1 -1
  9. package/dist/database.js +32 -9
  10. package/dist/database.js.map +1 -1
  11. package/dist/index.d.ts +1 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/query-sdk/NestedBuilders.d.ts +3 -2
  15. package/dist/query-sdk/NestedBuilders.d.ts.map +1 -1
  16. package/dist/query-sdk/NestedBuilders.js +7 -4
  17. package/dist/query-sdk/NestedBuilders.js.map +1 -1
  18. package/dist/query-sdk/QueryBuilder.d.ts +17 -15
  19. package/dist/query-sdk/QueryBuilder.d.ts.map +1 -1
  20. package/dist/query-sdk/QueryBuilder.js +126 -190
  21. package/dist/query-sdk/QueryBuilder.js.map +1 -1
  22. package/dist/query-sdk/index.d.ts +24 -1
  23. package/dist/query-sdk/index.d.ts.map +1 -1
  24. package/dist/query-sdk/index.js.map +1 -1
  25. package/dist/query-sdk/operators.d.ts +3 -2
  26. package/dist/query-sdk/operators.d.ts.map +1 -1
  27. package/dist/query-sdk/operators.js +7 -4
  28. package/dist/query-sdk/operators.js.map +1 -1
  29. package/dist/types.d.ts +17 -13
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/types.js.map +1 -1
  32. package/package.json +1 -1
  33. package/skills.md +5 -5
  34. package/src/client.ts +1 -7
  35. package/src/database.ts +159 -26
  36. package/src/index.ts +16 -10
  37. package/src/query-sdk/NestedBuilders.ts +14 -4
  38. package/src/query-sdk/QueryBuilder.ts +212 -235
  39. package/src/query-sdk/index.ts +19 -1
  40. package/src/query-sdk/operators.ts +15 -4
  41. package/src/query-sdk/tests/FieldConditionBuilder.test.ts +4 -2
  42. package/src/query-sdk/tests/NestedBuilders.test.ts +4 -3
  43. package/src/types.ts +26 -17
  44. package/.DS_Store +0 -0
package/src/database.ts CHANGED
@@ -9,20 +9,72 @@ import {
9
9
  CreateApiCollectionRequest,
10
10
  } from './types';
11
11
 
12
+ // ─── Write pricing (price index) ────────────────────────────────────────────
13
+ // Mirrors Rust: WritePricingModel + PriceConfigRequest (indexing/types.rs)
14
+
15
+ export type WritePricingModel = 'field_value' | 'per_kb' | 'per_record';
16
+
17
+ /** Configuration for write-time payment collection (price indexes). */
18
+ export interface WriteIndexConfig {
19
+ /** How the write cost is calculated. */
20
+ pricing_model?: WritePricingModel;
21
+ /** Cost per KB of data written, in USDC base units (6 decimals — e.g. 1_000_000 = 1 USDC). */
22
+ price_per_kb?: number;
23
+ /** Cost per record written, in USDC base units. */
24
+ price_per_record?: number;
25
+ }
26
+
27
+ // ─── Read pricing ────────────────────────────────────────────────────────────
28
+ // Mirrors Rust: ReadPricingModel + ReadPriceConfigRequest (indexing/types.rs)
29
+
30
+ export type ReadPricingModel = 'per_access' | 'per_kb' | 'per_query';
31
+
32
+ /** Configuration for read-time payment collection. */
33
+ export interface ReadIndexConfig {
34
+ /** How the read cost is calculated. */
35
+ pricing_model?: ReadPricingModel;
36
+ /** Cost per matched record returned, in USDC base units. */
37
+ price_per_access?: number;
38
+ /** Cost per KB of data returned, in USDC base units. */
39
+ price_per_kb?: number;
40
+ /** Flat cost per query execution, in USDC base units. */
41
+ price_per_query?: number;
42
+ }
43
+
44
+ // ─── Creator premium ─────────────────────────────────────────────────────────
45
+ // Mirrors Rust: CreatorCutModel + CreatorPremiumConfigRequest (indexing/types.rs)
46
+
47
+ export type CreatorCutModel = 'per_kb' | 'per_value_field' | 'per_value_percent' | 'fixed_amount';
48
+
49
+ /** Configuration for creator revenue sharing on writes. */
50
+ export interface CreatorPremiumConfig {
51
+ /** Dot-notation path to the creator's wallet address in the record (e.g. "user_address", "metadata.creator"). */
52
+ creator_address_resolution: string;
53
+ /** How the creator's cut is calculated. */
54
+ creator_cut_model: CreatorCutModel;
55
+ /** Amount or percentage value, depending on the model. */
56
+ creator_cut_value: number;
57
+ /** Field name used by per_value_field and per_value_percent models. */
58
+ value_field_name?: string;
59
+ }
60
+
61
+ // ─── Index ───────────────────────────────────────────────────────────────────
62
+
12
63
  export interface Index {
13
64
  name: string;
14
65
  collection: string;
15
66
  field_name: string;
16
67
  index_type: 'btree' | 'hash' | 'fulltext' | 'composite' | 'price';
17
68
  fields?: string[];
18
- options?: IndexOptions;
19
- price_config?: PriceConfig;
20
- }
21
-
22
- export interface PriceConfig {
23
- app_owner_percentage: number;
24
- platform_percentage: number;
25
- app_owner_address: string;
69
+ store_values?: boolean;
70
+ unique_constraint?: boolean;
71
+ sort_enabled?: boolean;
72
+ /** Write-time payment config — only for index_type: 'price'. */
73
+ price_config?: WriteIndexConfig;
74
+ /** Read-time payment config — can be attached to any index type. */
75
+ read_price_config?: ReadIndexConfig;
76
+ /** Creator revenue sharing config — can be attached to any index type. */
77
+ creator_premium_config?: CreatorPremiumConfig;
26
78
  }
27
79
 
28
80
  export interface IndexOptions {
@@ -100,37 +152,116 @@ export class DatabaseManager {
100
152
  }
101
153
 
102
154
  /**
103
- * Create a Price index for on-chain commerce
155
+ * Create a write-priced index (price index).
104
156
  *
105
- * Price indexes enable automatic payment splits when writing to collections.
106
- * Perfect for order/purchase collections where you want to charge based on item price.
157
+ * Charges writers a fee each time a record is written to the collection.
158
+ * The broker collects payment via the x402 protocol on every `/store` call.
159
+ *
160
+ * @param collection - Target collection name
161
+ * @param fieldName - Field to index (used for routing/lookups)
162
+ * @param config - Write pricing model and amounts (USDC base units, 6 decimals)
163
+ * @param opts - Optional: override generated index name, store_values, unique_constraint, sort_enabled
107
164
  *
108
165
  * @example
109
166
  * ```typescript
110
- * await db.database().createPriceIndex('orders', 'total_price', {
111
- * app_owner_percentage: 0.80,
112
- * platform_percentage: 0.20,
113
- * app_owner_address: 'celestia1abc...'
167
+ * await db.database().createWriteIndex('posts', 'author', {
168
+ * pricing_model: 'per_record',
169
+ * price_per_record: 500_000 // 0.50 USDC per write
114
170
  * });
115
171
  * ```
116
172
  */
117
- async createPriceIndex(
173
+ async createWriteIndex(
118
174
  collection: string,
119
175
  fieldName: string,
120
- config?: Partial<PriceConfig>
176
+ config: WriteIndexConfig,
177
+ opts?: { name?: string; storeValues?: boolean; uniqueConstraint?: boolean; sortEnabled?: boolean }
121
178
  ): Promise<Index> {
122
- const priceConfig: PriceConfig = {
123
- app_owner_percentage: config?.app_owner_percentage ?? 0.80,
124
- platform_percentage: config?.platform_percentage ?? 0.20,
125
- app_owner_address: config?.app_owner_address ?? ''
126
- };
127
-
128
179
  return this.createIndex({
129
- name: `${collection}_${fieldName}_price_index`,
180
+ name: opts?.name ?? `${collection}_${fieldName}_write_idx`,
130
181
  collection,
131
182
  field_name: fieldName,
132
183
  index_type: 'price',
133
- price_config: priceConfig
184
+ store_values: opts?.storeValues ?? true,
185
+ unique_constraint: opts?.uniqueConstraint ?? false,
186
+ sort_enabled: opts?.sortEnabled ?? true,
187
+ price_config: config,
188
+ });
189
+ }
190
+
191
+ /**
192
+ * Create a read-priced index.
193
+ *
194
+ * Charges readers a fee each time the index is hit during a query.
195
+ * Can be applied to any index type (btree, hash, fulltext).
196
+ *
197
+ * @param collection - Target collection name
198
+ * @param fieldName - Field to index
199
+ * @param config - Read pricing model and amounts (USDC base units, 6 decimals)
200
+ * @param opts - Optional: override index type (default btree), name, and other index options
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * await db.database().createReadIndex('articles', 'content', {
205
+ * pricing_model: 'per_access',
206
+ * price_per_access: 100_000 // 0.10 USDC per matched record
207
+ * }, { indexType: 'fulltext' });
208
+ * ```
209
+ */
210
+ async createReadIndex(
211
+ collection: string,
212
+ fieldName: string,
213
+ config: ReadIndexConfig,
214
+ opts?: { name?: string; indexType?: 'btree' | 'hash' | 'fulltext'; storeValues?: boolean; uniqueConstraint?: boolean; sortEnabled?: boolean }
215
+ ): Promise<Index> {
216
+ return this.createIndex({
217
+ name: opts?.name ?? `${collection}_${fieldName}_read_idx`,
218
+ collection,
219
+ field_name: fieldName,
220
+ index_type: opts?.indexType ?? 'btree',
221
+ store_values: opts?.storeValues ?? true,
222
+ unique_constraint: opts?.uniqueConstraint ?? false,
223
+ sort_enabled: opts?.sortEnabled ?? true,
224
+ read_price_config: config,
225
+ });
226
+ }
227
+
228
+ /**
229
+ * Create a creator-premium index.
230
+ *
231
+ * Routes a portion of write revenue directly to the content creator resolved
232
+ * from a field in each record. Creator gets 100% of the premium portion;
233
+ * the platform takes its 20% cut only from the base transaction.
234
+ *
235
+ * @param collection - Target collection name
236
+ * @param fieldName - Field to index
237
+ * @param config - Creator address resolution path, cut model, and cut value
238
+ * @param opts - Optional: override index type (default btree), name, and other index options
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * await db.database().createCreatorPremiumIndex('tracks', 'title', {
243
+ * creator_address_resolution: 'metadata.artist_address',
244
+ * creator_cut_model: 'per_value_percent',
245
+ * creator_cut_value: 10, // 10% of the price field
246
+ * value_field_name: 'price_usdc'
247
+ * });
248
+ * ```
249
+ */
250
+ async createCreatorPremiumIndex(
251
+ collection: string,
252
+ fieldName: string,
253
+ config: CreatorPremiumConfig,
254
+ opts?: { name?: string; indexType?: 'btree' | 'hash' | 'fulltext'; storeValues?: boolean; uniqueConstraint?: boolean; sortEnabled?: boolean }
255
+ ): Promise<Index> {
256
+ return this.createIndex({
257
+ name: opts?.name ?? `${collection}_${fieldName}_creator_idx`,
258
+ collection,
259
+ field_name: fieldName,
260
+ index_type: opts?.indexType ?? 'btree',
261
+ store_values: opts?.storeValues ?? true,
262
+ unique_constraint: opts?.uniqueConstraint ?? false,
263
+ sort_enabled: opts?.sortEnabled ?? true,
264
+ creator_premium_config: config,
134
265
  });
135
266
  }
136
267
 
@@ -148,9 +279,11 @@ export class DatabaseManager {
148
279
  }
149
280
 
150
281
  async queryView<T = any>(viewName: string, query: ViewQueryRequest = {}): Promise<ViewDataResponse<T>> {
282
+ // Server always requires `select` — default to empty object (return all fields)
283
+ const body = { select: {}, ...query };
151
284
  const response = await this.httpClient.post(
152
285
  `/api/views/${this.appId}/${viewName}/data`,
153
- query,
286
+ body,
154
287
  { headers: this.getHeaders() }
155
288
  );
156
289
  return response.data;
package/src/index.ts CHANGED
@@ -1,7 +1,21 @@
1
1
  // Main SDK exports
2
2
  export { OnDBClient } from './client';
3
3
  export { QueryBuilder } from './query-sdk';
4
- export { DatabaseManager, createDatabaseManager } from './database';
4
+ export {
5
+ DatabaseManager,
6
+ createDatabaseManager,
7
+ type Index,
8
+ type WriteIndexConfig,
9
+ type WritePricingModel,
10
+ type ReadIndexConfig,
11
+ type ReadPricingModel,
12
+ type CreatorPremiumConfig,
13
+ type CreatorCutModel,
14
+ IndexOptions,
15
+ MaterializedView,
16
+ ViewInfo,
17
+ ListViewsResponse,
18
+ } from './database';
5
19
 
6
20
  // Core type exports
7
21
  export type {
@@ -68,15 +82,7 @@ export type {
68
82
  PaymentMethod,
69
83
  } from './x402';
70
84
 
71
- // Database management type exports
72
- export type {
73
- Index,
74
- IndexOptions,
75
- PriceConfig,
76
- MaterializedView,
77
- ViewInfo,
78
- ListViewsResponse,
79
- } from './database';
85
+
80
86
 
81
87
  // Error exports
82
88
  export {
@@ -160,16 +160,26 @@ export class NestedFieldConditionBuilder {
160
160
  return this.cond('b64', value);
161
161
  }
162
162
 
163
- inDataset(dataset: string): LogicalOperator {
164
- return this.cond('inDataset', dataset);
163
+ /** Case-sensitive membership check — use this when exact casing matters. For case-insensitive use .in() */
164
+ inDataset(values: string[]): LogicalOperator {
165
+ return this.cond('inDataset', values as any);
165
166
  }
166
167
 
167
168
  inCountry(countryCode: string): LogicalOperator {
168
169
  return this.cond('inCountry', countryCode);
169
170
  }
170
171
 
171
- cidr(cidr: string): LogicalOperator {
172
- return this.cond('CIDR', cidr);
172
+ /**
173
+ * Checks whether the data IP falls within any of the given CIDR ranges.
174
+ * Always sends the "$cidr" alias — never "CIDR", which causes a stack overflow in Scepter.
175
+ */
176
+ cidr(ranges: string | string[]): LogicalOperator {
177
+ return this.cond('$cidr', (Array.isArray(ranges) ? ranges : [ranges]) as any);
178
+ }
179
+
180
+ /** Matches if the field value contains ANY of the given keywords (case-insensitive substring). */
181
+ keywords(keywords: string[]): LogicalOperator {
182
+ return this.cond('keywords', keywords as any);
173
183
  }
174
184
 
175
185
  // ===== CONVENIENCE =====