@@ -192,53 +192,55 @@ type WithFnsSeed<U> = {
192192 : WithFnsSeed < U [ K ] > ;
193193} ;
194194
195- /** Var seeds only - the half of {@link WithSeed} that stays small in
196- * declaration emit when the `use` fn override map is wide. */
195+ /** Var seeds only - the half of {@link WithSeed} that stays small when
196+ * the `use` fn override map is wide. */
197197type WithVarsSeed < RV > = { [ K in keyof RV ] ?: RV [ K ] } ;
198198
199199/**
200- * Flat `.with` seed map stored on exported fns. Evaluating ScopeOf /
201- * ModuleFns here (instead of embedding those wrappers as type arguments)
202- * keeps declaration emit small: `.d.ts` shows leaf var shapes and bound
203- * call signatures, not `ScopeOf<ResolvedVars<entire module graph>>`.
204- *
205- * Declaration emit stores {@link WithSeedStored} on the fn (var seeds
206- * only); terminating `.fn()` intersects a full {@link WithSeed} `.with`.
200+ * Flat `.with` seed map: var values plus bound call overrides for `use`
201+ * fns. Prefer this on {@link Instance.with} (builder-scoped) - putting
202+ * `ScopeOf` / `ModuleFns` onto an exported terminating fn's inferred type
203+ * blows past declaration serialize limits (TS7056).
207204 */
208205export type WithSeed < RV , U > = Prettify < WithVarsSeed < RV > & WithFnsSeed < U > > ;
209206
210- /** What declaration emit stores for `W` - var seeds only so TS does not
211- * inline `BoundFnCall` per used fn from the builder `use` graph. */
207+ /**
208+ * @deprecated Var-seed half of {@link WithSeed}. Terminating exports no
209+ * longer store this on `W` - use {@link WithSeedOpaque} / {@link Instance.with }.
210+ */
212211export type WithSeedStored < RV , _U = unknown > = WithVarsSeed < RV > ;
213212
214- /** What `v.fn` / `e.fn` returns: contract params plus a stored seed map
215- * for `.with`, never the raw ScopeOf / ModuleFns graph. */
213+ /**
214+ * Emit-safe `.with` seed on terminating / exported fns. A plain object
215+ * bag - declaration emit never inlines the builder's `ScopeOf` /
216+ * `ModuleFns` graph. Precise seed checking lives on {@link Instance.with}.
217+ */
218+ export type WithSeedOpaque = object ;
219+
220+ /** What `v.fn` / `e.fn` returns: contract params plus an opaque `.with`
221+ * seed slot - never `ScopeOf` / `ModuleFns` / {@link WithSeed}. */
216222export type PublicFn <
217223 A ,
218224 R ,
219225 K extends string ,
220226 I ,
221227 P extends readonly string [ ] ,
222228 Er ,
223- W = unknown ,
229+ W = WithSeedOpaque ,
224230 O = unknown ,
225231> = FnDefination < A , R , K , I , P , Er , W , O > ;
226232
227- /** Terminating `.fn()` product: compact { @link WithSeedStored} on the
228- * fn for declaration emit, full { @link WithSeed} on ` .with` while typing . */
233+ /** Terminating `.fn()` product: opaque `W` so `export const foo = b.fn(...)`
234+ * stays under TS7056. Precise seeds: `builder .with(foo, seed)` . */
229235type TerminatingFn <
230236 A ,
231237 R ,
232238 K extends string ,
233239 I ,
234240 P extends readonly string [ ] ,
235241 Er ,
236- RV ,
237- U ,
238242 O = unknown ,
239- > = PublicFn < A , R , K , I , P , Er , WithSeedStored < RV , U > , O > & {
240- with ( context : WithSeed < RV , U > ) : BoundCall < A , R , I , Er > ;
241- } ;
243+ > = PublicFn < A , R , K , I , P , Er , WithSeedOpaque , O > ;
242244
243245/** What `.with` returns: the same callable, context baked in.
244246 * Re-exported from the package entry so exporting `.with(...)` results
@@ -255,9 +257,10 @@ export interface FnDefination<
255257 I = unknown ,
256258 P extends readonly string [ ] = readonly string [ ] ,
257259 Er = NoErrors ,
258- /** `.with` seed map ({@link WithSeed}). Defaults keep structural
259- * `extends FnDefination<any, ...>` checks passing. */
260- W = unknown ,
260+ /** `.with` seed map. Terminating exports use {@link WithSeedOpaque};
261+ * defaults keep structural `extends FnDefination<any, ...>` checks
262+ * passing. */
263+ W = WithSeedOpaque ,
261264 O = unknown ,
262265> {
263266 ( ...args : CallArgs < A , I > ) : R ;
@@ -271,10 +274,10 @@ export interface FnDefination<
271274 /**
272275 * Call with a HAND-BUILT context. Keys naming a var SEED that var in a
273276 * fresh scope; keys naming a `use` fn OVERRIDE that binding for the
274- * whole subtree below. Both are typed from the fn's chain - what the
275- * BUILDER mounted counts, so `signOut.with({ user })` type-checks even
276- * though `signOut` itself never says `use: [user]`. A parent passed to
277- * the bound call is FORKED: its vars are copied in, never written back.
277+ * whole subtree below. On terminating / exported fns `W` is
278+ * { @link WithSeedOpaque} (emit-safe); for precise seed checking use
279+ * { @link Instance.with}. A parent passed to the bound call is FORKED:
280+ * its vars are copied in, never written back.
278281 */
279282 with ( context : W ) : BoundCall < A , R , I , Er > ;
280283 /** Brand, so a plugin module can be scanned for its fns. */
@@ -651,9 +654,7 @@ export interface Fn<
651654 Prefix extends "" ? string : Prefix ,
652655 unknown ,
653656 readonly string [ ] ,
654- NoErrors ,
655- ScopeOf < [ ] , Base , BasePL > ,
656- BaseFns
657+ NoErrors
657658 > ;
658659 < K extends LiteralString , R > (
659660 key : K ,
@@ -672,9 +673,7 @@ export interface Fn<
672673 `${Prefix } ${K } `,
673674 unknown ,
674675 readonly string [ ] ,
675- NoErrors ,
676- ScopeOf < [ ] , Base , BasePL > ,
677- BaseFns
676+ NoErrors
678677 > ;
679678
680679 <
@@ -712,8 +711,6 @@ export interface Fn<
712711 I ,
713712 P ,
714713 Er ,
715- ScopeOf < PL , Base , ChainPL < BasePL , PL > > ,
716- UsableInScope < BaseFns , PL , BasePL > ,
717714 O
718715 > ;
719716 <
@@ -753,8 +750,6 @@ export interface Fn<
753750 I ,
754751 P ,
755752 Er ,
756- ScopeOf < PL , Base , ChainPL < BasePL , PL > > ,
757- UsableInScope < BaseFns , PL , BasePL > ,
758753 O
759754 > ;
760755
@@ -1656,6 +1651,18 @@ export interface InstanceOn<Base, BaseFns, Prefix extends string> {
16561651 ) : OnEntry < `${Prefix } ${N } `, Ext > ;
16571652}
16581653
1654+ /** Bound call from a terminating fn - used by {@link Instance.with}. */
1655+ type BoundCallFrom < F > = F extends FnDefination <
1656+ infer A ,
1657+ infer R ,
1658+ string ,
1659+ infer I ,
1660+ any ,
1661+ infer Er
1662+ >
1663+ ? BoundCall < A , R , I , Er >
1664+ : never ;
1665+
16591666export type Instance <
16601667 Base ,
16611668 BaseFns ,
@@ -1676,6 +1683,16 @@ export type Instance<
16761683 /** Same as `v.on`, with the prefix on string targets and the handler
16771684 * typed against the matched target fn. */
16781685 on : InstanceOn < Base , BaseFns , Prefix > ;
1686+ /**
1687+ * Precise `.with` for fns built on this builder. Seeds are typed from
1688+ * the builder's mounted vars / `use` fns - without putting that graph
1689+ * onto the fn's exported declaration type (see {@link WithSeedOpaque}).
1690+ * Runtime is `fn.with(context)`.
1691+ */
1692+ with < F extends FnDefination < any , any , string , any , any , any > > (
1693+ fn : F ,
1694+ context : WithSeed < ScopeOf < [ ] , Base , PL > , BaseFns > ,
1695+ ) : BoundCallFrom < F > ;
16791696 /**
16801697 * The context a handler on this builder receives - a TYPE carrier for
16811698 * `typeof f.ctx` (helper signatures, plugin contracts). Every handler
@@ -1748,6 +1765,8 @@ const builderFn = (baseKey: string, base: Record<string, any>) => {
17481765 a ,
17491766 b ,
17501767 ) ,
1768+ with : ( fn : { with : ( context : unknown ) => unknown } , context : unknown ) =>
1769+ fn . with ( context ) ,
17511770 } ;
17521771 }
17531772 return defineFn ( key || "anonymous" , options , handler ) ;
0 commit comments