@cofhe/react 0.0.0-beta-20251106215647
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/README.md +156 -0
- package/dist/index.cjs +619 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +859 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +106 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.js +576 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +859 -0
- package/dist/styles.css.map +1 -0
- package/dist/styles.d.cts +2 -0
- package/dist/styles.d.ts +2 -0
- package/package.json +57 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
CofheProvider: () => CofheProvider,
|
|
34
|
+
FheTypesList: () => FheTypesList,
|
|
35
|
+
FnxEncryptInput: () => FnxEncryptInput,
|
|
36
|
+
encryptedValueToString: () => encryptedValueToString,
|
|
37
|
+
fheTypeToString: () => fheTypeToString,
|
|
38
|
+
useCofheContext: () => useCofheContext,
|
|
39
|
+
useEncryptInput: () => useEncryptInput
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(index_exports);
|
|
42
|
+
|
|
43
|
+
// src/providers/CofheProvider.tsx
|
|
44
|
+
var import_react = require("react");
|
|
45
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
46
|
+
var CofheContext = (0, import_react.createContext)(void 0);
|
|
47
|
+
function CofheProvider({ children, client: providedClient, config }) {
|
|
48
|
+
const [client, setClient] = (0, import_react.useState)(providedClient || null);
|
|
49
|
+
const [isInitialized, setIsInitialized] = (0, import_react.useState)(false);
|
|
50
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
51
|
+
(0, import_react.useEffect)(() => {
|
|
52
|
+
if (providedClient) {
|
|
53
|
+
setClient(providedClient);
|
|
54
|
+
setIsInitialized(true);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (config) {
|
|
58
|
+
try {
|
|
59
|
+
setIsInitialized(true);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
setError(err instanceof Error ? err : new Error("Failed to initialize CoFHE client"));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}, [providedClient, config]);
|
|
65
|
+
const contextValue = {
|
|
66
|
+
client,
|
|
67
|
+
isInitialized,
|
|
68
|
+
error
|
|
69
|
+
};
|
|
70
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CofheContext.Provider, { value: contextValue, children });
|
|
71
|
+
}
|
|
72
|
+
function useCofheContext() {
|
|
73
|
+
const context = (0, import_react.useContext)(CofheContext);
|
|
74
|
+
if (context === void 0) {
|
|
75
|
+
throw new Error("useCofheContext must be used within a CofheProvider");
|
|
76
|
+
}
|
|
77
|
+
return context;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/hooks/useEncryptInput.ts
|
|
81
|
+
var import_react2 = require("react");
|
|
82
|
+
var import_sdk = require("@cofhe/sdk");
|
|
83
|
+
var STEP_CONFIG = {
|
|
84
|
+
"initTfhe": {
|
|
85
|
+
label: "Initializing TFHE...",
|
|
86
|
+
progress: 5
|
|
87
|
+
},
|
|
88
|
+
"fetchKeys": {
|
|
89
|
+
label: "Fetching FHE keys...",
|
|
90
|
+
progress: 20
|
|
91
|
+
},
|
|
92
|
+
"pack": {
|
|
93
|
+
label: "Packing data...",
|
|
94
|
+
progress: 40
|
|
95
|
+
},
|
|
96
|
+
"prove": {
|
|
97
|
+
label: "Generating proof...",
|
|
98
|
+
progress: 70
|
|
99
|
+
},
|
|
100
|
+
"verify": {
|
|
101
|
+
label: "Verifying...",
|
|
102
|
+
progress: 90
|
|
103
|
+
},
|
|
104
|
+
"done": {
|
|
105
|
+
label: "Encryption complete!",
|
|
106
|
+
progress: 100
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function useEncryptInput() {
|
|
110
|
+
const { client } = useCofheContext();
|
|
111
|
+
const [isEncrypting, setIsEncrypting] = (0, import_react2.useState)(false);
|
|
112
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
113
|
+
const [encryptionStep, setEncryptionStep] = (0, import_react2.useState)(null);
|
|
114
|
+
const [encryptionProgress, setEncryptionProgress] = (0, import_react2.useState)(0);
|
|
115
|
+
const [encryptionProgressLabel, setEncryptionProgressLabel] = (0, import_react2.useState)("");
|
|
116
|
+
const onEncryptInput = (0, import_react2.useCallback)(async (type, value) => {
|
|
117
|
+
if (!client) {
|
|
118
|
+
throw new Error("CoFHE client not initialized");
|
|
119
|
+
}
|
|
120
|
+
setIsEncrypting(true);
|
|
121
|
+
setError(null);
|
|
122
|
+
try {
|
|
123
|
+
let convertedValue;
|
|
124
|
+
if (type === "bool") {
|
|
125
|
+
convertedValue = value.toLowerCase() === "true" || value === "1";
|
|
126
|
+
} else if (type === "address") {
|
|
127
|
+
convertedValue = value;
|
|
128
|
+
} else {
|
|
129
|
+
convertedValue = value.includes(".") ? parseFloat(value) : parseInt(value, 10);
|
|
130
|
+
}
|
|
131
|
+
let encryptableItem;
|
|
132
|
+
switch (type) {
|
|
133
|
+
case "bool":
|
|
134
|
+
encryptableItem = import_sdk.Encryptable.bool(convertedValue);
|
|
135
|
+
break;
|
|
136
|
+
case "uint8":
|
|
137
|
+
encryptableItem = import_sdk.Encryptable.uint8(BigInt(convertedValue));
|
|
138
|
+
break;
|
|
139
|
+
case "uint16":
|
|
140
|
+
encryptableItem = import_sdk.Encryptable.uint16(BigInt(convertedValue));
|
|
141
|
+
break;
|
|
142
|
+
case "uint32":
|
|
143
|
+
encryptableItem = import_sdk.Encryptable.uint32(BigInt(convertedValue));
|
|
144
|
+
break;
|
|
145
|
+
case "uint64":
|
|
146
|
+
encryptableItem = import_sdk.Encryptable.uint64(BigInt(convertedValue));
|
|
147
|
+
break;
|
|
148
|
+
case "uint128":
|
|
149
|
+
encryptableItem = import_sdk.Encryptable.uint128(BigInt(convertedValue));
|
|
150
|
+
break;
|
|
151
|
+
case "address":
|
|
152
|
+
encryptableItem = import_sdk.Encryptable.address(convertedValue);
|
|
153
|
+
break;
|
|
154
|
+
default:
|
|
155
|
+
encryptableItem = import_sdk.Encryptable.uint32(BigInt(convertedValue));
|
|
156
|
+
}
|
|
157
|
+
const encryptionBuilder = client.encryptInputs([encryptableItem]).setStepCallback((step, context) => {
|
|
158
|
+
const stepConfig = STEP_CONFIG[step];
|
|
159
|
+
if (stepConfig) {
|
|
160
|
+
setEncryptionStep(step);
|
|
161
|
+
setEncryptionProgress(stepConfig.progress);
|
|
162
|
+
setEncryptionProgressLabel(stepConfig.label);
|
|
163
|
+
}
|
|
164
|
+
if (step === "prove" && context?.isEnd) {
|
|
165
|
+
console.log("[Encryption] Worker Status:", {
|
|
166
|
+
useWorker: context.useWorker,
|
|
167
|
+
usedWorker: context.usedWorker,
|
|
168
|
+
workerFailedError: context.workerFailedError,
|
|
169
|
+
duration: context.duration + "ms"
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const result = await encryptionBuilder.encrypt();
|
|
174
|
+
if (!result.success) {
|
|
175
|
+
throw result.error;
|
|
176
|
+
}
|
|
177
|
+
setEncryptionStep("done");
|
|
178
|
+
setEncryptionProgress(100);
|
|
179
|
+
setEncryptionProgressLabel("Encryption complete!");
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
setEncryptionStep(null);
|
|
182
|
+
setEncryptionProgress(0);
|
|
183
|
+
setEncryptionProgressLabel("");
|
|
184
|
+
}, 1e3);
|
|
185
|
+
setIsEncrypting(false);
|
|
186
|
+
return result.data[0];
|
|
187
|
+
} catch (err) {
|
|
188
|
+
setEncryptionStep(null);
|
|
189
|
+
setEncryptionProgress(0);
|
|
190
|
+
setEncryptionProgressLabel("");
|
|
191
|
+
setIsEncrypting(false);
|
|
192
|
+
const error2 = err instanceof Error ? err : new Error("Encryption failed");
|
|
193
|
+
setError(error2);
|
|
194
|
+
throw error2;
|
|
195
|
+
}
|
|
196
|
+
}, [client]);
|
|
197
|
+
return {
|
|
198
|
+
onEncryptInput,
|
|
199
|
+
isEncryptingInput: isEncrypting,
|
|
200
|
+
encryptionStep,
|
|
201
|
+
encryptionProgress,
|
|
202
|
+
encryptionProgressLabel,
|
|
203
|
+
inputEncryptionDisabled: isEncrypting || !!error
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/components/FnxEncryptInput.tsx
|
|
208
|
+
var import_react3 = require("react");
|
|
209
|
+
|
|
210
|
+
// src/utils/cn.ts
|
|
211
|
+
var cn = (...classes) => {
|
|
212
|
+
return classes.filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/utils/debounce.ts
|
|
216
|
+
var debounce = (func, wait) => {
|
|
217
|
+
let timeoutId = null;
|
|
218
|
+
return (...args) => {
|
|
219
|
+
if (timeoutId !== null) {
|
|
220
|
+
clearTimeout(timeoutId);
|
|
221
|
+
}
|
|
222
|
+
timeoutId = setTimeout(() => {
|
|
223
|
+
func(...args);
|
|
224
|
+
}, wait);
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// src/utils/utils.ts
|
|
229
|
+
var FheTypesList = [
|
|
230
|
+
{
|
|
231
|
+
label: "Encrypted Bool",
|
|
232
|
+
value: "bool",
|
|
233
|
+
maxValue: BigInt(1),
|
|
234
|
+
// 0 or 1
|
|
235
|
+
description: "Boolean value (true/false)"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
label: "Encrypted Uint8",
|
|
239
|
+
value: "uint8",
|
|
240
|
+
maxValue: BigInt(2 ** 8 - 1),
|
|
241
|
+
// 255
|
|
242
|
+
description: "8-bit unsigned integer (0 to 255)"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
label: "Encrypted Uint16",
|
|
246
|
+
value: "uint16",
|
|
247
|
+
maxValue: BigInt(2 ** 16 - 1),
|
|
248
|
+
// 65,535
|
|
249
|
+
description: "16-bit unsigned integer (0 to 65,535)"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
label: "Encrypted Uint32",
|
|
253
|
+
value: "uint32",
|
|
254
|
+
maxValue: BigInt(2 ** 32 - 1),
|
|
255
|
+
// 4,294,967,295
|
|
256
|
+
description: "32-bit unsigned integer (0 to 4,294,967,295)"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
label: "Encrypted Uint64",
|
|
260
|
+
value: "uint64",
|
|
261
|
+
maxValue: BigInt(2 ** 64 - 1),
|
|
262
|
+
// 18,446,744,073,709,551,615
|
|
263
|
+
description: "64-bit unsigned integer (0 to 18,446,744,073,709,551,615)"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
label: "Encrypted Uint128",
|
|
267
|
+
value: "uint128",
|
|
268
|
+
maxValue: BigInt(2 ** 128 - 1),
|
|
269
|
+
// Very large number
|
|
270
|
+
description: "128-bit unsigned integer"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
label: "Encrypted Address",
|
|
274
|
+
value: "address",
|
|
275
|
+
maxValue: null,
|
|
276
|
+
// Address validation is different
|
|
277
|
+
description: "Ethereum address (0x...)"
|
|
278
|
+
}
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
// src/components/FnxEncryptInput.tsx
|
|
282
|
+
var import_Security = __toESM(require("@mui/icons-material/Security"), 1);
|
|
283
|
+
var import_KeyboardArrowDown = __toESM(require("@mui/icons-material/KeyboardArrowDown"), 1);
|
|
284
|
+
var import_ContentCopy = __toESM(require("@mui/icons-material/ContentCopy"), 1);
|
|
285
|
+
var import_Check = __toESM(require("@mui/icons-material/Check"), 1);
|
|
286
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
287
|
+
var FnxEncryptInput = ({
|
|
288
|
+
className,
|
|
289
|
+
testId,
|
|
290
|
+
placeholder = "Enter number or address...",
|
|
291
|
+
initialValue = "",
|
|
292
|
+
options = FheTypesList,
|
|
293
|
+
size = "md",
|
|
294
|
+
hasError = false,
|
|
295
|
+
errorMessage,
|
|
296
|
+
disabled = false,
|
|
297
|
+
showProgressBar = false,
|
|
298
|
+
debounceMs = 300,
|
|
299
|
+
onTextChange,
|
|
300
|
+
onTypeChange,
|
|
301
|
+
onEncryptStart,
|
|
302
|
+
onEncryptProgress,
|
|
303
|
+
onEncryptComplete,
|
|
304
|
+
onEncryptError
|
|
305
|
+
}) => {
|
|
306
|
+
const [textValue, setTextValue] = (0, import_react3.useState)(initialValue);
|
|
307
|
+
const [selectedType, setSelectedType] = (0, import_react3.useState)(options[0]?.value || "uint32");
|
|
308
|
+
const [isDropdownOpen, setIsDropdownOpen] = (0, import_react3.useState)(false);
|
|
309
|
+
const [showProgress, setShowProgress] = (0, import_react3.useState)(false);
|
|
310
|
+
const [encryptedResult, setEncryptedResult] = (0, import_react3.useState)(null);
|
|
311
|
+
const [copySuccess, setCopySuccess] = (0, import_react3.useState)(false);
|
|
312
|
+
const dropdownRef = (0, import_react3.useRef)(null);
|
|
313
|
+
const { onEncryptInput, isEncryptingInput, encryptionStep, encryptionProgress, encryptionProgressLabel } = useEncryptInput();
|
|
314
|
+
const debouncedValidation = (0, import_react3.useRef)(
|
|
315
|
+
debounce((value) => {
|
|
316
|
+
console.log("Debounced validation for:", value);
|
|
317
|
+
}, debounceMs)
|
|
318
|
+
).current;
|
|
319
|
+
(0, import_react3.useEffect)(() => {
|
|
320
|
+
if (showProgressBar && isEncryptingInput) {
|
|
321
|
+
setShowProgress(true);
|
|
322
|
+
} else if (!isEncryptingInput) {
|
|
323
|
+
const timer = setTimeout(() => setShowProgress(false), 500);
|
|
324
|
+
return () => clearTimeout(timer);
|
|
325
|
+
}
|
|
326
|
+
}, [showProgressBar, isEncryptingInput]);
|
|
327
|
+
(0, import_react3.useEffect)(() => {
|
|
328
|
+
if (isEncryptingInput && encryptionStep && encryptionProgress !== null && encryptionProgressLabel) {
|
|
329
|
+
onEncryptProgress?.({
|
|
330
|
+
step: encryptionStep.toString(),
|
|
331
|
+
progress: encryptionProgress,
|
|
332
|
+
label: encryptionProgressLabel
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}, [encryptionStep, encryptionProgress, encryptionProgressLabel, isEncryptingInput, onEncryptProgress]);
|
|
336
|
+
(0, import_react3.useEffect)(() => {
|
|
337
|
+
const handleClickOutside = (event) => {
|
|
338
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
339
|
+
setIsDropdownOpen(false);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
343
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
344
|
+
}, []);
|
|
345
|
+
const sizeClasses = {
|
|
346
|
+
sm: { input: "px-3 py-2 text-sm", dropdown: "px-2 py-1 text-xs", button: "px-3 py-1 text-sm" },
|
|
347
|
+
md: { input: "px-4 py-3 text-sm", dropdown: "px-3 py-2 text-sm", button: "px-4 py-2 text-sm" },
|
|
348
|
+
lg: { input: "px-5 py-4 text-base", dropdown: "px-4 py-3 text-base", button: "px-6 py-3 text-base" }
|
|
349
|
+
};
|
|
350
|
+
const inputContainerClasses = cn(
|
|
351
|
+
"relative flex items-center bg-white dark:bg-gray-800 border rounded-lg transition-colors",
|
|
352
|
+
"focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500",
|
|
353
|
+
hasError ? "border-red-500 focus-within:ring-red-500 focus-within:border-red-500" : "border-gray-300 dark:border-gray-600",
|
|
354
|
+
(disabled || isEncryptingInput) && "bg-gray-100 dark:bg-gray-700 opacity-50",
|
|
355
|
+
className
|
|
356
|
+
);
|
|
357
|
+
const inputClasses = cn(
|
|
358
|
+
"flex-1 bg-transparent border-0 outline-none placeholder-gray-400 dark:placeholder-gray-500",
|
|
359
|
+
"text-gray-900 dark:text-white",
|
|
360
|
+
sizeClasses[size].input,
|
|
361
|
+
"pr-20",
|
|
362
|
+
// Make space for the dropdown button
|
|
363
|
+
(disabled || isEncryptingInput) && "cursor-not-allowed"
|
|
364
|
+
);
|
|
365
|
+
const dropdownButtonClasses = cn(
|
|
366
|
+
"absolute right-0 top-0 bottom-0",
|
|
367
|
+
"flex items-center gap-1 px-2 rounded-r-md border-l border-gray-300 dark:border-gray-600",
|
|
368
|
+
"bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600",
|
|
369
|
+
"transition-colors duration-200 cursor-pointer",
|
|
370
|
+
"text-xs font-medium text-gray-700 dark:text-gray-300",
|
|
371
|
+
(disabled || isEncryptingInput) && "cursor-not-allowed opacity-50",
|
|
372
|
+
isDropdownOpen && "bg-gray-200 dark:bg-gray-600"
|
|
373
|
+
);
|
|
374
|
+
const dropdownItemClasses = (isSelected, isCompatible) => cn(
|
|
375
|
+
"px-3 py-2 text-sm transition-colors",
|
|
376
|
+
isCompatible ? "cursor-pointer hover:bg-blue-50 dark:hover:bg-blue-900/30 hover:text-blue-700 dark:hover:text-blue-300" : "cursor-not-allowed opacity-50 bg-gray-50 dark:bg-gray-700",
|
|
377
|
+
isSelected && isCompatible ? "bg-blue-100 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300 font-medium" : isCompatible ? "text-gray-700 dark:text-gray-300" : "text-gray-400 dark:text-gray-500"
|
|
378
|
+
);
|
|
379
|
+
const progressVariantClasses = {
|
|
380
|
+
primary: "bg-blue-600 dark:bg-blue-500",
|
|
381
|
+
success: "bg-green-600 dark:bg-green-500",
|
|
382
|
+
warning: "bg-yellow-600 dark:bg-yellow-500",
|
|
383
|
+
error: "bg-red-600 dark:bg-red-500"
|
|
384
|
+
};
|
|
385
|
+
const progressContainerClasses = cn(
|
|
386
|
+
"w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1 overflow-hidden",
|
|
387
|
+
// Debug: Add border to see container
|
|
388
|
+
"border"
|
|
389
|
+
);
|
|
390
|
+
const progressBarClasses = (variant = "primary") => cn(
|
|
391
|
+
"h-full transition-all duration-300 ease-out rounded-full",
|
|
392
|
+
progressVariantClasses[variant]
|
|
393
|
+
);
|
|
394
|
+
const isTypeCompatible = (typeValue, inputValue) => {
|
|
395
|
+
if (!inputValue.trim()) return true;
|
|
396
|
+
const typeInfo = FheTypesList.find((type) => type.value === typeValue);
|
|
397
|
+
if (!typeInfo) return false;
|
|
398
|
+
if (typeValue === "bool") {
|
|
399
|
+
const lowerValue = inputValue.toLowerCase();
|
|
400
|
+
return lowerValue === "true" || lowerValue === "false" || lowerValue === "0" || lowerValue === "1";
|
|
401
|
+
}
|
|
402
|
+
if (typeValue === "address") {
|
|
403
|
+
if (!inputValue.startsWith("0x")) return false;
|
|
404
|
+
const addressPart = inputValue.slice(2);
|
|
405
|
+
if (addressPart.length !== 40) return false;
|
|
406
|
+
const hexRegex = /^[a-fA-F0-9]+$/;
|
|
407
|
+
if (!hexRegex.test(addressPart)) return false;
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
if (typeInfo.maxValue) {
|
|
411
|
+
try {
|
|
412
|
+
const numValue = BigInt(inputValue);
|
|
413
|
+
return numValue >= 0 && numValue <= typeInfo.maxValue;
|
|
414
|
+
} catch (error) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return true;
|
|
419
|
+
};
|
|
420
|
+
const handleTextChange = (e) => {
|
|
421
|
+
const value = e.target.value;
|
|
422
|
+
setTextValue(value);
|
|
423
|
+
onTextChange?.(value);
|
|
424
|
+
setEncryptedResult(null);
|
|
425
|
+
setCopySuccess(false);
|
|
426
|
+
debouncedValidation(value);
|
|
427
|
+
};
|
|
428
|
+
const handleCopyResult = async () => {
|
|
429
|
+
if (!encryptedResult || copySuccess) return;
|
|
430
|
+
try {
|
|
431
|
+
const textToCopy = JSON.stringify(encryptedResult, (key, value) => {
|
|
432
|
+
if (typeof value === "bigint") {
|
|
433
|
+
return value.toString();
|
|
434
|
+
}
|
|
435
|
+
return value;
|
|
436
|
+
}, 2);
|
|
437
|
+
await navigator.clipboard.writeText(textToCopy);
|
|
438
|
+
console.log("Copied to clipboard:", textToCopy);
|
|
439
|
+
setCopySuccess(true);
|
|
440
|
+
setTimeout(() => {
|
|
441
|
+
setCopySuccess(false);
|
|
442
|
+
}, 2e3);
|
|
443
|
+
} catch (error) {
|
|
444
|
+
console.error("Failed to copy to clipboard:", error);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
const handleTypeSelect = async (type) => {
|
|
448
|
+
setSelectedType(type);
|
|
449
|
+
setIsDropdownOpen(false);
|
|
450
|
+
onTypeChange?.(type);
|
|
451
|
+
if (textValue.trim() !== "") {
|
|
452
|
+
try {
|
|
453
|
+
console.log("Auto-encrypting value:", textValue, "as type:", type);
|
|
454
|
+
onEncryptStart?.({ value: textValue, type });
|
|
455
|
+
(async () => {
|
|
456
|
+
try {
|
|
457
|
+
const encryptionResult = await onEncryptInput(type, textValue);
|
|
458
|
+
setEncryptedResult(encryptionResult);
|
|
459
|
+
const data = { value: textValue, encrypted: encryptionResult };
|
|
460
|
+
onEncryptComplete?.(data);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
const errorMessage2 = error instanceof Error ? error.message : "Encryption failed";
|
|
463
|
+
console.error("Encryption failed:", error);
|
|
464
|
+
onEncryptError?.(errorMessage2);
|
|
465
|
+
}
|
|
466
|
+
})();
|
|
467
|
+
} catch (error) {
|
|
468
|
+
const errorMessage2 = error instanceof Error ? error.message : "Encryption setup failed";
|
|
469
|
+
console.error("Encryption setup failed:", error);
|
|
470
|
+
onEncryptError?.(errorMessage2);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
const toggleDropdown = () => {
|
|
475
|
+
if (!disabled && !isEncryptingInput) {
|
|
476
|
+
setIsDropdownOpen(!isDropdownOpen);
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
const ShieldIcon = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_Security.default, { sx: { fontSize: 14 } });
|
|
480
|
+
const ChevronDownIcon = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_KeyboardArrowDown.default, { sx: { fontSize: 14 } });
|
|
481
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full", children: [
|
|
482
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex items-start gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1", children: [
|
|
483
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: inputContainerClasses, "data-testid": testId, children: [
|
|
484
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
485
|
+
"input",
|
|
486
|
+
{
|
|
487
|
+
type: "text",
|
|
488
|
+
className: inputClasses,
|
|
489
|
+
placeholder,
|
|
490
|
+
value: textValue,
|
|
491
|
+
onChange: handleTextChange,
|
|
492
|
+
disabled: disabled || isEncryptingInput,
|
|
493
|
+
"data-testid": testId ? `${testId}-input` : "fnx-encrypt-input"
|
|
494
|
+
}
|
|
495
|
+
),
|
|
496
|
+
(isEncryptingInput || encryptedResult) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute right-16 top-1/2 transform -translate-y-1/2", children: isEncryptingInput ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "bg-blue-500 px-2 py-1 text-xs text-white rounded animate-pulse", children: "Encrypting..." }) : encryptedResult ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
497
|
+
"button",
|
|
498
|
+
{
|
|
499
|
+
onClick: handleCopyResult,
|
|
500
|
+
disabled: copySuccess,
|
|
501
|
+
className: `px-2 py-1 text-xs text-white rounded flex items-center gap-1 transition-all duration-300 ${copySuccess ? "bg-green-600 cursor-default" : "bg-green-500 hover:bg-green-600"}`,
|
|
502
|
+
title: copySuccess ? "Copied to clipboard!" : "Copy encrypted result to clipboard",
|
|
503
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
504
|
+
copySuccess ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_Check.default, { sx: { fontSize: 12 } }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ContentCopy.default, { sx: { fontSize: 12 } }),
|
|
505
|
+
"Copy"
|
|
506
|
+
] })
|
|
507
|
+
}
|
|
508
|
+
) : null }),
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "cofhe-dropdown-container", ref: dropdownRef, children: [
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
511
|
+
"button",
|
|
512
|
+
{
|
|
513
|
+
type: "button",
|
|
514
|
+
className: dropdownButtonClasses,
|
|
515
|
+
onClick: toggleDropdown,
|
|
516
|
+
disabled: disabled || isEncryptingInput,
|
|
517
|
+
"data-testid": testId ? `${testId}-type-selector` : "fnx-type-selector",
|
|
518
|
+
children: [
|
|
519
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ShieldIcon, {}),
|
|
520
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDownIcon, {})
|
|
521
|
+
]
|
|
522
|
+
}
|
|
523
|
+
),
|
|
524
|
+
isDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "cofhe-dropdown-menu", children: options.map((option) => {
|
|
525
|
+
const isCompatible = isTypeCompatible(option.value, textValue);
|
|
526
|
+
const isSelected = option.value === selectedType;
|
|
527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
528
|
+
"div",
|
|
529
|
+
{
|
|
530
|
+
className: dropdownItemClasses(isSelected, isCompatible),
|
|
531
|
+
onClick: () => isCompatible && handleTypeSelect(option.value),
|
|
532
|
+
"data-testid": `${testId ? `${testId}-` : ""}type-option-${option.value}`,
|
|
533
|
+
title: !isCompatible ? `Value "${textValue}" is not compatible with ${option.label}` : void 0,
|
|
534
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-mono", children: option.label })
|
|
535
|
+
},
|
|
536
|
+
option.value
|
|
537
|
+
);
|
|
538
|
+
}) })
|
|
539
|
+
] })
|
|
540
|
+
] }),
|
|
541
|
+
showProgress && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
542
|
+
"div",
|
|
543
|
+
{
|
|
544
|
+
className: "mt-3 overflow-hidden",
|
|
545
|
+
style: {
|
|
546
|
+
animation: isEncryptingInput ? "slideDownFadeIn 0.5s ease-out forwards" : "slideUpFadeOut 0.5s ease-out forwards"
|
|
547
|
+
},
|
|
548
|
+
"data-testid": testId ? `${testId}-progress` : "fnx-encrypt-progress",
|
|
549
|
+
children: [
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex justify-between items-center mb-1", children: [
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: encryptionProgressLabel || "Processing..." }),
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
|
|
553
|
+
encryptionProgress || 0,
|
|
554
|
+
"%"
|
|
555
|
+
] })
|
|
556
|
+
] }),
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: progressContainerClasses, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
558
|
+
"div",
|
|
559
|
+
{
|
|
560
|
+
className: progressBarClasses("primary"),
|
|
561
|
+
style: {
|
|
562
|
+
width: `${Math.min(100, Math.max(0, encryptionProgress || 0))}%`,
|
|
563
|
+
transition: "width 0.3s ease-out"
|
|
564
|
+
},
|
|
565
|
+
"data-testid": testId ? `${testId}-progress-bar` : "fnx-encrypt-progress-bar"
|
|
566
|
+
}
|
|
567
|
+
) })
|
|
568
|
+
]
|
|
569
|
+
}
|
|
570
|
+
)
|
|
571
|
+
] }) }),
|
|
572
|
+
hasError && errorMessage && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
573
|
+
"p",
|
|
574
|
+
{
|
|
575
|
+
className: "mt-2 text-sm text-red-600 dark:text-red-400",
|
|
576
|
+
"data-testid": testId ? `${testId}-error` : "fnx-encrypt-error",
|
|
577
|
+
children: errorMessage
|
|
578
|
+
}
|
|
579
|
+
)
|
|
580
|
+
] });
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
// src/utils/logging.ts
|
|
584
|
+
var fheTypeToString = (fheType) => {
|
|
585
|
+
switch (fheType) {
|
|
586
|
+
case "bool":
|
|
587
|
+
return "ebool";
|
|
588
|
+
case "uint8":
|
|
589
|
+
return "euint8";
|
|
590
|
+
case "uint16":
|
|
591
|
+
return "euint16";
|
|
592
|
+
case "uint32":
|
|
593
|
+
return "euint32";
|
|
594
|
+
case "uint64":
|
|
595
|
+
return "euint64";
|
|
596
|
+
case "uint128":
|
|
597
|
+
return "euint128";
|
|
598
|
+
case "address":
|
|
599
|
+
return "eaddress";
|
|
600
|
+
default:
|
|
601
|
+
return "unknown";
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
var encryptedValueToString = (fheType, handle) => {
|
|
605
|
+
const hashStr = handle.toString();
|
|
606
|
+
const truncated = hashStr.slice(0, 6) + ".." + hashStr.slice(hashStr.length - 6);
|
|
607
|
+
return `${fheTypeToString(fheType)}(${truncated})`;
|
|
608
|
+
};
|
|
609
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
610
|
+
0 && (module.exports = {
|
|
611
|
+
CofheProvider,
|
|
612
|
+
FheTypesList,
|
|
613
|
+
FnxEncryptInput,
|
|
614
|
+
encryptedValueToString,
|
|
615
|
+
fheTypeToString,
|
|
616
|
+
useCofheContext,
|
|
617
|
+
useEncryptInput
|
|
618
|
+
});
|
|
619
|
+
//# sourceMappingURL=index.cjs.map
|