web3ql-client 1.2.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 (86) hide show
  1. package/README.md +66 -0
  2. package/contracts/PublicKeyRegistry.sol +87 -0
  3. package/dist/src/access.d.ts +176 -0
  4. package/dist/src/access.d.ts.map +1 -0
  5. package/dist/src/access.js +283 -0
  6. package/dist/src/access.js.map +1 -0
  7. package/dist/src/batch.d.ts +107 -0
  8. package/dist/src/batch.d.ts.map +1 -0
  9. package/dist/src/batch.js +188 -0
  10. package/dist/src/batch.js.map +1 -0
  11. package/dist/src/cli.d.ts +40 -0
  12. package/dist/src/cli.d.ts.map +1 -0
  13. package/dist/src/cli.js +361 -0
  14. package/dist/src/cli.js.map +1 -0
  15. package/dist/src/constraints.d.ts +126 -0
  16. package/dist/src/constraints.d.ts.map +1 -0
  17. package/dist/src/constraints.js +192 -0
  18. package/dist/src/constraints.js.map +1 -0
  19. package/dist/src/crypto.d.ts +118 -0
  20. package/dist/src/crypto.d.ts.map +1 -0
  21. package/dist/src/crypto.js +192 -0
  22. package/dist/src/crypto.js.map +1 -0
  23. package/dist/src/factory-client.d.ts +106 -0
  24. package/dist/src/factory-client.d.ts.map +1 -0
  25. package/dist/src/factory-client.js +202 -0
  26. package/dist/src/factory-client.js.map +1 -0
  27. package/dist/src/index-cache.d.ts +156 -0
  28. package/dist/src/index-cache.d.ts.map +1 -0
  29. package/dist/src/index-cache.js +265 -0
  30. package/dist/src/index-cache.js.map +1 -0
  31. package/dist/src/index.d.ts +60 -0
  32. package/dist/src/index.d.ts.map +1 -0
  33. package/dist/src/index.js +60 -0
  34. package/dist/src/index.js.map +1 -0
  35. package/dist/src/migrations.d.ts +114 -0
  36. package/dist/src/migrations.d.ts.map +1 -0
  37. package/dist/src/migrations.js +173 -0
  38. package/dist/src/migrations.js.map +1 -0
  39. package/dist/src/model.d.ts +198 -0
  40. package/dist/src/model.d.ts.map +1 -0
  41. package/dist/src/model.js +379 -0
  42. package/dist/src/model.js.map +1 -0
  43. package/dist/src/query.d.ts +155 -0
  44. package/dist/src/query.d.ts.map +1 -0
  45. package/dist/src/query.js +386 -0
  46. package/dist/src/query.js.map +1 -0
  47. package/dist/src/registry.d.ts +45 -0
  48. package/dist/src/registry.d.ts.map +1 -0
  49. package/dist/src/registry.js +80 -0
  50. package/dist/src/registry.js.map +1 -0
  51. package/dist/src/schema-manager.d.ts +109 -0
  52. package/dist/src/schema-manager.d.ts.map +1 -0
  53. package/dist/src/schema-manager.js +259 -0
  54. package/dist/src/schema-manager.js.map +1 -0
  55. package/dist/src/table-client.d.ts +156 -0
  56. package/dist/src/table-client.d.ts.map +1 -0
  57. package/dist/src/table-client.js +292 -0
  58. package/dist/src/table-client.js.map +1 -0
  59. package/dist/src/typed-table.d.ts +159 -0
  60. package/dist/src/typed-table.d.ts.map +1 -0
  61. package/dist/src/typed-table.js +246 -0
  62. package/dist/src/typed-table.js.map +1 -0
  63. package/dist/src/types.d.ts +48 -0
  64. package/dist/src/types.d.ts.map +1 -0
  65. package/dist/src/types.js +222 -0
  66. package/dist/src/types.js.map +1 -0
  67. package/keyManager.js +337 -0
  68. package/package.json +38 -0
  69. package/src/access.ts +421 -0
  70. package/src/batch.ts +259 -0
  71. package/src/cli.ts +349 -0
  72. package/src/constraints.ts +283 -0
  73. package/src/crypto.ts +239 -0
  74. package/src/factory-client.ts +237 -0
  75. package/src/index-cache.ts +351 -0
  76. package/src/index.ts +171 -0
  77. package/src/migrations.ts +215 -0
  78. package/src/model.ts +538 -0
  79. package/src/query.ts +508 -0
  80. package/src/registry.ts +100 -0
  81. package/src/schema-manager.ts +301 -0
  82. package/src/table-client.ts +393 -0
  83. package/src/typed-table.ts +340 -0
  84. package/src/types.ts +284 -0
  85. package/tsconfig.json +22 -0
  86. package/walletUtils.js +204 -0
