Skip to content

Invitation

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

An invitation lets a device into an identity, or a person into a space. You never make one with this namespace directly: Identity.share, Identity.join, Space.share and Space.join each return an Invitation.Flow, and Invitation drives that flow from either side. Its functions need no service, because they act on the flow handle itself.

share takes options that decide who can redeem the invitation and how:

  • authMethod: 'shared-secret' makes the guest enter the authorization code the host shows; 'none' admits anyone with the invitation code; 'known-public-key' admits only a guest whose key the host names.
  • type: 'interactive' needs host and guest online together; 'delegated' can be redeemed while the host is offline; 'multiuse' admits more than one guest.
  • target: with 'known-public-key', the key or DID of the one guest it admits.
import {
import Invitation
Invitation
,
import Space
Space
} from '@dxos/halo';
const
const options: Invitation.ShareOptions
options
:
import Invitation
Invitation
.
type ShareOptions = {
readonly authMethod?: Invitation.AuthMethod;
readonly type?: Invitation.Type;
readonly multiUse?: boolean;
readonly target?: string;
}

Options for initiating an invitation. Passed to

Identity.share

/

Space.share

.

ShareOptions
= {
authMethod?: Invitation.AuthMethod | undefined
authMethod
: 'none', // anyone with the code may join
type?: Invitation.Type | undefined
type
: 'delegated', // redeemable while the host is offline
multiUse?: boolean | undefined
multiUse
: true, // more than one guest
};
const
const open: Effect.Effect<Invitation.Flow, SpaceError, Space.Service>
open
=
import Space
Space
.
const share: (id: SpaceId, options?: Invitation.ShareOptions) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

Initiate a space invitation (requires

Service

).

share
(
const spaceId: SpaceId
spaceId
,
const options: Invitation.ShareOptions
options
);

Invitation.code is the string to send to the guest, usually inside a link or a QR code.

import * as
import Effect
Effect
from 'effect/Effect';
import {
import Invitation
Invitation
} from '@dxos/halo';
const
const showCode: Effect.Effect<string, InvitationError, never>
showCode
=
import Effect
Effect
.
const gen: <Effect.Effect<string, InvitationError, never>, string>(f: () => Generator<Effect.Effect<string, InvitationError, never>, string, never>) => Effect.Effect<string, InvitationError, never> (+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 code: string
code
= 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 `https://app.example.com/join?code=${
const code: string
code
}`;
});

Invitation.events streams the flow’s progress: connecting, connected, readyForAuthentication, authenticating, then one of success, cancelled or error. On the host, readyForAuthentication carries the authorization code to show. On the guest, it is the moment to call Invitation.authenticate.

import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Stream
Stream
from 'effect/Stream';
import {
import Invitation
Invitation
} from '@dxos/halo';
const
const follow: Effect.Effect<void, never, never>
follow
=
import Invitation
Invitation
.
const events: (flow: Invitation.Flow) => Stream.Stream<Invitation.Event>

Lifecycle event stream of a flow.

