@cofhe/sdk 0.5.1 → 0.5.2

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/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;
@@ -3000,6 +3000,96 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
3000
3000
  return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
3001
3001
  }
3002
3002
 
3003
+ // core/decrypt/submitRetry.ts
3004
+ var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
3005
+ function isRetryableSubmitStatus(status) {
3006
+ return status === 204 || status === 404;
3007
+ }
3008
+ function normalize404RetryTimeoutMs(params) {
3009
+ const { timeoutMs, operationLabel, errorCode } = params;
3010
+ if (timeoutMs === void 0)
3011
+ return DEFAULT_404_RETRY_TIMEOUT_MS;
3012
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
3013
+ throw new CofheError({
3014
+ code: errorCode,
3015
+ message: `${operationLabel} submit 404 retry timeout must be a finite number greater than or equal to 0`,
3016
+ context: {
3017
+ timeoutMs
3018
+ }
3019
+ });
3020
+ }
3021
+ return timeoutMs;
3022
+ }
3023
+ async function classifySubmitResponse(params) {
3024
+ const { response, extractErrorMessage } = params;
3025
+ if (isRetryableSubmitStatus(response.status)) {
3026
+ return { kind: "retryable", status: response.status };
3027
+ }
3028
+ if (response.ok) {
3029
+ return { kind: "parse-json" };
3030
+ }
3031
+ let errorMessage = `HTTP ${response.status}`;
3032
+ try {
3033
+ const errorBody = await response.json();
3034
+ const maybeErrorMessage = extractErrorMessage?.(errorBody);
3035
+ if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
3036
+ errorMessage = maybeErrorMessage;
3037
+ } else if (errorBody && typeof errorBody === "object") {
3038
+ const defaultMessage = errorBody.error_message;
3039
+ const fallbackMessage = errorBody.message;
3040
+ if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
3041
+ errorMessage = defaultMessage;
3042
+ } else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
3043
+ errorMessage = fallbackMessage;
3044
+ }
3045
+ }
3046
+ } catch {
3047
+ errorMessage = response.statusText || errorMessage;
3048
+ }
3049
+ return { kind: "fatal-http", errorMessage };
3050
+ }
3051
+ function throwIfSubmitRetryTimedOut(params) {
3052
+ const {
3053
+ operationLabel,
3054
+ errorCode,
3055
+ status,
3056
+ elapsedMs,
3057
+ retry404TimeoutMs,
3058
+ overallTimeoutMs,
3059
+ thresholdNetworkUrl,
3060
+ body,
3061
+ attemptIndex
3062
+ } = params;
3063
+ if (status === 404 && elapsedMs > retry404TimeoutMs) {
3064
+ throw new CofheError({
3065
+ code: errorCode,
3066
+ message: `${operationLabel} submit retried 404 responses without receiving request_id for ${retry404TimeoutMs}ms`,
3067
+ hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
3068
+ context: {
3069
+ thresholdNetworkUrl,
3070
+ body,
3071
+ attemptIndex,
3072
+ timeoutMs: retry404TimeoutMs,
3073
+ status
3074
+ }
3075
+ });
3076
+ }
3077
+ if (elapsedMs > overallTimeoutMs) {
3078
+ throw new CofheError({
3079
+ code: errorCode,
3080
+ message: `${operationLabel} submit retried without receiving request_id for ${overallTimeoutMs}ms`,
3081
+ hint: "The ciphertext may still be propagating. Try again later.",
3082
+ context: {
3083
+ thresholdNetworkUrl,
3084
+ body,
3085
+ attemptIndex,
3086
+ timeoutMs: overallTimeoutMs,
3087
+ status
3088
+ }
3089
+ });
3090
+ }
3091
+ }
3092
+
3003
3093
  // core/decrypt/tnSealOutputV2.ts
3004
3094
  var POLL_INTERVAL_MS = 1e3;
3005
3095
  var POLL_MAX_INTERVAL_MS = 1e4;
@@ -3061,7 +3151,7 @@ function parseCompletedSealOutputResponse(params) {
3061
3151
  }
3062
3152
  return convertSealedData(sealed);
3063
3153
  }
