@cofhe/sdk 0.5.1 → 0.6.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 (47) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/adapters/test/ethers5.test.ts +1 -1
  3. package/adapters/test/ethers6.test.ts +1 -1
  4. package/adapters/test/wagmi.test.ts +1 -1
  5. package/chains/chains/hardhat.ts +3 -3
  6. package/core/consts.ts +0 -3
  7. package/core/decrypt/decryptForTxBuilder.ts +21 -0
  8. package/core/decrypt/decryptForViewBuilder.ts +19 -0
  9. package/core/decrypt/submitRetry.ts +126 -0
  10. package/core/decrypt/tnDecryptV2.ts +48 -53
  11. package/core/decrypt/tnSealOutputV2.ts +48 -54
  12. package/core/encrypt/cofheMocksZkVerifySign.ts +2 -2
  13. package/core/encrypt/encryptInputsBuilder.ts +46 -11
  14. package/core/encrypt/zkPackProveVerify.ts +3 -3
  15. package/core/index.ts +13 -1
  16. package/core/test/decryptBuilders.test.ts +28 -0
  17. package/core/test/encryptInputsBuilder.test.ts +35 -0
  18. package/core/test/pollCallbacks.test.ts +226 -0
  19. package/core/types.ts +65 -5
  20. package/dist/chains.cjs +3 -3
  21. package/dist/chains.js +1 -1
  22. package/dist/{chunk-4FP4V35O.js → chunk-ESMZCFJY.js} +1 -2
  23. package/dist/{chunk-TBLR7NNE.js → chunk-MTRAXQXC.js} +3 -3
  24. package/dist/{chunk-S7OKGLFD.js → chunk-PE5V5CCV.js} +288 -153
  25. package/dist/{chunk-MRCKUMOS.js → chunk-VB62WYPL.js} +1 -1
  26. package/dist/{clientTypes-BSbwairE.d.cts → clientTypes-BDy1qIBu.d.cts} +78 -11
  27. package/dist/{clientTypes-DDmcgZ0a.d.ts → clientTypes-CyUvRRzA.d.ts} +78 -11
  28. package/dist/core.cjs +288 -155
  29. package/dist/core.d.cts +3 -5
  30. package/dist/core.d.ts +3 -5
  31. package/dist/core.js +4 -4
  32. package/dist/node.cjs +243 -108
  33. package/dist/node.d.cts +1 -1
  34. package/dist/node.d.ts +1 -1
  35. package/dist/node.js +4 -4
  36. package/dist/permits.d.cts +10 -6
  37. package/dist/permits.d.ts +10 -6
  38. package/dist/permits.js +2 -2
  39. package/dist/web.cjs +243 -108
  40. package/dist/web.d.cts +1 -1
  41. package/dist/web.d.ts +1 -1
  42. package/dist/web.js +4 -4
  43. package/dist/zkProve.worker.js +1 -1
  44. package/package.json +2 -2
  45. package/permits/store.ts +1 -0
  46. package/web/test/ssr.test.ts +23 -0
  47. package/web/test/tfheinit.web.test.ts +81 -5
package/dist/core.cjs CHANGED
@@ -16,51 +16,51 @@ var nacl__default = /*#__PURE__*/_interopDefault(nacl);
16
16
  // core/client.ts
17
17
 
18
18
  // core/error.ts
