Skip to content

Identity

import { Identity } from '@dxos/halo';

Identity manages the user on this device: the identity itself, its profile, its devices, its recovery credentials and the credentials it grants to services. Every function is an Effect or a Stream that needs Identity.Service. Run one with Effect.runPromise once the service is provided.

layerClient from @dxos/halo-adapter-client provides Identity.Service and Space.Service from a Client.

import {
class Client

The Client class encapsulates the core client-side API of DXOS.

Client
} from '@dxos/client';
import {
import Identity
Identity
} from '@dxos/halo';
import {
const layerClient: (client: Client) => Layer<Identity.Service | Service>

A single layer providing both HALO services (

Identity.Service

,

Space.Service

) backed by one

Client

. This is the composition-root layer that replaces direct @dxos/client access for HALO concerns. Invitation querying lives on these two services; flow-level verbs need no service.

layerClient
} from '@dxos/halo-adapter-client';
const
const client: Client
client
= new
new Client(options?: ClientOptions): Client

The Client class encapsulates the core client-side API of DXOS.

Client
();
await
const client: Client
client
.
Client.initialize(): Promise<Client>

Initializes internal resources in an idempotent way. Required before using the Client instance.

initialize
();
// Provides Identity.Service and Space.Service.
const
const halo: Layer<Identity.Service | Service, never, never>
halo
=
function layerClient(client: Client): Layer<Identity.Service | Service>

A single layer providing both HALO services (

Identity.Service

,

Space.Service

) backed by one

Client

. This is the composition-root layer that replaces direct @dxos/client access for HALO concerns. Invitation querying lives on these two services; flow-level verbs need no service.

layerClient
(
const client: Client
client
);

getSnapshot reads it once, as an Option that is empty before an identity exists. identity is a stream that emits the current value, then each change.

import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Option
Option
from 'effect/Option';
import * as
import Stream
Stream
from 'effect/Stream';
import {
import Identity
Identity
} from '@dxos/halo';
const
const whoAmI: Effect.Effect<Option.Option<string | undefined>, never, Identity.Service>
whoAmI
=
import Effect
Effect
.
const gen: <Effect.Effect<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>, Option.Option<string | undefined>>(f: () => Generator<Effect.Effect<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>, Option.Option<...>, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const
const identity: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
identity
= yield*
import Identity
Identity
.
const getSnapshot: Effect.Effect<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>

Synchronous snapshot of the local identity (requires

Service

).

getSnapshot
;
return
import Option
Option
.
const map: <{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, string | undefined>(self: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, f: (a: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}) => string | undefined) => Option.Option<...> (+1 overload)

Transforms the value inside a Some using the provided function, leaving None unchanged.

When to use

Use to apply a pure transformation to an Option's present value, especially when chaining transformations in a pipeline.

Details

  • Some → applies f and wraps the result in a new Some
  • None → returns None unchanged

Example (Mapping over an Option)

import { Option } from "effect"
Option.map(Option.some(2), (n) => n * 2) // => Option.some(4)
Option.map(Option.none(), (n: number) => n * 2) // => Option.none()

@see ― flatMap when f returns an Option

@see ― as to replace the value with a constant

@stability ― stable

@category ― mapping

@since ― 2.0.0

map
(
const identity: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
identity
, (
identity: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
identity
) =>
identity: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
identity
.
displayName?: string | undefined
displayName
);
});
const
const watch: Effect.Effect<void, never, Identity.Service>
watch
=
import Identity
Identity
.
const identity: Stream.Stream<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>

The local identity as a current-value stream (requires

Service

).

