Hyperlinkv0.8.0-beta.28

Hyperlink

Hyperlink.fromServiceconstsrc/Hyperlink.ts:3021
<Self, I>(): <const C extends Spec>(
  key: string,
  contract: C & Validate<C, I>,
  options?: { readonly description?: string; readonly kind?: string }
) => HyperlinkTag<Self, ResolveLocals<C, I>>

Build a resource tag from an existing service interface as the single source of truth. The type parameter I is the interface; the contract gives a schema only for the members you want on the wire — every other interface member becomes a local (surfaced via InjectLocal, carrying Local<I>). One merged handle, identical whether you hold the local layer or a client; the only difference is that a client can't call the locals (a compile error — unsatisfied Local).

Locals are written bareHyperlink.local, no () — and take their type from I. A bare local with no matching interface member is rejected at the call (see Validate).

Two type parameters, like Tag: Self (the class — the tag's nominal identity, Local brand) and I (the service interface — a standalone type; passing the class itself as I would be a circular base reference).

interface CounterShape {
  readonly current: Effect.Effect<number>;            // local (no schema)
  readonly add: (by: number) => Effect.Effect<number>; // wired
}
class Counter extends Hyperlink.fromService<Counter, CounterShape>()("counter", {
  current: Hyperlink.local,
  add: Hyperlink.effectFn(Schema.Number, Schema.Number),
}) {}
constructorsInjectLocalValidateTag
Source src/Hyperlink.ts:302123 lines
export const fromService = <Self, I>() => {
  function build<const C extends Spec>(
    key: string,
    contract: C & Validate<C, I>,
    options?: { readonly description?: string; readonly kind?: string },
  ): HyperlinkTag<Self, ResolveLocals<C, I>> {
    // single resource: key doubles as the group id (its wire prefix). The contract *value* is the
    // runtime spec (bare `local`s carry the LocalMethod brand); `S` is presented resolved at the type
    // level so `ImplOf`/`FromServiceOf` derive local types from the interface `I`.
    claimGroupId(key);
    return buildInstanceTag<Self, ResolveLocals<C, I>>(
      key,
      key,
      contract,
      buildRpcGroup(key, flattenSpec(contract)),
      options?.description,
      undefined,
      options?.kind,
      true,
    );
  }
  return build;
};