19
- var CofheErrorCode = /* @__PURE__ */ ((CofheErrorCode2) => {
20
- CofheErrorCode2["InternalError"] = "INTERNAL_ERROR";
21
- CofheErrorCode2["UnknownEnvironment"] = "UNKNOWN_ENVIRONMENT";
22
- CofheErrorCode2["InitTfheFailed"] = "INIT_TFHE_FAILED";
23
- CofheErrorCode2["InitViemFailed"] = "INIT_VIEM_FAILED";
24
- CofheErrorCode2["InitEthersFailed"] = "INIT_ETHERS_FAILED";
25
- CofheErrorCode2["NotConnected"] = "NOT_CONNECTED";
26
- CofheErrorCode2["MissingPublicClient"] = "MISSING_PUBLIC_CLIENT";
27
- CofheErrorCode2["MissingWalletClient"] = "MISSING_WALLET_CLIENT";
28
- CofheErrorCode2["MissingProviderParam"] = "MISSING_PROVIDER_PARAM";
29
- CofheErrorCode2["EmptySecurityZonesParam"] = "EMPTY_SECURITY_ZONES_PARAM";
30
- CofheErrorCode2["InvalidPermitData"] = "INVALID_PERMIT_DATA";
31
- CofheErrorCode2["InvalidPermitDomain"] = "INVALID_PERMIT_DOMAIN";
32
- CofheErrorCode2["PermitNotFound"] = "PERMIT_NOT_FOUND";
33
- CofheErrorCode2["CannotRemoveLastPermit"] = "CANNOT_REMOVE_LAST_PERMIT";
34
- CofheErrorCode2["AccountUninitialized"] = "ACCOUNT_UNINITIALIZED";
35
- CofheErrorCode2["ChainIdUninitialized"] = "CHAIN_ID_UNINITIALIZED";
36
- CofheErrorCode2["SealOutputFailed"] = "SEAL_OUTPUT_FAILED";
37
- CofheErrorCode2["SealOutputReturnedNull"] = "SEAL_OUTPUT_RETURNED_NULL";
38
- CofheErrorCode2["InvalidUtype"] = "INVALID_UTYPE";
39
- CofheErrorCode2["DecryptFailed"] = "DECRYPT_FAILED";
40
- CofheErrorCode2["DecryptReturnedNull"] = "DECRYPT_RETURNED_NULL";
41
- CofheErrorCode2["ZkMocksInsertCtHashesFailed"] = "ZK_MOCKS_INSERT_CT_HASHES_FAILED";
42
- CofheErrorCode2["ZkMocksCalcCtHashesFailed"] = "ZK_MOCKS_CALC_CT_HASHES_FAILED";
43
- CofheErrorCode2["ZkMocksVerifySignFailed"] = "ZK_MOCKS_VERIFY_SIGN_FAILED";
44
- CofheErrorCode2["ZkMocksCreateProofSignatureFailed"] = "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED";
45
- CofheErrorCode2["ZkVerifyFailed"] = "ZK_VERIFY_FAILED";
46
- CofheErrorCode2["ZkPackFailed"] = "ZK_PACK_FAILED";
47
- CofheErrorCode2["ZkProveFailed"] = "ZK_PROVE_FAILED";
48
- CofheErrorCode2["EncryptRemainingInItems"] = "ENCRYPT_REMAINING_IN_ITEMS";
49
- CofheErrorCode2["ZkUninitialized"] = "ZK_UNINITIALIZED";
50
- CofheErrorCode2["ZkVerifierUrlUninitialized"] = "ZK_VERIFIER_URL_UNINITIALIZED";
51
- CofheErrorCode2["ThresholdNetworkUrlUninitialized"] = "THRESHOLD_NETWORK_URL_UNINITIALIZED";
52
- CofheErrorCode2["MissingConfig"] = "MISSING_CONFIG";
53
- CofheErrorCode2["UnsupportedChain"] = "UNSUPPORTED_CHAIN";
54
- CofheErrorCode2["MissingZkBuilderAndCrsGenerator"] = "MISSING_ZK_BUILDER_AND_CRS_GENERATOR";
55
- CofheErrorCode2["MissingTfhePublicKeyDeserializer"] = "MISSING_TFHE_PUBLIC_KEY_DESERIALIZER";
56
- CofheErrorCode2["MissingCompactPkeCrsDeserializer"] = "MISSING_COMPACT_PKE_CRS_DESERIALIZER";
57
- CofheErrorCode2["MissingFheKey"] = "MISSING_FHE_KEY";
58
- CofheErrorCode2["MissingCrs"] = "MISSING_CRS";
59
- CofheErrorCode2["FetchKeysFailed"] = "FETCH_KEYS_FAILED";
60
- CofheErrorCode2["PublicWalletGetChainIdFailed"] = "PUBLIC_WALLET_GET_CHAIN_ID_FAILED";
61
- CofheErrorCode2["PublicWalletGetAddressesFailed"] = "PUBLIC_WALLET_GET_ADDRESSES_FAILED";
62
- CofheErrorCode2["RehydrateKeysStoreFailed"] = "REHYDRATE_KEYS_STORE_FAILED";
63
- return CofheErrorCode2;
19
+ var CofheErrorCode = /* @__PURE__ */ ((CofheErrorCode3) => {
20
+ CofheErrorCode3["InternalError"] = "INTERNAL_ERROR";
21
+ CofheErrorCode3["UnknownEnvironment"] = "UNKNOWN_ENVIRONMENT";
22
+ CofheErrorCode3["InitTfheFailed"] = "INIT_TFHE_FAILED";
23
+ CofheErrorCode3["InitViemFailed"] = "INIT_VIEM_FAILED";
24
+ CofheErrorCode3["InitEthersFailed"] = "INIT_ETHERS_FAILED";
25
+ CofheErrorCode3["NotConnected"] = "NOT_CONNECTED";
26
+ CofheErrorCode3["MissingPublicClient"] = "MISSING_PUBLIC_CLIENT";
27
+ CofheErrorCode3["MissingWalletClient"] = "MISSING_WALLET_CLIENT";
28
+ CofheErrorCode3["MissingProviderParam"] = "MISSING_PROVIDER_PARAM";
29
+ CofheErrorCode3["EmptySecurityZonesParam"] = "EMPTY_SECURITY_ZONES_PARAM";
30
+ CofheErrorCode3["InvalidPermitData"] = "INVALID_PERMIT_DATA";
31
+ CofheErrorCode3["InvalidPermitDomain"] = "INVALID_PERMIT_DOMAIN";
32
+ CofheErrorCode3["PermitNotFound"] = "PERMIT_NOT_FOUND";
33
+ CofheErrorCode3["CannotRemoveLastPermit"] = "CANNOT_REMOVE_LAST_PERMIT";
34
+ CofheErrorCode3["AccountUninitialized"] = "ACCOUNT_UNINITIALIZED";
35
+ CofheErrorCode3["ChainIdUninitialized"] = "CHAIN_ID_UNINITIALIZED";
36
+ CofheErrorCode3["SealOutputFailed"] = "SEAL_OUTPUT_FAILED";
37
+ CofheErrorCode3["SealOutputReturnedNull"] = "SEAL_OUTPUT_RETURNED_NULL";
38
+ CofheErrorCode3["InvalidUtype"] = "INVALID_UTYPE";
39
+ CofheErrorCode3["DecryptFailed"] = "DECRYPT_FAILED";
40
+ CofheErrorCode3["DecryptReturnedNull"] = "DECRYPT_RETURNED_NULL";
41
+ CofheErrorCode3["ZkMocksInsertCtHashesFailed"] = "ZK_MOCKS_INSERT_CT_HASHES_FAILED";
42
+ CofheErrorCode3["ZkMocksCalcCtHashesFailed"] = "ZK_MOCKS_CALC_CT_HASHES_FAILED";
43
+ CofheErrorCode3["ZkMocksVerifySignFailed"] = "ZK_MOCKS_VERIFY_SIGN_FAILED";
44
+ CofheErrorCode3["ZkMocksCreateProofSignatureFailed"] = "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED";
45
+ CofheErrorCode3["ZkVerifyFailed"] = "ZK_VERIFY_FAILED";
46
+ CofheErrorCode3["ZkPackFailed"] = "ZK_PACK_FAILED";
47
+ CofheErrorCode3["ZkProveFailed"] = "ZK_PROVE_FAILED";
48
+ CofheErrorCode3["EncryptRemainingInItems"] = "ENCRYPT_REMAINING_IN_ITEMS";
49
+ CofheErrorCode3["ZkUninitialized"] = "ZK_UNINITIALIZED";
50
+ CofheErrorCode3["ZkVerifierUrlUninitialized"] = "ZK_VERIFIER_URL_UNINITIALIZED";
51
+ CofheErrorCode3["ThresholdNetworkUrlUninitialized"] = "THRESHOLD_NETWORK_URL_UNINITIALIZED";
52
+ CofheErrorCode3["MissingConfig"] = "MISSING_CONFIG";
53
+ CofheErrorCode3["UnsupportedChain"] = "UNSUPPORTED_CHAIN";
54
+ CofheErrorCode3["MissingZkBuilderAndCrsGenerator"] = "MISSING_ZK_BUILDER_AND_CRS_GENERATOR";
55
+ CofheErrorCode3["MissingTfhePublicKeyDeserializer"] = "MISSING_TFHE_PUBLIC_KEY_DESERIALIZER";
56
+ CofheErrorCode3["MissingCompactPkeCrsDeserializer"] = "MISSING_COMPACT_PKE_CRS_DESERIALIZER";
57
+ CofheErrorCode3["MissingFheKey"] = "MISSING_FHE_KEY";
58
+ CofheErrorCode3["MissingCrs"] = "MISSING_CRS";
59
+ CofheErrorCode3["FetchKeysFailed"] = "FETCH_KEYS_FAILED";
60
+ CofheErrorCode3["PublicWalletGetChainIdFailed"] = "PUBLIC_WALLET_GET_CHAIN_ID_FAILED";
61
+ CofheErrorCode3["PublicWalletGetAddressesFailed"] = "PUBLIC_WALLET_GET_ADDRESSES_FAILED";
62
+ CofheErrorCode3["RehydrateKeysStoreFailed"] = "REHYDRATE_KEYS_STORE_FAILED";
63
+ return CofheErrorCode3;
64
64
  })(CofheErrorCode || {});
65
65
  var CofheError = class _CofheError extends Error {
66
66
  code;
@@ -154,7 +154,6 @@ var isCofheError = (error) => error instanceof CofheError;
154
154
  var TASK_MANAGER_ADDRESS = "0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9";
155
155
  var MOCKS_ZK_VERIFIER_ADDRESS = "0x0000000000000000000000000000000000005001";
156
156
  var MOCKS_THRESHOLD_NETWORK_ADDRESS = "0x0000000000000000000000000000000000005002";
157
- var TEST_BED_ADDRESS = "0x0000000000000000000000000000000000005003";
158
157
  var MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = "0x6C8D7F768A6BB4AAFE85E8A2F5A9680355239C7E14646ED62B044E39DE154512";
159
158
  var MOCKS_ZK_VERIFIER_SIGNER_ADDRESS = "0x6E12D8C87503D4287c294f2Fdef96ACd9DFf6bd2";
160
159
  var MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d";
@@ -546,7 +545,7 @@ var zkVerify = async (verifierUrl, serializedBytes, address, securityZone, chain
546
545
  }
547
546
  };
548
547
  var concatSigRecid = (signature, recid) => {
549
- return signature + (recid + 27).toString(16).padStart(2, "0");
548
+ return `${signature}${(recid + 27).toString(16).padStart(2, "0")}`;
550
549
  };
551
550
 
552
551
  // core/encrypt/MockZkVerifierAbi.ts
@@ -878,9 +877,9 @@ var hardhat2 = defineChain({
878
877
  name: "Hardhat",
879
878
  network: "localhost",
880
879
  // These are unused in the mock environment
881
- coFheUrl: "http://127.0.0.1:8448",
882
- verifierUrl: "http://127.0.0.1:3001",
883
- thresholdNetworkUrl: "http://127.0.0.1:3000",
880
+ coFheUrl: "http://ignored-in-mock-environment",
881
+ verifierUrl: "http://ignored-in-mock-environment",
882
+ thresholdNetworkUrl: "http://ignored-in-mock-environment",
884
883
  environment: "MOCK"
885
884
  });
886
885
  var CofheConfigSchema = zod.z.object({
@@ -1269,6 +1268,7 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1269
1268
  securityZone;
1270
1269
  stepCallback;
1271
1270
  inputItems;
1271
+ hpp = false;
1272
1272
  zkvWalletClient;
1273
1273
  tfhePublicKeyDeserializer;
1274
1274
  compactPkeCrsDeserializer;
@@ -1398,6 +1398,20 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1398
1398
  getSecurityZone() {
1399
1399
  return this.securityZone;
1400
1400
  }
1401
+ /**
1402
+ * Example:
1403
+ * ```typescript
1404
+ * const encrypted = await encryptInputs([Encryptable.uint128(10n)])
1405
+ * .asHashPlusProof()
1406
+ * .execute();
1407
+ * ```
1408
+ *
1409
+ * @returns Chainable EncryptInputsBuilder instance that will return a HashPlusProofResult instead of an array of EncryptedItemInputs.
1410
+ */
1411
+ asHashPlusProof() {
1412
+ this.hpp = true;
1413
+ return this;
1414
+ }
1401
1415
  /**
1402
1416
  * @param useWorker - Whether to use Web Workers for ZK proof generation.
1403
1417
  *
@@ -1679,6 +1693,15 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1679
1693
  this.fireStepEnd("verify" /* Verify */);
1680
1694
  return encryptedInputs;
1681
1695
  }
1696
+ structsToHashPlusProof(inItems) {
1697
+ let hashes = [];
1698
+ let proof = "";
1699
+ for (const item of inItems) {
1700
+ hashes.push("0x" + item.ctHash.toString(16).padStart(64, "0"));
1701
+ proof += item.signature;
1702
+ }
1703
+ return [...hashes, proof];
1704
+ }
1682
1705
  /**
1683
1706
  * Final step of the encryption process. MUST BE CALLED LAST IN THE CHAIN.
1684
1707
  *
@@ -1699,9 +1722,14 @@ var EncryptInputsBuilder = class extends BaseBuilder {
1699
1722
  * @returns The encrypted inputs.
1700
1723
  */
1701
1724
  async execute() {
1725
+ let items;
1702
1726
  if (this.chainId === chains.hardhat.id)
1703
- return this.mocksExecute();
1704
- return this.productionExecute();
1727
+ items = await this.mocksExecute();
1728
+ else
1729
+ items = await this.productionExecute();
1730
+ if (this.hpp)
1731
+ return this.structsToHashPlusProof(items);
1732
+ return items;
1705
1733
  }
1706
1734
  };
1707
1735
 
@@ -3000,6 +3028,96 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
3000
3028
  return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
3001
3029
  }
