Skip to content

Invite people

By the end of this page Alice can invite Bob into Book club, and Bob joins with two codes: one she sends him and one she tells him.

An invitation takes two codes, which travel by different routes. The invitation code is long and goes in a message or a link. The authorization code is six digits, which the host sees once the guest connects and passes on another way, such as reading it aloud. Someone who intercepts only the message cannot get in.

When the guest enters the right code, the two sides exchange contact cards: each names its identity and carries the keys the other needs. Then the host writes a delegation, a statement signed by a member allowed to make it, that admits the guest. Every member checks that delegation for itself, so no server has to vouch for the guest.

An invitation is a Flow. Its events say where the handshake is: connecting, connected, readyForAuthentication, authenticating, then success, cancelled or error. Invitations covers the rest.

  1. Invite someone. Space.share starts the invitation on the host, and Invitation.code is the code to send. shared-secret makes the guest enter the authorization code. Invite calls this and shows the code.

    src/app/Invitations.tsx
    import * as
    import Effect
    Effect
    from 'effect/Effect';
    2 collapsed lines
    import
    (alias) namespace React
    import React
    React
    , {
    function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

    Accepts a function that contains imperative, possibly effectful code.

    @param ― effect Imperative function that can return a cleanup function

    @param ― deps If present, effect will only activate if the values in the list change.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useEffect

    useEffect
    ,
    function useRef<T>(initialValue: T): React.RefObject<T> (+2 overloads)

    useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

    Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useRef

    useRef
    ,
    function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    } from 'react';
    import {
    import Invitation
    Invitation
    ,
    import Space
    Space
    } from '@dxos/halo';
    1 collapsed line
    import {
    const useHaloServices: () => Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ,
    const useInvitationFlow: (flow?: Invitation.Flow) => InvitationFlowState

    Tracks one

    Invitation.Flow

    for rendering, re-rendering on each lifecycle event. Needs no HaloProvider: a flow's streams and effects carry no service requirement.

    useInvitationFlow
    } from '@dxos/halo-react';
    import { type
    type SpaceId = string & {
    __SpaceId: true;
    }
    const SpaceId: Codec<SpaceId, string, never, never> & {
    byteLength: number;
    encode: (value: Uint8Array) => SpaceId;
    decode: (value: SpaceId) => Uint8Array;
    isValid: (value: unknown) => value is SpaceId;
    make: (value: string) => SpaceId;
    random: () => SpaceId;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    } from '@dxos/keys';
    8 collapsed lines
    import {
    const Copyable: ({ value }: {
    value: string;
    }) => React.JSX.Element
    Copyable
    ,
    const Prompt: ({ label, action, initial, multiline, compact, autoFocus, onSubmit, }: {
    label: string;
    action: string;
    initial?: string;
    multiline?: boolean;
    compact?: boolean;
    autoFocus?: boolean;
    onSubmit: (value: string) => Promise<unknown>;
    }) => React.JSX.Element

    A field and a button, which shows the error if onSubmit fails.

    Prompt
    } from './ui.tsx';
    /** Invite someone to the current space, or join a space with a code. */
    export const
    const InviteBar: ({ spaceId }: {
    spaceId?: SpaceId;
    }) => React.JSX.Element

    Invite someone to the current space, or join a space with a code.

    InviteBar
    = ({
    spaceId: SpaceId | undefined
    spaceId
    }: {
    spaceId?: SpaceId | undefined
    spaceId
    ?:
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    }) => {
    const
    const services: Context<HaloServices>
    services
    =
    function useHaloServices(): Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ();
    const [
    const open: "invite" | "join" | undefined
    open
    ,
    const setOpen: React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>
    setOpen
    ] =
    useState<"invite" | "join">(): ["invite" | "join" | undefined, React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <'invite' | 'join'>();
    /** Starts an invitation to the space, and returns the flow and the code to send. */
    const
    const handleInvite: (spaceId: SpaceId) => Promise<{
    flow: Invitation.Flow;
    code: string;
    }>

    Starts an invitation to the space, and returns the flow and the code to send.

    handleInvite
    = (
    spaceId: SpaceId
    spaceId
    :
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    ) =>
    import Effect
    Effect
    .
    const gen: <Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }>(f: () => Generator<Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }, never>) => Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, 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 share: (id: SpaceId, options?: Invitation.ShareOptions) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

    Initiate a space invitation (requires

    Service

    ).

    share
    (
    spaceId: SpaceId
    spaceId
    , {
    authMethod?: Invitation.AuthMethod | undefined
    authMethod
    : 'shared-secret',
    });
    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 {
    flow: Invitation.Flow
    flow
    ,
    code: string
    code
    };
    }).
    Pipeable.pipe<Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>, Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, never>, Promise<{
    flow: Invitation.Flow;
    code: string;
    }>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Promise<...>): Promise<...> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    );
  2. Join. On the guest, Space.join redeems the code and returns the guest’s own flow. Join calls this.

    src/app/Invitations.tsx
    import * as
    import Effect
    Effect
    from 'effect/Effect';
    2 collapsed lines
    import
    (alias) namespace React
    import React
    React
    , {
    function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

    Accepts a function that contains imperative, possibly effectful code.

    @param ― effect Imperative function that can return a cleanup function

    @param ― deps If present, effect will only activate if the values in the list change.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useEffect

    useEffect
    ,
    function useRef<T>(initialValue: T): React.RefObject<T> (+2 overloads)

    useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

    Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useRef

    useRef
    ,
    function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    } from 'react';
    import {
    import Invitation
    Invitation
    ,
    import Space
    Space
    } from '@dxos/halo';
    20 collapsed lines
    import {
    const useHaloServices: () => Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ,
    const useInvitationFlow: (flow?: Invitation.Flow) => InvitationFlowState

    Tracks one

    Invitation.Flow

    for rendering, re-rendering on each lifecycle event. Needs no HaloProvider: a flow's streams and effects carry no service requirement.

    useInvitationFlow
    } from '@dxos/halo-react';
    import { type
    type SpaceId = string & {
    __SpaceId: true;
    }
    const SpaceId: Codec<SpaceId, string, never, never> & {
    byteLength: number;
    encode: (value: Uint8Array) => SpaceId;
    decode: (value: SpaceId) => Uint8Array;
    isValid: (value: unknown) => value is SpaceId;
    make: (value: string) => SpaceId;
    random: () => SpaceId;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    } from '@dxos/keys';
    import {
    const Copyable: ({ value }: {
    value: string;
    }) => React.JSX.Element
    Copyable
    ,
    const Prompt: ({ label, action, initial, multiline, compact, autoFocus, onSubmit, }: {
    label: string;
    action: string;
    initial?: string;
    multiline?: boolean;
    compact?: boolean;
    autoFocus?: boolean;
    onSubmit: (value: string) => Promise<unknown>;
    }) => React.JSX.Element

    A field and a button, which shows the error if onSubmit fails.

    Prompt
    } from './ui.tsx';
    /** Invite someone to the current space, or join a space with a code. */
    export const
    const InviteBar: ({ spaceId }: {
    spaceId?: SpaceId;
    }) => React.JSX.Element

    Invite someone to the current space, or join a space with a code.

    InviteBar
    = ({
    spaceId: SpaceId | undefined
    spaceId
    }: {
    spaceId?: SpaceId | undefined
    spaceId
    ?:
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    }) => {
    const
    const services: Context<HaloServices>
    services
    =
    function useHaloServices(): Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ();
    const [
    const open: "invite" | "join" | undefined
    open
    ,
    const setOpen: React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>
    setOpen
    ] =
    useState<"invite" | "join">(): ["invite" | "join" | undefined, React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <'invite' | 'join'>();
    /** Starts an invitation to the space, and returns the flow and the code to send. */
    const
    const handleInvite: (spaceId: SpaceId) => Promise<{
    flow: Invitation.Flow;
    code: string;
    }>

    Starts an invitation to the space, and returns the flow and the code to send.

    handleInvite
    = (
    spaceId: SpaceId
    spaceId
    :
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    ) =>
    import Effect
    Effect
    .
    const gen: <Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }>(f: () => Generator<Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }, never>) => Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, 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 share: (id: SpaceId, options?: Invitation.ShareOptions) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

    Initiate a space invitation (requires

    Service

    ).

    share
    (
    spaceId: SpaceId
    spaceId
    , {
    authMethod?: Invitation.AuthMethod | undefined
    authMethod
    : 'shared-secret',
    });
    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 {
    flow: Invitation.Flow
    flow
    ,
    code: string
    code
    };
    }).
    Pipeable.pipe<Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>, Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, never>, Promise<{
    flow: Invitation.Flow;
    code: string;
    }>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Promise<...>): Promise<...> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    );
    /** Redeems the invitation `code`, and returns the flow. */
    const
    const handleJoin: (code: string) => Promise<Invitation.Flow>

    Redeems the invitation code, and returns the flow.

    handleJoin
    = (
    code: string
    code
    : string) =>
    import Space
    Space
    .
    const join: (code: string) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

    Redeem a space-invitation code (requires

    Service

    ).

    join
    (
    code: string
    code
    ).
    Pipeable.pipe<Effect.Effect<Invitation.Flow, SpaceError, Space.Service>, Effect.Effect<Invitation.Flow, SpaceError, never>, Promise<Invitation.Flow>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Invitation.Flow, SpaceError, Space.Service>) => Effect.Effect<Invitation.Flow, SpaceError, never>, bc: (_: Effect.Effect<Invitation.Flow, SpaceError, never>) => Promise<...>): Promise<...> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    );
  3. Follow the handshake. useInvitationFlow returns the flow’s latest event and re-renders on each one, until the flow ends. Both sides follow their flow with it. On the host, readyForAuthentication carries the authorization code to show; on the guest, it is the moment to ask for it.

    src/app/Invitations.tsx
    import {
    const useHaloServices: () => Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ,
    const useInvitationFlow: (flow?: Invitation.Flow) => InvitationFlowState

    Tracks one

    Invitation.Flow

    for rendering, re-rendering on each lifecycle event. Needs no HaloProvider: a flow's streams and effects carry no service requirement.

    useInvitationFlow
    } from '@dxos/halo-react';
    79 collapsed lines
    import { type
    type SpaceId = string & {
    __SpaceId: true;
    }
    const SpaceId: Codec<SpaceId, string, never, never> & {
    byteLength: number;
    encode: (value: Uint8Array) => SpaceId;
    decode: (value: SpaceId) => Uint8Array;
    isValid: (value: unknown) => value is SpaceId;
    make: (value: string) => SpaceId;
    random: () => SpaceId;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    } from '@dxos/keys';
    import {
    const Copyable: ({ value }: {
    value: string;
    }) => React.JSX.Element
    Copyable
    ,
    const Prompt: ({ label, action, initial, multiline, compact, autoFocus, onSubmit, }: {
    label: string;
    action: string;
    initial?: string;
    multiline?: boolean;
    compact?: boolean;
    autoFocus?: boolean;
    onSubmit: (value: string) => Promise<unknown>;
    }) => React.JSX.Element

    A field and a button, which shows the error if onSubmit fails.

    Prompt
    } from './ui.tsx';
    /** Invite someone to the current space, or join a space with a code. */
    export const
    const InviteBar: ({ spaceId }: {
    spaceId?: SpaceId;
    }) => React.JSX.Element

    Invite someone to the current space, or join a space with a code.

    InviteBar
    = ({
    spaceId: SpaceId | undefined
    spaceId
    }: {
    spaceId?: SpaceId | undefined
    spaceId
    ?:
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    }) => {
    const
    const services: Context<HaloServices>
    services
    =
    function useHaloServices(): Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ();
    const [
    const open: "invite" | "join" | undefined
    open
    ,
    const setOpen: React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>
    setOpen
    ] =
    useState<"invite" | "join">(): ["invite" | "join" | undefined, React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <'invite' | 'join'>();
    /** Starts an invitation to the space, and returns the flow and the code to send. */
    const
    const handleInvite: (spaceId: SpaceId) => Promise<{
    flow: Invitation.Flow;
    code: string;
    }>

    Starts an invitation to the space, and returns the flow and the code to send.

    handleInvite
    = (
    spaceId: SpaceId
    spaceId
    :
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    ) =>
    import Effect
    Effect
    .
    const gen: <Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }>(f: () => Generator<Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }, never>) => Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, 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 share: (id: SpaceId, options?: Invitation.ShareOptions) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

    Initiate a space invitation (requires

    Service

    ).

    share
    (
    spaceId: SpaceId
    spaceId
    , {
    authMethod?: Invitation.AuthMethod | undefined
    authMethod
    : 'shared-secret',
    });
    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 {
    flow: Invitation.Flow
    flow
    ,
    code: string
    code
    };
    }).
    Pipeable.pipe<Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>, Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, never>, Promise<{
    flow: Invitation.Flow;
    code: string;
    }>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Promise<...>): Promise<...> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    );
    /** Redeems the invitation `code`, and returns the flow. */
    const
    const handleJoin: (code: string) => Promise<Invitation.Flow>

    Redeems the invitation code, and returns the flow.

    handleJoin
    = (
    code: string
    code
    : string) =>
    import Space
    Space
    .
    const join: (code: string) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

    Redeem a space-invitation code (requires

    Service

    ).

    join
    (
    code: string
    code
    ).
    Pipeable.pipe<Effect.Effect<Invitation.Flow, SpaceError, Space.Service>, Effect.Effect<Invitation.Flow, SpaceError, never>, Promise<Invitation.Flow>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Invitation.Flow, SpaceError, Space.Service>) => Effect.Effect<Invitation.Flow, SpaceError, never>, bc: (_: Effect.Effect<Invitation.Flow, SpaceError, never>) => Promise<...>): Promise<...> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    );
    return (
    <
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
    className
    ='cb-invite'>
    <
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
    className
    ='cb-row'>
    <
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    React.HTMLAttributes<T>.className?: string | undefined
    className
    ='cb-button'
    React.ButtonHTMLAttributes<HTMLButtonElement>.disabled?: boolean | undefined
    disabled
    ={!
    spaceId: SpaceId | undefined
    spaceId
    }
    React.AriaAttributes["aria-pressed"]?: boolean | "false" | "mixed" | "true" | undefined

    Indicates the current "pressed" state of toggle buttons.

    @see ― aria-checked

    @see ― aria-selected.

    aria-pressed
    ={
    const open: "invite" | "join" | undefined
    open
    === 'invite'}
    React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
    onClick
    ={() =>
    const setOpen: (value: React.SetStateAction<"invite" | "join" | undefined>) => void
    setOpen
    (
    const open: "invite" | "join" | undefined
    open
    === 'invite' ?
    var undefined
    undefined
    : 'invite')}
    >
    Invite
    </
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    >
    <
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    React.HTMLAttributes<T>.className?: string | undefined
    className
    ='cb-button'
    React.AriaAttributes["aria-pressed"]?: boolean | "false" | "mixed" | "true" | undefined

    Indicates the current "pressed" state of toggle buttons.

    @see ― aria-checked

    @see ― aria-selected.

    aria-pressed
    ={
    const open: "invite" | "join" | undefined
    open
    === 'join'}
    React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
    onClick
    ={() =>
    const setOpen: (value: React.SetStateAction<"invite" | "join" | undefined>) => void
    setOpen
    (
    const open: "invite" | "join" | undefined
    open
    === 'join' ?
    var undefined
    undefined
    : 'join')}
    >
    Join
    </
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    >
    </
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    >
    {
    const open: "invite" | "join" | undefined
    open
    === 'invite' &&
    spaceId: SpaceId | undefined
    spaceId
    && (
    <
    const Host: ({ start, send, }: {
    start: () => Promise<Flow>;
    send: string;
    }) => React.JSX.Element

    The host's side of an invitation: the code to send, then the authorization code to tell.

    Host
    React.Attributes.key?: React.Key | null | undefined
    key
    ={
    spaceId: SpaceId
    spaceId
    }
    start: () => Promise<Flow>
    start
    ={() =>
    const handleInvite: (spaceId: SpaceId) => Promise<{
    flow: Invitation.Flow;
    code: string;
    }>

    Starts an invitation to the space, and returns the flow and the code to send.

    handleInvite
    (
    spaceId: SpaceId
    spaceId
    )}
    send: string
    send
    ='Send this invitation code to the person you invite:'
    />
    )}
    {
    const open: "invite" | "join" | undefined
    open
    === 'join' && (
    <
    const Guest: ({ label, join, onDone, }: {
    label: string;
    join: (code: string) => Promise<Invitation.Flow>;
    onDone?: () => void;
    }) => React.JSX.Element

    The guest's side of an invitation: paste the code, then type the authorization code.

    Guest
    label: string
    label
    ='Invitation code'
    join: (code: string) => Promise<Invitation.Flow>
    join
    ={
    const handleJoin: (code: string) => Promise<Invitation.Flow>

    Redeems the invitation code, and returns the flow.

    handleJoin
    }
    onDone?: (() => void) | undefined
    onDone
    ={() =>
    const setOpen: (value: React.SetStateAction<"invite" | "join" | undefined>) => void
    setOpen
    (
    var undefined
    undefined
    )}
    />
    )}
    </
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    >
    );
    };
    type
    type Flow = {
    flow: Invitation.Flow;
    code: string;
    }
    Flow
    = {
    flow: Invitation.Flow
    flow
    :
    import Invitation
    Invitation
    .
    interface Flow

    An in-flight invitation, host or guest side. Produced by

    Identity.share

    /join and

    Space.share

    /join; its lifecycle is then driven through this handle and the

    Service

    .

    Flow
    ;
    code: string
    code
    : string };
    /** The host's side of an invitation: the code to send, then the authorization code to tell. */
    export const
    const Host: ({ start, send, }: {
    start: () => Promise<Flow>;
    send: string;
    }) => React.JSX.Element

    The host's side of an invitation: the code to send, then the authorization code to tell.

    Host
    = ({
    start: () => Promise<Flow>
    start
    ,
    send: string
    send
    ,
    }: {
    start: () => Promise<Flow>
    start
    : () =>
    interface Promise<T>

    Represents the completion of an asynchronous operation

    Promise
    <
    type Flow = {
    flow: Invitation.Flow;
    code: string;
    }
    Flow
    >;
    send: string
    send
    : string;
    }) => {
    const [
    const flow: Flow | undefined
    flow
    ,
    const setFlow: React.Dispatch<React.SetStateAction<Flow | undefined>>
    setFlow
    ] =
    useState<Flow>(): [Flow | undefined, React.Dispatch<React.SetStateAction<Flow | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <
    type Flow = {
    flow: Invitation.Flow;
    code: string;
    }
    Flow
    >();
    const [
    const error: string | undefined
    error
    ,
    const setError: React.Dispatch<React.SetStateAction<string | undefined>>
    setError
    ] =
    useState<string>(): [string | undefined, React.Dispatch<React.SetStateAction<string | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <string>();
    const
    const started: React.RefObject<boolean>
    started
    =
    useRef<boolean>(initialValue: boolean): React.RefObject<boolean> (+2 overloads)

    useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

    Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useRef

    useRef
    (false);
    function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

    Accepts a function that contains imperative, possibly effectful code.

    @param ― effect Imperative function that can return a cleanup function

    @param ― deps If present, effect will only activate if the values in the list change.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useEffect

    useEffect
    (() => {
    if (!
    const started: React.RefObject<boolean>
    started
    .
    React.RefObject<boolean>.current: boolean

    The current value of the ref.

    current
    ) {
    const started: React.RefObject<boolean>
    started
    .
    React.RefObject<boolean>.current: boolean

    The current value of the ref.

    current
    = true;
    start: () => Promise<Flow>
    start
    ().
    Promise<Flow>.then<void, void>(onfulfilled?: ((value: Flow) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>

    Attaches callbacks for the resolution and/or rejection of the Promise.

    @param ― onfulfilled The callback to execute when the Promise is resolved.

    @param ― onrejected The callback to execute when the Promise is rejected.

    @returns ― A Promise for the completion of which ever callback is executed.

    then
    (
    const setFlow: React.Dispatch<React.SetStateAction<Flow | undefined>>
    setFlow
    , (
    error: any
    error
    ) =>
    const setError: (value: React.SetStateAction<string | undefined>) => void
    setError
    (
    var String: StringConstructor
    (value?: any) => string

    Allows manipulation and formatting of text strings and determination and location of substrings within strings.

    String
    (
    error: any
    error
    )));
    }
    }, []);
    /** The flow's latest event, re-rendering as the handshake moves on. */
    const {
    const event: Invitation.Event | undefined
    event
    } =
    function useInvitationFlow(flow?: Invitation.Flow): InvitationFlowState

    Tracks one

    Invitation.Flow

    for rendering, re-rendering on each lifecycle event. Needs no HaloProvider: a flow's streams and effects carry no service requirement.

    useInvitationFlow
    (
    const flow: Flow | undefined
    flow
    ?.
    flow: Invitation.Flow | undefined
    flow
    );
  4. Send the authorization code. On the guest, Invitation.authenticate sends the code the host showed. Send calls this.

    src/app/Invitations.tsx
    import * as
    import Effect
    Effect
    from 'effect/Effect';
    2 collapsed lines
    import
    (alias) namespace React
    import React
    React
    , {
    function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

    Accepts a function that contains imperative, possibly effectful code.

    @param ― effect Imperative function that can return a cleanup function

    @param ― deps If present, effect will only activate if the values in the list change.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useEffect

    useEffect
    ,
    function useRef<T>(initialValue: T): React.RefObject<T> (+2 overloads)

    useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

    Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useRef

    useRef
    ,
    function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    } from 'react';
    import {
    import Invitation
    Invitation
    ,
    import Space
    Space
    } from '@dxos/halo';
    126 collapsed lines
    import {
    const useHaloServices: () => Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ,
    const useInvitationFlow: (flow?: Invitation.Flow) => InvitationFlowState

    Tracks one

    Invitation.Flow

    for rendering, re-rendering on each lifecycle event. Needs no HaloProvider: a flow's streams and effects carry no service requirement.

    useInvitationFlow
    } from '@dxos/halo-react';
    import { type
    type SpaceId = string & {
    __SpaceId: true;
    }
    const SpaceId: Codec<SpaceId, string, never, never> & {
    byteLength: number;
    encode: (value: Uint8Array) => SpaceId;
    decode: (value: SpaceId) => Uint8Array;
    isValid: (value: unknown) => value is SpaceId;
    make: (value: string) => SpaceId;
    random: () => SpaceId;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    } from '@dxos/keys';
    import {
    const Copyable: ({ value }: {
    value: string;
    }) => React.JSX.Element
    Copyable
    ,
    const Prompt: ({ label, action, initial, multiline, compact, autoFocus, onSubmit, }: {
    label: string;
    action: string;
    initial?: string;
    multiline?: boolean;
    compact?: boolean;
    autoFocus?: boolean;
    onSubmit: (value: string) => Promise<unknown>;
    }) => React.JSX.Element

    A field and a button, which shows the error if onSubmit fails.

    Prompt
    } from './ui.tsx';
    /** Invite someone to the current space, or join a space with a code. */
    export const
    const InviteBar: ({ spaceId }: {
    spaceId?: SpaceId;
    }) => React.JSX.Element

    Invite someone to the current space, or join a space with a code.

    InviteBar
    = ({
    spaceId: SpaceId | undefined
    spaceId
    }: {
    spaceId?: SpaceId | undefined
    spaceId
    ?:
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    }) => {
    const
    const services: Context<HaloServices>
    services
    =
    function useHaloServices(): Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ();
    const [
    const open: "invite" | "join" | undefined
    open
    ,
    const setOpen: React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>
    setOpen
    ] =
    useState<"invite" | "join">(): ["invite" | "join" | undefined, React.Dispatch<React.SetStateAction<"invite" | "join" | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <'invite' | 'join'>();
    /** Starts an invitation to the space, and returns the flow and the code to send. */
    const
    const handleInvite: (spaceId: SpaceId) => Promise<{
    flow: Invitation.Flow;
    code: string;
    }>

    Starts an invitation to the space, and returns the flow and the code to send.

    handleInvite
    = (
    spaceId: SpaceId
    spaceId
    :
    type SpaceId = string & {
    __SpaceId: true;
    }

    A unique identifier for a space. Space keys are generated by creating a keypair, and then taking the first 20 bytes of the SHA-256 hash of the public key and encoding them to multibase RFC4648 base-32 format (prefixed with B, see Multibase Table).

    @example BA25QRC2FEWCSAMRP4RZL65LWJ7352CKE

    SpaceId
    ) =>
    import Effect
    Effect
    .
    const gen: <Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }>(f: () => Generator<Effect.Effect<Invitation.Flow, SpaceError, Space.Service> | Effect.Effect<string, InvitationError, never>, {
    flow: Invitation.Flow;
    code: string;
    }, never>) => Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, 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 share: (id: SpaceId, options?: Invitation.ShareOptions) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

    Initiate a space invitation (requires

    Service

    ).

    share
    (
    spaceId: SpaceId
    spaceId
    , {
    authMethod?: Invitation.AuthMethod | undefined
    authMethod
    : 'shared-secret',
    });
    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 {
    flow: Invitation.Flow
    flow
    ,
    code: string
    code
    };
    }).
    Pipeable.pipe<Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>, Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, never>, Promise<{
    flow: Invitation.Flow;
    code: string;
    }>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
    flow: Invitation.Flow;
    code: string;
    }, SpaceError | InvitationError, Space.Service>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Promise<...>): Promise<...> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    );
    /** Redeems the invitation `code`, and returns the flow. */
    const
    const handleJoin: (code: string) => Promise<Invitation.Flow>

    Redeems the invitation code, and returns the flow.

    handleJoin
    = (
    code: string
    code
    : string) =>
    import Space
    Space
    .
    const join: (code: string) => Effect.Effect<Invitation.Flow, SpaceError, Space.Service>

    Redeem a space-invitation code (requires

    Service

    ).

    join
    (
    code: string
    code
    ).
    Pipeable.pipe<Effect.Effect<Invitation.Flow, SpaceError, Space.Service>, Effect.Effect<Invitation.Flow, SpaceError, never>, Promise<Invitation.Flow>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Invitation.Flow, SpaceError, Space.Service>) => Effect.Effect<Invitation.Flow, SpaceError, never>, bc: (_: Effect.Effect<Invitation.Flow, SpaceError, never>) => Promise<...>): Promise<...> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    );
    return (
    <
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
    className
    ='cb-invite'>
    <
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
    className
    ='cb-row'>
    <
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    React.HTMLAttributes<T>.className?: string | undefined
    className
    ='cb-button'
    React.ButtonHTMLAttributes<HTMLButtonElement>.disabled?: boolean | undefined
    disabled
    ={!
    spaceId: SpaceId | undefined
    spaceId
    }
    React.AriaAttributes["aria-pressed"]?: boolean | "false" | "mixed" | "true" | undefined

    Indicates the current "pressed" state of toggle buttons.

    @see ― aria-checked

    @see ― aria-selected.

    aria-pressed
    ={
    const open: "invite" | "join" | undefined
    open
    === 'invite'}
    React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
    onClick
    ={() =>
    const setOpen: (value: React.SetStateAction<"invite" | "join" | undefined>) => void
    setOpen
    (
    const open: "invite" | "join" | undefined
    open
    === 'invite' ?
    var undefined
    undefined
    : 'invite')}
    >
    Invite
    </
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    >
    <
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    React.HTMLAttributes<T>.className?: string | undefined
    className
    ='cb-button'
    React.AriaAttributes["aria-pressed"]?: boolean | "false" | "mixed" | "true" | undefined

    Indicates the current "pressed" state of toggle buttons.

    @see ― aria-checked

    @see ― aria-selected.

    aria-pressed
    ={
    const open: "invite" | "join" | undefined
    open
    === 'join'}
    React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
    onClick
    ={() =>
    const setOpen: (value: React.SetStateAction<"invite" | "join" | undefined>) => void
    setOpen
    (
    const open: "invite" | "join" | undefined
    open
    === 'join' ?
    var undefined
    undefined
    : 'join')}
    >
    Join
    </
    React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
    button
    >
    </
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    >
    {
    const open: "invite" | "join" | undefined
    open
    === 'invite' &&
    spaceId: SpaceId | undefined
    spaceId
    && (
    <
    const Host: ({ start, send, }: {
    start: () => Promise<Flow>;
    send: string;
    }) => React.JSX.Element

    The host's side of an invitation: the code to send, then the authorization code to tell.

    Host
    React.Attributes.key?: React.Key | null | undefined
    key
    ={
    spaceId: SpaceId
    spaceId
    }
    start: () => Promise<Flow>
    start
    ={() =>
    const handleInvite: (spaceId: SpaceId) => Promise<{
    flow: Invitation.Flow;
    code: string;
    }>

    Starts an invitation to the space, and returns the flow and the code to send.

    handleInvite
    (
    spaceId: SpaceId
    spaceId
    )}
    send: string
    send
    ='Send this invitation code to the person you invite:'
    />
    )}
    {
    const open: "invite" | "join" | undefined
    open
    === 'join' && (
    <
    const Guest: ({ label, join, onDone, }: {
    label: string;
    join: (code: string) => Promise<Invitation.Flow>;
    onDone?: () => void;
    }) => React.JSX.Element

    The guest's side of an invitation: paste the code, then type the authorization code.

    Guest
    label: string
    label
    ='Invitation code'
    join: (code: string) => Promise<Invitation.Flow>
    join
    ={
    const handleJoin: (code: string) => Promise<Invitation.Flow>

    Redeems the invitation code, and returns the flow.

    handleJoin
    }
    onDone?: (() => void) | undefined
    onDone
    ={() =>
    const setOpen: (value: React.SetStateAction<"invite" | "join" | undefined>) => void
    setOpen
    (
    var undefined
    undefined
    )}
    />
    )}
    </
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    >
    );
    };
    type
    type Flow = {
    flow: Invitation.Flow;
    code: string;
    }
    Flow
    = {
    flow: Invitation.Flow
    flow
    :
    import Invitation
    Invitation
    .
    interface Flow

    An in-flight invitation, host or guest side. Produced by

    Identity.share

    /join and

    Space.share

    /join; its lifecycle is then driven through this handle and the

    Service

    .

    Flow
    ;
    code: string
    code
    : string };
    /** The host's side of an invitation: the code to send, then the authorization code to tell. */
    export const
    const Host: ({ start, send, }: {
    start: () => Promise<Flow>;
    send: string;
    }) => React.JSX.Element

    The host's side of an invitation: the code to send, then the authorization code to tell.

    Host
    = ({
    start: () => Promise<Flow>
    start
    ,
    send: string
    send
    ,
    }: {
    start: () => Promise<Flow>
    start
    : () =>
    interface Promise<T>

    Represents the completion of an asynchronous operation

    Promise
    <
    type Flow = {
    flow: Invitation.Flow;
    code: string;
    }
    Flow
    >;
    send: string
    send
    : string;
    }) => {
    const [
    const flow: Flow | undefined
    flow
    ,
    const setFlow: React.Dispatch<React.SetStateAction<Flow | undefined>>
    setFlow
    ] =
    useState<Flow>(): [Flow | undefined, React.Dispatch<React.SetStateAction<Flow | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <
    type Flow = {
    flow: Invitation.Flow;
    code: string;
    }
    Flow
    >();
    const [
    const error: string | undefined
    error
    ,
    const setError: React.Dispatch<React.SetStateAction<string | undefined>>
    setError
    ] =
    useState<string>(): [string | undefined, React.Dispatch<React.SetStateAction<string | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <string>();
    const
    const started: React.RefObject<boolean>
    started
    =
    useRef<boolean>(initialValue: boolean): React.RefObject<boolean> (+2 overloads)

    useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

    Note that useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useRef

    useRef
    (false);
    function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

    Accepts a function that contains imperative, possibly effectful code.

    @param ― effect Imperative function that can return a cleanup function

    @param ― deps If present, effect will only activate if the values in the list change.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useEffect

    useEffect
    (() => {
    if (!
    const started: React.RefObject<boolean>
    started
    .
    React.RefObject<boolean>.current: boolean

    The current value of the ref.

    current
    ) {
    const started: React.RefObject<boolean>
    started
    .
    React.RefObject<boolean>.current: boolean

    The current value of the ref.

    current
    = true;
    start: () => Promise<Flow>
    start
    ().
    Promise<Flow>.then<void, void>(onfulfilled?: ((value: Flow) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>

    Attaches callbacks for the resolution and/or rejection of the Promise.

    @param ― onfulfilled The callback to execute when the Promise is resolved.

    @param ― onrejected The callback to execute when the Promise is rejected.

    @returns ― A Promise for the completion of which ever callback is executed.

    then
    (
    const setFlow: React.Dispatch<React.SetStateAction<Flow | undefined>>
    setFlow
    , (
    error: any
    error
    ) =>
    const setError: (value: React.SetStateAction<string | undefined>) => void
    setError
    (
    var String: StringConstructor
    (value?: any) => string

    Allows manipulation and formatting of text strings and determination and location of substrings within strings.

    String
    (
    error: any
    error
    )));
    }
    }, []);
    /** The flow's latest event, re-rendering as the handshake moves on. */
    const {
    const event: Invitation.Event | undefined
    event
    } =
    function useInvitationFlow(flow?: Invitation.Flow): InvitationFlowState

    Tracks one

    Invitation.Flow

    for rendering, re-rendering on each lifecycle event. Needs no HaloProvider: a flow's streams and effects carry no service requirement.

    useInvitationFlow
    (
    const flow: Flow | undefined
    flow
    ?.
    flow: Invitation.Flow | undefined
    flow
    );
    if (
    const error: string | undefined
    error
    ) {
    return <
    React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
    p
    React.HTMLAttributes<T>.className?: string | undefined
    className
    ='cb-error'>{
    const error: string
    error
    }</
    React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
    p
    >;
    }
    if (!
    const flow: Flow | undefined
    flow
    ) {
    return <
    React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
    p
    React.HTMLAttributes<T>.className?: string | undefined
    className
    ='cb-muted'>Starting the invitation…</
    React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
    p
    >;
    }
    return (
    <
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    React.HTMLAttributes<HTMLDivElement>.className?: string | undefined
    className
    ='cb-panel'>
    <
    React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
    p
    >{
    send: string
    send
    }</
    React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
    p
    >
    <
    const Copyable: ({ value }: {
    value: string;
    }) => React.JSX.Element
    Copyable
    value: string
    value
    ={
    const flow: Flow
    flow
    .
    code: string
    code
    } />
    <
    const Status: ({ event, host, }: {
    event?: Invitation.Event;
    host?: boolean;
    }) => React.JSX.Element | null
    Status
    event?: Invitation.Event | undefined
    event
    ={
    const event: Invitation.Event | undefined
    event
    }
    host?: boolean | undefined
    host
    />
    </
    React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
    div
    >
    );
    };
    /** The guest's side of an invitation: paste the code, then type the authorization code. */
    export const
    const Guest: ({ label, join, onDone, }: {
    label: string;
    join: (code: string) => Promise<Invitation.Flow>;
    onDone?: () => void;
    }) => React.JSX.Element

    The guest's side of an invitation: paste the code, then type the authorization code.

    Guest
    = ({
    label: string
    label
    ,
    join: (code: string) => Promise<Invitation.Flow>
    join
    ,
    onDone: (() => void) | undefined
    onDone
    ,
    }: {
    label: string
    label
    : string;
    join: (code: string) => Promise<Invitation.Flow>
    join
    : (
    code: string
    code
    : string) =>
    interface Promise<T>

    Represents the completion of an asynchronous operation

    Promise
    <
    import Invitation
    Invitation
    .
    interface Flow

    An in-flight invitation, host or guest side. Produced by

    Identity.share

    /join and

    Space.share

    /join; its lifecycle is then driven through this handle and the

    Service

    .

    Flow
    >;
    onDone?: (() => void) | undefined
    onDone
    ?: () => void;
    }) => {
    const
    const services: Context<HaloServices>
    services
    =
    function useHaloServices(): Context<HaloServices>

    Returns the HALO services context. Throws if no

    HaloProvider

    is above in the tree.

    useHaloServices
    ();
    const [
    const flow: Invitation.Flow | undefined
    flow
    ,
    const setFlow: React.Dispatch<React.SetStateAction<Invitation.Flow | undefined>>
    setFlow
    ] =
    useState<Invitation.Flow>(): [Invitation.Flow | undefined, React.Dispatch<React.SetStateAction<Invitation.Flow | undefined>>] (+1 overload)

    Returns a stateful value, and a function to update it.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useState

    useState
    <
    import Invitation
    Invitation
    .
    interface Flow

    An in-flight invitation, host or guest side. Produced by

    Identity.share

    /join and

    Space.share

    /join; its lifecycle is then driven through this handle and the

    Service

    .

    Flow
    >();
    const {
    const event: Invitation.Event | undefined
    event
    } =
    function useInvitationFlow(flow?: Invitation.Flow): InvitationFlowState

    Tracks one

    Invitation.Flow

    for rendering, re-rendering on each lifecycle event. Needs no HaloProvider: a flow's streams and effects carry no service requirement.

    useInvitationFlow
    (
    const flow: Invitation.Flow | undefined
    flow
    );
    function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

    Accepts a function that contains imperative, possibly effectful code.

    @param ― effect Imperative function that can return a cleanup function

    @param ― deps If present, effect will only activate if the values in the list change.

    @version ― 16.8.0

    @see ― https://react.dev/reference/react/useEffect

    useEffect
    (() => {
    if (
    const event: Invitation.Event | undefined
    event
    ?.
    _tag: "connecting" | "connected" | "readyForAuthentication" | "authenticating" | "success" | "cancelled" | "error" | undefined
    _tag
    === 'success' &&
    onDone: (() => void) | undefined
    onDone
    ) {
    const
    const timeout: NodeJS.Timeout
    timeout
    =
    function setTimeout<[]>(callback: () => void, ms?: number): NodeJS.Timeout (+2 overloads)

    Schedules execution of a one-time callback after delay milliseconds.

    The callback will likely not be invoked in precisely delay milliseconds. Node.js makes no guarantees about the exact timing of when callbacks will fire, nor of their ordering. The callback will be called as close as possible to the time specified.

    When delay is larger than 2147483647 or less than 1, the delay will be set to 1. Non-integer delays are truncated to an integer.

    If callback is not a function, a TypeError will be thrown.

    This method has a custom variant for promises that is available using timersPromises.setTimeout().

    @since ― v0.0.1

    @param ― callback The function to call when the timer elapses.

    @param ― delay The number of milliseconds to wait before calling the callback.

    @param ― args Optional arguments to pass when the callback is called.

    @return ― for use with clearTimeout

    setTimeout
    (
    onDone: () => void
    onDone
    , 1500);
    return () =>
    function clearTimeout(timeoutId: NodeJS.Timeout | string | number | undefined): void (+1 overload)

    Cancels a Timeout object created by setTimeout().

    @since ― v0.0.1

    @param ― timeout A Timeout object as returned by setTimeout or the primitive of the Timeout object as a string or a number.

    clearTimeout
    (
    const timeout: NodeJS.Timeout
    timeout
    );
    }
    }, [
    const event: Invitation.Event | undefined
    event
    ]);
    if (!
    const flow: Invitation.Flow | undefined
    flow
    ) {
    return (
    <
    const Prompt: ({ label, action, initial, multiline, compact, autoFocus, onSubmit, }: {
    label: string;
    action: string;
    initial?: string;
    multiline?: boolean;
    compact?: boolean;
    autoFocus?: boolean;
    onSubmit: (value: string) => Promise<unknown>;
    }) => React.JSX.Element

    A field and a button, which shows the error if onSubmit fails.

    Prompt
    label: string
    label
    ={
    label: string
    label
    }
    action: string
    action
    ='Join'
    onSubmit: (value: string) => Promise<unknown>
    onSubmit
    ={(
    code: string
    code
    ) =>
    join: (code: string) => Promise<Invitation.Flow>
    join
    (
    code: string
    code
    .
    String.trim(): string

    Removes the leading and trailing white space and line terminator characters from a string.

    trim
    ()).
    Promise<Flow>.then<void, unknown>(onfulfilled?: ((value: Invitation.Flow) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => unknown) | null | undefined): Promise<unknown>

    Attaches callbacks for the resolution and/or rejection of the Promise.

    @param ― onfulfilled The callback to execute when the Promise is resolved.

    @param ― onrejected The callback to execute when the Promise is rejected.

    @returns ― A Promise for the completion of which ever callback is executed.

    then
    (
    const setFlow: React.Dispatch<React.SetStateAction<Invitation.Flow | undefined>>
    setFlow
    )}
    />
    );
    }
    /** Sends the authorization code the host shows. */
    const
    const handleAuthenticate: (authCode: string) => Promise<void>

    Sends the authorization code the host shows.

    handleAuthenticate
    = (
    authCode: string
    authCode
    : string) =>
    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
    ,
    authCode: string
    authCode
    .
    String.trim(): string

    Removes the leading and trailing white space and line terminator characters from a string.

    trim
    ()).
    Pipeable.pipe<Effect.Effect<void, InvitationError, never>, Effect.Effect<void, InvitationError, never>, Promise<void>>(this: Effect.Effect<void, InvitationError, never>, ab: (_: Effect.Effect<void, InvitationError, never>) => Effect.Effect<void, InvitationError, never>, bc: (_: Effect.Effect<void, InvitationError, never>) => Promise<void>): Promise<void> (+21 overloads)
    pipe
    (
    import Effect
    Effect
    .
    const provide: <HaloServices>(context: Context<HaloServices>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, HaloServices>> (+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 services: Context<HaloServices>
    services
    ),
    import Effect
    Effect
    .
    const runPromise: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>

    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
    ,
    );

Alice has Book club; Bob has nothing yet.

  1. On Alice’s device, press Invite and copy the code.
  2. On Bob’s, press Join, paste it and press Join.
  3. Alice’s device now shows an authorization code. Type it into Bob’s and press Send.

Bob’s dropdown now has Book club, and both devices list Alice and Bob under People. Rename one of them and watch the other follow.

You can invite someone into a space and join one, with an authorization code. Next, Your contacts gathers everyone you share a space with.