Hyperlinkv0.8.0-beta.28

Hyperlink

Hyperlink.serveInstancesconstsrc/Hyperlink.ts:3812
<S extends Spec>(
  factory: {
    readonly groupId: string
    readonly [specSym]: FlatSpec
    readonly [specTypeSym]?: S
    readonly [groupSym]: RpcGroupOf<S>
  },
  ...instances: ReadonlyArray<HyperlinkInstance<S>>
): Layer.Layer<HandlerContextOf<S>>

The family server layer: serve many instances of one factory behind a single contract group, dispatching each request to the right instance by the per-call key header. Instances share one tagFor factory (one spec, one RPC group); each is passed once via Hyperlink.instance.

Why one variadic call rather than one-layer-per-instance: composing instances as sibling layers would silently keep only the last (Effect's Context is a map — same-key layers last-write-wins). Passing them together is the foolproof shape: every instance is wired, and a duplicate key throws at assembly.

const Queue = Hyperlink.tagFor("queue", { pause: Hyperlink.effect(Schema.Void) });
class Jobs extends Queue<Jobs>("@app/Jobs") {}
class Mail extends Queue<Mail>("@app/Mail") {}

const serveAll = Hyperlink.serveInstances(
  Queue,
  Hyperlink.instance(Jobs, jobsImpl),
  Hyperlink.instance(Mail, mailImpl),
);
servingtagForHyperlink.instance
Source src/Hyperlink.ts:381256 lines
const serveInstances = <S extends Spec>(
  factory: {
    readonly groupId: string;
    readonly [specSym]: FlatSpec;
    readonly [specTypeSym]?: S;
    readonly [groupSym]: RpcGroupOf<S>;
  },
  ...instances: ReadonlyArray<HyperlinkInstance<S>>
): Layer.Layer<HandlerContextOf<S>> => {
  const group = factory[groupSym];
  const spec = factory[specSym];

  // Build the routing table once, at assembly: key → instance impl (flattened to path keys so nested
  // groups dispatch by the same path-keyed procedures the handlers use). A duplicate key is a wiring
  // mistake — fail loudly rather than silently shadow an instance.
  const table = new Map<string, Record<string, unknown>>();
  for (const { key, impl } of instances) {
    if (table.has(key)) {
      throw new DuplicateInstance({ key });
    }
    table.set(key, flattenImpl(impl as Record<string, unknown>, spec));
  }

  // One handler per contract method; each reads the instance-key header, looks up the
  // instance, and dispatches. A missing/unknown key is a protocol-level fault
  // (the contract is satisfied) → die, not a typed domain error.
  const handlers: Record<
    string,
    (payload: unknown, options: { readonly headers: Headers.Headers }) => unknown
  > = {};
  for (const key of Object.keys(spec)) {
    // handlers are keyed by the wire tag (group-prefixed), matching the group's procedures.
    handlers[wireTag(factory.groupId, key)] = (payload, options) => {
      const instanceKey = Option.getOrUndefined(Headers.get(options.headers, INSTANCE_KEY_HEADER));
      if (instanceKey === undefined) {
        return Effect.die(
          new InstanceRoutingError({ method: key, reason: "missing-key" }),
        );
      }
      const impl = table.get(instanceKey);
      if (impl === undefined) {
        return Effect.die(
          new InstanceRoutingError({ method: key, reason: "unknown-key", key: instanceKey }),
        );
      }
      const member = (impl as Record<string, unknown>)[key];
      return invokeWireMethod(member, spec[key] as AnyMethod, payload);
    };
  }

  // Boundary assertion (runtime-safe): handlers mirror the shared spec the group
  // was built from, and RPC validates every payload/result at the wire. Output pinned
  // to {@link HandlerContextOf} to keep the layer's requirement channel `never`.
  const handlerLayer: any = group.toLayer(handlers as any);
  return handlerLayer as any;
};