Hyperlinkv0.8.0-beta.28

Hyperlink

Hyperlink.clientfunctionsrc/Hyperlink.ts:5589
<Self, S extends Spec, HSelf>(
  tag: NodeBoundTag<Self, S, HSelf> & {
    readonly [nodeSym]: AddressedNode<HSelf>
  }
): Layer.Layer<Self, ClientVerifyError>
<Self, S extends Spec, HSelf>(
  tag: NodeBoundTag<Self, S, HSelf>
): Layer.Layer<Self, never, HSelf>
<Self, S extends Spec, HSelf>(
  tag: HyperlinkTag<Self, S>,
  node: AddressedNode<HSelf>
): Layer.Layer<Self, ClientVerifyError>
<Self, S extends Spec, HSelf>(
  tag: HyperlinkTag<Self, S>,
  node: NodeKey<HSelf>
): Layer.Layer<Self, never, HSelf>
<Self, S extends Spec>(tag: HyperlinkTag<Self, S>): Layer.Layer<
  Self,
  never,
  RpcClient.Protocol
>

The client layer for a resource: drive it over RPC as if it were local — the exact same yield* Tag code as the local layer, only the provided layer differs, so it doesn't matter where the resource actually runs.

Paths, by whether — and where — the tag names a Node:

  • node-bearing + AddressedNodeclient(Hosted) when the tag's { node } is dialable: auto-wires connect (R = never). Bare bound nodes still require the node service.
  • nodeless tag + AddressedNodeclient(tag, Worker) same auto-connect gate.
  • bare nodeclient(tag, Bare) / bare-bound client(Hosted) still require the node; provide Node.connect(Bare, protocol) (or lookup / discoverClient) yourself.
  • nodeless tag, ambient transport — ambient RpcClient.Protocol.
clientsNodeAddressedNodeNode.connect
Source src/Hyperlink.ts:558989 lines
function clientLayer<Self, S extends Spec, HSelf>(
  tag: NodeBoundTag<Self, S, HSelf> & {
    readonly [nodeSym]: AddressedNode<HSelf>;
  },
): Layer.Layer<Self, ClientVerifyError>;
function clientLayer<Self, S extends Spec, HSelf>(
  tag: NodeBoundTag<Self, S, HSelf>,
): Layer.Layer<Self, never, HSelf>;
function clientLayer<Self, S extends Spec, HSelf>(
  tag: HyperlinkTag<Self, S>,
  node: AddressedNode<HSelf>,
): Layer.Layer<Self, ClientVerifyError>;
function clientLayer<Self, S extends Spec, HSelf>(
  tag: HyperlinkTag<Self, S>,
  node: NodeKey<HSelf>,
): Layer.Layer<Self, never, HSelf>;
function clientLayer<Self, S extends Spec>(
  tag: HyperlinkTag<Self, S>,
): Layer.Layer<Self, never, RpcClient.Protocol>;
function clientLayer<Self, S extends Spec>(
  tag: HyperlinkTag<Self, S>,
  node?: NodeKey<unknown>,
): Layer.Layer<Self, ClientVerifyError, RpcClient.Protocol> {
  const group = tag[groupSym];
  // an explicit `node` (for a nodeless tag) wins; otherwise the tag's own node, if any.
  const nodeKey = node ?? tag[nodeSym];
  // no node anywhere: take the transport from the ambient `RpcClient.Protocol`.
  // `serviceOption` so a missing protocol surfaces as {@link MissingClientProtocol} (not Effect's
  // opaque "Service not found" die). Typed as `E = never` like before — this replaces a defect,
  // not a channel that callers already handled; Protocol stays required in `R`.
  if (nodeKey === undefined) {
    return Layer.effect(
      tag,
      Effect.gen(function* () {
        const protocol = yield* Effect.serviceOption(RpcClient.Protocol);
        if (Option.isNone(protocol)) {
          return yield* new MissingClientProtocol({ resource: tag.key });
        }
        const client = yield* Effect.provideService(
          RpcClient.make(group),
          RpcClient.Protocol,
          protocol.value,
        );
        return yield* buildClientService(tag, client);
      }),
    ) as any;
  }
  // node chosen (from the tag or the argument): resolve the transport from that node service and
  // provide it locally to the client, so the layer requires the node rather than the ambient
  // Protocol. Reading a provided node service can't fail and `RpcClient.make` has no error channel,
  // so client construction never fails or dies — only the resulting method calls carry typed errors.
  // The node identity is erased to `unknown` on the base tag; the two node-typed overloads pin the
  // precise `HSelf` for callers, so this one contained boundary assertion restates the impl's return.
  const layer: any = (Layer.effect as any)(
    tag,
    Effect.gen(function* () {
      const { protocol } = yield* nodeKey as any;
      const client = yield* (Effect.provideService as any)(
        (RpcClient.make as any)(group),
        RpcClient.Protocol,
        protocol,
      );
      return yield* buildClientService(tag, client);
    }) as any,
  );
  // Dialable node (explicit 2nd arg *or* tag-bound): bake the canonical connect Layer
  // (WeakMap-memoized per Node class) so multiple clients share one MemoMap transport.
  // Default-on verify (reject): peer down / wrong-or-stale contract fails Layer build —
  // opt out via {@link clientVerify}. Reserved NodeStatus is auto-served and absent from
  // `status.resources`, so it stays tier-1 (reachability only).
  if (isAddressedNode(nodeKey as AnyNode)) {
    const addressed = nodeKey as AddressedNode<unknown>;
    const connected: any = layer.pipe(Layer.provide(connectAddressed(addressed)));
    const deepResource =
      tag.groupId === "@pm/node-status"
        ? undefined
        : {
            resource: tag.groupId,
            contractHash: contractHash(tag),
          };
    return Layer.unwrap(
      Effect.gen(function* () {
        yield* applyClientVerify(addressed, deepResource);
        return connected;
      }),
    ) as any;
  }
  return layer as any;
}
Referenced by 4 symbols