@orbinum/sdk 0.8.0 → 0.8.1

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/dist/index.d.mts CHANGED
@@ -844,18 +844,35 @@ declare class IndexerClient {
844
844
  * For the current Orbinum testnet/mainnet scale this is the recommended approach.
845
845
  */
846
846
  getAllSpentNullifiers(): Promise<Set<string>>;
847
+ /** Server-enforced max items per by-nullifiers / by-commitments request. */
848
+ private static readonly TRANSFER_LOOKUP_CHUNK;
849
+ /**
850
+ * Chunked fetch for the transfer timestamp lookups. The reader silently
851
+ * truncates each request to 50 items, so larger inputs MUST be split or
852
+ * results are silently lost. Responses are merged per extrinsic
853
+ * (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
854
+ * sorted by block descending.
855
+ *
856
+ * Privacy note: these lookups send the wallet's own note identifiers to
857
+ * the indexer — a bounded, documented linkage tradeoff for timestamp
858
+ * recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
859
+ * comes from the anonymous full-set `/shielded/nullifiers/all` download).
860
+ */
861
+ private fetchTransfersChunked;
847
862
  /**
848
863
  * Returns temporal metadata for private transfers that spent any of the given nullifiers.
849
864
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
850
865
  * between inputs and outputs to prevent graph reconstruction.
851
- * Accepts up to 50 nullifiers (0x-prefixed hex).
866
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
867
+ * and merged per extrinsic.
852
868
  */
853
869
  getTransfersByNullifiers(nullifiers: string[]): Promise<PrivateTransferTimestamp[]>;
854
870
  /**
855
871
  * Returns temporal metadata for private transfers that produced any of the given commitments.
856
872
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
857
873
  * between outputs and inputs to prevent graph reconstruction.
858
- * Accepts up to 50 commitments (0x-prefixed hex).
874
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
875
+ * and merged per extrinsic.
859
876
  */
860
877
  getTransfersByCommitments(commitments: string[]): Promise<PrivateTransferTimestamp[]>;
861
878
  /** Returns a paginated list of unshield events. */
package/dist/index.d.ts CHANGED
@@ -844,18 +844,35 @@ declare class IndexerClient {
844
844
  * For the current Orbinum testnet/mainnet scale this is the recommended approach.
845
845
  */
846
846
  getAllSpentNullifiers(): Promise<Set<string>>;
847
+ /** Server-enforced max items per by-nullifiers / by-commitments request. */
848
+ private static readonly TRANSFER_LOOKUP_CHUNK;
849
+ /**
850
+ * Chunked fetch for the transfer timestamp lookups. The reader silently
851
+ * truncates each request to 50 items, so larger inputs MUST be split or
852
+ * results are silently lost. Responses are merged per extrinsic
853
+ * (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
854
+ * sorted by block descending.
855
+ *
856
+ * Privacy note: these lookups send the wallet's own note identifiers to
857
+ * the indexer — a bounded, documented linkage tradeoff for timestamp
858
+ * recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
859
+ * comes from the anonymous full-set `/shielded/nullifiers/all` download).
860
+ */
861
+ private fetchTransfersChunked;
847
862
  /**
848
863
  * Returns temporal metadata for private transfers that spent any of the given nullifiers.
849
864
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
850
865
  * between inputs and outputs to prevent graph reconstruction.
851
- * Accepts up to 50 nullifiers (0x-prefixed hex).
866
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
867
+ * and merged per extrinsic.
852
868
  */
853
869
  getTransfersByNullifiers(nullifiers: string[]): Promise<PrivateTransferTimestamp[]>;
854
870
  /**
855
871
  * Returns temporal metadata for private transfers that produced any of the given commitments.
856
872
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
857
873
  * between outputs and inputs to prevent graph reconstruction.
858
- * Accepts up to 50 commitments (0x-prefixed hex).
874
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
875
+ * and merged per extrinsic.
859
876
  */
860
877
  getTransfersByCommitments(commitments: string[]): Promise<PrivateTransferTimestamp[]>;
861
878
  /** Returns a paginated list of unshield events. */
package/dist/index.js CHANGED
@@ -1147,7 +1147,7 @@ var EvmExplorer = class _EvmExplorer {
1147
1147
  };
1148
1148
 
1149
1149
  // src/indexer/IndexerClient.ts
1150
- var IndexerClient = class {
1150
+ var IndexerClient = class _IndexerClient {
1151
1151
  baseUrl;
1152
1152
  timeoutMs;
1153
1153
  constructor(config) {
@@ -1247,37 +1247,82 @@ var IndexerClient = class {
1247
1247
  return new Set(res.data.map((h) => h.toLowerCase()));
1248
1248
  }
1249
1249
  // ─── Private transfers ─────────────────────────────────────────────────────
1250
+ /** Server-enforced max items per by-nullifiers / by-commitments request. */
1251
+ static TRANSFER_LOOKUP_CHUNK = 50;
1252
+ /**
1253
+ * Chunked fetch for the transfer timestamp lookups. The reader silently
1254
+ * truncates each request to 50 items, so larger inputs MUST be split or
1255
+ * results are silently lost. Responses are merged per extrinsic
1256
+ * (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
1257
+ * sorted by block descending.
1258
+ *
1259
+ * Privacy note: these lookups send the wallet's own note identifiers to
1260
+ * the indexer — a bounded, documented linkage tradeoff for timestamp
1261
+ * recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
1262
+ * comes from the anonymous full-set `/shielded/nullifiers/all` download).
1263
+ */
1264
+ async fetchTransfersChunked(path, param, items, matchedField) {
1265
+ if (items.length === 0) return [];
1266
+ const normalized = items.map((i) => i.toLowerCase());
1267
+ const chunks = [];
1268
+ for (let i = 0; i < normalized.length; i += _IndexerClient.TRANSFER_LOOKUP_CHUNK) {
1269
+ chunks.push(normalized.slice(i, i + _IndexerClient.TRANSFER_LOOKUP_CHUNK));
1270
+ }
1271
+ const responses = await Promise.all(
1272
+ chunks.map((chunk) => {
1273
+ const qs = this.buildQuery({ [param]: chunk.join(",") });
1274
+ return this.get(
1275
+ `${path}${qs}`
1276
+ );
1277
+ })
1278
+ );
1279
+ const byExtrinsic = /* @__PURE__ */ new Map();
1280
+ for (const res of responses) {
1281
+ for (const transfer of res.data) {
1282
+ const key = `${transfer.blockNumber}:${transfer.extrinsicIndex ?? "null"}`;
1283
+ const existing = byExtrinsic.get(key);
1284
+ if (!existing) {
1285
+ byExtrinsic.set(key, transfer);
1286
+ continue;
1287
+ }
1288
+ const merged = /* @__PURE__ */ new Set([
1289
+ ...existing[matchedField] ?? [],
1290
+ ...transfer[matchedField] ?? []
1291
+ ]);
1292
+ existing[matchedField] = [...merged];
1293
+ }
1294
+ }
1295
+ return [...byExtrinsic.values()].sort((a, b) => b.blockNumber - a.blockNumber);
1296
+ }
1250
1297
  /**
1251
1298
  * Returns temporal metadata for private transfers that spent any of the given nullifiers.
1252
1299
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
1253
1300
  * between inputs and outputs to prevent graph reconstruction.
1254
- * Accepts up to 50 nullifiers (0x-prefixed hex).
1301
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
1302
+ * and merged per extrinsic.
1255
1303
  */
1256
1304
  async getTransfersByNullifiers(nullifiers) {
1257
- if (nullifiers.length === 0) return [];
1258
- const qs = this.buildQuery({
1259
- nullifiers: nullifiers.map((n) => n.toLowerCase()).join(",")
1260
- });
1261
- const res = await this.get(
1262
- `/shielded/transfers/by-nullifiers${qs}`
1305
+ return this.fetchTransfersChunked(
1306
+ "/shielded/transfers/by-nullifiers",
1307
+ "nullifiers",
1308
+ nullifiers,
1309
+ "matchedNullifiers"
1263
1310
  );
1264
- return res.data;
1265
1311
  }
1266
1312
  /**
1267
1313
  * Returns temporal metadata for private transfers that produced any of the given commitments.
1268
1314
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
1269
1315
  * between outputs and inputs to prevent graph reconstruction.
1270
- * Accepts up to 50 commitments (0x-prefixed hex).
1316
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
1317
+ * and merged per extrinsic.
1271
1318
  */
1272
1319
  async getTransfersByCommitments(commitments) {
1273
- if (commitments.length === 0) return [];
1274
- const qs = this.buildQuery({
1275
- commitments: commitments.map((c) => c.toLowerCase()).join(",")
1276
- });
1277
- const res = await this.get(
1278
- `/shielded/transfers/by-commitments${qs}`
1320
+ return this.fetchTransfersChunked(
1321
+ "/shielded/transfers/by-commitments",
1322
+ "commitments",
1323
+ commitments,
1324
+ "matchedCommitments"
1279
1325
  );
1280
- return res.data;
1281
1326
  }
1282
1327
  // ─── Unshields ─────────────────────────────────────────────────────────────
1283
1328
  /** Returns a paginated list of unshield events. */
package/dist/index.mjs CHANGED
@@ -1020,7 +1020,7 @@ var EvmExplorer = class _EvmExplorer {
1020
1020
  };
1021
1021
 
1022
1022
  // src/indexer/IndexerClient.ts
1023
- var IndexerClient = class {
1023
+ var IndexerClient = class _IndexerClient {
1024
1024
  baseUrl;
1025
1025
  timeoutMs;
1026
1026
  constructor(config) {
@@ -1120,37 +1120,82 @@ var IndexerClient = class {
1120
1120
  return new Set(res.data.map((h) => h.toLowerCase()));
1121
1121
  }
1122
1122
  // ─── Private transfers ─────────────────────────────────────────────────────
1123
+ /** Server-enforced max items per by-nullifiers / by-commitments request. */
1124
+ static TRANSFER_LOOKUP_CHUNK = 50;
1125
+ /**
1126
+ * Chunked fetch for the transfer timestamp lookups. The reader silently
1127
+ * truncates each request to 50 items, so larger inputs MUST be split or
1128
+ * results are silently lost. Responses are merged per extrinsic
1129
+ * (`blockNumber:extrinsicIndex`), concatenating the matched arrays, and
1130
+ * sorted by block descending.
1131
+ *
1132
+ * Privacy note: these lookups send the wallet's own note identifiers to
1133
+ * the indexer — a bounded, documented linkage tradeoff for timestamp
1134
+ * recovery. They are NEVER used for spent-STATUS checks (PIR-A: status
1135
+ * comes from the anonymous full-set `/shielded/nullifiers/all` download).
1136
+ */
1137
+ async fetchTransfersChunked(path, param, items, matchedField) {
1138
+ if (items.length === 0) return [];
1139
+ const normalized = items.map((i) => i.toLowerCase());
1140
+ const chunks = [];
1141
+ for (let i = 0; i < normalized.length; i += _IndexerClient.TRANSFER_LOOKUP_CHUNK) {
1142
+ chunks.push(normalized.slice(i, i + _IndexerClient.TRANSFER_LOOKUP_CHUNK));
1143
+ }
1144
+ const responses = await Promise.all(
1145
+ chunks.map((chunk) => {
1146
+ const qs = this.buildQuery({ [param]: chunk.join(",") });
1147
+ return this.get(
1148
+ `${path}${qs}`
1149
+ );
1150
+ })
1151
+ );
1152
+ const byExtrinsic = /* @__PURE__ */ new Map();
1153
+ for (const res of responses) {
1154
+ for (const transfer of res.data) {
1155
+ const key = `${transfer.blockNumber}:${transfer.extrinsicIndex ?? "null"}`;
1156
+ const existing = byExtrinsic.get(key);
1157
+ if (!existing) {
1158
+ byExtrinsic.set(key, transfer);
1159
+ continue;
1160
+ }
1161
+ const merged = /* @__PURE__ */ new Set([
1162
+ ...existing[matchedField] ?? [],
1163
+ ...transfer[matchedField] ?? []
1164
+ ]);
1165
+ existing[matchedField] = [...merged];
1166
+ }
1167
+ }
1168
+ return [...byExtrinsic.values()].sort((a, b) => b.blockNumber - a.blockNumber);
1169
+ }
1123
1170
  /**
1124
1171
  * Returns temporal metadata for private transfers that spent any of the given nullifiers.
1125
1172
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
1126
1173
  * between inputs and outputs to prevent graph reconstruction.
1127
- * Accepts up to 50 nullifiers (0x-prefixed hex).
1174
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
1175
+ * and merged per extrinsic.
1128
1176
  */
1129
1177
  async getTransfersByNullifiers(nullifiers) {
1130
- if (nullifiers.length === 0) return [];
1131
- const qs = this.buildQuery({
1132
- nullifiers: nullifiers.map((n) => n.toLowerCase()).join(",")
1133
- });
1134
- const res = await this.get(
1135
- `/shielded/transfers/by-nullifiers${qs}`
1178
+ return this.fetchTransfersChunked(
1179
+ "/shielded/transfers/by-nullifiers",
1180
+ "nullifiers",
1181
+ nullifiers,
1182
+ "matchedNullifiers"
1136
1183
  );
1137
- return res.data;
1138
1184
  }
1139
1185
  /**
1140
1186
  * Returns temporal metadata for private transfers that produced any of the given commitments.
1141
1187
  * Only blockNumber, extrinsicIndex, timestampMs, and hash are returned — no cross-link
1142
1188
  * between outputs and inputs to prevent graph reconstruction.
1143
- * Accepts up to 50 commitments (0x-prefixed hex).
1189
+ * Inputs of any size are transparently chunked into requests of 50 (the server cap)
1190
+ * and merged per extrinsic.
1144
1191
  */
1145
1192
  async getTransfersByCommitments(commitments) {
1146
- if (commitments.length === 0) return [];
1147
- const qs = this.buildQuery({
1148
- commitments: commitments.map((c) => c.toLowerCase()).join(",")
1149
- });
1150
- const res = await this.get(
1151
- `/shielded/transfers/by-commitments${qs}`
1193
+ return this.fetchTransfersChunked(
1194
+ "/shielded/transfers/by-commitments",
1195
+ "commitments",
1196
+ commitments,
1197
+ "matchedCommitments"
1152
1198
  );
1153
- return res.data;
1154
1199
  }
1155
1200
  // ─── Unshields ─────────────────────────────────────────────────────────────
1156
1201
  /** Returns a paginated list of unshield events. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orbinum/sdk",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Official TypeScript SDK for Orbinum.",
5
5
  "author": "Orbinum",
6
6
  "license": "MIT",