@cofhe/sdk 0.5.0 → 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/node.cjs CHANGED
@@ -2809,6 +2809,96 @@ function computeMinuteRampPollIntervalMs(elapsedMs, params) {
2809
2809
  return Math.min(params.maxIntervalMs, Math.max(params.minIntervalMs, intervalMs));
2810
2810
  }
2811
2811
 
2812
+ // core/decrypt/submitRetry.ts
2813
+ var DEFAULT_404_RETRY_TIMEOUT_MS = 1e4;
2814
+ function isRetryableSubmitStatus(status) {
2815
+ return status === 204 || status === 404;
2816
+ }
2817
+ function normalize404RetryTimeoutMs(params) {
2818
+ const { timeoutMs, operationLabel, errorCode } = params;
2819
+ if (timeoutMs === void 0)
2820
+ return DEFAULT_404_RETRY_TIMEOUT_MS;
2821
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
2822
+ throw new CofheError({
2823
+ code: errorCode,
2824
+ message: `${operationLabel} submit 404 retry timeout must be a finite number greater than or equal to 0`,
2825
+ context: {
2826
+ timeoutMs
2827
+ }
2828
+ });
2829
+ }
2830
+ return timeoutMs;
2831
+ }
2832
+ async function classifySubmitResponse(params) {
2833
+ const { response, extractErrorMessage } = params;
2834
+ if (isRetryableSubmitStatus(response.status)) {
2835
+ return { kind: "retryable", status: response.status };
2836
+ }
2837
+ if (response.ok) {
2838
+ return { kind: "parse-json" };
2839
+ }
2840
+ let errorMessage = `HTTP ${response.status}`;
2841
+ try {
2842
+ const errorBody = await response.json();
2843
+ const maybeErrorMessage = extractErrorMessage?.(errorBody);
2844
+ if (typeof maybeErrorMessage === "string" && maybeErrorMessage.length > 0) {
2845
+ errorMessage = maybeErrorMessage;
2846
+ } else if (errorBody && typeof errorBody === "object") {
2847
+ const defaultMessage = errorBody.error_message;
2848
+ const fallbackMessage = errorBody.message;
2849
+ if (typeof defaultMessage === "string" && defaultMessage.length > 0) {
2850
+ errorMessage = defaultMessage;
2851
+ } else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
2852
+ errorMessage = fallbackMessage;
2853
+ }
2854
+ }
2855
+ } catch {
2856
+ errorMessage = response.statusText || errorMessage;
2857
+ }
2858
+ return { kind: "fatal-http", errorMessage };
2859
+ }
2860
+ function throwIfSubmitRetryTimedOut(params) {
2861
+ const {
2862
+ operationLabel,
2863
+ errorCode,
2864
+ status,
2865
+ elapsedMs,
2866
+ retry404TimeoutMs,
2867
+ overallTimeoutMs,
2868
+ thresholdNetworkUrl,
2869
+ body,
2870
+ attemptIndex
2871
+ } = params;
2872
+ if (status === 404 && elapsedMs > retry404TimeoutMs) {
2873
+ throw new CofheError({
2874
+ code: errorCode,
2875
+ message: `${operationLabel} submit retried 404 responses without receiving request_id for ${retry404TimeoutMs}ms`,
2876
+ hint: "The ciphertext may not be indexed yet. Increase set404RetryTimeout(...) if the backend is slow to index ciphertexts.",
2877
+ context: {
2878
+ thresholdNetworkUrl,
2879
+ body,
2880
+ attemptIndex,
2881
+ timeoutMs: retry404TimeoutMs,
2882
+ status
2883
+ }
2884
+ });
2885
+ }
2886
+ if (elapsedMs > overallTimeoutMs) {
2887
+ throw new CofheError({
2888
+ code: errorCode,
2889
+ message: `${operationLabel} submit retried without receiving request_id for ${overallTimeoutMs}ms`,
2890
+ hint: "The ciphertext may still be propagating. Try again later.",
2891
+ context: {
2892
+ thresholdNetworkUrl,
2893
+ body,
2894
+ attemptIndex,
2895
+ timeoutMs: overallTimeoutMs,
2896
+ status
2897
+ }
2898
+ });
2899
+ }
2900
+ }
2901
+
2812
2902
  // core/decrypt/tnSealOutputV2.ts