@@ -0,0 +1,292 @@
1
+ /**
2
+ * @file table-client.ts
3
+ * @notice Base encrypted table client.
4
+ *
5
+ * This class wraps a Web3QL table contract proxy and handles ALL
6
+ * encryption/decryption client-side. The chain only ever sees:
7
+ * • ciphertext blobs (AES-equivalent via NaCl secretbox)
8
+ * • per-user encrypted key blobs (NaCl box)
9
+ *
10
+ * Plaintext and symmetric keys never leave this class.
11
+ *
12
+ * Usage pattern:
13
+ * ─────────────────────────────────────────────────────────────
14
+ * const client = new EncryptedTableClient(tableAddress, signer, keypair);
15
+ *
16
+ * // Write — encrypts automatically
17
+ * await client.write(1n, JSON.stringify({ name: 'Alice' }));
18
+ *
19
+ * // Read — decrypts automatically
20
+ * const data = await client.read(1n); // '{"name":"Alice"}'
21
+ *
22
+ * // Share with Bob (needs Bob registered in registry)
23
+ * await client.share(1n, bobAddress, Role.VIEWER, registry);
24
+ *
25
+ * // Revoke
26
+ * await client.revoke(1n, bobAddress);
27
+ */
28
+ import { ethers } from 'ethers';
29
+ import { generateSymmetricKey, encryptData, decryptData, encryptKeyForSelf, encryptKeyForRecipient, decryptKeyForSelf, decryptKeyFromSender, } from './crypto.js';
30
+ // ─────────────────────────────────────────────────────────────
31
+ // Types
32
+ // ─────────────────────────────────────────────────────────────
33
+ export var Role;
34
+ (function (Role) {
35
+ Role[Role["VIEWER"] = 1] = "VIEWER";
36
+ Role[Role["EDITOR"] = 2] = "EDITOR";
37
+ })(Role || (Role = {}));
38
+ // ─────────────────────────────────────────────────────────────
39
+ // Minimal ABI — functions shared by all Web3QL table contracts
40
+ // ─────────────────────────────────────────────────────────────
41
+ const TABLE_ABI = [
42
+ // core
43
+ 'function write(bytes32 key, bytes calldata ciphertext, bytes calldata encryptedKey) external',
44
+ 'function read(bytes32 key) external view returns (bytes memory ciphertext, bool deleted, uint256 version, uint256 updatedAt, address owner)',
45
+ 'function update(bytes32 key, bytes calldata ciphertext, bytes calldata encryptedKey) external',
46
+ 'function deleteRecord(bytes32 key) external',
47
+ // key management
48
+ 'function getMyEncryptedKey(bytes32 key) external view returns (bytes memory)',
49
+ // access control
50
+ 'function grantAccess(bytes32 key, address user, uint8 role, bytes calldata encryptedKeyForUser) external',
51
+ 'function revokeAccess(bytes32 key, address user) external',
52
+ // views
53
+ 'function recordExists(bytes32 key) external view returns (bool)',
54
+ 'function recordOwner(bytes32 key) external view returns (address)',
55
+ 'function collaboratorCount(bytes32 key) external view returns (uint8)',
56
+ 'function getCollaborators(bytes32 key) external view returns (address[] memory)',
57
+ 'function getRole(bytes32 resource, address user) external view returns (uint8)',
58
+ // owner record enumeration
59
+ 'function ownerRecordCount(address addr) external view returns (uint256)',
60
+ 'function getOwnerRecords(address addr, uint256 start, uint256 limit) external view returns (bytes32[] memory)',
61
+ 'function getActiveOwnerRecords(address addr, uint256 start, uint256 limit) external view returns (bytes32[] memory)',
62
+ // table metadata
63
+ 'function tableName() external view returns (string memory)',
64
+ ];
65
+ // ─────────────────────────────────────────────────────────────
66
+ // EncryptedTableClient
67
+ // ─────────────────────────────────────────────────────────────
68
+ export class EncryptedTableClient {
69
+ tableAddress;
70
+ contract;
71
+ signer;
72
+ /** The caller's X25519 keypair — private key STAYS in memory only. */
73
+ keypair;
74
+ /** Shorthand for casting contract to any so strict index checks don't block calls. */
75
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
+ get c() { return this.contract; }
77
+ constructor(tableAddress, signer, keypair, abi = TABLE_ABI) {
78
+ this.tableAddress = tableAddress;
79
+ this.signer = signer;
80
+ this.keypair = keypair;
81
+ this.contract = new ethers.Contract(tableAddress, abi, signer);
82
+ }
83
+ // ── Key derivation ─────────────────────────────────────────
84
+ /**
85
+ * Derive the bytes32 on-chain record key from a table name + primary key.
86
+ * Canonical scheme: keccak256(abi.encodePacked(tableName, id))
87
+ * Matches the Solidity generator and connector — all three layers are aligned.
88
+ */
89
+ deriveKey(tableName, id) {
90
+ return ethers.solidityPackedKeccak256(['string', 'uint256'], [tableName, id]);
91
+ }
92
+ // ── Write ──────────────────────────────────────────────────
93
+ /**
94
+ * Encrypt `plaintext` and store it as a new record.
95
+ * The symmetric key is encrypted for the caller (owner).
96
+ *
97
+ * @param key bytes32 record key (use deriveKey or pass directly).
98
+ * @param plaintext Any data you want to store — string or raw bytes.
99
+ */
100
+ async writeRaw(key, plaintext) {
101
+ const data = toBytes(plaintext);
102
+ const symKey = generateSymmetricKey();
103
+ const ciphertext = encryptData(data, symKey);
104
+ const encryptedKey = encryptKeyForSelf(symKey, this.keypair);
105
+ const tx = await this.c.write(key, ciphertext, encryptedKey);
106
+ return tx.wait();
107
+ }
108
+ /**
109
+ * Encrypt `plaintext` for self — returns the raw ciphertext and
110
+ * encrypted symmetric key bytes WITHOUT submitting any transaction.
111
+ *
112
+ * Used by Model.relatedCreate() to hand the encrypted bytes to a
113
+ * RelationWire contract that will call table.write() on behalf of
114
+ * the user within an atomic transaction.
115
+ */
116
+ async encryptForSelf(plaintext) {
117
+ const data = toBytes(plaintext);
118
+ const symKey = generateSymmetricKey();
119
+ const ciphertext = encryptData(data, symKey);
120
+ const encryptedKey = encryptKeyForSelf(symKey, this.keypair);
121
+ return { ciphertext, encryptedKey };
122
+ }
123
+ // ── Read ───────────────────────────────────────────────────
124
+ /**
125
+ * Read and decrypt a record.
126
+ * Returns the plaintext as a UTF-8 string.
127
+ * Throws if the record is deleted, doesn't exist, or you lack access.
128
+ */
129
+ async readPlaintext(key) {
130
+ return new TextDecoder().decode(await this.readBytes(key));
131
+ }
132
+ /**
133
+ * Read and decrypt a record — returns raw bytes.
134
+ */
135
+ async readBytes(key) {
136
+ const raw = await this.readRaw(key);
137
+ const encKey = await this.getMyEncryptedKey(key);
138
+ const symKey = decryptKeyForSelf(encKey, this.keypair);
139
+ return decryptData(raw.ciphertext, symKey);
140
+ }
141
+ /**
142
+ * Get the raw (still-encrypted) record from chain.
143
+ */
144
+ async readRaw(key) {
145
+ const [ciphertext, deleted, version, updatedAt, owner] = await this.c.read(key);
146
+ if (deleted)
147
+ throw new Error(`EncryptedTableClient: record ${key} is deleted`);
148
+ return {
149
+ ciphertext: toUint8Array(ciphertext),
150
+ deleted,
151
+ version,
152
+ updatedAt,
153
+ owner,
154
+ };
155
+ }
156
+ // ── Update ─────────────────────────────────────────────────
157
+ /**
158
+ * Update an existing record with new plaintext.
159
+ * Re-encrypts with a FRESH symmetric key — old key copies are NOT
160
+ * automatically re-shared. Call reshareAfterUpdate() afterwards
161
+ * if collaborators need access to the updated version.
162
+ */
163
+ async updateRaw(key, plaintext) {
164
+ const data = toBytes(plaintext);
165
+ const symKey = generateSymmetricKey();
166
+ const ciphertext = encryptData(data, symKey);
167
+ const encryptedKey = encryptKeyForSelf(symKey, this.keypair);
168
+ const tx = await this.c.update(key, ciphertext, encryptedKey);
169
+ return tx.wait();
170
+ }
171
+ // ── Delete ─────────────────────────────────────────────────
172
+ /**
173
+ * Delete a record. The contract scrubs ALL collaborator key copies
174
+ * on-chain. Ciphertext remains but is permanently unreadable by
175
+ * anyone (the symmetric key is gone).
176
+ */
177
+ async deleteRecord(key) {
178
+ const tx = await this.c.deleteRecord(key);
179
+ return tx.wait();
180
+ }
181
+ // ── Sharing ────────────────────────────────────────────────
182
+ /**
183
+ * Share a record with another user.
184
+ *
185
+ * Flow:
186
+ * 1. Fetch caller's encrypted key from chain
187
+ * 2. Decrypt to recover the symmetric key (requires caller's privkey)
188
+ * 3. Fetch recipient's X25519 public key from the registry
189
+ * 4. Re-encrypt the symmetric key for the recipient
190
+ * 5. Call grantAccess on-chain with the new encrypted key copy
191
+ *
192
+ * @param key bytes32 record key
193
+ * @param recipient Address to share with
194
+ * @param role Role.VIEWER or Role.EDITOR
195
+ * @param registry PublicKeyRegistryClient to look up recipient's pubkey
196
+ */
197
+ async share(key, recipient, role, registry) {
198
+ // 1. Get our own encrypted key copy from chain
199
+ const myEncKey = await this.getMyEncryptedKey(key);
200
+ // 2. Decrypt to get the plain symmetric key
201
+ const symKey = decryptKeyForSelf(myEncKey, this.keypair);
202
+ // 3. Look up recipient's public key from registry
203
+ const recipientPubKey = await registry.getPublicKey(recipient);
204
+ // 4. Re-encrypt the symmetric key for the recipient
205
+ const recipientEncKey = encryptKeyForRecipient(symKey, recipientPubKey, this.keypair.privateKey);
206
+ // 5. Grant access on-chain
207
+ const tx = await this.c.grantAccess(key, recipient, role, recipientEncKey);
208
+ return tx.wait();
209
+ }
210
+ /**
211
+ * Revoke a user's access. Their encrypted key copy is scrubbed
212
+ * on-chain — they can no longer decrypt the record.
213
+ * (They may have decrypted and cached it locally — that is a
214
+ * client-side concern, not something the chain can prevent.)
215
+ */
216
+ async revoke(key, user) {
217
+ const tx = await this.c.revokeAccess(key, user);
218
+ return tx.wait();
219
+ }
220
+ /**
221
+ * After updating a record (which rotates the key), re-share with
222
+ * all current collaborators so they can decrypt the new ciphertext.
223
+ *
224
+ * @param key bytes32 record key
225
+ * @param collaborators List of addresses to re-share with
226
+ * @param roles Role for each address (parallel array)
227
+ * @param registry PublicKeyRegistryClient
228
+ */
229
+ async reshareAfterUpdate(key, collaborators, roles, registry) {
230
+ if (collaborators.length !== roles.length) {
231
+ throw new Error('reshareAfterUpdate: collaborators and roles arrays must be same length');
232
+ }
233
+ for (let i = 0; i < collaborators.length; i++) {
234
+ await this.share(key, collaborators[i], roles[i], registry);
235
+ }
236
+ }
237
+ // ── Key helpers ────────────────────────────────────────────
238
+ /** Fetch this caller's encrypted key blob from chain (still encrypted). */
239
+ async getMyEncryptedKey(key) {
240
+ const hex = await this.c.getMyEncryptedKey(key);
241
+ return ethers.getBytes(hex);
242
+ }
243
+ /**
244
+ * Decrypt a symmetric key blob that was encrypted by a known sender
245
+ * (use when you are a collaborator, not the owner — the sender's
246
+ * public key must be passed explicitly).
247
+ */
248
+ decryptSharedKey(encryptedKey, senderPublicKey) {
249
+ return decryptKeyFromSender(encryptedKey, senderPublicKey, this.keypair.privateKey);
250
+ }
251
+ // ── Views ──────────────────────────────────────────────────
252
+ async exists(key) {
253
+ return this.c.recordExists(key);
254
+ }
255
+ async owner(key) {
256
+ return this.c.recordOwner(key);
257
+ }
258
+ async collaboratorCount(key) {
259
+ return Number(await this.c.collaboratorCount(key));
260
+ }
261
+ /** List bytes32 record keys owned by `addr` (paginated).
262
+ * Prefers getActiveOwnerRecords (skips deleted) when available;
263
+ * falls back to getOwnerRecords for older contract versions.
264
+ */
265
+ async listOwnerRecords(addr, start = 0n, limit = 50n) {
266
+ try {
267
+ return await this.c.getActiveOwnerRecords(addr, start, limit);
268
+ }
269
+ catch {
270
+ // Older contract without getActiveOwnerRecords — fall back
271
+ return this.c.getOwnerRecords(addr, start, limit);
272
+ }
273
+ }
274
+ /** Total number of records written by `addr` (including deleted). */
275
+ async ownerRecordCount(addr) {
276
+ return this.c.ownerRecordCount(addr);
277
+ }
278
+ }
279
+ // ─────────────────────────────────────────────────────────────
280
+ // Helpers
281
+ // ─────────────────────────────────────────────────────────────
282
+ function toBytes(data) {
283
+ if (typeof data === 'string')
284
+ return new TextEncoder().encode(data);
285
+ return data;
286
+ }
287
+ function toUint8Array(value) {
288
+ if (value instanceof Uint8Array)
289
+ return value;
290
+ return ethers.getBytes(value); // hex string
291
+ }
292
+ //# sourceMappingURL=table-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-client.js","sourceRoot":"","sources":["../../src/table-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * @file typed-table.ts
3
+ * @notice High-level Prisma-style API for Web3QL encrypted tables.
4
+ *
5
+ * v1.1 upgrades:
6
+ * • Optional SchemaDefinition support — auto validates, encodes, and decodes
7
+ * fields using the extended type system (TIMESTAMP, UUID, ENUM, DECIMAL, etc.)
8
+ * • NOT NULL + DEFAULT enforcement on write
9
+ * • findMany with full query builder support: where/orderBy/limit/select/distinct
10
+ * • findAll — convenience method (fetches + decrypts all records in batches)
11
+ * • aggregate — COUNT/SUM/AVG/MIN/MAX over filtered decrypted records
12
+ * • seed — bulk insert an array of records
13
+ *
14
+ * Usage (basic, schema-less — identical to v1.0):
15
+ * ─────────────────────────────────────────────────────────────
16
+ * const users = new TypedTableClient<User>('users', db.table('0xTABLE'))
17
+ * await users.create(1n, { id: 1n, name: 'Alice' })
18
+ * const alice = await users.findUnique(1n)
19
+ *
20
+ * Usage (with schema for validation + type coercion):
21
+ * ─────────────────────────────────────────────────────────────
22
+ * const schema: SchemaDefinition = [
23
+ * { name: 'id', type: 'INT', primaryKey: true },
24
+ * { name: 'name', type: 'TEXT', notNull: true },
25
+ * { name: 'email', type: 'TEXT', notNull: true },
26
+ * { name: 'createdAt', type: 'TIMESTAMP', default: () => new Date() },
27
+ * { name: 'role', type: 'ENUM', enumValues: ['user','admin'], default: 'user' },
28
+ * ]
29
+ * const users = new TypedTableClient<User>('users', db.table('0xADDR'), schema)
30
+ *
31
+ * // findMany with query builder
32
+ * const admins = await users.findMany(ownerAddr, {
33
+ * where: [['role', 'eq', 'admin']],
34
+ * orderBy: [['createdAt', 'desc']],
35
+ * limit: 20,
36
+ * select: ['id', 'name', 'email'],
37
+ * })
38
+ * ─────────────────────────────────────────────────────────────
39
+ */
40
+ import { ethers } from 'ethers';
41
+ import type { EncryptedTableClient } from './table-client.js';
42
+ import { SchemaDefinition } from './types.js';
43
+ import { WhereOperator, SortDirection, AggregateOptions, AggregateResult } from './query.js';
44
+ export type { SchemaDefinition } from './types.js';
45
+ /** A single WHERE clause expressed as a tuple. */
46
+ export type WhereTuple = [field: string, op: 'isNull' | 'isNotNull'] | [field: string, op: 'in' | 'notIn', values: unknown[]] | [field: string, op: 'between', range: [unknown, unknown]] | [field: string, op: WhereOperator, value: unknown];
47
+ export interface FindManyOptions {
48
+ /**
49
+ * Starting index into the owner's record list when fetching from chain.
50
+ * Applied BEFORE client-side filtering — increase if paginating large tables.
51
+ * Default: 0.
52
+ */
53
+ chainOffset?: bigint;
54
+ /**
55
+ * Maximum records to fetch from chain per page.
56
+ * Default: 200 (raised from v1.0's 50 to allow client-side filtering).
57
+ */
58
+ chainLimit?: bigint;
59
+ /** WHERE conditions — ANDed together. Applied after decrypt. */
60
+ where?: WhereTuple[];
61
+ /** Sort order — applied after filtering. */
62
+ orderBy?: [field: string, dir?: SortDirection][];
63
+ /** Max records returned after filtering (client-side LIMIT). */
64
+ limit?: number;
65
+ /** Skip N records after filtering (client-side OFFSET). */
66
+ offset?: number;
67
+ /** Return only these fields. */
68
+ select?: string[];
69
+ /** Deduplicate on this field value. */
70
+ distinct?: string;
71
+ }
72
+ export interface RecordWithId<T> {
73
+ /**
74
+ * The uint256 primary key cannot be recovered from the on-chain bytes32 key alone
75
+ * (it is a keccak256 hash). This field is always `0n` when records are fetched via
76
+ * `findMany()`. Store the primary key inside your data payload and read it from
77
+ * `record.data.id` instead.
78
+ */
79
+ id: bigint;
80
+ /** Decrypted, typed record data. */
81
+ data: T;
82
+ /** bytes32 on-chain key (hex string). */
83
+ recordKey: string;
84
+ }
85
+ export declare class TypedTableClient<T extends Record<string, unknown>> {
86
+ private tableName;
87
+ private inner;
88
+ private schema?;
89
+ /**
90
+ * @param tableName Must match the name used in the SQL schema and createTable().
91
+ * @param inner An EncryptedTableClient from DatabaseClient.table(address).
92
+ * @param schema Optional field descriptors — enables validation, type coercion,
93
+ * NOT NULL enforcement, and DEFAULT values.
94
+ */
95
+ constructor(tableName: string, inner: EncryptedTableClient, schema?: SchemaDefinition);
96
+ /** Derive the canonical bytes32 on-chain key for a given primary key id. */
97
+ key(id: bigint): string;
98
+ private encode;
99
+ private decode;
100
+ /**
101
+ * Validate, encode, encrypt, and store a new record.
102
+ * Throws if a non-deleted record with the same id already exists.
103
+ */
104
+ create(id: bigint, data: T): Promise<ethers.TransactionReceipt>;
105
+ /**
106
+ * Bulk-insert an array of records. Each record must include the primary key field.
107
+ * Records are written sequentially — fails on first error.
108
+ */
109
+ seed(rows: {
110
+ id: bigint;
111
+ data: T;
112
+ }[]): Promise<ethers.TransactionReceipt[]>;
113
+ /**
114
+ * Read and decrypt a single record by primary key.
115
+ * Returns `null` if the record does not exist or has been deleted.
116
+ */
117
+ findUnique(id: bigint): Promise<T | null>;
118
+ /**
119
+ * List and decrypt all records owned by `ownerAddress`, with optional
120
+ * client-side filtering, sorting, pagination, and projection.
121
+ *
122
+ * ⚠ Records are decrypted client-side. Use `chainLimit` to constrain
123
+ * chain reads on large tables. For production scale, use the relay-
124
+ * maintained index endpoint (v1.2) instead.
125
+ */
126
+ findMany(ownerAddress: string, options?: FindManyOptions): Promise<RecordWithId<Partial<T>>[]>;
127
+ /**
128
+ * Convenience: fetch and decrypt ALL records the wallet owns (no chain limit).
129
+ * Useful for small tables or full exports. Decrypts in parallel batches of 20.
130
+ */
131
+ findAll(ownerAddress: string): Promise<RecordWithId<T>[]>;
132
+ /**
133
+ * Aggregate over owner's records: COUNT, SUM, AVG, MIN, MAX, GROUP BY.
134
+ *
135
+ * @example
136
+ * await users.aggregate(ownerAddress, { count: '*', groupBy: 'role' })
137
+ * // => [{ group: 'admin', count: 3 }, { group: 'user', count: 47 }]
138
+ */
139
+ aggregate(ownerAddress: string, opts: AggregateOptions, where?: WhereTuple[], chainLimit?: bigint): Promise<AggregateResult[]>;
140
+ /**
141
+ * Fetch existing data, merge with `patch`, re-encrypt, and update on-chain.
142
+ */
143
+ update(id: bigint, patch: Partial<T>): Promise<ethers.TransactionReceipt>;
144
+ /**
145
+ * Replace a record's data entirely (no merge).
146
+ * More gas-efficient when you have the full new payload ready.
147
+ */
148
+ replace(id: bigint, data: T): Promise<ethers.TransactionReceipt>;
149
+ /**
150
+ * Soft-delete a record. The symmetric key is scrubbed for all collaborators.
151
+ * Only the record owner can call this.
152
+ */
153
+ remove(id: bigint): Promise<ethers.TransactionReceipt>;
154
+ /** Total number of records ever written by `ownerAddress` (including deleted). */
155
+ count(ownerAddress: string): Promise<bigint>;
156
+ /** True if a live (non-deleted) record exists for the given id. */
157
+ exists(id: bigint): Promise<boolean>;
158
+ }
159
+ //# sourceMappingURL=typed-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-table.d.ts","sourceRoot":"","sources":["../../src/typed-table.ts"],"names":[],"mappings":"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"}