3064
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
3154
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3065
3155
  const body = {
3066
3156
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3067
3157
  host_chain_id: chainId,
@@ -3091,17 +3181,11 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3091
3181
  }
3092
3182
  });
3093
3183
  }
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
- }
3184
+ const responseClassification = await classifySubmitResponse({ response });
3185
+ if (responseClassification.kind === "fatal-http") {
3102
3186
  throw new CofheError({
3103
3187
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3104
- message: `sealOutput request failed: ${errorMessage}`,
3188
+ message: `sealOutput request failed: ${responseClassification.errorMessage}`,
3105
3189
  hint: "Check the threshold network URL and request parameters.",
3106
3190
  context: {
3107
3191
  thresholdNetworkUrl,
@@ -3112,8 +3196,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3112
3196
  }
3113
3197
  });
3114
3198
  }
3115
- let submitResponse;
3116
- if (response.status !== 204) {
3199
+ if (responseClassification.kind === "parse-json") {
3200
+ let submitResponse;
3117
3201
  try {
3118
3202
  submitResponse = await response.json();
3119
3203
  } catch (e) {
@@ -3141,46 +3225,39 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
3141
3225
  if (submitResponse.request_id) {
3142
3226
  return { kind: "request_id", requestId: submitResponse.request_id };
3143
3227
  }
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
3228
+ throw new CofheError({
3229
+ code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3230
+ message: `sealOutput submit response missing request_id`,
3231
+ context: {
3232
+ thresholdNetworkUrl,
3233
+ body,
3234
+ submitResponse,
3235
+ attemptIndex
3236
+ }
3169
3237
  });
3170
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
3171
- attemptIndex += 1;
3172
- continue;
3173
3238
  }
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
- }
3239
+ const elapsedMs = Date.now() - overallStartTime;
3240
+ throwIfSubmitRetryTimedOut({
3241
+ operationLabel: "sealOutput",
3242
+ errorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3243
+ status: responseClassification.status,
3244
+ elapsedMs,
3245
+ retry404TimeoutMs,
3246
+ overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
3247
+ thresholdNetworkUrl,
3248
+ body,
3249
+ attemptIndex
3183
3250
  });
3251
+ onPoll?.({
3252
+ operation: "sealoutput",
3253
+ requestId: "",
3254
+ attemptIndex,
3255
+ elapsedMs,
3256
+ intervalMs: SUBMIT_RETRY_INTERVAL_MS,
3257
+ timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
3258
+ });
3259
+ await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
3260
+ attemptIndex += 1;
3184
3261
  }
3185
3262
  }
3186
3263
  async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
@@ -3295,7 +3372,12 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3295
3372
  });
3296
3373
  }
3297
3374
  async function tnSealOutputV2(params) {
3298
- const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
3375
+ const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
3376
+ const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3377
+ timeoutMs: retry404TimeoutMs,
3378
+ operationLabel: "sealOutput",
3379
+ errorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
3380
+ });
3299
3381
  const overallStartTime = Date.now();
