better-call 0.0.0-experimental.06264e12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +254 -0
  3. package/dist/error.cjs +67 -0
  4. package/dist/error.cjs.map +1 -0
  5. package/dist/error.d.cts +46 -0
  6. package/dist/error.d.mts +46 -0
  7. package/dist/error.mjs +64 -0
  8. package/dist/error.mjs.map +1 -0
  9. package/dist/fn.cjs +335 -0
  10. package/dist/fn.cjs.map +1 -0
  11. package/dist/fn.d.cts +312 -0
  12. package/dist/fn.d.mts +312 -0
  13. package/dist/fn.mjs +335 -0
  14. package/dist/fn.mjs.map +1 -0
  15. package/dist/index.cjs +37 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.cts +46 -0
  18. package/dist/index.d.mts +46 -0
  19. package/dist/index.mjs +24 -0
  20. package/dist/index.mjs.map +1 -0
  21. package/dist/module.cjs +111 -0
  22. package/dist/module.cjs.map +1 -0
  23. package/dist/module.d.cts +249 -0
  24. package/dist/module.d.mts +249 -0
  25. package/dist/module.mjs +102 -0
  26. package/dist/module.mjs.map +1 -0
  27. package/dist/plugins/http.cjs +185 -0
  28. package/dist/plugins/http.cjs.map +1 -0
  29. package/dist/plugins/http.d.cts +1261 -0
  30. package/dist/plugins/http.d.mts +1261 -0
  31. package/dist/plugins/http.mjs +175 -0
  32. package/dist/plugins/http.mjs.map +1 -0
  33. package/dist/plugins/read-only.cjs +19 -0
  34. package/dist/plugins/read-only.cjs.map +1 -0
  35. package/dist/plugins/read-only.d.cts +17 -0
  36. package/dist/plugins/read-only.d.mts +17 -0
  37. package/dist/plugins/read-only.mjs +19 -0
  38. package/dist/plugins/read-only.mjs.map +1 -0
  39. package/dist/schema.cjs +167 -0
  40. package/dist/schema.cjs.map +1 -0
  41. package/dist/schema.d.cts +225 -0
  42. package/dist/schema.d.mts +225 -0
  43. package/dist/schema.mjs +159 -0
  44. package/dist/schema.mjs.map +1 -0
  45. package/dist/scope.d.cts +18 -0
  46. package/dist/scope.d.mts +18 -0
  47. package/dist/storage.cjs +256 -0
  48. package/dist/storage.cjs.map +1 -0
  49. package/dist/storage.d.cts +195 -0
  50. package/dist/storage.d.mts +195 -0
  51. package/dist/storage.mjs +253 -0
  52. package/dist/storage.mjs.map +1 -0
  53. package/dist/types.d.cts +8 -0
  54. package/dist/types.d.mts +8 -0
  55. package/dist/var.cjs +162 -0
  56. package/dist/var.cjs.map +1 -0
  57. package/dist/var.d.cts +36 -0
  58. package/dist/var.d.mts +36 -0
  59. package/dist/var.mjs +154 -0
  60. package/dist/var.mjs.map +1 -0
  61. package/package.json +92 -0