events
(
const flow: Invitation.Flow
flow
).
Pipeable.pipe<Stream.Stream<Invitation.Event, never, never>, Stream.Stream<Invitation.Event, never, never>, Effect.Effect<void, never, never>>(this: Stream.Stream<Invitation.Event, never, never>, ab: (_: Stream.Stream<Invitation.Event, never, never>) => Stream.Stream<Invitation.Event, never, never>, bc: (_: Stream.Stream<Invitation.Event, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const takeUntil: <Invitation.Event>(predicate: (a: Invitation.Event, n: number) => boolean, options?: {
readonly excludeLast?: boolean | undefined;
}) => <E, R>(self: Stream.Stream<Invitation.Event, E, R>) => Stream.Stream<Invitation.Event, E, R> (+1 overload)

Takes elements until the predicate matches.

Details

When excludeLast is true, the matching element is dropped.

Example (Taking until a predicate matches)

import { Effect, Stream } from "effect"
const stream = Stream.range(1, 5)
const program = Effect.gen(function*() {
const inclusive = yield* stream.pipe(
Stream.takeUntil((n) => n % 3 === 0),
Stream.runCollect
)
inclusive // => [ 1, 2, 3 ]
const exclusive = yield* stream.pipe(
Stream.takeUntil((n) => n % 3 === 0, { excludeLast: true }),
Stream.runCollect
)
exclusive // => [ 1, 2 ]
})
await Effect.runPromise(program)

@stability ― stable

@category ― filtering

@since ― 2.0.0

takeUntil
(
(
event: Invitation.Event
event
) =>
event: Invitation.Event
event
.
_tag: "connecting" | "connected" | "readyForAuthentication" | "authenticating" | "success" | "cancelled" | "error"
_tag
=== 'success' ||
event: {
readonly _tag: "connecting";
} | {
readonly _tag: "connected";
} | {
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
} | {
readonly _tag: "authenticating";
} | {
readonly _tag: "cancelled";
} | {
readonly _tag: "error";
readonly message: string;
}
event
.
_tag: "connecting" | "connected" | "readyForAuthentication" | "authenticating" | "cancelled" | "error"
_tag
=== 'error' ||
event: {
readonly _tag: "connecting";
} | {
readonly _tag: "connected";
} | {
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
} | {
readonly _tag: "authenticating";
} | {
readonly _tag: "cancelled";
}
event
.
_tag: "connecting" | "connected" | "readyForAuthentication" | "authenticating" | "cancelled"
_tag
=== 'cancelled',
),
import Stream
Stream
.
const runForEach: <Invitation.Event, void, never, never>(f: (a: Invitation.Event) => Effect.Effect<void, never, never>) => <E, R>(self: Stream.Stream<Invitation.Event, E, R>) => Effect.Effect<void, E, R> (+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
((
event: Invitation.Event
event
) =>
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
(() => {
switch (
event: Invitation.Event
event
.
_tag: "connecting" | "connected" | "readyForAuthentication" | "authenticating" | "success" | "cancelled" | "error"
_tag
) {
case 'readyForAuthentication':
return
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
('auth code',
event: {
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}
event
.
authCode?: string | undefined
authCode
);
case 'success':
return
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
('joined space',
event: {
readonly _tag: "success";
readonly result: Invitation.Result;
}
event
.
result: Invitation.Result
result
.
spaceId?: SpaceId | undefined
spaceId
);
case 'error':
return
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
(
event: {
readonly _tag: "error";
readonly message: string;
}
event
.
message: string
message
);
}
}),
),
);
import * as
import Effect
Effect
from 'effect/Effect';
import * as
import Stream
Stream
from 'effect/Stream';
import {
import Invitation
Invitation
,
import Space
Space
} from '@dxos/halo';
declare const
const code: string
code
: string;
declare const
const authCode: string
authCode
: string;
const
const join: Effect.Effect<void, SpaceError | InvitationError, Space.Service>
join
=
import Effect
Effect
.
const gen: <Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<void, InvitationError, never>, void>(f: () => Generator<Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<void, InvitationError, never>, void, never>) => Effect.Effect<void, SpaceError | InvitationError, Space.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 Space
Space
.
const join: (code: string) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

Redeem a space-invitation code (requires

Service

).

join
(
const code: string
code
);
yield*
import Invitation
Invitation
.
const events: (flow: Invitation.Flow) => Stream.Stream<Invitation.Event>

Lifecycle event stream of a flow.

events
(
const flow: Invitation.Flow
flow
).
Pipeable.pipe<Stream.Stream<Invitation.Event, never, never>, Stream.Stream<{
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}, never, never>, Stream.Stream<{
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}, never, never>, Effect.Effect<void, never, never>>(this: Stream.Stream<...>, ab: (_: Stream.Stream<Invitation.Event, never, never>) => Stream.Stream<{
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}, never, never>, bc: (_: Stream.Stream<{
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}, never, never>) => Stream.Stream<...>, cd: (_: Stream.Stream<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Stream
Stream
.
const filter: <Invitation.Event, {
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}>(refinement: Refinement<Invitation.Event, {
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}>) => <E, R>(self: Stream.Stream<Invitation.Event, E, R>) => Stream.Stream<{
readonly _tag: "readyForAuthentication";
readonly authCode?: string;
}, E, R> (+3 overloads)

Filters a stream to the elements that satisfy a predicate.

Example (Filtering stream values)

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

@stability ― stable

@category ― filtering

@since ― 2.0.0

filter
((
event: Invitation.Event
event
) =>
event: Invitation.Event
event
.
_tag: "connecting" | "connected" | "readyForAuthentication" | "authenticating" | "success" | "cancelled" | "error"
_tag
=== 'readyForAuthentication'),
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 runDrain: <A, E, R>(self: Stream.Stream<A, E, R>) => Effect.Effect<void, E, R>

Runs the stream for its effects, discarding emitted elements.

Example (Draining a stream run)

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

@stability ― stable

@category ― destructors

@since ― 2.0.0

runDrain
,
);
yield*
import Invitation
Invitation
.
const authenticate: (flow: Invitation.Flow, code: string) => Effect.Effect<void, InvitationError>

Supply the auth code to a flow awaiting authentication. Flow verbs operate on a

Flow

handle directly and require no service; the active-flow set is queried through

Identity

(device invitations) and

Space

(space invitations).

authenticate
(
const flow: Invitation.Flow
flow
,
const authCode: string
authCode
);
});

Either side can cancel. The host can list its open flows with Space.invitations or Identity.invitations.

import {
import Invitation
Invitation
,
import Space
Space
} from '@dxos/halo';
const
const stop: Effect.Effect<void, never, never>
stop
=
import Invitation
Invitation
.
const cancel: (flow: Invitation.Flow) => Effect.Effect<void>

Abort a flow.

cancel
(
const flow: Invitation.Flow
flow
);
// the flows this host has open for the space
const
const pending: Stream.Stream<readonly Invitation.Flow[], never, Space.Service>
pending
=
import Space
Space
.
const invitations: (id: SpaceId) => Stream.Stream<readonly Invitation.Flow[], never, Space.Service>

A space's active invitation flows as a current-value stream (requires

Service

).