3002
3030
 
3031
+ // core/decrypt/submitRetry.ts
3032
+ var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
3033
+ function isRetryableSubmitStatus(status) {
3034
+ return status === 204 || status === 404;
3035
+ }
3036
+ function normalize404RetryTimeoutMs(params) {
3037
+ const { timeoutMs, operationLabel, errorCode } = params;
3038
+ if (timeoutMs === void 0)
3039
+ return DEFAULT_404_RETRY_TIMEOUT_MS;
3040
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
3041
+ throw new CofheError({
3042
+ code: errorCode,
3043
+ message: `${operationLabel} submit 404 retry timeout must be a finite number greater than or equal to 0`,
3044
+ context: {
3045
+ timeoutMs
3046
+ }
3047
+ });
3048
+ }
3049
+ return timeoutMs;
3050
+ }
3051
+ async function classifySubmitResponse(params) {
3052
+ const { response, extractErrorMessage } = params;
3053
+ if (isRetryableSubmitStatus(response.status)) {
3054
+ return { kind: "retryable", status: response.status };
3055
+ }
3056
+ if (response.ok) {
3057
+ return { kind: "parse-json" };
3058
+ }
3059
+ let errorMessage = `HTTP ${response.status}`;
3060
+ try {
3061
+ const errorBody = await response.json();
3062
+ const maybeErrorMessage = extractErrorMessage?.(errorBody);
3063
+ if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
3064
+ errorMessage = maybeErrorMessage;
3065
+ } else if (errorBody && typeof errorBody === "object") {
3066
+ const defaultMessage = errorBody.error_message;
3067
+ const fallbackMessage = errorBody.message;
3068
+ if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
3069
+ errorMessage = defaultMessage;
3070
+ } else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
3071
+ errorMessage = fallbackMessage;
3072
+ }
3073
+ }
3074
+ } catch {
3075
+ errorMessage = response.statusText || errorMessage;
3076
+ }
3077
+ return { kind: "fatal-http", errorMessage };
3078
+ }
3079
+ function throwIfSubmitRetryTimedOut(params) {
3080
+ const {
3081
+ operationLabel,
3082
+ errorCode,
3083
+ status,
3084
+ elapsedMs,
3085
+ retry404TimeoutMs,
3086
+ overallTimeoutMs,
3087
+ thresholdNetworkUrl,
3088
+ body,
3089
+ attemptIndex
3090
+ } = params;
3091
+ if (status === 404 && elapsedMs > retry404TimeoutMs) {
3092
+ throw new CofheError({
3093
+ code: errorCode,
3094
+ message: `${operationLabel} submit retried 404 responses without receiving request_id for ${retry404TimeoutMs}ms`,
3095
+ hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
3096
+ context: {
3097
+ thresholdNetworkUrl,
3098
+ body,
3099
+ attemptIndex,
3100
+ timeoutMs: retry404TimeoutMs,
3101
+ status
3102
+ }
3103
+ });
3104
+ }
3105
+ if (elapsedMs > overallTimeoutMs) {
3106
+ throw new CofheError({
3107
+ code: errorCode,
3108
+ message: `${operationLabel} submit retried without receiving request_id for ${overallTimeoutMs}ms`,
3109
+ hint: "The ciphertext may still be propagating. Try again later.",
3110
+ context: {
3111
+ thresholdNetworkUrl,
3112
+ body,
3113
+ attemptIndex,
3114
+ timeoutMs: overallTimeoutMs,
3115
+ status
3116
+ }
3117
+ });
3118
+ }
3119
+ }
3120
+
3003
3121
  // core/decrypt/tnSealOutputV2.ts