identity
.
Pipeable.pipe<Stream.Stream<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>, Effect.Effect<void, never, Identity.Service>>(this: Stream.Stream<...>, ab: (_: Stream.Stream<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const runForEach: <Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, void, never, never>(f: (a: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>) => Effect.Effect<void, never, never>) => <E, R>(self: Stream.Stream<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, E, R>) => Effect.Effect<...> (+1 overload)

Runs the provided effectful callback for each element of the stream.

Example (Running an effect for each value)

import { Effect, Stream } from "effect"
const stream = Stream.make(1, 2, 3)
const values: Array<string> = []
const program = Effect.gen(function*() {
yield* Stream.runForEach(stream, (n) => Effect.sync(() => values.push(`Processing: ${n}`)))
})
await Effect.runPromise(program)
values // => ["Processing: 1", "Processing: 2", "Processing: 3"]

@stability ― stable

@category ― destructors

@since ― 2.0.0

runForEach
((
identity: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
identity
) =>
import Effect
Effect
.
const sync: <void>(thunk: LazyArg<void>) => Effect.Effect<void, never, never>

Creates an Effect that represents a synchronous side-effectful computation.

When to use

Use when you need to wrap a synchronous side-effectful operation that is not expected to throw.

Details

The provided function is evaluated lazily when the effect runs.

Gotchas

The function must not throw. If it throws, the thrown value is treated as a defect, not as a typed failure. Use try when throwing is expected.

Example (Capturing synchronous logging in an Effect)

import { Effect } from "effect"
const output: Array<unknown> = []
const log = (message: string) =>
Effect.sync(() => {
void output.push(message) // side effect
})
// ┌─── Effect<void, never, never>
// ▼
const program = log("Hello, World!")
Effect.runSync(program)
output // => ["Hello, World!"]

@see ― try_try for a version that can handle failures.

@stability ― stable

@category ― constructors

@since ― 2.0.0

sync
(() =>
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@since ― v0.1.100

log
(
import Option
Option
.
const match: <{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, string, string | undefined>(self: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, options: {
readonly onNone: LazyArg<string>;
readonly onSome: (a: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}) => string | undefined;
}) => string | undefined (+1 overload)

Pattern-matches on an Option, handling both None and Some cases.

When to use

Use when you need to handle both Some and None in one expression and transform an Option into a plain value.

Details

  • If None, calls onNone and returns its result
  • If Some, calls onSome with the value and returns its result
  • Supports the dual API (data-last and data-first)

Example (Matching on an Option)

import { Option } from "effect"
Option.match(Option.some(1), {
onNone: () => "Option is empty",
onSome: (value) => `Option has a value: ${value}`
}) // => "Option has a value: 1"

@see ― getOrElse for unwrapping with a default

@stability ― stable

@category ― pattern matching

@since ― 2.0.0

match
(
identity: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
identity
, {
onNone: LazyArg<string>
onNone
: () => 'no identity yet',
onSome: (a: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}) => string | undefined
onSome
: (
identity: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
identity
) =>
identity: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
identity
.
displayName?: string | undefined
displayName
,
}),
),
),
),
);

Code outside Effect can take the service itself and use its synchronous methods: subscribe calls back with each change and returns a function that stops it. Identity.atom gives the same value as an Atom.

import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Option
Option
from 'effect/Option';
import {
import Identity
Identity
} from '@dxos/halo';
// The synchronous methods, for code outside Effect.
const
const service: Effect.Effect<{
unsubscribe: () => void;
atom: Atom<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>>;
}, never, Identity.Service>
service
=
import Effect
Effect
.
const gen: <Effect.Effect<Identity.ServiceApi, never, Identity.Service>, {
unsubscribe: () => void;
atom: Atom<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>>;
}>(f: () => Generator<Effect.Effect<Identity.ServiceApi, never, Identity.Service>, {
unsubscribe: () => void;
atom: Atom<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>>;
}, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const
const identity: Identity.ServiceApi
identity
= yield*
import Identity
Identity
.
class Service
Service
;
const
const unsubscribe: () => void
unsubscribe
=
const identity: Identity.ServiceApi
identity
.
ServiceApi.subscribe: (callback: (identity: Option.Option<Identity.Info>) => void) => () => void

Subscribe to local-identity changes (imperative). Invokes callback immediately with the current value, then on each change. Returns an unsubscribe function.

subscribe
((
current: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
current
) =>
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@since ― v0.1.100

log
(
import Option
Option
.
const isSome: <{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>(self: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>) => self is Option.Some<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>

Checks whether an Option contains a value (Some).

When to use

Use when you need to branch on a present Option before accessing .value.

Details

  • Acts as a type guard, narrowing to Some<A>

Example (Checking for Some)

import { Option } from "effect"
Option.isSome(Option.some(1)) // => true
Option.isSome(Option.none()) // => false

@see ― isNone for the opposite check.

@stability ― stable

@category ― guards

@since ― 2.0.0

isSome
(
current: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
current
) ? 'signed in' : 'signed out'),
);
// An Atom of the same value, for Atom-driven code.
const
const atom: Atom<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>>
atom
=
import Identity
Identity
.
const atom: (service: Identity.ServiceApi) => Atom<Option.Option<Identity.Info>>

The local identity as an Atom, for reactive non-React consumers (app-graph builders and other Atom-driven code). Seeded from the synchronous snapshot and updated through subscribe, so a reader that evaluates before the first stream tick sees the current identity rather than none.

Keyed by service reference, not structurally: the shape holds streams whose accessors a structural key would read.

atom
(
const identity: Identity.ServiceApi
identity
);
return {
unsubscribe: () => void
unsubscribe
,
atom: Atom<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>>
atom
};
});