package/dist/fn.d.cts ADDED
@@ -0,0 +1,312 @@
1
+ import { FnError } from "./error.cjs";
2
+ import { LiteralString, Prettify } from "./types.cjs";
3
+ import { InferArgs, InferInput, OutputSchemaOf, vTypes } from "./schema.cjs";
4
+ import { VarDefination } from "./var.cjs";
5
+ import { ApplyOns, Module, ModuleFns, OnEntry, TargetMatches, VarGetContext, VarSetContext, WithDerived } from "./module.cjs";
6
+ import { ResolvedVars, ScopeOf, VarName, VarScope } from "./scope.cjs";
7
+ //#region src/fn.d.ts
8
+ type ParentContext = Record<string, any>;
9
+ /** The call shape: a TUPLE input spreads - one parameter per position,
10
+ * the parent context last. Everything else takes (input?, parent?). */
11
+ type CallArgs<A, I> = I extends readonly unknown[] ? A extends readonly unknown[] ? [...A] | [...A, ParentContext] : never : [A] extends [void] ? [input?: undefined, parent?: ParentContext] : [input: A, parent?: ParentContext];
12
+ /** The union of a fn's DECLARED errors, as thrown values. */
13
+ type FnErrorsOf<Er> = { [T in keyof Er & string]: FnError<T, InferInput<Er[T]>>; }[keyof Er & string];
14
+ /** The declared-error union of a fn - for typing catch sites. */
15
+ type FnErrors<F> = F extends FnDefination<any, any, any, any, any, infer Er> ? FnErrorsOf<Er> : never;
16
+ type TryResult<R, Er> = R extends Promise<infer V> ? Promise<{
17
+ ok: true;
18
+ value: V;
19
+ } | {
20
+ ok: false;
21
+ error: FnErrorsOf<Er>;
22
+ }> : {
23
+ ok: true;
24
+ value: R;
25
+ } | {
26
+ ok: false;
27
+ error: FnErrorsOf<Er>;
28
+ };
29
+ /** No declared errors - the default error channel. */
30
+ type NoErrors = Record<never, never>;
31
+ /** The `use` half of `.with`: fn overrides by name, recursing into
32
+ * GROUPS so a nested binding can be overridden too. A var alias takes a
33
+ * SEED for the var it points at. */
34
+ type WithFns<U> = { [K in keyof U]?: U[K] extends FnDefination<any, any, any, any, any, any> ? BoundFn<U[K]> : U[K] extends VarDefination<any, infer T, any, any> ? T : WithFns<U[K]>; };
35
+ /** The context `.with` accepts: any var of the fn's WHOLE chain scope
36
+ * (the builder's `use` included, not just the fn's own), plus any `use`
37
+ * fn as an override - and nothing else. Kept as PLAIN mapped types: with
38
+ * `RV`/`U` unknown both halves collapse to `{}`, which keeps every
39
+ * `extends FnDefination<any, ...>` structural check passing.
40
+ *
41
+ * Prefer {@link WithSeed} for values stored on {@link FnDefination} - it
42
+ * is what `v.fn` returns, and stays declaration-emit safe. */
43
+ type WithContext<RV, U> = { [K in keyof RV]?: RV[K]; } & WithFns<U>;
44
+ /** Storage (or the FnEntries slice of one): anything carrying `$models`.
45
+ * Nested under a module as `{ db }`, it must not flow into `.with` seeds -
46
+ * model schemas alone blow past declaration serialize limits. ModuleFns
47
+ * drops `$adapter`/`$on`/collections, so duck-typing `$models` alone. */
48
+ type StorageLike = {
49
+ $models: object;
50
+ };
51
+ /** Flatten `use` members to `.with` overrides: bound call signatures, var
52
+ * alias values, nested groups. Storage is dropped (mount-only). */
53
+ type WithFnsSeed<U> = { [K in keyof U as U[K] extends StorageLike ? never : K]?: U[K] extends FnDefination<any, any, any, any, any, any> ? BoundFn<U[K]> : U[K] extends VarDefination<any, infer T, any, any> ? T : WithFnsSeed<U[K]>; };
54
+ /**
55
+ * Flat `.with` seed map stored on exported fns. Evaluating ScopeOf /
56
+ * ModuleFns here (instead of embedding those wrappers as type arguments)
57
+ * keeps declaration emit small: `.d.ts` shows leaf var shapes and bound
58
+ * call signatures, not `ScopeOf<ResolvedVars<entire module graph>>`.
59
+ */
60
+ type WithSeed<RV, U> = Prettify<{ [K in keyof RV]?: RV[K]; } & WithFnsSeed<U>>;
61
+ /** What `v.fn` / `e.fn` returns: contract params plus a flat {@link WithSeed}
62
+ * for `.with`, never the raw ScopeOf / ModuleFns graph. */
63
+ type PublicFn<A, R, K extends string, I, P extends readonly string[], Er, RV, U, O = unknown> = FnDefination<A, R, K, I, P, Er, WithSeed<RV, U>, O>;
64
+ /** What `.with` returns: the same callable, context baked in. */
65
+ interface BoundCall<A, R, I, Er> {
66
+ (...args: CallArgs<A, I>): R;
67
+ try(...args: CallArgs<A, I>): TryResult<R, Er>;
68
+ }
69
+ interface FnDefination<A, R, K extends string = string, I = unknown, P extends readonly string[] = readonly string[], Er = NoErrors,
70
+ /** `.with` seed map ({@link WithSeed}). Defaults keep structural
71
+ * `extends FnDefination<any, ...>` checks passing. */
72
+ W = unknown, O = unknown> {
73
+ (...args: CallArgs<A, I>): R;
74
+ /**
75
+ * Call with DECLARED errors caught as a value: `{ ok: true, value }`
76
+ * or `{ ok: false, error }`, narrowed by `error.tag`. Only tagged,
77
+ * expected errors become results - defects and contract violations
78
+ * still throw, exactly as they should.
79
+ */
80
+ try(...args: CallArgs<A, I>): TryResult<R, Er>;
81
+ /**
82
+ * Call with a HAND-BUILT context. Keys naming a var SEED that var in a
83
+ * fresh scope; keys naming a `use` fn OVERRIDE that binding for the
84
+ * whole subtree below. Both are typed from the fn's chain - what the
85
+ * BUILDER mounted counts, so `signOut.with({ user })` type-checks even
86
+ * though `signOut` itself never says `use: [user]`. A parent passed to
87
+ * the bound call is FORKED: its vars are copied in, never written back.
88
+ */
89
+ with(context: W): BoundCall<A, R, I, Er>;
90
+ /** Brand, so a plugin module can be scanned for its fns. */
91
+ readonly $fn: true;
92
+ /** The name interceptors target - literal, so `ApplyOn` can match it. */
93
+ readonly key: K;
94
+ /** The declared contract, retained AS WRITTEN for runtime
95
+ * introspection (tool cards, docs renderers): the raw input/output
96
+ * schemas, error tag map, and required vars. Optional so structural
97
+ * `extends FnDefination` checks keep passing for hand-built fns. */
98
+ readonly $schema?: {
99
+ input?: unknown;
100
+ output?: unknown;
101
+ errors?: Record<string, unknown>;
102
+ requires?: readonly string[];
103
+ /** Declared idempotence - same args, same result, safe to repeat. */
104
+ idempotent?: boolean;
105
+ };
106
+ /** Vars this fn promises to set when ITS OWN body runs - the literal
107
+ * list, readable by graph tooling at both type and runtime level. */
108
+ readonly provides: P;
109
+ /** Phantom: the raw declared input, so extensions of the vars it
110
+ * references can widen used-fn call sites. Never set at runtime. */
111
+ readonly $input?: I;
112
+ /** Phantom: the raw declared output, the counterpart of `$input` - the
113
+ * schema as written, for type-level introspection. Never set at runtime. */
114
+ readonly $output?: O;
115
+ /** Phantom: declared error tags -> payload schemas. */
116
+ readonly $errors?: Er;
117
+ }
118
+ type ArgsOf<I> = I extends readonly unknown[] ? { -readonly [K in keyof I]: InferArgs<I[K]>; } : unknown extends I ? void : InferArgs<I>;
119
+ type OptionType<I, O, P, Q, PL, RO extends boolean = boolean, Er = any> = {
120
+ /**
121
+ * The fn's DECLARED failures: tag -> payload schema. The THIRD
122
+ * contract door - input validates on entry, output on exit, errors at
123
+ * `throw c.error(tag, data)`. Once declared, any UNTAGGED throw
124
+ * escaping the body is a defect and comes out as `UnexpectedError` -
125
+ * callers can tell a domain refusal from a bug without string
126
+ * matching.
127
+ */
128
+ errors?: Er;
129
+ /**
130
+ * A readonly fn cannot write vars - not in its handler, not in
131
+ * anything it calls, not from interceptors mounted on it. Enforced at
132
+ * the type level (vars readonly on `c`, declared writers uncallable)
133
+ * and at runtime (the whole subtree's store locks).
134
+ */
135
+ readonly?: RO;
136
+ /**
137
+ * Declared idempotence: calling with the same args always produces the
138
+ * same result and repeating the call is harmless - a read, a lookup, a
139
+ * pure computation. Part of the retained contract (`$schema`), so
140
+ * hosts may DEDUPE calls: the script engine serves repeated
141
+ * same-args calls to an idempotent fn from one dispatch per session.
142
+ * Note this is a different promise than `readonly` (writes no vars) -
143
+ * an fn can be readonly and still hit a non-idempotent API.
144
+ */
145
+ idempotent?: boolean;
146
+ input?: I;
147
+ /**
148
+ * The fn's return contract. A bare schema is BOTH the signature and
149
+ * the exit check; the wrapper `{ def?, validation? }` splits them -
150
+ * `{ def }` documents the return (tool cards, handler typing) without
151
+ * runtime validation, `validation` is the schema the exit check runs
152
+ * (defaults to none in the wrapper form).
153
+ */
154
+ output?: O;
155
+ /** Vars this fn guarantees to set. Checked on exit. */
156
+ provides?: P;
157
+ /** Vars that must already be set. Checked on entry, before the body. */
158
+ requires?: Q;
159
+ /**
160
+ * Module namespaces to pull in. Their vars come into scope, their fns
161
+ * land directly on `c` already bound to this context (a plain-record
162
+ * member nests as a NAMESPACE: `c.cookies.setCookie`), and their `on`
163
+ * entries stay active for everything below.
164
+ */
165
+ use?: PL;
166
+ };
167
+ /** A used fn, with the parent context already applied. A tuple-input fn
168
+ * keeps its positional signature. */
169
+ type BoundFn<F> = F extends FnDefination<infer A, infer R, string, infer I, any, any> ? I extends readonly unknown[] ? A extends readonly unknown[] ? (...args: [...A]) => R : never : [A] extends [void] ? () => R : (input: A) => R : never;
170
+ /** Keys of a usable map whose member is a VAR alias. */
171
+ type UseVarKeys<U> = { [K in keyof U]: U[K] extends VarDefination<any, any, any, any> ? K : never; }[keyof U];
172
+ /** A var alias' surface: the var's VALUE, read and written in place. */
173
+ type UseVarValue<V> = V extends VarDefination<any, infer T, any, any> ? T : never;
174
+ type UseApi<U> = Prettify<{ [K in Exclude<keyof U, UseVarKeys<U>>]: U[K] extends FnDefination<any, any, any, any, any, any> ? BoundFn<U[K]> : UseApi<U[K]>; } & { [K in UseVarKeys<U>]: UseVarValue<U[K]>; }>;
175
+ /** Used fns inside a readonly fn: declared writers become uncallable,
176
+ * with the reason on hover instead of a generic type error; var aliases
177
+ * become readonly properties. */
178
+ type ReadUseApi<U> = Prettify<{ [K in Exclude<keyof U, UseVarKeys<U>>]: U[K] extends FnDefination<any, any, any, any, infer P, any> ? P extends readonly [] ? BoundFn<U[K]> : `writes "${P[number] & string}" - not callable from a readonly fn` : ReadUseApi<U[K]>; } & { readonly [K in UseVarKeys<U>]: UseVarValue<U[K]>; }>;
179
+ type Context<I, RV, Required, U = unknown, FnApi = Fn, RO extends boolean = false, Errs = NoErrors> = {
180
+ input: InferInput<I>;
181
+ /**
182
+ * Mint a DECLARED error - tag-checked, payload validated at creation:
183
+ * `throw c.error("invalid_credentials", { attempts: 3 })`. Only tags
184
+ * from this fn's `errors` exist; the payload validates like input.
185
+ */
186
+ error: <T extends keyof Errs & string>(tag: T, ...data: Record<never, never> extends InferArgs<Errs[T]> ? [data?: InferArgs<Errs[T]>] : [data: InferArgs<Errs[T]>]) => FnError<T, InferInput<Errs[T]>>;
187
+ /** Define fns from inside: this fn's scope and key carry over, so
188
+ * anything built here is typed exactly like a chained builder. */
189
+ fn: FnApi;
190
+ /** The schema constructors (string, number, object, ...). */
191
+ types: typeof vTypes;
192
+ } & /** Every var in scope, directly on `c`: read `c.session`, write by
193
+ * plain assignment (`c.session = {...}`). Every var is a readonly
194
+ * property on a readonly fn. */ VarScope<RV, Required, RO> &
195
+ /** Fns from `use`, directly on `c` and already threaded with this
196
+ * context: `c.createUser({...})`. */
197
+ (RO extends true ? ReadUseApi<U> : UseApi<U>);
198
+ type InferReturn<O> = unknown extends O ? unknown : InferInput<OutputSchemaOf<O>>;
199
+ interface Fn<Base = unknown, BaseFns = unknown, BasePL extends readonly Module[] = [], Prefix extends string = ""> {
200
+ /**
201
+ * The builder FN is a schema too: `create: v.fn` (never called) declares
202
+ * "any function" - typed `(...args: any[]) => any`, runtime checks only
203
+ * `typeof value === "function"`.
204
+ */
205
+ readonly $fnSchema: {
206
+ input?: unknown;
207
+ output?: unknown;
208
+ };
209
+ /**
210
+ * "A fn with THIS signature", as a schema: `create: v.fn.type({ input,
211
+ * output })` types the field as that fn and validates what a signature
212
+ * CAN be validated for - the value is a function, and a plain closure
213
+ * gets the declared input checked at its door on every call.
214
+ *
215
+ * This exists apart from a handler-less `v.fn({ input, output })` for
216
+ * INLINE use: `v.fn`'s handler overloads return a callable, which makes
217
+ * TypeScript defer any inline `v.fn(...)` call inside another generic
218
+ * call's arguments (higher-order inference) - the enclosing `v.object`/
219
+ * `v.var` then loses its shape inference entirely. `v.fn.type` returns a
220
+ * plain carrier, so it composes inline anywhere.
221
+ */
222
+ readonly type: <I = unknown, O = unknown>(signature?: {
223
+ input?: I;
224
+ output?: O;
225
+ }) => {
226
+ readonly $fnSchema: {
227
+ input?: I;
228
+ output?: O;
229
+ };
230
+ };
231
+ <R>(fn: (ctx: Context<unknown, ScopeOf<[], Base, BasePL>, never, BaseFns, Fn<Base, BaseFns, BasePL, Prefix>>) => R): PublicFn<void, R, Prefix extends "" ? string : Prefix, unknown, readonly string[], NoErrors, ScopeOf<[], Base, BasePL>, BaseFns>;
232
+ <K extends LiteralString, R>(key: K, fn: (ctx: Context<unknown, ScopeOf<[], Base, BasePL>, never, BaseFns, Fn<Base, BaseFns, BasePL, `${Prefix}${K}`>>) => R): PublicFn<void, R, `${Prefix}${K}`, unknown, readonly string[], NoErrors, ScopeOf<[], Base, BasePL>, BaseFns>;
233
+ <const I, O, R extends InferReturn<O> | Promise<InferReturn<O>>, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], RO extends boolean = false, Er extends Record<string, unknown> = NoErrors>(options: OptionType<I, O, P, Q, PL, RO, Er>, fn: (ctx: Context<I, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, WithDerived<PL, BasePL, Q[number]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, Fn<Base & ResolvedVars<PL>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, readonly [...BasePL, ...PL], Prefix>, RO, Er>) => R): PublicFn<ArgsOf<I>, R, Prefix extends "" ? string : Prefix, I, P, Er, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, O>;
234
+ <K extends LiteralString, const I, O, R extends InferReturn<O> | Promise<InferReturn<O>>, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], RO extends boolean = false, Er extends Record<string, unknown> = NoErrors>(key: K, options: OptionType<I, O, P, Q, PL, RO, Er>, fn: (ctx: Context<I, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, WithDerived<PL, BasePL, Q[number]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, Fn<Base & ResolvedVars<PL>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, readonly [...BasePL, ...PL], `${Prefix}${K}`>, RO, Er>) => R): PublicFn<ArgsOf<I>, R, `${Prefix}${K}`, I, P, Er, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, O>;
235
+ <K extends LiteralString>(key: K): Instance<Base, BaseFns, BasePL, `${Prefix}${K}`>;
236
+ <I, O, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly []>(options: OptionType<I, O, P, Q, PL>): Instance<Base & ResolvedVars<PL>, BaseFns & ApplyOns<ModuleFns<PL>, PL>, readonly [...BasePL, ...PL], Prefix, I, O>;
237
+ <K extends LiteralString, I, O, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly []>(key: K, options: OptionType<I, O, P, Q, PL>): Instance<Base & ResolvedVars<PL>, BaseFns & ApplyOns<ModuleFns<PL>, PL>, readonly [...BasePL, ...PL], `${Prefix}${K}`, I, O>;
238
+ }
239
+ /** Every target worth suggesting on a builder's `on`: the mounted fns'
240
+ * keys (prefix-stripped, so they are valid RELATIVE targets), the scope's
241
+ * var-write events by name, and the two wildcards. Arbitrary strings stay
242
+ * legal - these only feed completion. */
243
+ type OnTargetSuggest<Base, BaseFns, Prefix extends string> = FnTargetSuggest<BaseFns, Prefix> | `var.set.${keyof ScopeOf<[], Base> & string}` | "var.set.*" | `var.get.${keyof ScopeOf<[], Base> & string}` | "var.get.*" | "*";
244
+ type FnTargetSuggest<Fns, Prefix extends string> = { [K in keyof Fns]: Fns[K] extends FnDefination<any, any, infer FK, any, any, any> ? FK extends `${Prefix}${infer Rest}` ? Rest : never : never; }[keyof Fns];
245
+ type VarNameOfT<T extends string> = T extends `var.${"set" | "get"}.${infer N}` ? N extends `${string}*${string}` ? string : N : string;
246
+ /** The scope's value for a var-event target - `unknown` when inexact. */
247
+ type VarValueOfT<T extends string, Base> = VarNameOfT<T> extends keyof ScopeOf<[], Base> ? ScopeOf<[], Base>[VarNameOfT<T>] : unknown;
248
+ /** The fns among `Fns` whose key the (already prefixed) target hits. */
249
+ type MatchedFn<Fns, T extends string> = { [K in keyof Fns]: Fns[K] extends FnDefination<any, any, infer FK, any, any, any> ? TargetMatches<T, FK & string> extends true ? Fns[K] : never : never; }[keyof Fns];
250
+ /** The intercepted input: the matched fn's (a union under wildcards),
251
+ * or an open record when the target names nothing the builder knows. */
252
+ type MatchedInput<F> = [F] extends [never] ? Record<string, any> : F extends FnDefination<any, any, any, infer I, any, any> ? InferInput<I> : never;
253
+ /** What `next()` resolves to: the matched fn's own result. */
254
+ type MatchedResult<F> = [F] extends [never] ? any : F extends FnDefination<any, infer R, any, any, any, any> ? Awaited<R> : never;
255
+ /** What a builder-scoped `on` handler sees: vars and `use` fns directly
256
+ * on `c` from the builder, `input` from the TARGET fn when known. */
257
+ type OnContext<Base, BaseFns, F, Ext = unknown> = {
258
+ input: MatchedInput<F> & (unknown extends Ext ? unknown : InferInput<Ext>);
259
+ types: typeof vTypes;
260
+ fn: unknown;
261
+ } & VarScope<ScopeOf<[], Base>, never> & UseApi<BaseFns>;
262
+ /** `v.on`, scoped: string targets get the builder's key prefix; the
263
+ * handler's `c` and `next()` are typed against the matched target fn. */
264
+ interface InstanceOn<Base, BaseFns, Prefix extends string> {
265
+ /** A fn REFERENCE targets its own key - never prefixed, fully typed
266
+ * from the fn itself plus the builder's scope. */
267
+ <F extends FnDefination<any, any, string, any, any, any>>(target: F, handler: (c: OnContext<Base, BaseFns, F>, next: () => Promise<MatchedResult<F>>) => any): OnEntry<F["key"]>;
268
+ /** Var-write events: never prefixed (vars are global), and `value`
269
+ * is typed from the builder's scope when the target is exact. */
270
+ <T extends `var.set.${keyof ScopeOf<[], Base> & string}` | "var.set.*" | `var.set.${string}`>(target: T, handler: (c: VarSetContext<VarNameOfT<T>> & {
271
+ value: VarValueOfT<T, Base>;
272
+ }, next: () => void) => void): OnEntry<T>;
273
+ /** Var-read events: `next()` yields the stored value and the handler's
274
+ * return becomes the read result - typed from the scope when exact. */
275
+ <T extends `var.get.${keyof ScopeOf<[], Base> & string}` | "var.get.*" | `var.get.${string}`>(target: T, handler: (c: VarGetContext<VarNameOfT<T>>, next: () => VarValueOfT<T, Base>) => VarValueOfT<T, Base>): OnEntry<T>;
276
+ (target: RegExp, handler: (c: OnContext<Base, BaseFns, never>, next: () => Promise<any>) => any): OnEntry<string>;
277
+ <N extends OnTargetSuggest<Base, BaseFns, Prefix> | LiteralString>(target: N, handler: (c: OnContext<Base, BaseFns, MatchedFn<BaseFns, `${Prefix}${N}`>>, next: () => Promise<MatchedResult<MatchedFn<BaseFns, `${Prefix}${N}`>>>) => any): OnEntry<`${Prefix}${N}`>;
278
+ <const Ext>(target: RegExp, extend: {
279
+ input: Ext;
280
+ }, handler: (c: OnContext<Base, BaseFns, never, Ext>, next: () => Promise<any>) => any): OnEntry<string, Ext>;
281
+ <N extends OnTargetSuggest<Base, BaseFns, Prefix> | LiteralString, const Ext>(target: N, extend: {
282
+ input: Ext;
283
+ }, handler: (c: OnContext<Base, BaseFns, MatchedFn<BaseFns, `${Prefix}${N}`>, Ext>, next: () => Promise<MatchedResult<MatchedFn<BaseFns, `${Prefix}${N}`>>>) => any): OnEntry<`${Prefix}${N}`, Ext>;
284
+ }
285
+ type Instance<Base, BaseFns, PL extends readonly Module[] = [], Prefix extends string = "", I = unknown, O = unknown> = {
286
+ /** Same as `v.fn`, with this builder's key prefix and options baked in. */
287
+ fn: Fn<Base, BaseFns, PL, Prefix>;
288
+ /**
289
+ * A handler-less builder doubles as an input SCHEMA: used as `input`
290
+ * (or an input field) it declares "a FN from `input` to `output`" -
291
+ * the value crossing is the fn itself. Carries the declared schemas
292
+ * for inference here and validation at runtime (see `isFnSchema`).
293
+ */
294
+ readonly $fnSchema: {
295
+ input?: I;
296
+ output?: O;
297
+ };
298
+ /** Same as `v.on`, with the prefix on string targets and the handler
299
+ * typed against the matched target fn. */
300
+ on: InstanceOn<Base, BaseFns, Prefix>;
301
+ /**
302
+ * The context a handler on this builder receives - a TYPE carrier for
303
+ * `typeof f.ctx` (helper signatures, plugin contracts). Every handler
304
+ * context on this builder is assignable to it: `input` and `fn` are
305
+ * loosened since they vary per fn. A real context only exists per
306
+ * invocation, so this is `undefined` at runtime.
307
+ */
308
+ readonly ctx: Context<unknown, ScopeOf<[], Base, PL>, never, BaseFns, unknown>;
309
+ };
310
+ //#endregion
311
+ export { ArgsOf, BoundCall, Context, Fn, FnDefination, FnErrors, FnErrorsOf, InferReturn, Instance, InstanceOn, OptionType, ParentContext, UseApi, WithContext, WithSeed };
312
+ //# sourceMappingURL=fn.d.cts.map
package/dist/fn.d.mts ADDED
@@ -0,0 +1,312 @@
1
+ import { FnError } from "./error.mjs";
2
+ import { LiteralString, Prettify } from "./types.mjs";
3
+ import { InferArgs, InferInput, OutputSchemaOf, vTypes } from "./schema.mjs";
4
+ import { VarDefination } from "./var.mjs";
5
+ import { ApplyOns, Module, ModuleFns, OnEntry, TargetMatches, VarGetContext, VarSetContext, WithDerived } from "./module.mjs";
6
+ import { ResolvedVars, ScopeOf, VarName, VarScope } from "./scope.mjs";
7
+ //#region src/fn.d.ts
8
+ type ParentContext = Record<string, any>;
9
+ /** The call shape: a TUPLE input spreads - one parameter per position,
10
+ * the parent context last. Everything else takes (input?, parent?). */
11
+ type CallArgs<A, I> = I extends readonly unknown[] ? A extends readonly unknown[] ? [...A] | [...A, ParentContext] : never : [A] extends [void] ? [input?: undefined, parent?: ParentContext] : [input: A, parent?: ParentContext];
12
+ /** The union of a fn's DECLARED errors, as thrown values. */
13
+ type FnErrorsOf<Er> = { [T in keyof Er & string]: FnError<T, InferInput<Er[T]>>; }[keyof Er & string];
14
+ /** The declared-error union of a fn - for typing catch sites. */
15
+ type FnErrors<F> = F extends FnDefination<any, any, any, any, any, infer Er> ? FnErrorsOf<Er> : never;
16
+ type TryResult<R, Er> = R extends Promise<infer V> ? Promise<{
17
+ ok: true;
18
+ value: V;
19
+ } | {
20
+ ok: false;
21
+ error: FnErrorsOf<Er>;
22
+ }> : {
23
+ ok: true;
24
+ value: R;
25
+ } | {
26
+ ok: false;
27
+ error: FnErrorsOf<Er>;
28
+ };
29
+ /** No declared errors - the default error channel. */
30
+ type NoErrors = Record<never, never>;
31
+ /** The `use` half of `.with`: fn overrides by name, recursing into
32
+ * GROUPS so a nested binding can be overridden too. A var alias takes a
33
+ * SEED for the var it points at. */
34
+ type WithFns<U> = { [K in keyof U]?: U[K] extends FnDefination<any, any, any, any, any, any> ? BoundFn<U[K]> : U[K] extends VarDefination<any, infer T, any, any> ? T : WithFns<U[K]>; };
35
+ /** The context `.with` accepts: any var of the fn's WHOLE chain scope
36
+ * (the builder's `use` included, not just the fn's own), plus any `use`
37
+ * fn as an override - and nothing else. Kept as PLAIN mapped types: with
38
+ * `RV`/`U` unknown both halves collapse to `{}`, which keeps every
39
+ * `extends FnDefination<any, ...>` structural check passing.
40
+ *
41
+ * Prefer {@link WithSeed} for values stored on {@link FnDefination} - it
42
+ * is what `v.fn` returns, and stays declaration-emit safe. */
43
+ type WithContext<RV, U> = { [K in keyof RV]?: RV[K]; } & WithFns<U>;
44
+ /** Storage (or the FnEntries slice of one): anything carrying `$models`.
45
+ * Nested under a module as `{ db }`, it must not flow into `.with` seeds -
46
+ * model schemas alone blow past declaration serialize limits. ModuleFns
47
+ * drops `$adapter`/`$on`/collections, so duck-typing `$models` alone. */
48
+ type StorageLike = {
49
+ $models: object;
50
+ };
51
+ /** Flatten `use` members to `.with` overrides: bound call signatures, var
52
+ * alias values, nested groups. Storage is dropped (mount-only). */
53
+ type WithFnsSeed<U> = { [K in keyof U as U[K] extends StorageLike ? never : K]?: U[K] extends FnDefination<any, any, any, any, any, any> ? BoundFn<U[K]> : U[K] extends VarDefination<any, infer T, any, any> ? T : WithFnsSeed<U[K]>; };
54
+ /**
55
+ * Flat `.with` seed map stored on exported fns. Evaluating ScopeOf /
56
+ * ModuleFns here (instead of embedding those wrappers as type arguments)
57
+ * keeps declaration emit small: `.d.ts` shows leaf var shapes and bound
58
+ * call signatures, not `ScopeOf<ResolvedVars<entire module graph>>`.
59
+ */
60
+ type WithSeed<RV, U> = Prettify<{ [K in keyof RV]?: RV[K]; } & WithFnsSeed<U>>;
61
+ /** What `v.fn` / `e.fn` returns: contract params plus a flat {@link WithSeed}
62
+ * for `.with`, never the raw ScopeOf / ModuleFns graph. */
63
+ type PublicFn<A, R, K extends string, I, P extends readonly string[], Er, RV, U, O = unknown> = FnDefination<A, R, K, I, P, Er, WithSeed<RV, U>, O>;
64
+ /** What `.with` returns: the same callable, context baked in. */
65
+ interface BoundCall<A, R, I, Er> {
66
+ (...args: CallArgs<A, I>): R;
67
+ try(...args: CallArgs<A, I>): TryResult<R, Er>;
68
+ }
69
+ interface FnDefination<A, R, K extends string = string, I = unknown, P extends readonly string[] = readonly string[], Er = NoErrors,
70
+ /** `.with` seed map ({@link WithSeed}). Defaults keep structural
71
+ * `extends FnDefination<any, ...>` checks passing. */
72
+ W = unknown, O = unknown> {
73
+ (...args: CallArgs<A, I>): R;
74
+ /**
75
+ * Call with DECLARED errors caught as a value: `{ ok: true, value }`
76
+ * or `{ ok: false, error }`, narrowed by `error.tag`. Only tagged,
77
+ * expected errors become results - defects and contract violations
78
+ * still throw, exactly as they should.
79
+ */
80
+ try(...args: CallArgs<A, I>): TryResult<R, Er>;
81
+ /**
82
+ * Call with a HAND-BUILT context. Keys naming a var SEED that var in a
83
+ * fresh scope; keys naming a `use` fn OVERRIDE that binding for the
84
+ * whole subtree below. Both are typed from the fn's chain - what the
85
+ * BUILDER mounted counts, so `signOut.with({ user })` type-checks even
86
+ * though `signOut` itself never says `use: [user]`. A parent passed to
87
+ * the bound call is FORKED: its vars are copied in, never written back.
88
+ */
89
+ with(context: W): BoundCall<A, R, I, Er>;
90
+ /** Brand, so a plugin module can be scanned for its fns. */
91
+ readonly $fn: true;
92
+ /** The name interceptors target - literal, so `ApplyOn` can match it. */
93
+ readonly key: K;
94
+ /** The declared contract, retained AS WRITTEN for runtime
95
+ * introspection (tool cards, docs renderers): the raw input/output
96
+ * schemas, error tag map, and required vars. Optional so structural
97
+ * `extends FnDefination` checks keep passing for hand-built fns. */
98
+ readonly $schema?: {
99
+ input?: unknown;
100
+ output?: unknown;
101
+ errors?: Record<string, unknown>;
102
+ requires?: readonly string[];
103
+ /** Declared idempotence - same args, same result, safe to repeat. */
104
+ idempotent?: boolean;
105
+ };
106
+ /** Vars this fn promises to set when ITS OWN body runs - the literal
107
+ * list, readable by graph tooling at both type and runtime level. */
108
+ readonly provides: P;
109
+ /** Phantom: the raw declared input, so extensions of the vars it
110
+ * references can widen used-fn call sites. Never set at runtime. */
111
+ readonly $input?: I;
112
+ /** Phantom: the raw declared output, the counterpart of `$input` - the
113
+ * schema as written, for type-level introspection. Never set at runtime. */
114
+ readonly $output?: O;
115
+ /** Phantom: declared error tags -> payload schemas. */
116
+ readonly $errors?: Er;
117
+ }
118
+ type ArgsOf<I> = I extends readonly unknown[] ? { -readonly [K in keyof I]: InferArgs<I[K]>; } : unknown extends I ? void : InferArgs<I>;
119
+ type OptionType<I, O, P, Q, PL, RO extends boolean = boolean, Er = any> = {
120
+ /**
121
+ * The fn's DECLARED failures: tag -> payload schema. The THIRD
122
+ * contract door - input validates on entry, output on exit, errors at
123
+ * `throw c.error(tag, data)`. Once declared, any UNTAGGED throw
124
+ * escaping the body is a defect and comes out as `UnexpectedError` -
125
+ * callers can tell a domain refusal from a bug without string
126
+ * matching.
127
+ */
128
+ errors?: Er;
129
+ /**
130
+ * A readonly fn cannot write vars - not in its handler, not in
131
+ * anything it calls, not from interceptors mounted on it. Enforced at
132
+ * the type level (vars readonly on `c`, declared writers uncallable)
133
+ * and at runtime (the whole subtree's store locks).
134
+ */
135
+ readonly?: RO;
136
+ /**
137
+ * Declared idempotence: calling with the same args always produces the
138
+ * same result and repeating the call is harmless - a read, a lookup, a
139
+ * pure computation. Part of the retained contract (`$schema`), so
140
+ * hosts may DEDUPE calls: the script engine serves repeated
141
+ * same-args calls to an idempotent fn from one dispatch per session.
142
+ * Note this is a different promise than `readonly` (writes no vars) -
143
+ * an fn can be readonly and still hit a non-idempotent API.
144
+ */
145
+ idempotent?: boolean;
146
+ input?: I;
147
+ /**
148
+ * The fn's return contract. A bare schema is BOTH the signature and
149
+ * the exit check; the wrapper `{ def?, validation? }` splits them -
150
+ * `{ def }` documents the return (tool cards, handler typing) without
151
+ * runtime validation, `validation` is the schema the exit check runs
152
+ * (defaults to none in the wrapper form).
153
+ */
154
+ output?: O;
155
+ /** Vars this fn guarantees to set. Checked on exit. */
156
+ provides?: P;
157
+ /** Vars that must already be set. Checked on entry, before the body. */
158
+ requires?: Q;
159
+ /**
160
+ * Module namespaces to pull in. Their vars come into scope, their fns
161
+ * land directly on `c` already bound to this context (a plain-record
162
+ * member nests as a NAMESPACE: `c.cookies.setCookie`), and their `on`
163
+ * entries stay active for everything below.
164
+ */
165
+ use?: PL;
166
+ };
167
+ /** A used fn, with the parent context already applied. A tuple-input fn
168
+ * keeps its positional signature. */
169
+ type BoundFn<F> = F extends FnDefination<infer A, infer R, string, infer I, any, any> ? I extends readonly unknown[] ? A extends readonly unknown[] ? (...args: [...A]) => R : never : [A] extends [void] ? () => R : (input: A) => R : never;
170
+ /** Keys of a usable map whose member is a VAR alias. */
171
+ type UseVarKeys<U> = { [K in keyof U]: U[K] extends VarDefination<any, any, any, any> ? K : never; }[keyof U];
172
+ /** A var alias' surface: the var's VALUE, read and written in place. */
173
+ type UseVarValue<V> = V extends VarDefination<any, infer T, any, any> ? T : never;
174
+ type UseApi<U> = Prettify<{ [K in Exclude<keyof U, UseVarKeys<U>>]: U[K] extends FnDefination<any, any, any, any, any, any> ? BoundFn<U[K]> : UseApi<U[K]>; } & { [K in UseVarKeys<U>]: UseVarValue<U[K]>; }>;
175
+ /** Used fns inside a readonly fn: declared writers become uncallable,
176
+ * with the reason on hover instead of a generic type error; var aliases
177
+ * become readonly properties. */
178
+ type ReadUseApi<U> = Prettify<{ [K in Exclude<keyof U, UseVarKeys<U>>]: U[K] extends FnDefination<any, any, any, any, infer P, any> ? P extends readonly [] ? BoundFn<U[K]> : `writes "${P[number] & string}" - not callable from a readonly fn` : ReadUseApi<U[K]>; } & { readonly [K in UseVarKeys<U>]: UseVarValue<U[K]>; }>;
179
+ type Context<I, RV, Required, U = unknown, FnApi = Fn, RO extends boolean = false, Errs = NoErrors> = {
180
+ input: InferInput<I>;
181
+ /**
182
+ * Mint a DECLARED error - tag-checked, payload validated at creation:
183
+ * `throw c.error("invalid_credentials", { attempts: 3 })`. Only tags
184
+ * from this fn's `errors` exist; the payload validates like input.
185
+ */
186
+ error: <T extends keyof Errs & string>(tag: T, ...data: Record<never, never> extends InferArgs<Errs[T]> ? [data?: InferArgs<Errs[T]>] : [data: InferArgs<Errs[T]>]) => FnError<T, InferInput<Errs[T]>>;
187
+ /** Define fns from inside: this fn's scope and key carry over, so
188
+ * anything built here is typed exactly like a chained builder. */
189
+ fn: FnApi;
190
+ /** The schema constructors (string, number, object, ...). */
191
+ types: typeof vTypes;
192
+ } & /** Every var in scope, directly on `c`: read `c.session`, write by
193
+ * plain assignment (`c.session = {...}`). Every var is a readonly
194
+ * property on a readonly fn. */ VarScope<RV, Required, RO> &
195
+ /** Fns from `use`, directly on `c` and already threaded with this
196
+ * context: `c.createUser({...})`. */
197
+ (RO extends true ? ReadUseApi<U> : UseApi<U>);
198
+ type InferReturn<O> = unknown extends O ? unknown : InferInput<OutputSchemaOf<O>>;
199
+ interface Fn<Base = unknown, BaseFns = unknown, BasePL extends readonly Module[] = [], Prefix extends string = ""> {
200
+ /**
201
+ * The builder FN is a schema too: `create: v.fn` (never called) declares
202
+ * "any function" - typed `(...args: any[]) => any`, runtime checks only
203
+ * `typeof value === "function"`.
204
+ */
205
+ readonly $fnSchema: {
206
+ input?: unknown;
207
+ output?: unknown;
208
+ };
209
+ /**
210
+ * "A fn with THIS signature", as a schema: `create: v.fn.type({ input,
211
+ * output })` types the field as that fn and validates what a signature
212
+ * CAN be validated for - the value is a function, and a plain closure
213
+ * gets the declared input checked at its door on every call.
214
+ *
215
+ * This exists apart from a handler-less `v.fn({ input, output })` for
216
+ * INLINE use: `v.fn`'s handler overloads return a callable, which makes
217
+ * TypeScript defer any inline `v.fn(...)` call inside another generic
218
+ * call's arguments (higher-order inference) - the enclosing `v.object`/
219
+ * `v.var` then loses its shape inference entirely. `v.fn.type` returns a
220
+ * plain carrier, so it composes inline anywhere.
221
+ */
222
+ readonly type: <I = unknown, O = unknown>(signature?: {
223
+ input?: I;
224
+ output?: O;
225
+ }) => {
226
+ readonly $fnSchema: {
227
+ input?: I;
228
+ output?: O;
229
+ };
230
+ };
231
+ <R>(fn: (ctx: Context<unknown, ScopeOf<[], Base, BasePL>, never, BaseFns, Fn<Base, BaseFns, BasePL, Prefix>>) => R): PublicFn<void, R, Prefix extends "" ? string : Prefix, unknown, readonly string[], NoErrors, ScopeOf<[], Base, BasePL>, BaseFns>;
232
+ <K extends LiteralString, R>(key: K, fn: (ctx: Context<unknown, ScopeOf<[], Base, BasePL>, never, BaseFns, Fn<Base, BaseFns, BasePL, `${Prefix}${K}`>>) => R): PublicFn<void, R, `${Prefix}${K}`, unknown, readonly string[], NoErrors, ScopeOf<[], Base, BasePL>, BaseFns>;
233
+ <const I, O, R extends InferReturn<O> | Promise<InferReturn<O>>, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], RO extends boolean = false, Er extends Record<string, unknown> = NoErrors>(options: OptionType<I, O, P, Q, PL, RO, Er>, fn: (ctx: Context<I, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, WithDerived<PL, BasePL, Q[number]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, Fn<Base & ResolvedVars<PL>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, readonly [...BasePL, ...PL], Prefix>, RO, Er>) => R): PublicFn<ArgsOf<I>, R, Prefix extends "" ? string : Prefix, I, P, Er, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, O>;
234
+ <K extends LiteralString, const I, O, R extends InferReturn<O> | Promise<InferReturn<O>>, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], RO extends boolean = false, Er extends Record<string, unknown> = NoErrors>(key: K, options: OptionType<I, O, P, Q, PL, RO, Er>, fn: (ctx: Context<I, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, WithDerived<PL, BasePL, Q[number]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, Fn<Base & ResolvedVars<PL>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, readonly [...BasePL, ...PL], `${Prefix}${K}`>, RO, Er>) => R): PublicFn<ArgsOf<I>, R, `${Prefix}${K}`, I, P, Er, ScopeOf<PL, Base, readonly [...BasePL, ...PL]>, ApplyOns<ModuleFns<PL>, PL> & BaseFns, O>;
235
+ <K extends LiteralString>(key: K): Instance<Base, BaseFns, BasePL, `${Prefix}${K}`>;
236
+ <I, O, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly []>(options: OptionType<I, O, P, Q, PL>): Instance<Base & ResolvedVars<PL>, BaseFns & ApplyOns<ModuleFns<PL>, PL>, readonly [...BasePL, ...PL], Prefix, I, O>;
237
+ <K extends LiteralString, I, O, const PL extends readonly Module[] = [], const P extends readonly VarName<ScopeOf<PL, Base>>[] = readonly [], const Q extends readonly VarName<ScopeOf<PL, Base>>[] = readonly []>(key: K, options: OptionType<I, O, P, Q, PL>): Instance<Base & ResolvedVars<PL>, BaseFns & ApplyOns<ModuleFns<PL>, PL>, readonly [...BasePL, ...PL], `${Prefix}${K}`, I, O>;
238
+ }
239
+ /** Every target worth suggesting on a builder's `on`: the mounted fns'
240
+ * keys (prefix-stripped, so they are valid RELATIVE targets), the scope's
241
+ * var-write events by name, and the two wildcards. Arbitrary strings stay
242
+ * legal - these only feed completion. */
243
+ type OnTargetSuggest<Base, BaseFns, Prefix extends string> = FnTargetSuggest<BaseFns, Prefix> | `var.set.${keyof ScopeOf<[], Base> & string}` | "var.set.*" | `var.get.${keyof ScopeOf<[], Base> & string}` | "var.get.*" | "*";
244
+ type FnTargetSuggest<Fns, Prefix extends string> = { [K in keyof Fns]: Fns[K] extends FnDefination<any, any, infer FK, any, any, any> ? FK extends `${Prefix}${infer Rest}` ? Rest : never : never; }[keyof Fns];
245
+ type VarNameOfT<T extends string> = T extends `var.${"set" | "get"}.${infer N}` ? N extends `${string}*${string}` ? string : N : string;
246
+ /** The scope's value for a var-event target - `unknown` when inexact. */
247
+ type VarValueOfT<T extends string, Base> = VarNameOfT<T> extends keyof ScopeOf<[], Base> ? ScopeOf<[], Base>[VarNameOfT<T>] : unknown;
248
+ /** The fns among `Fns` whose key the (already prefixed) target hits. */
249
+ type MatchedFn<Fns, T extends string> = { [K in keyof Fns]: Fns[K] extends FnDefination<any, any, infer FK, any, any, any> ? TargetMatches<T, FK & string> extends true ? Fns[K] : never : never; }[keyof Fns];
250
+ /** The intercepted input: the matched fn's (a union under wildcards),
251
+ * or an open record when the target names nothing the builder knows. */
252
+ type MatchedInput<F> = [F] extends [never] ? Record<string, any> : F extends FnDefination<any, any, any, infer I, any, any> ? InferInput<I> : never;
253
+ /** What `next()` resolves to: the matched fn's own result. */
254
+ type MatchedResult<F> = [F] extends [never] ? any : F extends FnDefination<any, infer R, any, any, any, any> ? Awaited<R> : never;
255
+ /** What a builder-scoped `on` handler sees: vars and `use` fns directly
256
+ * on `c` from the builder, `input` from the TARGET fn when known. */
257
+ type OnContext<Base, BaseFns, F, Ext = unknown> = {
258
+ input: MatchedInput<F> & (unknown extends Ext ? unknown : InferInput<Ext>);
259
+ types: typeof vTypes;
260
+ fn: unknown;
261
+ } & VarScope<ScopeOf<[], Base>, never> & UseApi<BaseFns>;
262
+ /** `v.on`, scoped: string targets get the builder's key prefix; the
263
+ * handler's `c` and `next()` are typed against the matched target fn. */
264
+ interface InstanceOn<Base, BaseFns, Prefix extends string> {
265
+ /** A fn REFERENCE targets its own key - never prefixed, fully typed
266
+ * from the fn itself plus the builder's scope. */
267
+ <F extends FnDefination<any, any, string, any, any, any>>(target: F, handler: (c: OnContext<Base, BaseFns, F>, next: () => Promise<MatchedResult<F>>) => any): OnEntry<F["key"]>;
268
+ /** Var-write events: never prefixed (vars are global), and `value`
269
+ * is typed from the builder's scope when the target is exact. */
270
+ <T extends `var.set.${keyof ScopeOf<[], Base> & string}` | "var.set.*" | `var.set.${string}`>(target: T, handler: (c: VarSetContext<VarNameOfT<T>> & {
271
+ value: VarValueOfT<T, Base>;
272
+ }, next: () => void) => void): OnEntry<T>;
273
+ /** Var-read events: `next()` yields the stored value and the handler's
274
+ * return becomes the read result - typed from the scope when exact. */
275
+ <T extends `var.get.${keyof ScopeOf<[], Base> & string}` | "var.get.*" | `var.get.${string}`>(target: T, handler: (c: VarGetContext<VarNameOfT<T>>, next: () => VarValueOfT<T, Base>) => VarValueOfT<T, Base>): OnEntry<T>;
276
+ (target: RegExp, handler: (c: OnContext<Base, BaseFns, never>, next: () => Promise<any>) => any): OnEntry<string>;
277
+ <N extends OnTargetSuggest<Base, BaseFns, Prefix> | LiteralString>(target: N, handler: (c: OnContext<Base, BaseFns, MatchedFn<BaseFns, `${Prefix}${N}`>>, next: () => Promise<MatchedResult<MatchedFn<BaseFns, `${Prefix}${N}`>>>) => any): OnEntry<`${Prefix}${N}`>;
278
+ <const Ext>(target: RegExp, extend: {
279
+ input: Ext;
280
+ }, handler: (c: OnContext<Base, BaseFns, never, Ext>, next: () => Promise<any>) => any): OnEntry<string, Ext>;
281
+ <N extends OnTargetSuggest<Base, BaseFns, Prefix> | LiteralString, const Ext>(target: N, extend: {
282
+ input: Ext;
283
+ }, handler: (c: OnContext<Base, BaseFns, MatchedFn<BaseFns, `${Prefix}${N}`>, Ext>, next: () => Promise<MatchedResult<MatchedFn<BaseFns, `${Prefix}${N}`>>>) => any): OnEntry<`${Prefix}${N}`, Ext>;
284
+ }
285
+ type Instance<Base, BaseFns, PL extends readonly Module[] = [], Prefix extends string = "", I = unknown, O = unknown> = {
286
+ /** Same as `v.fn`, with this builder's key prefix and options baked in. */
287
+ fn: Fn<Base, BaseFns, PL, Prefix>;
288
+ /**
289
+ * A handler-less builder doubles as an input SCHEMA: used as `input`
290
+ * (or an input field) it declares "a FN from `input` to `output`" -
291
+ * the value crossing is the fn itself. Carries the declared schemas
292
+ * for inference here and validation at runtime (see `isFnSchema`).
293
+ */
294
+ readonly $fnSchema: {
295
+ input?: I;
296
+ output?: O;
297
+ };
298
+ /** Same as `v.on`, with the prefix on string targets and the handler
299
+ * typed against the matched target fn. */
300
+ on: InstanceOn<Base, BaseFns, Prefix>;
301
+ /**
302
+ * The context a handler on this builder receives - a TYPE carrier for
303
+ * `typeof f.ctx` (helper signatures, plugin contracts). Every handler
304
+ * context on this builder is assignable to it: `input` and `fn` are
305
+ * loosened since they vary per fn. A real context only exists per
306
+ * invocation, so this is `undefined` at runtime.
307
+ */
308
+ readonly ctx: Context<unknown, ScopeOf<[], Base, PL>, never, BaseFns, unknown>;
309
+ };
310
+ //#endregion
311
+ export { ArgsOf, BoundCall, Context, Fn, FnDefination, FnErrors, FnErrorsOf, InferReturn, Instance, InstanceOn, OptionType, ParentContext, UseApi, WithContext, WithSeed };
312
+ //# sourceMappingURL=fn.d.mts.map