Hyperlinkv0.9.0-beta.0

Hyperlink

Hyperlink.Tagconstsrc/Hyperlink.ts:3595
<Self>(): SchemaTagBuilder<Self>
<Self, I>(): InterfaceTagBuilder<Self, I>
<const S extends Spec>(
  wireKey: string,
  spec: S & RejectBareLocal<S>,
  options?: TagOptions & { readonly node?: NodeKey<unknown> }
): SharedTagFactory<S>

Create a HyperService service tag.

Solo (schema)Tag<Self>()(key, spec): value type inferred from the spec; wire key = .key.

class Counter extends Hyperlink.Tag<Counter>()("Counter", {
  increment: Hyperlink.effectFn({ by: Schema.Number }),
  current: Hyperlink.effect(Schema.Number),
}) {}

Optional { defaults } on the options bag is sugar for .pipe(Hyperlink.defaults(…)) — bag keys widen Service / yield* Tag the same way.

Solo (interface)Tag<Self, I>()(key, contract): interface I is SSOT; bare local takes its type from I.

Shared SpecTag(wireKey, spec) then Factory<Self>()(instanceKey): one RpcGroup prefixed by wireKey, many Context identities routed by header key. Use only when every instance has the same procedure names and schemas. Serve with ordinary serve / serveRemote (merge layers); dial with ordinary client.

const Counters = Hyperlink.Tag("demo/SharedCounters", {
  snapshot: Hyperlink.effect(Schema.Number),
});
class Nwsl extends Counters<Nwsl>()("@app/Nwsl/counters") {}
class Mls extends Counters<Mls>()("@app/Mls/counters") {}

Layer.mergeAll(
  Hyperlink.serve(Nwsl, { snapshot: Effect.succeed(1) }),
  Hyperlink.serve(Mls, { snapshot: Effect.succeed(2) }),
);

Keys must be unique: a duplicate throws at declaration. Solo tags also claim their key as the wire prefix; shared factories claim wireKey once for the whole family of instances.

constructorslocalserveserveRemoteclient
Source src/Hyperlink.ts:359590 lines
const makeTag = retype<{
  /** Schema-driven solo: infer the service from `spec`; bare {@link local} is a compile error. */
  <Self>(): SchemaTagBuilder<Self>;
  /** Interface-driven solo: `I` is SSOT; bare {@link local} takes its type from `I`. */
  <Self, I>(): InterfaceTagBuilder<Self, I>;
  /** Shared Spec: one wire key, many instance tags (`Factory<Self>()(instanceKey)`). */
  <const S extends Spec>(
    wireKey: string,
    spec: S & RejectBareLocal<S>,
    options?: TagOptions & { readonly node?: NodeKey<unknown> },
  ): SharedTagFactory<S>;
}>(function makeTag(
  wireKeyOrNever?: string,
  sharedSpec?: Spec,
  sharedOptions?: TagOptions & { readonly node?: NodeKey<unknown> },
) {
  // Shared-Spec factory: Tag(wireKey, spec) → Factory<Self>()(instanceKey).
  if (typeof wireKeyOrNever === "string" && sharedSpec !== undefined) {
    const wireKey = wireKeyOrNever;
    claimWireKey(wireKey);
    const flat = flattenSpec(sharedSpec);
    const group = retype<RpcGroupOf<Spec>>(
      buildRpcGroup(wireKey, flat) as never,
    );
    const factoryKind = sharedOptions?.kind ?? wireKey;
    const factoryNode = sharedOptions?.node;
    const mint =
      () =>
      (
        key: string,
        instanceOptions?: {
          readonly description?: string;
          readonly node?: NodeKey<unknown>;
          readonly defaults?: DefaultsBag;
        },
      ) => {
        const tag = buildInstanceTag<unknown, Spec>(
          wireKey,
          key,
          sharedSpec,
          group,
          instanceOptions?.description ?? sharedOptions?.description,
          instanceOptions?.node ?? factoryNode,
          factoryKind,
          false,
          true,
        );
        return applyTagDefaults(tag, instanceOptions?.defaults);
      };
    return Object.assign(mint, {
      wireKey,
      kind: factoryKind,
      description: sharedOptions?.description,
      [specSym]: flat,
      [groupSym]: group,
    });
  }

  // Solo builder — overload surface discriminates schema vs interface.
  // `options.node` rides the call so its identity `HSelf` infers; node-bearing overloads narrow
  // `[nodeSym]` for {@link Hyperlink.client}. An {@link AddressedNode} further enables auto-connect.
  // Self/S are phantom here: the public overloads restate them; pin `unknown`/`Spec` so this body
  // does not chase a free type parameter into RpcGroupOf / ServiceOf.
  function build(
    key: string,
    spec: Spec,
    options?: TagOptions & {
      readonly node?: NodeKey<unknown>;
      readonly defaults?: DefaultsBag;
    },
  ) {
    claimWireKey(key);
    const flat = flattenSpec(spec);
    const interfaceLocals = Object.values(flat).some((m) =>
      Predicate.hasProperty(m, bareLocalSym),
    );
    const tag = buildInstanceTag<unknown, Spec>(
      key,
      key,
      spec,
      retype<RpcGroupOf<Spec>>(buildRpcGroup(key, flat) as never),
      options?.description,
      options?.node,
      options?.kind,
      interfaceLocals,
    );
    return applyTagDefaults(tag, options?.defaults);
  }
  return build;
} as never);
Referenced by 9 symbols