create makes the identity and this device its first member, and stores the device’s key on the device. updateProfile changes the display name and any profile data, such as an avatar.

import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Option
Option
from 'effect/Option';
import {
import Identity
Identity
} from '@dxos/halo';
const
const signIn: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>
signIn
=
import Effect
Effect
.
const gen: <Effect.Effect<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service> | Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>, {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>(f: () => Generator<...>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const
const existing: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
existing
= yield*
import Identity
Identity
.
const getSnapshot: Effect.Effect<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>

Synchronous snapshot of the local identity (requires

Service

).

getSnapshot
;
if (
import Option
Option
.
const isSome: <{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>(self: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>) => self is Option.Some<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>

Checks whether an Option contains a value (Some).

When to use

Use when you need to branch on a present Option before accessing .value.

Details

  • Acts as a type guard, narrowing to Some<A>

Example (Checking for Some)

import { Option } from "effect"
Option.isSome(Option.some(1)) // => true
Option.isSome(Option.none()) // => false

@see ― isNone for the opposite check.

@stability ― stable

@category ― guards

@since ― 2.0.0

isSome
(
const existing: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
existing
)) {
return
const existing: Option.Some<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>
existing
.
Some<{ readonly did: IdentityDid; readonly identityKey?: string | undefined; readonly displayName?: string | undefined; readonly data?: { readonly [x: string]: any; } | undefined; }>.value: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
value
;
}
return yield*
import Identity
Identity
.
const create: (options?: {
displayName?: string;
data?: Record<string, unknown>;
deviceLabel?: string;
}) => Effect.Effect<Identity.Info, IdentityError, Identity.Service>

Create the local identity (requires

Service

).

create
({
displayName?: string | undefined
displayName
: 'Ada',
deviceLabel?: string | undefined
deviceLabel
: 'Laptop' });
});
const
const rename: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>
rename
=
import Identity
Identity
.
const updateProfile: (profile: {
displayName?: string;
data?: Record<string, unknown>;
}) => Effect.Effect<Identity.Info, IdentityError, Identity.Service>

Update the identity profile (requires

Service

).

updateProfile
({
displayName?: string | undefined
displayName
: 'Ada Lovelace',
data?: Record<string, unknown> | undefined
data
: {
emoji: string
emoji
: '🦊' },
});
const
const me: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
me
= await
import Effect
Effect
.
const runPromise: <{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError>(effect: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, never>, options?: Effect.RunOptions | undefined) => Promise<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>

Executes an effect and returns the result as a Promise.

When to use

Use when you need to execute an effect and work with the result using Promise syntax, typically for compatibility with other promise-based code.

If the effect succeeds, the promise will resolve with the result. If the effect fails, the promise will reject with an error.

Example (Running a successful effect as a Promise)

import { Effect } from "effect"
await Effect.runPromise(Effect.succeed(1)) // => 1

Example (Running effects as promises)

//Example: Handling a Failing Effect as a Rejected Promise
import { Effect } from "effect"
const output: Array<unknown> = []
await Effect.runPromise(Effect.fail("my error")).catch(() => {
void output.push("rejected")
})
output // => ["rejected"]

@see ― runPromiseExit for a version that returns an Exit type instead of rejecting.

@stability ― stable

@category ― running

@since ― 2.0.0

runPromise
(
const signIn: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>
signIn
.
Pipeable.pipe<Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>, Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect
Effect
.
const provide: <Identity.Service | Service, never, never>(layer: Layer<Identity.Service | Service, never, never>, options?: {
readonly local?: boolean | undefined;
} | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Identity.Service | Service>> (+5 overloads)

Provides dependencies to an effect using layers or a context. Use options.local to build the layer every time; by default, layers are shared between provide calls.

Example (Providing dependencies with a layer)

import { Context, Effect, Layer } from "effect"
interface Database {
readonly query: (sql: string) => Effect.Effect<string>
}
const Database = Context.Service<Database>("Database")
const DatabaseLayer = Layer.succeed(Database)({
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Result for: ${sql}`))
})
const program = Effect.gen(function*() {
const db = yield* Database
return yield* db.query("SELECT * FROM users")
})
const provided = Effect.provide(program, DatabaseLayer)
await Effect.runPromise(provided) // => "Result for: SELECT * FROM users"

@stability ― stable

@category ― providing services

@since ― 2.0.0

provide
(
const halo: Layer<Identity.Service | Service, never, never>
halo
)));
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@since ― v0.1.100

log
(
const me: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
me
.
did: IdentityDid
did
,
const me: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
me
.
displayName?: string | undefined
displayName
);

personalSpaceId is the id of the identity’s personal space, or nothing before the identity exists.

import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Option
Option
from 'effect/Option';
import {
import Identity
Identity
} from '@dxos/halo';
const
const personalSpace: Effect.Effect<SpaceId | undefined, IdentityError, Identity.Service>
personalSpace
=
import Effect
Effect
.
const gen: <Effect.Effect<Option.Option<SpaceId>, IdentityError, Identity.Service>, SpaceId | undefined>(f: () => Generator<Effect.Effect<Option.Option<SpaceId>, IdentityError, Identity.Service>, SpaceId | undefined, never>) => Effect.Effect<SpaceId | undefined, IdentityError, Identity.Service> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const
const id: Option.Option<SpaceId>
id
= yield*
import Identity
Identity
.
const personalSpaceId: Effect.Effect<Option.Option<SpaceId>, IdentityError, Identity.Service>

Id of the identity's personal (HALO) space (requires

Service

).

personalSpaceId
;
return
import Option
Option
.
const getOrUndefined: <SpaceId>(self: Option.Option<SpaceId>) => SpaceId | undefined

Extracts the value from a Some, or returns undefined for None.

When to use

Use when you need to pass absent Option values to APIs that expect undefined.

Details

  • Some → the inner value
  • None → undefined

Example (Unwrapping to undefined)

import { Option } from "effect"
Option.getOrUndefined(Option.some(1)) // => 1
Option.getOrUndefined(Option.none()) // => undefined

@see ― getOrNull to return null instead

@see ― getOrElse for a custom fallback

@stability ― stable

@category ― getters

@since ― 2.0.0

getOrUndefined
(
const id: Option.Option<SpaceId>
id
);
});

getDevicesSnapshot lists the identity’s devices once, and devices streams the list. Each device has a key, a kind, a presence and, when set, a label.

import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Stream
Stream
from 'effect/Stream';
import {
import Identity
Identity
} from '@dxos/halo';
const
const listDevices: Effect.Effect<void, never, Identity.Service>
listDevices
=
import Effect
Effect
.
const gen: <Effect.Effect<readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[], never, Identity.Service>, void>(f: () => Generator<Effect.Effect<readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[], never, Identity.Service>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const
const devices: readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[]
devices
= yield*
import Identity
Identity
.
const getDevicesSnapshot: Effect.Effect<readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[], never, Identity.Service>

Synchronous snapshot of the local identity's devices (requires

Service

).

getDevicesSnapshot
;
for (const
const device: {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}
device
of
const devices: readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[]
devices
) {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@since ― v0.1.100

log
(
const device: {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}
device
.
label?: string | undefined

User-assigned name, when set.

label
??
const device: {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}
device
.
key: string

Hex-encoded device key.

key
,
const device: {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}
device
.
kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined
kind
,
const device: {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}
device
.
presence?: "online" | "offline" | "removed" | undefined

Whether the device is currently reachable.

presence
);
}
});
// The same list, again on every change.
const
const watchDevices: Effect.Effect<void, never, Identity.Service>
watchDevices
=
import Identity
Identity
.
const devices: Stream.Stream<readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[], never, Identity.Service>

Devices belonging to the local identity as a current-value stream (requires

Service

).

devices
.
Pipeable.pipe<Stream.Stream<readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[], never, Identity.Service>, Effect.Effect<void, never, Identity.Service>>(this: Stream.Stream<...>, ab: (_: Stream.Stream<readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[], never, Identity.Service>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const runForEach: <readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[], void, never, never>(f: (a: readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[]) => Effect.Effect<...>) => <E, R>(self: Stream.Stream<...>) => Effect.Effect<...> (+1 overload)

Runs the provided effectful callback for each element of the stream.

Example (Running an effect for each value)

import { Effect, Stream } from "effect"
const stream = Stream.make(1, 2, 3)
const values: Array<string> = []
const program = Effect.gen(function*() {
yield* Stream.runForEach(stream, (n) => Effect.sync(() => values.push(`Processing: ${n}`)))
})
await Effect.runPromise(program)
values // => ["Processing: 1", "Processing: 2", "Processing: 3"]

@stability ― stable

@category ― destructors

@since ― 2.0.0

runForEach
((
devices: readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[]
devices
) =>
import Effect
Effect
.
const sync: <void>(thunk: LazyArg<void>) => Effect.Effect<void, never, never>

Creates an Effect that represents a synchronous side-effectful computation.

When to use

Use when you need to wrap a synchronous side-effectful operation that is not expected to throw.

Details

The provided function is evaluated lazily when the effect runs.

Gotchas

The function must not throw. If it throws, the thrown value is treated as a defect, not as a typed failure. Use try when throwing is expected.

Example (Capturing synchronous logging in an Effect)

import { Effect } from "effect"
const output: Array<unknown> = []
const log = (message: string) =>
Effect.sync(() => {
void output.push(message) // side effect
})
// ┌─── Effect<void, never, never>
// ▼
const program = log("Hello, World!")
Effect.runSync(program)
output // => ["Hello, World!"]

@see ― try_try for a version that can handle failures.

@stability ― stable

@category ― constructors

@since ― 2.0.0

sync
(() =>
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@since ― v0.1.100

log
(
devices: readonly {
readonly key: string;
readonly current: boolean;
readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined;
readonly label?: string | undefined;
readonly os?: string | undefined;
readonly platform?: string | undefined;
readonly presence?: "online" | "offline" | "removed" | undefined;
}[]
devices
.
ReadonlyArray<{ readonly key: string; readonly current: boolean; readonly kind?: "unknown" | "browser" | "native" | "mobile" | "agent" | "agent-managed" | undefined; readonly label?: string | undefined; readonly os?: string | undefined; readonly platform?: string | undefined; readonly presence?: "online" | ... 2 more ... | undefined; }>.length: number

Gets the length of the array. This is a number one higher than the highest element defined in an array.

length
, 'devices')),
),
);

To add one, share starts a device invitation and join accepts it on the new device. Both return an Invitation.Flow. invitations streams the device invitations this device has open.

import * as
import Effect
Effect
from 'effect/Effect';
import {
import Identity
Identity
,
import Invitation
Invitation
} from '@dxos/halo';
const
const addDevice: Effect.Effect<Invitation.Flow, IdentityError | InvitationError, Identity.Service>
addDevice
=
import Effect
Effect
.
const gen: <Effect.Effect<Invitation.Flow, IdentityError, Identity.Service> | Effect.Effect<string, InvitationError, never>, Invitation.Flow>(f: () => Generator<Effect.Effect<Invitation.Flow, IdentityError, Identity.Service> | Effect.Effect<string, InvitationError, never>, Invitation.Flow, never>) => Effect.Effect<Invitation.Flow, IdentityError | InvitationError, Identity.Service> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const
const flow: Invitation.Flow
flow
= yield*
import Identity
Identity
.
const share: (options?: Invitation.ShareOptions) => Effect.Effect<Invitation.Flow, IdentityError, Identity.Service>

Initiate a device invitation (requires

Service

).

share
({
authMethod?: Invitation.AuthMethod | undefined
authMethod
: 'shared-secret' });
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@since ― v0.1.100

log
('Open this on the new device:', yield*
import Invitation
Invitation
.
const code: (flow: Invitation.Flow) => Effect.Effect<string, InvitationError>

Encoded, shareable code for a flow.

code
(
const flow: Invitation.Flow
flow
));
return
const flow: Invitation.Flow
flow
;
});
declare const
const invitationCode: string
invitationCode
: string;
const
const joinIdentity: Effect.Effect<Invitation.Flow, IdentityError, Identity.Service>
joinIdentity
=
import Identity
Identity
.
const join: (code: string) => Effect.Effect<Invitation.Flow, IdentityError, Identity.Service>

Redeem a device-invitation code (requires

Service

).

join
(
const invitationCode: string
invitationCode
);

createRecoveryCredential with no options returns a recovery code. Pass externalKey to register a passkey instead. recover admits a new device with a recovery code, a passkey assertion or an OAuth token, and revokeRecoveryCredential withdraws a credential by its lookup key. HALO refuses to revoke the last active one.

import * as
import Effect
Effect
from 'effect/Effect';
import {
import Identity
Identity
} from '@dxos/halo';
const
const backup: Effect.Effect<void, IdentityError, Identity.Service>
backup
=
import Effect
Effect
.
const gen: <Effect.Effect<{
recoveryCode?: string;
}, IdentityError, Identity.Service>, void>(f: () => Generator<Effect.Effect<{
recoveryCode?: string;
}, IdentityError, Identity.Service>, void, never>) => Effect.Effect<void, IdentityError, Identity.Service> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const {
const recoveryCode: string | undefined
recoveryCode
} = yield*
import Identity
Identity
.
const createRecoveryCredential: (options?: Identity.RecoveryCredentialOptions) => Effect.Effect<{
recoveryCode?: string;
}, IdentityError, Identity.Service>

Write a recovery credential (requires

Service

).

createRecoveryCredential
();
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@since ― v0.1.100

log
('Write this down:',
const recoveryCode: string | undefined
recoveryCode
);
});
declare const
const recoveryCode: string
recoveryCode
: string;
const
const restore: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>
restore
=
import Identity
Identity
.
const recover: (args: Identity.RecoverArgs) => Effect.Effect<Identity.Info, IdentityError, Identity.Service>

Re-admit this device via a recovery credential (requires

Service

).

recover
({
recoveryCode: string
recoveryCode
});
declare const
const lookupKey: string
lookupKey
: string;
const
const revoke: Effect.Effect<void, IdentityError, Identity.Service>
revoke
=
import Identity
Identity
.
const revokeRecoveryCredential: (lookupKey: string) => Effect.Effect<void, IdentityError, Identity.Service>

Revoke a recovery credential by lookup key (requires

Service

).

revokeRecoveryCredential
(
const lookupKey: string
lookupKey
);

A passkey signs a challenge before recover. requestRecoveryChallenge gets it from EDGE; Passkey recovery walks through the whole ceremony.

import {
import Identity
Identity
} from '@dxos/halo';
// For a passkey: the challenge the passkey signs before `recover`.
const
const challenge: Effect.Effect<{
readonly deviceKey: string;
readonly controlFeedKey: string;
readonly challenge: string;
}, IdentityError, Identity.Service>
challenge
=
import Identity
Identity
.
const requestRecoveryChallenge: Effect.Effect<{
readonly deviceKey: string;
readonly controlFeedKey: string;
readonly challenge: string;
}, IdentityError, Identity.Service>

Request a recovery challenge for this device (requires

Service

).

requestRecoveryChallenge
;

credentials streams the credentials the identity holds. A recovery credential carries its kind, label, lookup key and whether it has been revoked.

import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Stream
Stream
from 'effect/Stream';
import {
import Identity
Identity
} from '@dxos/halo';
const
const activeRecovery: Effect.Effect<{
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
}[], never, Identity.Service>
activeRecovery
=
import Effect
Effect
.
const gen: <Effect.Effect<(readonly {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}[])[], never, Identity.Service>, {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
}[]>(f: () => Generator<...>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
const [
const credentials: readonly {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}[]
credentials
] = yield*
import Identity
Identity
.
const credentials: Stream.Stream<readonly {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}[], never, Identity.Service>

HALO credentials as a current-value stream (requires

Service

).

credentials
.
Pipeable.pipe<Stream.Stream<readonly {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}[], never, Identity.Service>, Stream.Stream<readonly {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}[], never, Identity.Service>, Effect.Effect<...>>(this: Stream.Stream<...>, ab: (_: Stream.Stream<...>) => Stream.Stream<...>, bc: (_: Stream.Stream<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const take: (n: number) => <A, E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<A, E, R> (+1 overload)

Takes the first n elements from this stream.

Details

Finite fractional values of n are rounded down. NaN and non-positive values return Stream.empty without evaluating the source stream.

Example (Taking values from the left)

import { Effect, Stream } from "effect"
const program = Effect.gen(function*() {
const values = yield* Stream.make(1, 2, 3, 4, 5).pipe(
Stream.take(3),
Stream.runCollect
)
values // => [ 1, 2, 3 ]
})
await Effect.runPromise(program)

@stability ― stable

@category ― filtering

@since ― 2.0.0

take
(1),
import Stream
Stream
.
const runCollect: <A, E, R>(self: Stream.Stream<A, E, R>) => Effect.Effect<Array<A>, E, R>

Runs the stream and collects all elements into an array.

Example (Collecting stream values)

import { Effect, Stream } from "effect"
const stream = Stream.make(1, 2, 3, 4, 5)
const program = Effect.gen(function*() {
const collected = yield* Stream.runCollect(stream)
collected // => [ 1, 2, 3, 4, 5 ]
})
await Effect.runPromise(program)

@stability ― stable

@category ― destructors

@since ― 2.0.0

runCollect
,
);
return
const credentials: readonly {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}[]
credentials
.
ReadonlyArray<{ readonly type: string; readonly id?: string | undefined; readonly issuanceDate?: Date | undefined; readonly recovery?: { readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown"; readonly revoked: boolean; readonly lookupKey?: string | undefined; readonly label?: string | undefined; } | undefined; }>.flatMap<{
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
}, undefined>(callback: (this: undefined, value: {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}, index: number, array: {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}[]) => {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | readonly {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
}[], thisArg?: undefined): {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
}[]

Calls a defined callback function on each element of an array. Then, flattens the result into a new array. This is identical to a map followed by flat with depth 1.

@param ― callback A function that accepts up to three arguments. The flatMap method calls the callback function one time for each element in the array.

@param ― thisArg An object to which the this keyword can refer in the callback function. If thisArg is omitted, undefined is used as the this value.

flatMap
((
credential: {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}
credential
) =>
credential: {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}
credential
.
recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined
recovery
&& !
credential: {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}
credential
.
recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
}
recovery
.
revoked: boolean

Whether an IdentityRecoveryRevoked assertion cancels this credential.

revoked
? [
credential: {
readonly type: string;
readonly id?: string | undefined;
readonly issuanceDate?: Date | undefined;
readonly recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
} | undefined;
}
credential
.
recovery?: {
readonly kind: "passkey" | "recovery-code" | "oauth" | "unknown";
readonly revoked: boolean;
readonly lookupKey?: string | undefined;
readonly label?: string | undefined;
}
recovery
]
: [],
);
});

grantServiceAccess writes a credential that lets the identity use an EDGE or Hub service. createApiToken mints a token a CLI or a server can use to act as the identity. The token’s secret is returned once, so store it straight away. getEdgeIdentity is the identity as EDGE authenticates it, for an HTTP or WebSocket client.

import * as
import Effect
Effect
from 'effect/Effect';
import {
import Identity
Identity
} from '@dxos/halo';
const
const connect: Effect.Effect<AccessToken, IdentityError, Identity.Service>
connect
=
import Effect
Effect
.
const gen: <Effect.Effect<void, IdentityError, Identity.Service>, AccessToken>(f: () => Generator<Effect.Effect<void, IdentityError, Identity.Service>, AccessToken, never>) => Effect.Effect<AccessToken, IdentityError, Identity.Service> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to use

Use when you want to write effectful code that looks and behaves like synchronous code, while still handling asynchronous tasks, errors, and complex control flow such as loops and conditions.

Generator functions work similarly to async/await but keep errors, requirements, and interruption in the Effect type. You can yield* values from effects and return the final result at the end.

Example (Sequencing effects with generators)

import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
await Effect.runPromise(program) // => "Final amount to charge: 96"

@stability ― stable

@category ― constructors

@since ― 2.0.0

gen
(function* () {
yield*
import Identity
Identity
.
const grantServiceAccess: (options: Identity.ServiceAccessOptions) => Effect.Effect<void, IdentityError, Identity.Service>

Grant the identity access to an EDGE/Hub service (requires

Service

).

grantServiceAccess
({
serverName: string

Target server name (e.g. hub.dxos.network).

serverName
: 'hub.example.com',
capabilities: readonly string[]

Capabilities to grant (e.g. ['composer:beta']).

capabilities
: ['compute'],
});
return yield*
import Identity
Identity
.
const createApiToken: (options: Identity.ApiTokenOptions) => Effect.Effect<AccessToken, IdentityError, Identity.Service>

Mint an API token bound to this identity's account (requires

Service

).

createApiToken
({
label: string

Shown where the account's tokens are listed.

label
: 'CI',
expiresAt?: number | undefined

Epoch milliseconds; the token never expires when omitted.

expiresAt
:
var Date: DateConstructor

Enables basic storage and retrieval of dates and times.

Date
.
DateConstructor.now(): number

Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC).

now
() + 30 * 24 * 60 * 60 * 1000,
});
});
// The identity as EDGE authenticates it, for an HTTP or WebSocket client.
const
const edgeIdentity: Effect.Effect<Option.Option<Identity.EdgeIdentity>, never, Identity.Service>
edgeIdentity
=
import Identity
Identity
.
const getEdgeIdentity: Effect.Effect<Option.Option<Identity.EdgeIdentity>, never, Identity.Service>

The signed-in identity as an EDGE/Hub authentication principal (requires

Service

).

getEdgeIdentity
;
Member Summary
Service The Effect service
getSnapshot identity atom The identity: once, as a stream, as an Atom
create updateProfile Make the identity and edit its profile
personalSpaceId The identity’s personal space
getDevicesSnapshot devices The identity’s devices
share join invitations Device invitations
createRecoveryCredential recover revokeRecoveryCredential Recovery
requestRecoveryChallenge The challenge a passkey signs
credentials The credentials the identity holds
grantServiceAccess createApiToken getEdgeIdentity Access to EDGE and Hub services

The full list is in the API reference.

Every function that can fail fails with IdentityError, whose message says what went wrong. Handle it by its tag:

import * as
import Effect
Effect
from 'effect/Effect';
const
const safeRename: Effect.Effect<void | {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, never, Identity.Service>
safeRename
=
const rename: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>
rename
.
Pipeable.pipe<Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>, Effect.Effect<void | {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, never, Identity.Service>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}, IdentityError, Identity.Service>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect
Effect
.
const catchTag: <"IdentityError", IdentityError, void, never, never, unassigned, never, never>(k: "IdentityError", f: (e: IdentityError) => Effect.Effect<void, never, never>, orElse?: ((e: never) => Effect.Effect<unassigned, never, never>) | undefined) => <A, R>(self: Effect.Effect<A, IdentityError, R>) => Effect.Effect<void | A, never, R> (+1 overload)

Catches and handles specific errors by their _tag field, which is used as a discriminator.

When to use

Use when you need to recover from one specific tagged error in an effect error channel.

Details

The error type must have a readonly _tag field. catchTag matches that field and only handles errors with the requested tag.

Example (Handling a tagged error)

import { Effect } from "effect"
class NetworkError {
readonly _tag = "NetworkError"
constructor(readonly message: string) {}
}
class ValidationError {
readonly _tag = "ValidationError"
constructor(readonly message: string) {}
}
const task: Effect.Effect<string, NetworkError | ValidationError> =
Effect.fail(new NetworkError("offline"))
const program = Effect.catchTag(
task,
"NetworkError",
(error) => Effect.succeed(`Recovered from network error: ${error.message}`)
)
Effect.runSync(program) // => "Recovered from network error: offline"

@see ― catchTags for handling multiple tagged errors in one call

@see ― catchIf for recovering from errors that match a predicate

@stability ― stable

@category ― error handling

@since ― 2.0.0

catchTag
('IdentityError', (
error: IdentityError
error
) =>
import Effect
Effect
.
const sync: <void>(thunk: LazyArg<void>) => Effect.Effect<void, never, never>

Creates an Effect that represents a synchronous side-effectful computation.

When to use

Use when you need to wrap a synchronous side-effectful operation that is not expected to throw.

Details

The provided function is evaluated lazily when the effect runs.

Gotchas

The function must not throw. If it throws, the thrown value is treated as a defect, not as a typed failure. Use try when throwing is expected.

Example (Capturing synchronous logging in an Effect)

import { Effect } from "effect"
const output: Array<unknown> = []
const log = (message: string) =>
Effect.sync(() => {
void output.push(message) // side effect
})
// ┌─── Effect<void, never, never>
// ▼
const program = log("Hello, World!")
Effect.runSync(program)
output // => ["Hello, World!"]

@see ― try_try for a version that can handle failures.

@stability ― stable

@category ― constructors

@since ― 2.0.0

sync
(() =>
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@see ― source

console
.
Console.error(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stderr with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const code = 5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr

If formatting elements (e.g. %d) are not found in the first string then util.inspect() is called on each argument and the resulting string values are concatenated. See util.format() for more information.

@since ― v0.1.100

error
('Could not rename:',
error: IdentityError
error
.
message: string
message
)),
),
);

@dxos/halo also exports the errors Keyhive raises when it checks a membership operation. They name why a delegation or a revocation was refused:

Error Raised when
NotAuthorizedError The acting member lacks the access, such as revoking without seniority
UnknownPrincipalError The identity, device or group named is not known
InvalidSignatureError A signed operation fails verification
MissingDependencyError An operation refers to earlier operations that have not arrived