3004
3122
  var POLL_INTERVAL_MS = 1e3;
3005
3123
  var POLL_MAX_INTERVAL_MS = 1e4;
@@ -3061,7 +3179,7 @@ function parseCompletedSealOutputResponse(params) {
3061
3179
  }
3062
3180
  return convertSealedData(sealed);
3063
3181
  }
3064
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
3182
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3065
3183
  const body = {
3066
3184
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3067
3185
  host_chain_id: chainId,
@@ -3091,17 +3209,11 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3091
3209
  }
3092
3210
  });
3093
3211
  }
3094
- if (!response.ok) {
3095
- let errorMessage = `HTTP ${response.status}`;
3096
- try {
3097
- const errorBody = await response.json();
3098
- errorMessage = errorBody.error_message || errorBody.message || errorMessage;
3099
- } catch {
3100
- errorMessage = response.statusText || errorMessage;
3101
- }
3212
+ const responseClassification = await classifySubmitResponse({ response });
3213
+ if (responseClassification.kind === "fatal-http") {
3102
3214
  throw new CofheError({
3103
3215
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3104
- message: `sealOutput request failed: ${errorMessage}`,
3216
+ message: `sealOutput request failed: ${responseClassification.errorMessage}`,
3105
3217
  hint: "Check the threshold network URL and request parameters.",
3106
3218
  context: {
3107
3219
  thresholdNetworkUrl,
@@ -3112,8 +3224,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3112
3224
  }
3113
3225
  });
3114
3226
  }
3115
- let submitResponse;
3116
- if (response.status !== 204) {
3227
+ if (responseClassification.kind === "parse-json") {
3228
+ let submitResponse;
3117
3229
  try {
3118
3230
  submitResponse = await response.json();
3119
3231
  } catch (e) {
@@ -3141,46 +3253,39 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3141
3253
  if (submitResponse.request_id) {
3142
3254
  return { kind: "request_id", requestId: submitResponse.request_id };
3143
3255
  }
3144
- }
3145
- if (response.status === 204) {
3146
- const elapsedMs = Date.now() - overallStartTime;
3147
- if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
3148
- throw new CofheError({
3149
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3150
- message: `sealOutput submit retried without receiving request_id for ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
3151
- hint: "The ciphertext may still be propagating. Try again later.",
3152
- context: {
3153
- thresholdNetworkUrl,
3154
- body,
3155
- attemptIndex,
3156
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
3157
- submitResponse,
3158
- status: response.status
3159
- }
3160
- });
3161
- }
3162
- onPoll?.({
3163
- operation: "sealoutput",
3164
- requestId: "",
3165
- attemptIndex,
3166
- elapsedMs,
3167
- intervalMs: SUBMIT_RETRY_INTERVAL_MS,
3168
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
3256
+ throw new CofheError({
3257
+ code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3258
+ message: `sealOutput submit response missing request_id`,
3259
+ context: {
3260
+ thresholdNetworkUrl,
3261
+ body,
3262
+ submitResponse,
3263
+ attemptIndex
3264
+ }
3169
3265
  });
3170
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
3171
- attemptIndex += 1;
3172
- continue;
3173
3266
  }
3174
- throw new CofheError({
3175
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3176
- message: `sealOutput submit response missing request_id`,
3177
- context: {
3178
- thresholdNetworkUrl,
3179
- body,
3180
- submitResponse,
3181
- attemptIndex
3182
- }
3267
+ const elapsedMs = Date.now() - overallStartTime;
3268
+ throwIfSubmitRetryTimedOut({
3269
+ operationLabel: "sealOutput",
3270
+ errorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3271
+ status: responseClassification.status,
3272
+ elapsedMs,
3273
+ retry404TimeoutMs,
3274
+ overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
3275
+ thresholdNetworkUrl,
3276
+ body,
3277
+ attemptIndex
3183
3278
  });
3279
+ onPoll?.({
3280
+ operation: "sealoutput",
3281
+ requestId: "",
3282
+ attemptIndex,
3283
+ elapsedMs,
3284
+ intervalMs: SUBMIT_RETRY_INTERVAL_MS,
3285
+ timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
3286
+ });
3287
+ await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
3288
+ attemptIndex += 1;
3184
3289
  }
3185
3290
  }
3186
3291
  async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
@@ -3295,7 +3400,12 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3295
3400
  });
3296
3401
  }
3297
3402
  async function tnSealOutputV2(params) {
3298
- const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
3403
+ const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
3404
+ const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3405
+ timeoutMs: retry404TimeoutMs,
3406
+ operationLabel: "sealOutput",
3407
+ errorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
3408
+ });
3299
3409
  const overallStartTime = Date.now();
3300
3410
  const submitResult = await submitSealOutputRequest(
3301
3411
  thresholdNetworkUrl,
@@ -3303,6 +3413,7 @@ async function tnSealOutputV2(params) {
3303
3413
  chainId,
3304
3414
  permission,
3305
3415
  overallStartTime,
3416
+ normalized404RetryTimeoutMs,
3306
3417
  onPoll
3307
3418
  );
3308
3419
  if (submitResult.kind === "completed") {
@@ -3312,12 +3423,14 @@ async function tnSealOutputV2(params) {
3312
3423
  }
3313
3424
 
3314
3425
  // core/decrypt/decryptForViewBuilder.ts
3426
+ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
3315
3427
  var DecryptForViewBuilder = class extends BaseBuilder {
3316
3428
  ctHash;
3317
3429
  utype;
3318
3430
  permitHash;
3319
3431
  permit;
3320
3432
  pollCallback;
3433
+ retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
3321
3434
  constructor(params) {
3322
3435
  super({
3323
3436
  config: params.config,
@@ -3378,6 +3491,19 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3378
3491
  this.pollCallback = callback;
3379
3492
  return this;
3380
3493
  }
3494
+ set404RetryTimeout(timeoutMs) {
3495
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
3496
+ throw new CofheError({
3497
+ code: "INTERNAL_ERROR" /* InternalError */,
3498
+ message: "decryptForView: set404RetryTimeout(timeoutMs) expects a finite number greater than or equal to 0.",
3499
+ context: {
3500
+ timeoutMs
3501
+ }
3502
+ });
3503
+ }
3504
+ this.retry404TimeoutMs = timeoutMs;
3505
+ return this;
3506
+ }
3381
3507
  withPermit(permitOrPermitHash) {
3382
3508
  if (typeof permitOrPermitHash === "string") {
3383
3509
  this.permitHash = permitOrPermitHash;
@@ -3506,6 +3632,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3506
3632
  chainId: this.chainId,
3507
3633
  permission,
3508
3634
  thresholdNetworkUrl,
3635
+ retry404TimeoutMs: this.retry404TimeoutMs,
3509
3636
  onPoll: this.pollCallback
3510
3637
  });
3511
3638
  return PermitUtils.unseal(permit, sealed);
@@ -3781,7 +3908,7 @@ function assertDecryptStatusResponseV2(value) {
3781
3908
  }
3782
3909
  return value;
3783
3910
  }
3784
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
3911
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3785
3912
  const body = {
3786
3913
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3787
3914
  host_chain_id: chainId
@@ -3813,19 +3940,11 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3813
3940
  }
3814
3941
  });
3815
3942
  }
3816
- if (!response.ok) {
3817
- let errorMessage = `HTTP ${response.status}`;
3818
- try {
3819
- const errorBody = await response.json();
3820
- const maybeMessage = errorBody.error_message || errorBody.message;
3821
- if (typeof maybeMessage === "string" && maybeMessage.length > 0)
3822
- errorMessage = maybeMessage;
3823
- } catch {
3824
- errorMessage = response.statusText || errorMessage;
3825
- }
3943
+ const responseClassification = await classifySubmitResponse({ response });
3944
+ if (responseClassification.kind === "fatal-http") {
3826
3945
  throw new CofheError({
3827
3946
  code: "DECRYPT_FAILED" /* DecryptFailed */,
3828
- message: `decrypt request failed: ${errorMessage}`,
3947
+ message: `decrypt request failed: ${responseClassification.errorMessage}`,
3829
3948
  hint: "Check the threshold network URL and request parameters.",
3830
3949
  context: {
3831
3950
  thresholdNetworkUrl,
@@ -3836,8 +3955,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3836
3955
  }
3837
3956
  });
3838
3957
  }
3839
- let submitResponse;
3840
- if (response.status !== 204) {
3958
+ if (responseClassification.kind === "parse-json") {
3959
+ let submitResponse;
3841
3960
  let rawJson;
3842
3961
  try {
3843
3962
  rawJson = await response.json();
@@ -3867,46 +3986,39 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3867
3986
  if (submitResponse.request_id) {
3868
3987
  return { kind: "request_id", requestId: submitResponse.request_id };
3869
3988
  }
3870
- }
3871
- if (response.status === 204) {
3872
- const elapsedMs = Date.now() - overallStartTime;
3873
- if (elapsedMs > DECRYPT_TIMEOUT_MS) {
3874
- throw new CofheError({
3875
- code: "DECRYPT_FAILED" /* DecryptFailed */,
3876
- message: `decrypt submit retried without receiving request_id for ${DECRYPT_TIMEOUT_MS}ms`,
3877
- hint: "The ciphertext may still be propagating. Try again later.",
3878
- context: {
3879
- thresholdNetworkUrl,
3880
- body,
3881
- attemptIndex,
3882
- timeoutMs: DECRYPT_TIMEOUT_MS,
3883
- submitResponse,
3884
- status: response.status
3885
- }
3886
- });
3887
- }
3888
- onPoll?.({
3889
- operation: "decrypt",
3890
- requestId: "",
3891
- attemptIndex,
3892
- elapsedMs,
3893
- intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
3894
- timeoutMs: DECRYPT_TIMEOUT_MS
3989
+ throw new CofheError({
3990
+ code: "DECRYPT_FAILED" /* DecryptFailed */,
3991
+ message: `decrypt submit response missing request_id`,
3992
+ context: {
3993
+ thresholdNetworkUrl,
3994
+ body,
3995
+ submitResponse,
3996
+ attemptIndex
3997
+ }
3895
3998
  });
3896
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
3897
- attemptIndex += 1;
3898
- continue;
3899
3999
  }
3900
- throw new CofheError({
3901
- code: "DECRYPT_FAILED" /* DecryptFailed */,
3902
- message: `decrypt submit response missing request_id`,
3903
- context: {
3904
- thresholdNetworkUrl,
3905
- body,
3906
- submitResponse,
3907
- attemptIndex
3908
- }
4000
+ const elapsedMs = Date.now() - overallStartTime;
4001
+ throwIfSubmitRetryTimedOut({
4002
+ operationLabel: "decrypt",
4003
+ errorCode: "DECRYPT_FAILED" /* DecryptFailed */,
4004
+ status: responseClassification.status,
4005
+ elapsedMs,
4006
+ retry404TimeoutMs,
4007
+ overallTimeoutMs: DECRYPT_TIMEOUT_MS,
4008
+ thresholdNetworkUrl,
4009
+ body,
4010
+ attemptIndex
3909
4011
  });
4012
+ onPoll?.({
4013
+ operation: "decrypt",
4014
+ requestId: "",
4015
+ attemptIndex,
4016
+ elapsedMs,
4017
+ intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
4018
+ timeoutMs: DECRYPT_TIMEOUT_MS
4019
+ });
4020
+ await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
4021
+ attemptIndex += 1;
3910
4022
  }
3911
4023
  }
3912
4024
  async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
@@ -4024,7 +4136,12 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
4024
4136
  });
4025
4137
  }
4026
4138
  async function tnDecryptV2(params) {
4027
- const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
4139
+ const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
4140
+ const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4141
+ timeoutMs: retry404TimeoutMs,
4142
+ operationLabel: "decrypt",
4143
+ errorCode: "DECRYPT_FAILED" /* DecryptFailed */
4144
+ });
4028
4145
  const overallStartTime = Date.now();
4029
4146
  const submitResult = await submitDecryptRequestV2(
4030
4147
  thresholdNetworkUrl,
@@ -4032,6 +4149,7 @@ async function tnDecryptV2(params) {
4032
4149
  chainId,
4033
4150
  permission,
4034
4151
  overallStartTime,
4152
+ normalized404RetryTimeoutMs,
4035
4153
  onPoll
4036
4154
  );
4037
4155
  if (submitResult.kind === "completed") {
@@ -4041,12 +4159,14 @@ async function tnDecryptV2(params) {
4041
4159
  }
4042
4160
 
4043
4161
  // core/decrypt/decryptForTxBuilder.ts
4162
+ var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
4044
4163
  var DecryptForTxBuilder = class extends BaseBuilder {
4045
4164
  ctHash;
4046
4165
  permitHash;
4047
4166
  permit;
4048
4167
  permitSelection = "unset";
4049
4168
  pollCallback;
4169
+ retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
4050
4170
  constructor(params) {
4051
4171
  super({
4052
4172
  config: params.config,
@@ -4076,6 +4196,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4076
4196
  this.pollCallback = callback;
4077
4197
  return this;
4078
4198
  }
4199
+ set404RetryTimeout(timeoutMs) {
4200
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
4201
+ throw new CofheError({
4202
+ code: "INTERNAL_ERROR" /* InternalError */,
4203
+ message: "decryptForTx: set404RetryTimeout(timeoutMs) expects a finite number greater than or equal to 0.",
4204
+ context: {
4205
+ timeoutMs
4206
+ }
4207
+ });
4208
+ }
4209
+ this.retry404TimeoutMs = timeoutMs;
4210
+ return this;
4211
+ }
4079
4212
  withPermit(permitOrPermitHash) {
4080
4213
  if (this.permitSelection === "with-permit") {
4081
4214
  throw new CofheError({
@@ -4208,6 +4341,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4208
4341
  chainId: this.chainId,
4209
4342
  permission,
4210
4343
  thresholdNetworkUrl,
4344
+ retry404TimeoutMs: this.retry404TimeoutMs,
4211
4345
  onPoll: this.pollCallback
4212
4346
  });
4213
4347
  return {
@@ -4538,7 +4672,6 @@ exports.MOCKS_ZK_VERIFIER_ADDRESS = MOCKS_ZK_VERIFIER_ADDRESS;
4538
4672
  exports.MOCKS_ZK_VERIFIER_SIGNER_ADDRESS = MOCKS_ZK_VERIFIER_SIGNER_ADDRESS;
4539
4673
  exports.MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY = MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY;
4540
4674
  exports.TASK_MANAGER_ADDRESS = TASK_MANAGER_ADDRESS;
4541
- exports.TEST_BED_ADDRESS = TEST_BED_ADDRESS;
4542
4675
  exports.TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT = TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT;
4543
4676
  exports.TFHE_RS_ZK_MAX_BITS = TFHE_RS_ZK_MAX_BITS;
4544
4677
  exports.assertCorrectEncryptedItemInput = assertCorrectEncryptedItemInput;