| /** | |
| * Defines a platform-independent service for cryptographic operations. | |
| * | |
| * Runtime packages provide concrete implementations backed by the host | |
| * platform's cryptography APIs. This module defines the service interface and a | |
| * constructor from random-byte and digest primitives. The service provides | |
| * secure random bytes and numbers, UUIDv4 and UUIDv7 generation, shuffling, and | |
| * SHA message digests. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| import * as Context from "./Context.js"; | |
| import * as Effect from "./Effect.js"; | |
| import * as PlatformError from "./PlatformError.js"; | |
| const TypeId = "~effect/platform/Crypto"; | |
| /** | |
| * Service tag for platform cryptography. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to provide or retrieve the full platform cryptography | |
| * service from an effect's context. | |
| * | |
| * **Details** | |
| * | |
| * Providing this service supplies platform-agnostic cryptographic operations | |
| * such as hashing, UUID generation, and secure random values. | |
| * | |
| * @see {@link make} for constructing a Crypto service from primitive operations | |
| * | |
| * @category services | |
| * @since 4.0.0 | |
| */ | |
| export const Crypto = /*#__PURE__*/Context.Service("effect/Crypto"); | |
| /** | |
| * Creates a `Crypto` service from the primitive implementation, deriving the | |
| * random generator helpers and UUID generation from those primitives. | |
| * | |
| * **When to use** | |
| * | |
| * Use to build a Crypto service for a platform integration, test layer, or | |
| * custom runtime from primitive random-byte and digest operations. | |
| * | |
| * **Details** | |
| * | |
| * The constructor derives random numbers, booleans, integer ranges, shuffling, | |
| * and UUID generation from `impl.randomBytes`. Digest operations delegate to | |
| * `impl.digest`. | |
| * | |
| * **Gotchas** | |
| * | |
| * `impl.randomBytes` must return cryptographically secure bytes of the | |
| * requested length. UUID formatting mutates the byte array returned for UUID | |
| * generation, so the implementation should return a fresh array for each call. | |
| * | |
| * **Example** (Creating a Crypto service) | |
| * | |
| * ```ts | |
| * import { Crypto, Effect, Layer } from "effect" | |
| * | |
| * const TestCrypto = Layer.succeed( | |
| * Crypto.Crypto, | |
| * Crypto.make({ | |
| * randomBytes: (size) => new Uint8Array(size), | |
| * digest: (_algorithm, data) => Effect.succeed(data) | |
| * }) | |
| * ) | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const make = impl => { | |
| const randomBytesUnsafe = impl.randomBytes; | |
| const randomBytes = size => Effect.map(validateSize("randomBytes", size), randomBytesUnsafe); | |
| const nextDoubleUnsafe = () => { | |
| const bytes = randomBytesUnsafe(7); | |
| const value = (bytes[0] & 0x1f) * 2 ** 48 + bytes[1] * 2 ** 40 + bytes[2] * 2 ** 32 + bytes[3] * 2 ** 24 + bytes[4] * 2 ** 16 + bytes[5] * 2 ** 8 + bytes[6]; | |
| return value / 2 ** 53; | |
| }; | |
| const nextIntUnsafe = () => Math.floor(nextDoubleUnsafe() * (Number.MAX_SAFE_INTEGER - Number.MIN_SAFE_INTEGER + 1)) + Number.MIN_SAFE_INTEGER; | |
| return Crypto.of({ | |
| [TypeId]: TypeId, | |
| randomBytes, | |
| nextDoubleUnsafe, | |
| nextIntUnsafe, | |
| digest: impl.digest, | |
| random: Effect.sync(() => nextDoubleUnsafe()), | |
| randomBoolean: Effect.sync(() => nextDoubleUnsafe() > 0.5), | |
| randomInt: Effect.sync(() => nextIntUnsafe()), | |
| randomBetween: (min, max) => Effect.sync(() => nextDoubleUnsafe() * (max - min) + min), | |
| randomIntBetween(min, max, options) { | |
| const extra = options?.halfOpen === true ? 0 : 1; | |
| return Effect.sync(() => { | |
| const minInt = Math.ceil(min); | |
| const maxInt = Math.floor(max); | |
| return Math.floor(nextDoubleUnsafe() * (maxInt - minInt + extra)) + minInt; | |
| }); | |
| }, | |
| randomShuffle: elements => Effect.sync(() => { | |
| const buffer = Array.from(elements); | |
| for (let i = buffer.length - 1; i >= 1; i = i - 1) { | |
| const index = Math.min(i, Math.floor(nextDoubleUnsafe() * (i + 1))); | |
| const value = buffer[i]; | |
| buffer[i] = buffer[index]; | |
| buffer[index] = value; | |
| } | |
| return buffer; | |
| }), | |
| randomUUIDv4: Effect.sync(() => formatUUIDv4(randomBytesUnsafe(16))), | |
| randomUUIDv7: Effect.clockWith(clock => Effect.succeed(formatUUIDv7(clock.currentTimeMillisUnsafe(), randomBytesUnsafe(16)))) | |
| }); | |
| }; | |
| const validateSize = (method, size) => Number.isSafeInteger(size) && size >= 0 ? Effect.succeed(size) : Effect.fail(PlatformError.badArgument({ | |
| module: "Crypto", | |
| method, | |
| description: "size must be a non-negative safe integer" | |
| })); | |
| const hex = byte => byte.toString(16).padStart(2, "0"); | |
| const formatUUID = bytes => { | |
| const segments = [bytes.subarray(0, 4), bytes.subarray(4, 6), bytes.subarray(6, 8), bytes.subarray(8, 10), bytes.subarray(10, 16)]; | |
| return segments.map(segment => Array.from(segment, hex).join("")).join("-"); | |
| }; | |
| const formatUUIDv4 = bytes => { | |
| bytes[6] = bytes[6] & 0x0f | 0x40; | |
| bytes[8] = bytes[8] & 0x3f | 0x80; | |
| return formatUUID(bytes); | |
| }; | |
| const maxUUIDv7Timestamp = 2 ** 48 - 1; | |
| const formatUUIDv7 = (timestampMillis, bytes) => { | |
| const timestamp = Math.min(Math.max(0, Math.trunc(timestampMillis)), maxUUIDv7Timestamp); | |
| bytes[0] = Math.floor(timestamp / 2 ** 40); | |
| bytes[1] = Math.floor(timestamp / 2 ** 32) & 0xff; | |
| bytes[2] = Math.floor(timestamp / 2 ** 24) & 0xff; | |
| bytes[3] = Math.floor(timestamp / 2 ** 16) & 0xff; | |
| bytes[4] = Math.floor(timestamp / 2 ** 8) & 0xff; | |
| bytes[5] = timestamp & 0xff; | |
| bytes[6] = bytes[6] & 0x0f | 0x70; | |
| bytes[8] = bytes[8] & 0x3f | 0x80; | |
| return formatUUID(bytes); | |
| }; | |
| //# sourceMappingURL=Crypto.js.map |
Xet Storage Details
- Size:
- 5.44 kB
- Xet hash:
- c283303bb1c500a2db50d71c2c24573bd76229b6bd3443b5a3a88a45db97f6c9
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.