invitations
(
const spaceId: SpaceId
spaceId
);
Member Summary
Flow An invitation in progress, host or guest side
code The invitation code to send
events The flow’s progress as a stream
authenticate Send the authorization code
cancel End the flow
ShareOptions authMethod, type, multiUse and target

The full list is in the API reference.

code and authenticate fail with InvitationError, for example when the guest sends a wrong authorization code. The flow also emits an error event, so a UI following events needs no separate handler.

import * as
import Effect
Effect
from 'effect/Effect';
import {
import Invitation
Invitation
} from '@dxos/halo';
const
const retry: Effect.Effect<void, never, never>
retry
=
import Invitation
Invitation
.
const authenticate: (flow: Invitation.Flow, code: string) => Effect.Effect<void, InvitationError>

Supply the auth code to a flow awaiting authentication. Flow verbs operate on a

Flow

handle directly and require no service; the active-flow set is queried through

Identity

(device invitations) and

Space

(space invitations).

authenticate
(
const flow: Invitation.Flow
flow
,
const authCode: string
authCode
).
Pipeable.pipe<Effect.Effect<void, InvitationError, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, InvitationError, never>, ab: (_: Effect.Effect<void, InvitationError, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect
Effect
.
const catchTag: <"InvitationError", InvitationError, void, never, never, unassigned, never, never>(k: "InvitationError", f: (e: InvitationError) => Effect.Effect<void, never, never>, orElse?: ((e: never) => Effect.Effect<unassigned, never, never>) | undefined) => <A, R>(self: Effect.Effect<A, InvitationError, 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
('InvitationError', (
error: InvitationError
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
('Wrong code?',
error: InvitationError
error
.
message: string
message
)),
),
);

share and join fail with the error of the namespace that started the flow: IdentityError for a device invitation and SpaceError for a space invitation.