Hyperlinkv0.9.0-beta.0

Hyperlink

Hyperlink.defaultsconstsrc/Hyperlink.ts:890
<const D extends DefaultsBag>(bag: DefaultsInput<D>): <
  T extends PipeableTag
>(
  tag: T
) => TagWithDefaults<T, D>
<T extends PipeableTag, const D extends DefaultsBag>(
  tag: T,
  bag: DefaultsInput<D>
): TagWithDefaults<T, D>

Pipe multiple Tag-baked defaults onto a Tag — batteries on every local/client handle. Spec stays branded builders; this bag is the extras surface.

Singular fields belong in the contract via default (fully typed on Service). Piped bag keys widen Service / yield* Tag at construction (via remapTagService) so bag keys are typed without a use-site cast — same licensed-cast pattern as named Gate / WorkPool handles. Same key as a Spec path (or a prior bag key) → DuplicateDefaultKey at pipe time.

Layer/serve may override bag keys at the provide site only — overrides do not travel over the wire; clients always see the Tag-baked bag. Prefer Layer.updateService for post-hoc local patches.

class Jobs extends WorkPool.Tag<Jobs>()("@app/Jobs", jobSpec).pipe(
  Hyperlink.defaults({
    label: (n: number) => `job=${n}`,
    tags: ["admin", "beta"],
  }),
) {}
// equivalent factory sugar:
class Jobs2 extends WorkPool.Tag<Jobs2>()("@app/Jobs2", {
  payload: JobSchema,
  defaults: { label: (n: number) => `job=${n}` },
}) {}
const jobs = yield* Jobs
jobs.label(1) // typed on Service — no WithDefaults cast
spec fieldsdefaultremapTagServiceDuplicateDefaultKeyLayer.updateService
Source src/Hyperlink.ts:89037 lines
export const defaults: {
  <const D extends DefaultsBag>(
    bag: DefaultsInput<D>,
  ): <T extends PipeableTag>(tag: T) => TagWithDefaults<T, D>;
  <T extends PipeableTag, const D extends DefaultsBag>(
    tag: T,
    bag: DefaultsInput<D>,
  ): TagWithDefaults<T, D>;
} = Fn.dual(
  2,
  <T extends PipeableTag, D extends DefaultsBag>(
    tag: T,
    bag: D,
  ): TagWithDefaults<T, D> => {
    const flat = tag[specSym];
    for (const key of Object.keys(bag)) {
      if (defaultsCollidesWithSpec(flat, key)) {
        throw new DuplicateDefaultKey({ key });
      }
    }
    const prior =
      defaultsSym in tag
        ? ((tag as { readonly [defaultsSym]?: DefaultsBag })[defaultsSym] ?? {})
        : {};
    for (const key of Object.keys(bag)) {
      if (Object.hasOwn(prior, key)) {
        throw new DuplicateDefaultKey({ key });
      }
    }
    // Soundness: test/defaults-handle.test-d.ts (Svc ⇄ Svc & bag; toolkit keeps named handle).
    return remapTagService<TagWithDefaults<T, D>>(
      Object.assign(tag, {
        [defaultsSym]: { ...prior, ...bag },
      }),
    );
  },
);