3300
3382
  const submitResult = await submitSealOutputRequest(
3301
3383
  thresholdNetworkUrl,
@@ -3303,6 +3385,7 @@ async function tnSealOutputV2(params) {
3303
3385
  chainId,
3304
3386
  permission,
3305
3387
  overallStartTime,
3388
+ normalized404RetryTimeoutMs,
3306
3389
  onPoll
3307
3390
  );
3308
3391
  if (submitResult.kind === "completed") {
@@ -3312,12 +3395,14 @@ async function tnSealOutputV2(params) {
3312
3395
  }
3313
3396
 
3314
3397
  // core/decrypt/decryptForViewBuilder.ts
3398
+ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
3315
3399
  var DecryptForViewBuilder = class extends BaseBuilder {
3316
3400
  ctHash;
3317
3401
  utype;
3318
3402
  permitHash;
3319
3403
  permit;
3320
3404
  pollCallback;
3405
+ retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
3321
3406
  constructor(params) {
3322
3407
  super({
3323
3408
  config: params.config,
@@ -3378,6 +3463,19 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3378
3463
  this.pollCallback = callback;
3379
3464
  return this;
3380
3465
  }
3466
+ set404RetryTimeout(timeoutMs) {
3467
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
3468
+ throw new CofheError({
3469
+ code: "INTERNAL_ERROR" /* InternalError */,
3470
+ message: "decryptForView: set404RetryTimeout(timeoutMs) expects a finite number greater than or equal to 0.",
3471
+ context: {
3472
+ timeoutMs
3473
+ }
3474
+ });
3475
+ }
3476
+ this.retry404TimeoutMs = timeoutMs;
3477
+ return this;
3478
+ }
3381
3479
  withPermit(permitOrPermitHash) {
3382
3480
  if (typeof permitOrPermitHash === "string") {
3383
3481
  this.permitHash = permitOrPermitHash;
@@ -3506,6 +3604,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3506
3604
  chainId: this.chainId,
3507
3605
  permission,
3508
3606
  thresholdNetworkUrl,
3607
+ retry404TimeoutMs: this.retry404TimeoutMs,
3509
3608
  onPoll: this.pollCallback
3510
3609
  });
3511
3610
  return PermitUtils.unseal(permit, sealed);
@@ -3781,7 +3880,7 @@ function assertDecryptStatusResponseV2(value) {
3781
3880
  }
3782
3881
  return value;
3783
3882
  }
3784
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
3883
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3785
3884
  const body = {
3786
3885
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3787
3886
  host_chain_id: chainId
@@ -3813,19 +3912,11 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3813
3912
  }
3814
3913
  });
3815
3914
  }
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
- }
3915
+ const responseClassification = await classifySubmitResponse({ response });
3916
+ if (responseClassification.kind === "fatal-http") {
3826
3917
  throw new CofheError({
3827
3918
  code: "DECRYPT_FAILED" /* DecryptFailed */,
3828
- message: `decrypt request failed: ${errorMessage}`,
3919
+ message: `decrypt request failed: ${responseClassification.errorMessage}`,
3829
3920
  hint: "Check the threshold network URL and request parameters.",
3830
3921
  context: {
3831
3922
  thresholdNetworkUrl,
@@ -3836,8 +3927,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3836
3927
  }
3837
3928
  });
3838
3929
  }
3839
- let submitResponse;
3840
- if (response.status !== 204) {
3930
+ if (responseClassification.kind === "parse-json") {
3931
+ let submitResponse;
3841
3932
  let rawJson;
3842
3933
  try {
3843
3934
  rawJson = await response.json();
@@ -3867,46 +3958,39 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3867
3958
  if (submitResponse.request_id) {
3868
3959
  return { kind: "request_id", requestId: submitResponse.request_id };
3869
3960
  }
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
3961
+ throw new CofheError({
3962
+ code: "DECRYPT_FAILED" /* DecryptFailed */,
3963
+ message: `decrypt submit response missing request_id`,
3964
+ context: {
3965
+ thresholdNetworkUrl,
3966
+ body,
3967
+ submitResponse,
3968
+ attemptIndex
3969
+ }
3895
3970
  });
3896
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
3897
- attemptIndex += 1;
3898
- continue;
3899
3971
  }
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
- }
3972
+ const elapsedMs = Date.now() - overallStartTime;
3973
+ throwIfSubmitRetryTimedOut({
3974
+ operationLabel: "decrypt",
3975
+ errorCode: "DECRYPT_FAILED" /* DecryptFailed */,
3976
+ status: responseClassification.status,
3977
+ elapsedMs,
3978
+ retry404TimeoutMs,
3979
+ overallTimeoutMs: DECRYPT_TIMEOUT_MS,
3980
+ thresholdNetworkUrl,
3981
+ body,
3982
+ attemptIndex
3909
3983
  });
3984
+ onPoll?.({
3985
+ operation: "decrypt",
3986
+ requestId: "",
3987
+ attemptIndex,
3988
+ elapsedMs,
3989
+ intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
3990
+ timeoutMs: DECRYPT_TIMEOUT_MS
3991
+ });
3992
+ await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
3993
+ attemptIndex += 1;
3910
3994
  }
3911
3995
  }
3912
3996
  async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