2813
2903
  var POLL_INTERVAL_MS = 1e3;
2814
2904
  var POLL_MAX_INTERVAL_MS = 1e4;
@@ -2870,7 +2960,7 @@ function parseCompletedSealOutputResponse(params) {
2870
2960
  }
2871
2961
  return convertSealedData(sealed);
2872
2962
  }
2873
- async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
2963
+ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
2874
2964
  const body = {
2875
2965
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
2876
2966
  host_chain_id: chainId,
@@ -2900,17 +2990,11 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
2900
2990
  }
2901
2991
  });
2902
2992
  }
2903
- if (!response.ok) {
2904
- let errorMessage = `HTTP ${response.status}`;
2905
- try {
2906
- const errorBody = await response.json();
2907
- errorMessage = errorBody.error_message || errorBody.message || errorMessage;
2908
- } catch {
2909
- errorMessage = response.statusText || errorMessage;
2910
- }
2993
+ const responseClassification = await classifySubmitResponse({ response });
2994
+ if (responseClassification.kind === "fatal-http") {
2911
2995
  throw new CofheError({
2912
2996
  code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
2913
- message: `sealOutput request failed: ${errorMessage}`,
2997
+ message: `sealOutput request failed: ${responseClassification.errorMessage}`,
2914
2998
  hint: "Check the threshold network URL and request parameters.",
2915
2999
  context: {
2916
3000
  thresholdNetworkUrl,
@@ -2921,8 +3005,8 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
2921
3005
  }
2922
3006
  });
2923
3007
  }
2924
- let submitResponse;
2925
- if (response.status !== 204) {
3008
+ if (responseClassification.kind === "parse-json") {
3009
+ let submitResponse;
2926
3010
  try {
2927
3011
  submitResponse = await response.json();
2928
3012
  } catch (e) {
@@ -2950,46 +3034,39 @@ async function submitSealOutputRequest(thresholdNetworkUrl, ctHash, chainId, per
2950
3034
  if (submitResponse.request_id) {
2951
3035
  return { kind: "request_id", requestId: submitResponse.request_id };
2952
3036
  }
2953
- }
2954
- if (response.status === 204) {
2955
- const elapsedMs = Date.now() - overallStartTime;
2956
- if (elapsedMs > SEAL_OUTPUT_TIMEOUT_MS) {
2957
- throw new CofheError({
2958
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
2959
- message: `sealOutput submit retried without receiving request_id for ${SEAL_OUTPUT_TIMEOUT_MS}ms`,
2960
- hint: "The ciphertext may still be propagating. Try again later.",
2961
- context: {
2962
- thresholdNetworkUrl,
2963
- body,
2964
- attemptIndex,
2965
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
2966
- submitResponse,
2967
- status: response.status
2968
- }
2969
- });
2970
- }
2971
- onPoll?.({
2972
- operation: "sealoutput",
2973
- requestId: "",
2974
- attemptIndex,
2975
- elapsedMs,
2976
- intervalMs: SUBMIT_RETRY_INTERVAL_MS,
2977
- timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
3037
+ throw new CofheError({
3038
+ code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3039
+ message: `sealOutput submit response missing request_id`,
3040
+ context: {
3041
+ thresholdNetworkUrl,
3042
+ body,
3043
+ submitResponse,
3044
+ attemptIndex
3045
+ }
2978
3046
  });
2979
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
2980
- attemptIndex += 1;
2981
- continue;
2982
3047
  }
2983
- throw new CofheError({
2984
- code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
2985
- message: `sealOutput submit response missing request_id`,
2986
- context: {
2987
- thresholdNetworkUrl,
2988
- body,
2989
- submitResponse,
2990
- attemptIndex
2991
- }
3048
+ const elapsedMs = Date.now() - overallStartTime;
3049
+ throwIfSubmitRetryTimedOut({
3050
+ operationLabel: "sealOutput",
3051
+ errorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
3052
+ status: responseClassification.status,
3053
+ elapsedMs,
3054
+ retry404TimeoutMs,
3055
+ overallTimeoutMs: SEAL_OUTPUT_TIMEOUT_MS,
3056
+ thresholdNetworkUrl,
3057
+ body,
3058
+ attemptIndex
2992
3059
  });
3060
+ onPoll?.({
3061
+ operation: "sealoutput",
3062
+ requestId: "",
3063
+ attemptIndex,
3064
+ elapsedMs,
3065
+ intervalMs: SUBMIT_RETRY_INTERVAL_MS,
3066
+ timeoutMs: SEAL_OUTPUT_TIMEOUT_MS
3067
+ });
3068
+ await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS));
3069
+ attemptIndex += 1;
2993
3070
  }
2994
3071
  }
2995
3072
  async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
@@ -3104,7 +3181,12 @@ async function pollSealOutputStatus(thresholdNetworkUrl, requestId, overallStart
3104
3181
  });
3105
3182
  }
3106
3183
  async function tnSealOutputV2(params) {
3107
- const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
3184
+ const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
3185
+ const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3186
+ timeoutMs: retry404TimeoutMs,
3187
+ operationLabel: "sealOutput",
3188
+ errorCode: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */
3189
+ });
3108
3190
  const overallStartTime = Date.now();
3109
3191
  const submitResult = await submitSealOutputRequest(
3110
3192
  thresholdNetworkUrl,
@@ -3112,6 +3194,7 @@ async function tnSealOutputV2(params) {
3112
3194
  chainId,
3113
3195
  permission,
3114
3196
  overallStartTime,
3197
+ normalized404RetryTimeoutMs,
3115
3198
  onPoll
3116
3199
  );
3117
3200
  if (submitResult.kind === "completed") {
@@ -3121,12 +3204,14 @@ async function tnSealOutputV2(params) {
3121
3204
  }
3122
3205
 
3123
3206
  // core/decrypt/decryptForViewBuilder.ts
3207
+ var DEFAULT_404_RETRY_TIMEOUT_MS2 = 1e4;
3124
3208
  var DecryptForViewBuilder = class extends BaseBuilder {
3125
3209
  ctHash;
3126
3210
  utype;
3127
3211
  permitHash;
3128
3212
  permit;
3129
3213
  pollCallback;
3214
+ retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS2;
3130
3215
  constructor(params) {
3131
3216
  super({
3132
3217
  config: params.config,
@@ -3187,6 +3272,19 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3187
3272
  this.pollCallback = callback;
3188
3273
  return this;
3189
3274
  }
3275
+ set404RetryTimeout(timeoutMs) {
3276
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
3277
+ throw new CofheError({
3278
+ code: "INTERNAL_ERROR" /* InternalError */,
3279
+ message: "decryptForView: set404RetryTimeout(timeoutMs) expects a finite number greater than or equal to 0.",
3280
+ context: {
3281
+ timeoutMs
3282
+ }
3283
+ });
3284
+ }
3285
+ this.retry404TimeoutMs = timeoutMs;
3286
+ return this;
3287
+ }
3190
3288
  withPermit(permitOrPermitHash) {
3191
3289
  if (typeof permitOrPermitHash === "string") {
3192
3290
  this.permitHash = permitOrPermitHash;
@@ -3315,6 +3413,7 @@ var DecryptForViewBuilder = class extends BaseBuilder {
3315
3413
  chainId: this.chainId,
3316
3414
  permission,
3317
3415
  thresholdNetworkUrl,
3416
+ retry404TimeoutMs: this.retry404TimeoutMs,
3318
3417
  onPoll: this.pollCallback
3319
3418
  });
3320
3419
  return PermitUtils.unseal(permit, sealed);
@@ -3590,7 +3689,7 @@ function assertDecryptStatusResponseV2(value) {
3590
3689
  }
3591
3690
  return value;
3592
3691
  }
3593
- async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, onPoll) {
3692
+ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, permission, overallStartTime, retry404TimeoutMs, onPoll) {
3594
3693
  const body = {
3595
3694
  ct_tempkey: BigInt(ctHash).toString(16).padStart(64, "0"),
3596
3695
  host_chain_id: chainId
@@ -3622,19 +3721,11 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3622
3721
  }
3623
3722
  });
3624
3723
  }
3625
- if (!response.ok) {
3626
- let errorMessage = `HTTP ${response.status}`;
3627
- try {
3628
- const errorBody = await response.json();
3629
- const maybeMessage = errorBody.error_message || errorBody.message;
3630
- if (typeof maybeMessage === "string" && maybeMessage.length > 0)
3631
- errorMessage = maybeMessage;
3632
- } catch {
3633
- errorMessage = response.statusText || errorMessage;
3634
- }
3724
+ const responseClassification = await classifySubmitResponse({ response });
3725
+ if (responseClassification.kind === "fatal-http") {
3635
3726
  throw new CofheError({
3636
3727
  code: "DECRYPT_FAILED" /* DecryptFailed */,
3637
- message: `decrypt request failed: ${errorMessage}`,
3728
+ message: `decrypt request failed: ${responseClassification.errorMessage}`,
3638
3729
  hint: "Check the threshold network URL and request parameters.",
3639
3730
  context: {
3640
3731
  thresholdNetworkUrl,
@@ -3645,8 +3736,8 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3645
3736
  }
3646
3737
  });
3647
3738
  }
3648
- let submitResponse;
3649
- if (response.status !== 204) {
3739
+ if (responseClassification.kind === "parse-json") {
3740
+ let submitResponse;
3650
3741
  let rawJson;
3651
3742
  try {
3652
3743
  rawJson = await response.json();
@@ -3676,46 +3767,39 @@ async function submitDecryptRequestV2(thresholdNetworkUrl, ctHash, chainId, perm
3676
3767
  if (submitResponse.request_id) {
3677
3768
  return { kind: "request_id", requestId: submitResponse.request_id };
3678
3769
  }
3679
- }
3680
- if (response.status === 204) {
3681
- const elapsedMs = Date.now() - overallStartTime;
3682
- if (elapsedMs > DECRYPT_TIMEOUT_MS) {
3683
- throw new CofheError({
3684
- code: "DECRYPT_FAILED" /* DecryptFailed */,
3685
- message: `decrypt submit retried without receiving request_id for ${DECRYPT_TIMEOUT_MS}ms`,
3686
- hint: "The ciphertext may still be propagating. Try again later.",
3687
- context: {
3688
- thresholdNetworkUrl,
3689
- body,
3690
- attemptIndex,
3691
- timeoutMs: DECRYPT_TIMEOUT_MS,
3692
- submitResponse,
3693
- status: response.status
3694
- }
3695
- });
3696
- }
3697
- onPoll?.({
3698
- operation: "decrypt",
3699
- requestId: "",
3700
- attemptIndex,
3701
- elapsedMs,
3702
- intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
3703
- timeoutMs: DECRYPT_TIMEOUT_MS
3770
+ throw new CofheError({
3771
+ code: "DECRYPT_FAILED" /* DecryptFailed */,
3772
+ message: `decrypt submit response missing request_id`,
3773
+ context: {
3774
+ thresholdNetworkUrl,
3775
+ body,
3776
+ submitResponse,
3777
+ attemptIndex
3778
+ }
3704
3779
  });
3705
- await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
3706
- attemptIndex += 1;
3707
- continue;
3708
3780
  }
3709
- throw new CofheError({
3710
- code: "DECRYPT_FAILED" /* DecryptFailed */,
3711
- message: `decrypt submit response missing request_id`,
3712
- context: {
3713
- thresholdNetworkUrl,
3714
- body,
3715
- submitResponse,
3716
- attemptIndex
3717
- }
3781
+ const elapsedMs = Date.now() - overallStartTime;
3782
+ throwIfSubmitRetryTimedOut({
3783
+ operationLabel: "decrypt",
3784
+ errorCode: "DECRYPT_FAILED" /* DecryptFailed */,
3785
+ status: responseClassification.status,
3786
+ elapsedMs,
3787
+ retry404TimeoutMs,
3788
+ overallTimeoutMs: DECRYPT_TIMEOUT_MS,
3789
+ thresholdNetworkUrl,
3790
+ body,
3791
+ attemptIndex
3718
3792
  });
3793
+ onPoll?.({
3794
+ operation: "decrypt",
3795
+ requestId: "",
3796
+ attemptIndex,
3797
+ elapsedMs,
3798
+ intervalMs: SUBMIT_RETRY_INTERVAL_MS2,
3799
+ timeoutMs: DECRYPT_TIMEOUT_MS
3800
+ });
3801
+ await new Promise((resolve) => setTimeout(resolve, SUBMIT_RETRY_INTERVAL_MS2));
3802
+ attemptIndex += 1;
3719
3803
  }
3720
3804
  }
3721
3805
  async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartTime, onPoll) {
@@ -3833,7 +3917,12 @@ async function pollDecryptStatusV2(thresholdNetworkUrl, requestId, overallStartT
3833
3917
  });
3834
3918
  }
3835
3919
  async function tnDecryptV2(params) {
3836
- const { thresholdNetworkUrl, ctHash, chainId, permission, onPoll } = params;
3920
+ const { thresholdNetworkUrl, ctHash, chainId, permission, retry404TimeoutMs, onPoll } = params;
3921
+ const normalized404RetryTimeoutMs = normalize404RetryTimeoutMs({
3922
+ timeoutMs: retry404TimeoutMs,
3923
+ operationLabel: "decrypt",
3924
+ errorCode: "DECRYPT_FAILED" /* DecryptFailed */
3925
+ });
3837
3926
  const overallStartTime = Date.now();
3838
3927
  const submitResult = await submitDecryptRequestV2(
3839
3928
  thresholdNetworkUrl,
@@ -3841,6 +3930,7 @@ async function tnDecryptV2(params) {
3841
3930
  chainId,
3842
3931
  permission,
3843
3932
  overallStartTime,
3933
+ normalized404RetryTimeoutMs,
3844
3934
  onPoll
3845
3935
  );
3846
3936
  if (submitResult.kind === "completed") {
@@ -3850,12 +3940,14 @@ async function tnDecryptV2(params) {
3850
3940
  }
3851
3941
 
3852
3942
  // core/decrypt/decryptForTxBuilder.ts
3943
+ var DEFAULT_404_RETRY_TIMEOUT_MS3 = 1e4;
3853
3944
  var DecryptForTxBuilder = class extends BaseBuilder {
3854
3945
  ctHash;
3855
3946
  permitHash;
3856
3947
  permit;
3857
3948
  permitSelection = "unset";
3858
3949
  pollCallback;
3950
+ retry404TimeoutMs = DEFAULT_404_RETRY_TIMEOUT_MS3;
3859
3951
  constructor(params) {
3860
3952
  super({
3861
3953
  config: params.config,
@@ -3885,6 +3977,19 @@ var DecryptForTxBuilder = class extends BaseBuilder {
3885
3977
  this.pollCallback = callback;
3886
3978
  return this;
3887
3979
  }
3980
+ set404RetryTimeout(timeoutMs) {
3981
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
3982
+ throw new CofheError({
3983
+ code: "INTERNAL_ERROR" /* InternalError */,
3984
+ message: "decryptForTx: set404RetryTimeout(timeoutMs) expects a finite number greater than or equal to 0.",
3985
+ context: {
3986
+ timeoutMs
3987
+ }
3988
+ });
3989
+ }
3990
+ this.retry404TimeoutMs = timeoutMs;
3991
+ return this;
3992
+ }
3888
3993
  withPermit(permitOrPermitHash) {
3889
3994
  if (this.permitSelection === "with-permit") {
3890
3995
  throw new CofheError({
@@ -4017,6 +4122,7 @@ var DecryptForTxBuilder = class extends BaseBuilder {
4017
4122
  chainId: this.chainId,
4018
4123
  permission,
4019
4124
  thresholdNetworkUrl,
4125
+ retry404TimeoutMs: this.retry404TimeoutMs,
4020
4126
  onPoll: this.pollCallback
4021
4127
  });
4022
4128
  return {
package/dist/node.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-BSbwairE.cjs';
1
+ import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-BJbFeeno.cjs';
2
2
  import 'viem';
3
3
  import './types-C07FK-cL.cjs';
4
4
  import 'zod';
package/dist/node.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-DDmcgZ0a.js';
1
+ import { C as CofheInputConfig, a as CofheConfig, b as CofheClient } from './clientTypes-CEno_BEf.js';
2
2
  import 'viem';
3
3
  import './types-C07FK-cL.js';
4
4
  import 'zod';
package/dist/node.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createCofheConfigBase, createCofheClientBase } from './chunk-S7OKGLFD.js';
1
+ import { createCofheConfigBase, createCofheClientBase } from './chunk-YDOK4BDL.js';
2
2
  import './chunk-TBLR7NNE.js';
3
3
  import './chunk-MRCKUMOS.js';
4
4
  import { TFHE_RS_SAFE_SERIALIZATION_SIZE_LIMIT } from './chunk-4FP4V35O.js';