///|
/// JavaScript runtime-backed random bytes.
extern "js" fn js_crypto_random(buf : Bytes, len : Int) -> Int =
#| (buf, len) => {
#| const chunkSize = 32768;
#| globalThis.__moonbit_nanoid_random_error = "";
#| const errorMessage = (prefix, error) => {
#| const detail = error && error.message ? error.message : String(error);
#| return `${prefix}: ${detail}`;
#| };
#| try {
#| const view = new Uint8Array(buf.buffer, buf.byteOffset, len);
#| if (globalThis.crypto?.getRandomValues) {
#| for (let offset = 0; offset < len; offset += chunkSize) {
#| globalThis.crypto.getRandomValues(
#| view.subarray(offset, Math.min(offset + chunkSize, len)),
#| );
#| }
#| return 0;
#| }
#| if (typeof require !== "undefined") {
#| const crypto = require("crypto");
#| for (let offset = 0; offset < len; offset += chunkSize) {
#| const end = Math.min(offset + chunkSize, len);
#| view.set(crypto.randomBytes(end - offset), offset);
#| }
#| return 0;
#| }
#| globalThis.__moonbit_nanoid_random_error =
#| "No JavaScript crypto source available";
#| return -1;
#| } catch (error) {
#| globalThis.__moonbit_nanoid_random_error =
#| errorMessage("JavaScript crypto random generation failed", error);
#| return -1;
#| }
#| }
///|
extern "js" fn js_crypto_random_error() -> String =
#| () => globalThis.__moonbit_nanoid_random_error ||
#| "Failed to get random bytes from JavaScript runtime"
///|
fn get_random_bytes(size : Int) -> Result[Array[Int], NanoidError] {
if size <= 0 {
return Ok([])
}
let random_bytes = Bytes::new(size)
if js_crypto_random(random_bytes, size) == 0 {
Ok(bytes_to_int_array(random_bytes, size))
} else {
Err(RandomGenerationError(js_crypto_random_error()))
}
}