@@ -4024,7 +4108,12 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
4024
4108
  });
4025
4109
  }
4026
4110
  async function tnDecryptV2(params) {
4027
- const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
4111
+ const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
4112
+ const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
4113
+ timeoutMs: retry404TimeoutMs,
4114
+ operationLabel: "decrypt",
4115
+ errorCode: "DECRYPT_FAILED" /* DecryptFailed */
4116
+ });
4028
4117
  const overallStartTime = Date.now();
4029
4118
  const submitResult = await submitDecryptRequestV2(
4030
4119
  thresholdNetworkUrl,
@@ -4032,6 +4121,7 @@ async function tnDecryptV2(params) {
4032
4121
  chainId,
4033
4122
  permission,
4034
4123
  overallStartTime,
4124
+ normalized404RetryTimeoutMs,
4035
4125
  onPoll
4036
4126
  );
4037
4127
  if (submitResult.kind === "completed") {
@@ -4041,12 +4131,14 @@ async function tnDecryptV2(params) {
4041
4131
  }
4042
4132
 
4043
4133
  // core/decrypt/decryptForTxBuilder.ts
4134
+ var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
4044
4135
  var DecryptForTxBuilder = class extends BaseBuilder {
4045
4136
  ctHash;
4046
4137
  permitHash;
4047
4138
  permit;
4048
4139
  permitSelection = "unset";
4049
4140
  pollCallback;
4141
+ retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
4050
4142
  constructor(params) {
4051
4143
  super({
4052
4144
  config: params.config,
@@ -4076,6 +4168,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4076
4168
  this.pollCallback = callback;
4077
4169
  return this;
4078
4170
  }
4171
+ set404RetryTimeout(timeoutMs) {
4172
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
4173
+ throw new CofheError({
4174
+ code: "INTERNAL_ERROR" /* InternalError */,
4175
+ message: "decryptForTx: set404RetryTimeout(timeoutMs) expects a finite number greater than or equal to 0.",
4176
+ context: {
4177
+ timeoutMs
4178
+ }
4179
+ });
4180
+ }
4181
+ this.retry404TimeoutMs = timeoutMs;
4182
+ return this;
4183
+ }
4079
4184
  withPermit(permitOrPermitHash) {
4080
4185
  if (this.permitSelection === "with-permit") {
4081
4186
  throw new CofheError({
@@ -4208,6 +4313,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4208
4313
  chainId: this.chainId,
4209
4314
  permission,
4210
4315
  thresholdNetworkUrl,
4316
+ retry404TimeoutMs: this.retry404TimeoutMs,
4211
4317
  onPoll: this.pollCallback
4212
4318
  });
4213
4319
  return {
package/dist/core.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-BSbwairE.cjs';
2
- export { h as CofheClientPermits, C as CofheInputConfig, f as CofheInternalConfig, G as DecryptEndpoint, $ as DecryptForTxBuilder, a0 as DecryptForTxResult, _ as DecryptForViewBuilder, B as DecryptPollCallbackContext, D as DecryptPollCallbackFunction, Z as EncryptInputsBuilder, H as EncryptSetStateFn, Q as EncryptStep, J as EncryptStepCallbackContext, N as Encryptable, o as EncryptableAddress, i as EncryptableBool, E as EncryptableItem, z as EncryptableToEncryptedItemInputMap, n as EncryptableUint128, k as EncryptableUint16, l as EncryptableUint32, m as EncryptableUint64, j as EncryptableUint8, x as EncryptedAddressInput, r as EncryptedBoolInput, q as EncryptedItemInput, y as EncryptedItemInputs, p as EncryptedNumber, w as EncryptedUint128Input, t as EncryptedUint16Input, u as EncryptedUint32Input, v as EncryptedUint64Input, s as EncryptedUint8Input, M as FheAllUTypes, V as FheKeyDeserializer, A as FheTypeValue, K as FheUintUTypes, I as IStorage, X as KeysStorage, Y as KeysStore, L as LiteralToPrimitive, P as Primitive, U as UnsealedItem, a1 as ZkBuilderAndCrsGenerator, a2 as ZkProveWorkerFunction, a3 as ZkProveWorkerRequest, a4 as ZkProveWorkerResponse, S as assertCorrectEncryptedItemInput, e as createCofheConfigBase, W as createKeysStore, T as fetchKeys, g as getCofheConfigItem, O as isEncryptableItem, R as isLastEncryptionStep, a5 as zkProveWithWorker } from './clientTypes-BSbwairE.cjs';
1
+ import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-BJbFeeno.cjs';
2
+ export { h as CofheClientPermits, C as CofheInputConfig, f as CofheInternalConfig, G as DecryptEndpoint, $ as DecryptForTxBuilder, a0 as DecryptForTxResult, _ as DecryptForViewBuilder, B as DecryptPollCallbackContext, D as DecryptPollCallbackFunction, Z as EncryptInputsBuilder, H as EncryptSetStateFn, Q as EncryptStep, J as EncryptStepCallbackContext, N as Encryptable, o as EncryptableAddress, i as EncryptableBool, E as EncryptableItem, z as EncryptableToEncryptedItemInputMap, n as EncryptableUint128, k as EncryptableUint16, l as EncryptableUint32, m as EncryptableUint64, j as EncryptableUint8, x as EncryptedAddressInput, r as EncryptedBoolInput, q as EncryptedItemInput, y as EncryptedItemInputs, p as EncryptedNumber, w as EncryptedUint128Input, t as EncryptedUint16Input, u as EncryptedUint32Input, v as EncryptedUint64Input, s as EncryptedUint8Input, M as FheAllUTypes, V as FheKeyDeserializer, A as FheTypeValue, K as FheUintUTypes, I as IStorage, X as KeysStorage, Y as KeysStore, L as LiteralToPrimitive, P as Primitive, U as UnsealedItem, a1 as ZkBuilderAndCrsGenerator, a2 as ZkProveWorkerFunction, a3 as ZkProveWorkerRequest, a4 as ZkProveWorkerResponse, S as assertCorrectEncryptedItemInput, e as createCofheConfigBase, W as createKeysStore, T as fetchKeys, g as getCofheConfigItem, O as isEncryptableItem, R as isLastEncryptionStep, a5 as zkProveWithWorker } from './clientTypes-BJbFeeno.cjs';
3
3
  import { Hex, PublicClient } from 'viem';
4
4
  import './types-C07FK-cL.cjs';
5
5
  import 'zod';
package/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-DDmcgZ0a.js';
2
- export { h as CofheClientPermits, C as CofheInputConfig, f as CofheInternalConfig, G as DecryptEndpoint, $ as DecryptForTxBuilder, a0 as DecryptForTxResult, _ as DecryptForViewBuilder, B as DecryptPollCallbackContext, D as DecryptPollCallbackFunction, Z as EncryptInputsBuilder, H as EncryptSetStateFn, Q as EncryptStep, J as EncryptStepCallbackContext, N as Encryptable, o as EncryptableAddress, i as EncryptableBool, E as EncryptableItem, z as EncryptableToEncryptedItemInputMap, n as EncryptableUint128, k as EncryptableUint16, l as EncryptableUint32, m as EncryptableUint64, j as EncryptableUint8, x as EncryptedAddressInput, r as EncryptedBoolInput, q as EncryptedItemInput, y as EncryptedItemInputs, p as EncryptedNumber, w as EncryptedUint128Input, t as EncryptedUint16Input, u as EncryptedUint32Input, v as EncryptedUint64Input, s as EncryptedUint8Input, M as FheAllUTypes, V as FheKeyDeserializer, A as FheTypeValue, K as FheUintUTypes, I as IStorage, X as KeysStorage, Y as KeysStore, L as LiteralToPrimitive, P as Primitive, U as UnsealedItem, a1 as ZkBuilderAndCrsGenerator, a2 as ZkProveWorkerFunction, a3 as ZkProveWorkerRequest, a4 as ZkProveWorkerResponse, S as assertCorrectEncryptedItemInput, e as createCofheConfigBase, W as createKeysStore, T as fetchKeys, g as getCofheConfigItem, O as isEncryptableItem, R as isLastEncryptionStep, a5 as zkProveWithWorker } from './clientTypes-DDmcgZ0a.js';
1
+ import { a as CofheConfig, c as CofheClientParams, b as CofheClient, d as CofheClientConnectionState, F as FheTypes } from './clientTypes-CEno_BEf.js';
2
+ export { h as CofheClientPermits, C as CofheInputConfig, f as CofheInternalConfig, G as DecryptEndpoint, $ as DecryptForTxBuilder, a0 as DecryptForTxResult, _ as DecryptForViewBuilder, B as DecryptPollCallbackContext, D as DecryptPollCallbackFunction, Z as EncryptInputsBuilder, H as EncryptSetStateFn, Q as EncryptStep, J as EncryptStepCallbackContext, N as Encryptable, o as EncryptableAddress, i as EncryptableBool, E as EncryptableItem, z as EncryptableToEncryptedItemInputMap, n as EncryptableUint128, k as EncryptableUint16, l as EncryptableUint32, m as EncryptableUint64, j as EncryptableUint8, x as EncryptedAddressInput, r as EncryptedBoolInput, q as EncryptedItemInput, y as EncryptedItemInputs, p as EncryptedNumber, w as EncryptedUint128Input, t as EncryptedUint16Input, u as EncryptedUint32Input, v as EncryptedUint64Input, s as EncryptedUint8Input, M as FheAllUTypes, V as FheKeyDeserializer, A as FheTypeValue, K as FheUintUTypes, I as IStorage, X as KeysStorage, Y as KeysStore, L as LiteralToPrimitive, P as Primitive, U as UnsealedItem, a1 as ZkBuilderAndCrsGenerator, a2 as ZkProveWorkerFunction, a3 as ZkProveWorkerRequest, a4 as ZkProveWorkerResponse, S as assertCorrectEncryptedItemInput, e as createCofheConfigBase, W as createKeysStore, T as fetchKeys, g as getCofheConfigItem, O as isEncryptableItem, R as isLastEncryptionStep, a5 as zkProveWithWorker } from './clientTypes-CEno_BEf.js';
3
3
  import { Hex, PublicClient } from 'viem';
4
4
  import './types-C07FK-cL.js';
5
5
  import 'zod';
package/dist/core.js CHANGED
@@ -1,4 +1,4 @@
1
- export { InitialConnectStore as CONNECT_STORE_DEFAULTS, CofheError, CofheErrorCode, DecryptForTxBuilder, DecryptForViewBuilder, EncryptInputsBuilder, EncryptStep, Encryptable, FheAllUTypes, FheTypes, FheUintUTypes, assertCorrectEncryptedItemInput, createCofheClientBase, createCofheConfigBase, createKeysStore, fetchKeys, fheTypeToString, getCofheConfigItem, isCofheError, isEncryptableItem, isLastEncryptionStep, verifyDecryptResult, zkProveWithWorker } from './chunk-S7OKGLFD.js';
1
+ export { InitialConnectStore as CONNECT_STORE_DEFAULTS, CofheError, CofheErrorCode, DecryptForTxBuilder, DecryptForViewBuilder, EncryptInputsBuilder, EncryptStep, Encryptable, FheAllUTypes, FheTypes, FheUintUTypes, assertCorrectEncryptedItemInput, createCofheClientBase, createCofheConfigBase, createKeysStore, fetchKeys, fheTypeToString, getCofheConfigItem, isCofheError, isEncryptableItem, isLastEncryptionStep, verifyDecryptResult, zkProveWithWorker } from './chunk-YDOK4BDL.js';
2
2
  import './chunk-TBLR7NNE.js';
3
3
  import './chunk-MRCKUMOS.js';
4
4
  export { MOCKS_DECRYPT_RESULT_SIGNER_PRIVATE_KEY, MOCKS_THRESHOLD_NETWORK_ADDRESS, MOCKS_ZK_VERIFIER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_ADDRESS, MOCKS_ZK_VERIFIER_SIGNER_PRIVATE_KEY, TASK_MANAGER_ADDRESS, TEST_BED_ADDRESS, TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT, TFHE_RS_ZK_MAX_BITS } from './chunk-4FP4V35O.js';