1/**
2 * Deno-backed implementation of Effect's Crypto service.
3 *
4 * This module uses Deno's global Web Crypto API.
5 *
6 * @since 4.0.0
7 */
8import * as Context from "effect/Context"
9import * as EffectCrypto from "effect/Crypto"
10import * as Effect from "effect/Effect"
11import * as Layer from "effect/Layer"
12import * as PlatformError from "effect/PlatformError"
13
14/**
15 * Provides the Web Crypto API used by the Crypto service implementation.
16 *
17 * @category services
18 * @since 4.0.0
19 */
20export const WebCrypto = Context.Reference<Crypto>("@effect/platform-deno/Crypto/WebCrypto", {
21 defaultValue: () => globalThis.crypto
22})
23
24/**
25 * A layer that provides Effect's Crypto service using Deno's Web Crypto API.
26 *
27 * @category layers
28 * @since 4.0.0
29 */
30export const layer: Layer.Layer<EffectCrypto.Crypto> = Layer.effect(
31 EffectCrypto.Crypto,
32 Effect.gen(function*() {
33 const crypto = yield* WebCrypto
34 const randomBytes = (size: number): Uint8Array => {
35 const bytes = new Uint8Array(size)
36 for (let offset = 0; offset < bytes.length; offset += 65_536) {
37 crypto.getRandomValues(bytes.subarray(offset, offset + 65_536))
38 }
39 return bytes
40 }
41
42 const digest: EffectCrypto.Crypto["digest"] = (algorithm, data) =>
43 Effect.map(
44 Effect.tryPromise({
45 try: () => crypto.subtle.digest(algorithm, new Uint8Array(data)),
46 catch: (cause) =>
47 PlatformError.systemError({
48 module: "Crypto",
49 method: "digest",
50 _tag: "Unknown",
51 description: "Could not compute digest",
52 cause
53 })
54 }),
55 (buffer) => new Uint8Array(buffer)
56 )
57
58 return EffectCrypto.make({
59 randomBytes,
60 digest
61 })
62 })
63)