@zapier/kitcore 0.0.0 → 0.5.0

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.
@@ -0,0 +1,3383 @@
1
+ import { z } from 'zod';
2
+
3
+ declare module "zod" {
4
+ interface GlobalMeta {
5
+ internal?: boolean;
6
+ deprecated?: boolean;
7
+ valueHint?: string;
8
+ }
9
+ }
10
+
11
+ /**
12
+ * Pagination shapes used by the plugin framework.
13
+ */
14
+ /**
15
+ * Single page of a paginated SDK list result. Returned from the page-level
16
+ * promise and yielded from the page-level async iterable.
17
+ */
18
+ interface SdkPage<T = unknown> {
19
+ data: T[];
20
+ nextCursor?: string;
21
+ }
22
+ /**
23
+ * Return type of every paginated SDK method. The same value is both:
24
+ *
25
+ * - a Promise that resolves to the first page (`SdkPage<TItem>`), and
26
+ * - an AsyncIterable that yields each page in turn,
27
+ *
28
+ * with an `.items()` method that returns an AsyncIterable over individual
29
+ * items across all pages. Named so paginated plugin signatures serialize
30
+ * as `PaginatedSdkResult<AppItem>` in `.d.ts` rather than expanding the
31
+ * full triple-intersection at every callsite.
32
+ *
33
+ * The faces share one underlying cursor, so a result is consumed once:
34
+ *
35
+ * - `await` / `.then()` read the buffered first page without starting the
36
+ * stream, so awaiting is a repeatable peek and you can still iterate the
37
+ * result afterward.
38
+ * - The page-iterable and `.items()` are two views over one page stream, so
39
+ * consuming either drains the other: the second view yields nothing (it
40
+ * does not replay page 1). To read a result more than once, call the
41
+ * method again for a fresh result.
42
+ */
43
+ interface PaginatedSdkResult<TItem> extends Promise<SdkPage<TItem>>, AsyncIterable<SdkPage<TItem>> {
44
+ items(): AsyncIterable<TItem>;
45
+ }
46
+ type PaginatedSdkFunction<TOptions, TItem> = (options: TOptions) => PaginatedSdkResult<TItem>;
47
+
48
+ interface FormattedItem {
49
+ title: string;
50
+ /**
51
+ * Secondary identifying context shown dimmed after the title (ids, keys,
52
+ * slugs, ...). A dumb visual string a renderer shows verbatim, never
53
+ * structured data it has to interpret; the same role as a prompt choice's
54
+ * `hint`. An array is joined with ", ". Structured fields live on the
55
+ * response / `outputSchema`, not here, so the renderer stays dumb.
56
+ */
57
+ hint?: string | string[];
58
+ /** @deprecated Use `hint` (the renderer no longer interprets ids). */
59
+ id?: string;
60
+ /** @deprecated Use `hint`. */
61
+ key?: string;
62
+ /** @deprecated Use `hint`. */
63
+ keys?: string[];
64
+ description?: string;
65
+ /** If provided, the renderer shows this raw (verbatim) instead of `details`. */
66
+ raw?: unknown;
67
+ details: Array<{
68
+ label?: string;
69
+ text: string;
70
+ style: "normal" | "dim" | "accent" | "warning" | "success";
71
+ }>;
72
+ }
73
+ interface OutputFormatter<TSdk, TItem = unknown, TParams = Record<string, unknown>, TContext = unknown> {
74
+ fetch?: (sdk: TSdk, params: TParams, item: TItem, context: TContext | undefined) => Promise<TContext>;
75
+ format: (item: TItem, context?: TContext) => FormattedItem;
76
+ }
77
+ declare function getOutputSchema(inputSchema: z.ZodType): z.ZodType | undefined;
78
+ declare function withOutputSchema<T extends z.ZodType>(inputSchema: T, outputSchema: z.ZodType): T & {
79
+ _def: T["_def"] & {
80
+ outputSchema: z.ZodType;
81
+ };
82
+ };
83
+ /** A selectable option in a prompt. `label` is the display text; `value` is
84
+ * what the resolver returns when picked. */
85
+ interface PromptConfigChoice {
86
+ label: string;
87
+ value: unknown;
88
+ /**
89
+ * Optional secondary info shown after the label. The CLI wraps it in
90
+ * dimmed parens; an array is joined with ", ". Use for keys, ids, or
91
+ * other context that's useful but shouldn't compete visually with
92
+ * the primary label.
93
+ */
94
+ hint?: string | string[];
95
+ }
96
+ /**
97
+ * The pre-rename choice shape, kept so existing resolvers keep compiling while
98
+ * they migrate to {@link PromptConfigChoice}.
99
+ * @deprecated Use {@link PromptConfigChoice} with `label` instead of `name`.
100
+ */
101
+ interface DeprecatedPromptConfigChoice {
102
+ /** @deprecated Use `label` instead. */
103
+ name: string;
104
+ value: unknown;
105
+ hint?: string | string[];
106
+ }
107
+ interface PromptConfig {
108
+ type: "list" | "checkbox" | "confirm";
109
+ /**
110
+ * The answer key. The framework supplies it from the resolver's attachment
111
+ * (the param the resolver resolves), so authors should omit it; a provided
112
+ * value is overwritten.
113
+ * @deprecated Omit; the framework supplies the param key.
114
+ */
115
+ name?: string;
116
+ message: string;
117
+ choices?: Array<PromptConfigChoice | DeprecatedPromptConfigChoice>;
118
+ default?: unknown;
119
+ /** Informational, non-selectable lines shown with the prompt (e.g. "enable X
120
+ * to see more"). A host renders them dimmed, after the choices. The framework
121
+ * stays agnostic about their content; the resolver composes the text. */
122
+ notes?: string[];
123
+ filter?: (value: unknown) => unknown;
124
+ /**
125
+ * Return `true` for valid; a string for a custom invalid message; or
126
+ * `false` for invalid with a generic fallback message ("X: invalid
127
+ * value."). Prefer returning a string so users see something specific.
128
+ */
129
+ validate?: (value: unknown) => boolean | string;
130
+ }
131
+ /** A PromptConfig narrowed to single-select list mode. */
132
+ type ListPromptConfig = PromptConfig & {
133
+ type: "list";
134
+ };
135
+ /**
136
+ * The prompt config the NEW-model resolvers (`defineResolver`) return. It omits
137
+ * three fields the resolution controller does not honor, so authors can't
138
+ * supply a silent no-op:
139
+ * - `name` — the framework supplies the answer key (always was overwritten).
140
+ * - `default`— no resolver uses it; the controller has no preselect concept.
141
+ * - `filter` — no resolver uses it; transform values in `listItems` instead.
142
+ * (The legacy `SchemaParameterResolver` still honors `default`/`filter`, so the
143
+ * full `PromptConfig` stays for that path.)
144
+ */
145
+ type ResolverPromptConfig = Omit<PromptConfig, "name" | "default" | "filter">;
146
+ interface Resolver$1 {
147
+ type: string;
148
+ depends?: readonly string[] | string[];
149
+ }
150
+ interface StaticResolver$1 extends Resolver$1 {
151
+ type: "static";
152
+ inputType?: "text" | "password" | "email";
153
+ placeholder?: string;
154
+ }
155
+ /**
156
+ * A resolver that always resolves to a fixed value, never prompts. Use to
157
+ * pin an implicit parameter that downstream resolvers or SDK calls require
158
+ * but the user shouldn't have to provide. Triggers, for example, are always
159
+ * `actionType: "read"` from the SDK's perspective; createTriggerInbox
160
+ * declares `actionType: { type: "constant", value: "read" }` so the
161
+ * standard `actionKeyResolver` and `inputsResolver` (which depend on
162
+ * `actionType`) work without any pinned variants.
163
+ *
164
+ * Constants attached to keys that aren't in the schema are seeded into
165
+ * `resolvedParams` upfront, so dependent resolvers find them in context
166
+ * without the key appearing in the user-facing surface (TS option type,
167
+ * CLI flags, generated docs).
168
+ */
169
+ interface ConstantResolver$1 extends Resolver$1 {
170
+ type: "constant";
171
+ value: unknown;
172
+ }
173
+ /**
174
+ * Fields shared by both variants of {@link DynamicResolver}.
175
+ */
176
+ interface DynamicResolverBase<TSdk, TItem, TParams> extends Resolver$1 {
177
+ type: "dynamic";
178
+ prompt: (items: TItem[], params: TParams) => PromptConfig;
179
+ /** Capabilities that expand results. The parameter resolver shows a hint for any that aren't enabled. */
180
+ requireCapabilities?: string[];
181
+ /**
182
+ * Optional hook called before fetch/prompt. If it returns a non-null object,
183
+ * resolvedValue is used directly and fetch/prompt are skipped entirely. Return
184
+ * null to fall through to the normal resolution flow. Implementations should
185
+ * catch their own errors and return null on failure rather than throwing, so
186
+ * that a transient API error does not block the CLI entirely.
187
+ */
188
+ tryResolveWithoutPrompt?: (sdk: TSdk, params: TParams) => Promise<{
189
+ resolvedValue: unknown;
190
+ } | null>;
191
+ }
192
+ /**
193
+ * The classic dynamic-resolver variant: `fetch` returns a list of items
194
+ * that the CLI renders as a search-filterable dropdown. The user picks one.
195
+ */
196
+ interface DynamicListResolver<TSdk, TItem, TParams> extends DynamicResolverBase<TSdk, TItem, TParams> {
197
+ /** Explicitly absent on the list variant; set `inputType: "search"` to opt into the search variant. */
198
+ inputType?: never;
199
+ /** Only meaningful for the search variant; set to `never` here so TS catches misuse. */
200
+ placeholder?: never;
201
+ fetch: (sdk: TSdk, resolvedParams: TParams) => PromiseLike<TItem[] | {
202
+ data: TItem[];
203
+ nextCursor?: string;
204
+ } | AsyncIterable<{
205
+ data: TItem[];
206
+ nextCursor?: string;
207
+ }>>;
208
+ }
209
+ /**
210
+ * The search-input variant: the CLI prompts the user for free-form text
211
+ * first, then calls `fetch` with `{ ...resolvedParams, search }`.
212
+ *
213
+ * `fetch` can short-circuit by returning a primitive (`string | number`),
214
+ * which the CLI treats as an exact match — no dropdown is rendered. Any
215
+ * other return (array, page, async iterable) is rendered as the normal
216
+ * search-filterable dropdown.
217
+ *
218
+ * The `search` key is injected by the CLI at call time; it isn't part of
219
+ * `TParams` because callers that invoke `fetch` directly (outside the CLI)
220
+ * are responsible for passing it themselves. Search-mode resolvers should
221
+ * type `TParams` as `{ search?: string; ...otherDeps }` to make this
222
+ * explicit.
223
+ */
224
+ interface DynamicSearchResolver<TSdk, TItem, TParams> extends Omit<DynamicResolverBase<TSdk, TItem, TParams>, "prompt"> {
225
+ inputType: "search";
226
+ /**
227
+ * Hint text appended to the search prompt's message. NOT used as
228
+ * inquirer's `default` value, because inquirer prefills `default` as
229
+ * editable text that the user has to delete before typing.
230
+ */
231
+ placeholder?: string;
232
+ /**
233
+ * Search-mode always renders a single-select @inquirer/search dropdown,
234
+ * so `prompt` must return a list-typed PromptConfig. Checkbox/confirm
235
+ * configs would be silently ignored at runtime; the type narrows so
236
+ * misuse fails at compile time.
237
+ *
238
+ * Note: a primitive return from `fetch` (string | number) is treated
239
+ * as an exact match and short-circuits without running this prompt or
240
+ * the resolver's validate/filter. Canonicalize inside `fetch` if the
241
+ * exact-match path needs normalization.
242
+ */
243
+ prompt: (items: TItem[], params: TParams) => ListPromptConfig;
244
+ fetch: (sdk: TSdk, resolvedParams: TParams) => PromiseLike<string | number | TItem[] | {
245
+ data: TItem[];
246
+ nextCursor?: string;
247
+ } | AsyncIterable<{
248
+ data: TItem[];
249
+ nextCursor?: string;
250
+ }>>;
251
+ }
252
+ /**
253
+ * A dynamic resolver: either a classic list (`inputType` absent) or a
254
+ * search-input variant (`inputType: "search"`). The discriminator is the
255
+ * `inputType` field; TS narrows to the right variant when you check it.
256
+ */
257
+ type DynamicResolver$1<TSdk, TItem = unknown, TParams = Record<string, unknown>> = DynamicListResolver<TSdk, TItem, TParams> | DynamicSearchResolver<TSdk, TItem, TParams>;
258
+ interface ResolverFieldItem {
259
+ type: string;
260
+ key: string;
261
+ title?: string;
262
+ is_required?: boolean;
263
+ value_type?: string;
264
+ choices?: Array<{
265
+ label: string;
266
+ value: string;
267
+ }>;
268
+ fields?: ResolverFieldItem[];
269
+ resolver?: ResolverMetadata<any, any, any>;
270
+ }
271
+ interface FieldsResolver<TSdk, TParams = Record<string, unknown>, TResult = Record<string, unknown>> extends Resolver$1 {
272
+ type: "fields";
273
+ fetch: (sdk: TSdk, resolvedParams: TParams) => Promise<ResolverFieldItem[]>;
274
+ transform?: (value: Record<string, unknown>) => TResult;
275
+ }
276
+ interface ArrayResolver$1<TSdk, TParams = Record<string, unknown>> extends Resolver$1 {
277
+ type: "array";
278
+ fetch: (sdk: TSdk, resolvedParams: TParams) => Promise<ResolverMetadata<TSdk, unknown, TParams>>;
279
+ minItems?: number;
280
+ maxItems?: number;
281
+ }
282
+ type ResolverMetadata<TSdk, TItem = unknown, TParams = Record<string, unknown>> = StaticResolver$1 | ConstantResolver$1 | DynamicResolver$1<TSdk, TItem, TParams> | FieldsResolver<TSdk, TParams> | ArrayResolver$1<TSdk, TParams>;
283
+ /**
284
+ * Extract the SDK shape a resolver requires by inferring it from the resolver's
285
+ * `fetch` callback. Static and Constant resolvers have no fetch and produce
286
+ * `unknown`, meaning they impose no requirement on the plugin's SDK.
287
+ */
288
+ type RequiredSdkOf<R> = R extends {
289
+ fetch: (sdk: infer S, ...args: any[]) => any;
290
+ } ? S : unknown;
291
+ /**
292
+ * Per-entry resolver-slot validator. For each key, if the plugin's `TSdk`
293
+ * satisfies the resolver's required SDK, the entry passes through unchanged;
294
+ * otherwise the slot widens to `ResolverMetadata<TSdk, any, any>`, so TS
295
+ * surfaces the mismatch at the specific offending key rather than at the
296
+ * whole `resolvers` object.
297
+ *
298
+ * Pair with `NoInfer<TSdk>` at the call site to prevent TS from inferring
299
+ * `TSdk` from a resolver entry (which would silently accommodate the
300
+ * mismatch). With `NoInfer`, the only inference site for `TSdk` is the
301
+ * `sdk` argument, and each resolver is then checked against it.
302
+ */
303
+ type ValidResolvers<TSdk, R> = {
304
+ [K in keyof R]: TSdk extends RequiredSdkOf<R[K]> ? R[K] : ResolverMetadata<TSdk, any, any>;
305
+ };
306
+ interface ResolverConfig<TSdk, TItem = unknown, TParams = Record<string, unknown>> {
307
+ resolver: ResolverMetadata<TSdk, TItem, TParams>;
308
+ }
309
+ declare function withResolver<T extends z.ZodType, TSdk, TItem = unknown, TParams = Record<string, unknown>>(schema: T, config: ResolverConfig<TSdk, TItem, TParams>): T;
310
+ declare function getSchemaDescription(schema: z.ZodSchema): string | undefined;
311
+ declare function getFieldDescriptions(schema: z.ZodObject<z.ZodRawShape>): Record<string, string>;
312
+ interface PositionalMetadata {
313
+ positionalMeta: {
314
+ positional: true;
315
+ };
316
+ }
317
+ declare function withPositional<T extends z.ZodType>(schema: T): T & {
318
+ _def: T["_def"] & PositionalMetadata;
319
+ };
320
+ declare function isPositional(schema: z.ZodType): boolean;
321
+ declare function openEnum<const T extends readonly [string, ...string[]]>(values: T, description: string): z.ZodUnion<readonly [z.ZodEnum<{ [k_1 in T[number]]: k_1; } extends infer T_1 ? { [k in keyof T_1]: { [k_1 in T[number]]: k_1; }[k]; } : never>, z.ZodString]>;
322
+
323
+ /**
324
+ * Method-call lifecycle hooks. Plugins contribute `onMethodStart` and/or
325
+ * `onMethodEnd` on their context; `buildHooks` composes contributions across
326
+ * plugins so multiple observers can coexist. Composition is right-additive
327
+ * (newer plugins fire after earlier ones); only opt-in methods built through
328
+ * `createPluginMethod` / `createPaginatedPluginMethod` trigger the hooks.
329
+ */
330
+ interface OnMethodStartContext {
331
+ methodName: string;
332
+ args: unknown[];
333
+ isPaginated: boolean;
334
+ /**
335
+ * Depth of this method invocation in the SDK call tree. 0 = outermost
336
+ * (user-initiated) call; 1+ = called from inside another SDK method.
337
+ * Observers can use this to ignore nested calls if they only want
338
+ * top-level events.
339
+ */
340
+ depth: number;
341
+ }
342
+ type OnMethodStart = (ctx: OnMethodStartContext) => void;
343
+ interface OnMethodEndContext {
344
+ methodName: string;
345
+ args: unknown[];
346
+ isPaginated: boolean;
347
+ depth: number;
348
+ durationMs: number;
349
+ error?: Error;
350
+ }
351
+ type OnMethodEnd = (ctx: OnMethodEndContext) => void;
352
+ interface MethodHooks {
353
+ onMethodStart?: OnMethodStart;
354
+ onMethodEnd?: OnMethodEnd;
355
+ }
356
+
357
+ /**
358
+ * Descriptive metadata a leaf carries for the registry / CLI / MCP / docs:
359
+ * description, categories, type, formatter, resolvers, etc.
360
+ * Reuses the shipped `PluginMeta` minus `inputSchema`, which is a first-class
361
+ * descriptor field (it also drives `input` typing and runtime validation).
362
+ */
363
+ type LeafMeta = Omit<PluginMeta, "inputSchema">;
364
+ /**
365
+ * The descriptive registry fields a `defineMethod` / `defineProperty` author
366
+ * sets directly on the config (hoisted, not nested under a `meta` wrapper).
367
+ * The impl folds whichever are present back into the stored `LeafMeta`. This is
368
+ * the strict, explicit subset of `PluginMeta` (no `[key: string]: any` escape
369
+ * hatch, no `inputSchema` / `formatter` / `resolvers` — those are first-class
370
+ * config fields of their own).
371
+ */
372
+ interface LeafMetaFields {
373
+ description?: string;
374
+ categories?: (string | CategoryDefinition)[];
375
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
376
+ itemType?: string;
377
+ returnType?: string;
378
+ outputSchema?: z.ZodSchema;
379
+ inputParameters?: Array<{
380
+ name: string;
381
+ schema: z.ZodSchema;
382
+ }>;
383
+ packages?: string[];
384
+ experimental?: boolean;
385
+ confirm?: "create-secret" | "delete";
386
+ deprecation?: FunctionDeprecation;
387
+ aliases?: Record<string, string>;
388
+ supportsJsonOutput?: boolean;
389
+ }
390
+ /** One segment of a {@link DynamicMember} path: a literal binding/segment name,
391
+ * or a `{ param }` placeholder for an open-ended key (rendered `{param}`). */
392
+ type DynamicMemberSegment = string | {
393
+ param: string;
394
+ };
395
+ /**
396
+ * A templated registry member: a dynamic sub-surface with no static binding
397
+ * (e.g. `apps.{appKey}.{actionType}.{actionKey}`), backed at runtime by a proxy.
398
+ * It is a bodyless declaration — the same descriptive fields an author sets on a
399
+ * leaf, keyed by a `path` instead of a `name`. The framework derives the
400
+ * registry name by joining the path (params rendered `{param}`) and folds these
401
+ * fields into a `PluginMeta` for the registry / CLI / MCP / docs projection.
402
+ * `path[0]` must be a literal that resolves to a real surfaced binding (the
403
+ * owning member).
404
+ */
405
+ type DynamicMember = {
406
+ path: readonly DynamicMemberSegment[];
407
+ /** Projection-only input schema (no runtime; the proxy validates its own). */
408
+ inputSchema?: z.ZodType;
409
+ } & LeafMetaFields;
410
+ /** A {@link DynamicMember} normalized at define time: the derived registry name,
411
+ * the literal root segment (validated against the surface), and the folded meta. */
412
+ interface NormalizedDynamicMember {
413
+ name: string;
414
+ rootBinding: string;
415
+ meta: PluginMeta;
416
+ }
417
+ type AnyMethodPlugin = MethodPlugin<string, any, any, readonly string[]>;
418
+ type AnyPropertyPlugin = PropertyPlugin<string, any>;
419
+ /** A leaf plugin: a method (callable) or a property (value). */
420
+ type AnyLeafPlugin = AnyMethodPlugin | AnyPropertyPlugin;
421
+ /**
422
+ * How a module declares its imports: an array. Each element binds under its own
423
+ * name (a leaf under its name, a module under each of its export names); a
424
+ * `selectExports(...)` element contributes its chosen bindings. To rename or
425
+ * subset, wrap an element in `selectExports`; there is no alias-map form.
426
+ */
427
+ type ImportsInput = readonly AnyPlugin[];
428
+ /** A resolved import edge: the local binding name and the plugin id it reads
429
+ * from `context.plugins` (id, not identity, so a swap stays transparent). */
430
+ interface ImportBinding {
431
+ binding: string;
432
+ id: string;
433
+ /** True when the edge came from a `declareOptionalProperty` stand-in: if no real
434
+ * plugin satisfies the id, the binding resolves to `undefined` instead of
435
+ * failing the build as a missing dependency. */
436
+ optional?: boolean;
437
+ }
438
+ /**
439
+ * Collapse a union to an intersection. Turns the per-dependency
440
+ * `{ name: signature }` union into one `imports` object type.
441
+ */
442
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
443
+ /**
444
+ * A method's callable signature. A method with no declared input infers
445
+ * `TInput = unknown`; make its input optional so it is callable with no
446
+ * argument. An input whose properties are all optional (e.g. a `list` method
447
+ * whose only input is the framework's `cursor` / `pageSize` / `maxItems`) is
448
+ * also callable with no argument. A real required input keeps the arg required.
449
+ */
450
+ type MethodCall<TInput, TOutput> = [unknown] extends [TInput] ? (input?: TInput) => TOutput : {} extends TInput ? (input?: TInput) => TOutput : (input: TInput) => TOutput;
451
+ /**
452
+ * Project the canonical input through an ordered list of key names into a
453
+ * positional argument tuple, preserving trailing-optionality: a key that is
454
+ * optional in `TInput` becomes an optional argument (so `fetch(url)` is legal
455
+ * when `init` is optional). A name that is not a key of `TInput` is an error.
456
+ */
457
+ type PositionalArgs<TInput, TNames extends readonly PropertyKey[]> = TNames extends readonly [
458
+ infer Head extends keyof TInput,
459
+ ...infer Tail extends readonly (keyof TInput)[]
460
+ ] ? {} extends Pick<TInput, Head> ? [arg?: TInput[Head], ...PositionalArgs<TInput, Tail>] : [arg: TInput[Head], ...PositionalArgs<TInput, Tail>] : [];
461
+ /**
462
+ * The public call signature of a method on the surface and in `imports`. With
463
+ * no positional projection it is the canonical single-object `MethodCall`; with
464
+ * one it is the positional signature derived from the input. Middleware does
465
+ * NOT use this (its bag carries one canonical `input`); see `MiddlewareMap`.
466
+ */
467
+ type SurfaceCall<TInput, TOutput, TPositional extends readonly string[]> = TPositional extends readonly [] ? MethodCall<TInput, TOutput> : (...args: PositionalArgs<TInput, TPositional>) => TOutput;
468
+ /**
469
+ * The bindings one array-form dependency contributes to `imports`: a leaf under
470
+ * its own name (method callable or property value), an aggregate under each of
471
+ * its export names — exactly the dependency's {@link PluginSurface}.
472
+ */
473
+ type BindingsOf<TDep extends AnyPlugin> = PluginSurface<TDep>;
474
+ /**
475
+ * The `imports` a body receives. Each element contributes its bindings
476
+ * (`BindingsOf`); empty imports yield an empty object.
477
+ */
478
+ type ImportsOf<TImports extends ImportsInput> = TImports extends readonly [] ? Record<never, never> : UnionToIntersection<{
479
+ [K in keyof TImports]: BindingsOf<TImports[K]>;
480
+ }[number]>;
481
+ /**
482
+ * The bag a method body receives. `imports` is the dependency-narrowed reach;
483
+ * `state` is the plugin's private constructor result (undefined when none);
484
+ * `input` is the canonical call argument.
485
+ */
486
+ interface MethodRunBag<TImports, TInput, TState = unknown> {
487
+ imports: TImports;
488
+ state: TState;
489
+ input: TInput;
490
+ }
491
+ /** Shared plumbing for the method attachments: each declares its own
492
+ * dependencies. Resolvers and formatters are otherwise separate concepts. */
493
+ interface MethodAttachment {
494
+ imports: readonly AnyPlugin[];
495
+ /** Binding-name to plugin-id edges, normalized from `imports`; what the
496
+ * narrowed bag captured at materialization is built from. */
497
+ importBindings: readonly ImportBinding[];
498
+ }
499
+ /**
500
+ * A resolver's kind, the discriminant of the {@link Resolver} union. Scalars
501
+ * (`dynamic` / `static` / `constant`) resolve one value; `info` resolves none
502
+ * (display-only); `object` / `array` compose nested resolvers. Names borrow
503
+ * JSON Schema's structural vocabulary (`object`/`array`/`properties`/`items`),
504
+ * but a resolver carries behavior (fetch/prompt), not validation.
505
+ */
506
+ type ResolverType = "dynamic" | "static" | "constant" | "info" | "object" | "array";
507
+ /**
508
+ * A reference from a field (or array `items`) to a reusable resolver in the
509
+ * nearest `definitions` block. `input` are merged into the referenced
510
+ * resolver's `input` (e.g. the field key a shared choices-fetcher needs).
511
+ * Used when a fetch-built field needs an import-bearing resolver, which can't
512
+ * be inlined at fetch time (its imports bind at materialization).
513
+ */
514
+ interface ResolverRef {
515
+ ref: string;
516
+ input?: Record<string, unknown>;
517
+ }
518
+ /**
519
+ * One member of an object resolver's `properties` (literal or fetch-built): the
520
+ * resolver for the value plus its per-occurrence meta. `required` / `valueType`
521
+ * live here, not on the resolver, because the same resolver can be required in
522
+ * one object and optional in another, and a fetch-built field (no schema) has
523
+ * nowhere else to carry them.
524
+ */
525
+ interface Field {
526
+ resolver: Resolver | ResolverRef;
527
+ label?: string;
528
+ required?: boolean;
529
+ valueType?: string;
530
+ }
531
+ /** Shared gates for resolvers that resolve a value: the attachment plumbing
532
+ * plus the param-dataflow prerequisite. (`info` skips these.) */
533
+ interface ResolverBase extends MethodAttachment {
534
+ /** Sibling parameters that must resolve before this resolver runs (it reads
535
+ * their values from `input`). The param-dataflow prerequisite, distinct from
536
+ * `imports`' SDK-capability graph. */
537
+ requireParameters?: readonly string[];
538
+ }
539
+ /** List candidate items and prompt the user to pick one. */
540
+ interface DynamicResolver extends ResolverBase {
541
+ type: "dynamic";
542
+ inputType?: "text" | "password" | "email" | "search";
543
+ placeholder?: string;
544
+ /** Compute side-context once, before `listItems`, with the narrowed `imports`
545
+ * bag (no items yet — it runs pre-fetch so it can shape the fetch). The result
546
+ * flows into `listItems` and `prompt` as `context`. Use it to resolve, in one
547
+ * place, anything both the fetch and the render need (e.g. a capability gate:
548
+ * compute `includeShared` here, gate the fetch in `listItems`, surface a
549
+ * `notes` hint in `prompt`). May run more than once across re-asks, so keep it
550
+ * cheap/idempotent. */
551
+ getContext?: (bag: {
552
+ imports: Record<string, unknown>;
553
+ input: Record<string, unknown>;
554
+ }) => PromiseLike<unknown>;
555
+ /** Produce the candidate list. Behaves like an SDK list method: returns a
556
+ * paginated result (await for the first page + `nextCursor`, or iterate pages),
557
+ * never a bare array. `cursor` is the stateless re-entry hook for "load more":
558
+ * an in-process host iterates the result; a distributed host awaits one page,
559
+ * carries `nextCursor`, and calls again with `cursor`. Required: a dynamic
560
+ * resolver IS a candidate-lister; a free-text field (with or without
561
+ * auto-resolution someday) is the `static` kind's job. */
562
+ listItems: (bag: {
563
+ imports: Record<string, unknown>;
564
+ input: Record<string, unknown>;
565
+ /** The value `getContext` returned, if any. */
566
+ context?: unknown;
567
+ /** Free-text term injected by the CLI for search-mode resolvers. A separate
568
+ * key, not part of `input`, so it never collides with a method parameter
569
+ * also named `search`. */
570
+ search?: string;
571
+ cursor?: string;
572
+ }) => ListItemsResult<unknown>;
573
+ prompt?: (bag: {
574
+ items: unknown[];
575
+ input: Record<string, unknown>;
576
+ /** The value `getContext` returned, if any. */
577
+ context?: unknown;
578
+ }) => ResolverPromptConfig;
579
+ /** Resolve with no user input at all (e.g. a configured default), skipping the
580
+ * prompt. Runs before prompting; used always in non-interactive mode and as a
581
+ * "can we skip asking?" check otherwise. Returns null to fall through to a prompt. */
582
+ tryResolveWithoutPrompt?: (bag: {
583
+ imports: Record<string, unknown>;
584
+ input: Record<string, unknown>;
585
+ }) => Promise<{
586
+ resolvedValue: unknown;
587
+ } | null>;
588
+ /** Search-mode exact match: the user typed `search`; if it already names a
589
+ * valid value (e.g. validated via the API), return it to skip the picker.
590
+ * Distinct from `tryResolveWithoutPrompt` (no input) — this is interactive,
591
+ * mid-prompt, with the typed term. Returns null to fall through to `listItems`. */
592
+ tryResolveFromSearch?: (bag: {
593
+ imports: Record<string, unknown>;
594
+ input: Record<string, unknown>;
595
+ search?: string;
596
+ }) => Promise<{
597
+ resolvedValue: unknown;
598
+ } | null>;
599
+ }
600
+ /** Free-text input, no candidate list. */
601
+ interface StaticResolver extends ResolverBase {
602
+ type: "static";
603
+ inputType?: "text" | "password" | "email" | "search";
604
+ placeholder?: string;
605
+ }
606
+ /** A fixed value, no prompt. */
607
+ interface ConstantResolver extends ResolverBase {
608
+ type: "constant";
609
+ value: unknown;
610
+ }
611
+ /** Display-only text; resolves no value (its key is skipped in the result). */
612
+ interface InfoResolver extends MethodAttachment {
613
+ type: "info";
614
+ text: string;
615
+ }
616
+ /** A keyed object. `properties` are known up front; `getProperties` builds them
617
+ * when the key set is dynamic (re-invoked as `input` grow, for depends-on
618
+ * fields). Returns the property map raw (no envelope: nothing to paginate).
619
+ * `definitions` holds reusable resolvers reached by `{ ref }` from built fields
620
+ * that need an import. */
621
+ interface ObjectResolver extends ResolverBase {
622
+ type: "object";
623
+ properties?: Record<string, Field>;
624
+ getProperties?: (bag: {
625
+ imports: Record<string, unknown>;
626
+ input: Record<string, unknown>;
627
+ }) => PromiseLike<Record<string, Field>>;
628
+ definitions?: Record<string, Resolver>;
629
+ }
630
+ /** A homogeneous list: each element resolves through `items`. */
631
+ interface ArrayResolver extends ResolverBase {
632
+ type: "array";
633
+ items: Resolver | ResolverRef;
634
+ minItems?: number;
635
+ maxItems?: number;
636
+ /** Coarse value type of each element, so a free-text item answer coerces
637
+ * (e.g. `"5"` → `5` for `z.array(z.number())`) the way object fields do via
638
+ * `Field.valueType`. `items` is a bare resolver with no `valueType` slot of
639
+ * its own, so the element type rides here. */
640
+ itemValueType?: string;
641
+ definitions?: Record<string, Resolver>;
642
+ }
643
+ /**
644
+ * An input resolver descriptor (produced by `defineResolver`, attached to a
645
+ * method parameter). A discriminated union on `type`; composites (`object` /
646
+ * `array`) recurse. Callbacks take a narrowed `imports` bag; the materializer
647
+ * captures it and produces a {@link BoundResolver}. Stored loosely (the precise
648
+ * `imports` / item / param types live on the `defineResolver` config), like
649
+ * `MethodPlugin.run`.
650
+ */
651
+ type Resolver = DynamicResolver | StaticResolver | ConstantResolver | InfoResolver | ObjectResolver | ArrayResolver;
652
+ /**
653
+ * An output formatter descriptor (produced by `defineFormatter`, attached to a
654
+ * method's output). `getContext` reaches the narrowed `imports` bag; the
655
+ * materializer captures it and produces a {@link BoundFormatter}. Stored
656
+ * loosely, like {@link Resolver}. Both callbacks receive the method's `input`
657
+ * (the formatter runs post-execution, so the input is complete, unlike a
658
+ * resolver's partial `input`).
659
+ */
660
+ interface Formatter extends MethodAttachment {
661
+ getContext?: (bag: {
662
+ imports: Record<string, unknown>;
663
+ items: unknown[];
664
+ input: Record<string, unknown>;
665
+ context?: unknown;
666
+ }) => Promise<unknown>;
667
+ format: (bag: {
668
+ item: unknown;
669
+ input: Record<string, unknown>;
670
+ context?: unknown;
671
+ }) => FormattedItem;
672
+ }
673
+ /** What a dynamic resolver's `listItems` yields: an SDK list-method result
674
+ * (`await` for the first page + `nextCursor`, or iterate pages in-process), or a
675
+ * plain page / promise of one. No bare array and no scalar: it behaves like any
676
+ * other list method, and exact-match short-circuits live on `tryResolveFromSearch`. */
677
+ type ListItemsResult<TItem> = PaginatedSdkResult<TItem> | SdkPage<TItem> | Promise<SdkPage<TItem>>;
678
+ /** A bound object resolver's literal property: its resolver is already bound
679
+ * (or a `{ ref }` the CLI resolves against `definitions` at runtime). */
680
+ interface BoundField {
681
+ resolver: BoundResolver | ResolverRef;
682
+ label?: string;
683
+ required?: boolean;
684
+ valueType?: string;
685
+ }
686
+ /** Fields shared by every bound resolver kind. */
687
+ interface BoundResolverBase {
688
+ /** Sibling parameters that must resolve before this resolver runs (it reads
689
+ * their values from `input`). The param-dataflow prerequisite, distinct from
690
+ * `imports`' SDK-capability graph. */
691
+ requireParameters?: readonly string[];
692
+ }
693
+ /** Free-text input, no candidate list. */
694
+ interface BoundStaticResolver extends BoundResolverBase {
695
+ type: "static";
696
+ inputType?: "text" | "password" | "email" | "search";
697
+ placeholder?: string;
698
+ }
699
+ /** A fixed value the author pinned; auto-settles, never asks. */
700
+ interface BoundConstantResolver extends BoundResolverBase {
701
+ type: "constant";
702
+ value: unknown;
703
+ }
704
+ /** Display-only text; resolves no value, never asks. */
705
+ interface BoundInfoResolver extends BoundResolverBase {
706
+ type: "info";
707
+ text: string;
708
+ }
709
+ /** List candidate items (`listItems`) and prompt to pick one; carries the
710
+ * auto-resolution hooks (`tryResolveWithoutPrompt`, `tryResolveFromSearch`). */
711
+ interface BoundDynamicResolver extends BoundResolverBase {
712
+ type: "dynamic";
713
+ inputType?: "text" | "password" | "email" | "search";
714
+ placeholder?: string;
715
+ getContext?: (bag: {
716
+ input: Record<string, unknown>;
717
+ }) => PromiseLike<unknown>;
718
+ listItems: (bag: {
719
+ input: Record<string, unknown>;
720
+ context?: unknown;
721
+ search?: string;
722
+ cursor?: string;
723
+ }) => ListItemsResult<unknown>;
724
+ prompt?: (bag: {
725
+ items: unknown[];
726
+ input: Record<string, unknown>;
727
+ context?: unknown;
728
+ }) => ResolverPromptConfig;
729
+ tryResolveWithoutPrompt?: (bag: {
730
+ input: Record<string, unknown>;
731
+ }) => Promise<{
732
+ resolvedValue: unknown;
733
+ } | null>;
734
+ tryResolveFromSearch?: (bag: {
735
+ input: Record<string, unknown>;
736
+ search?: string;
737
+ }) => Promise<{
738
+ resolvedValue: unknown;
739
+ } | null>;
740
+ }
741
+ /** Keyed members: static `properties` (bound) or a `getProperties`-built
742
+ * (unbound) field map; `definitions` holds ref targets. */
743
+ interface BoundObjectResolver extends BoundResolverBase {
744
+ type: "object";
745
+ properties?: Record<string, BoundField>;
746
+ definitions?: Record<string, BoundResolver>;
747
+ getProperties?: (bag: {
748
+ input: Record<string, unknown>;
749
+ }) => PromiseLike<Record<string, Field>>;
750
+ }
751
+ /** A homogeneous list resolved through `items` (bound, or a ref into
752
+ * `definitions`). */
753
+ interface BoundArrayResolver extends BoundResolverBase {
754
+ type: "array";
755
+ items: BoundResolver | ResolverRef;
756
+ minItems?: number;
757
+ maxItems?: number;
758
+ /** The element's coarse value type, used to coerce a free-text item answer
759
+ * before validation (see {@link ArrayResolver.itemValueType}). */
760
+ itemValueType?: string;
761
+ definitions?: Record<string, BoundResolver>;
762
+ }
763
+ /**
764
+ * The runtime resolver `defineResolver` binds to: its imports are already
765
+ * captured, so the CLI calls these with input (and `search`) only, no sdk.
766
+ * `prompt` stays pure (no SDK reach). A discriminated union mirroring
767
+ * {@link Resolver}, so kind-specific field access compiles only behind a
768
+ * `type` narrow (the binder's switch is the one exhaustiveness-checked
769
+ * dispatch; the engine's if-chains get the field-access check).
770
+ */
771
+ type BoundResolver = BoundStaticResolver | BoundConstantResolver | BoundInfoResolver | BoundDynamicResolver | BoundObjectResolver | BoundArrayResolver;
772
+ /**
773
+ * The runtime formatter `defineFormatter` binds to: `getContext` runs once per
774
+ * rendered batch (imports captured, no sdk) to build shared context; `format`
775
+ * is pure and synchronous, turning one item + context into a `FormattedItem`.
776
+ */
777
+ interface BoundFormatter<TItem = unknown, TInput = Record<string, unknown>, TContext = unknown> {
778
+ getContext?: (bag: {
779
+ items: TItem[];
780
+ input: TInput;
781
+ context?: TContext;
782
+ }) => Promise<TContext>;
783
+ format: (bag: {
784
+ item: TItem;
785
+ input: TInput;
786
+ context?: TContext;
787
+ }) => FormattedItem;
788
+ }
789
+ /**
790
+ * A leaf plugin that is a single function: it IS the method. `pluginType` is
791
+ * the node-kind discriminant; `name` is its identity and default
792
+ * binding name. `imports` are the other plugins it depends on. The stored
793
+ * `run` is loosely typed for `imports` (the precise type lives on the
794
+ * `defineMethod` authoring surface, like the shipped definePlugin).
795
+ */
796
+ interface MethodPlugin<TName extends string = string, TInput = unknown, TOutput = unknown, TPositional extends readonly string[] = readonly []> {
797
+ pluginType: "method";
798
+ name: TName;
799
+ namespace?: string;
800
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
801
+ id: string;
802
+ /** True for a `declareMethod` stand-in: a typed reference with no real
803
+ * implementation. A real plugin under the same id satisfies it. */
804
+ standIn?: boolean;
805
+ /** True for a `declareOptionalProperty` stand-in over a method id: dependents bind
806
+ * `undefined` if no real plugin satisfies it. */
807
+ optional?: boolean;
808
+ imports: readonly AnyPlugin[];
809
+ /** Binding-name to plugin-id edges, normalized from `imports`;
810
+ * what the `imports` bag is built from. */
811
+ importBindings: readonly ImportBinding[];
812
+ /** Optional per-materialization constructor: runs once at createSdk
813
+ * (dependencies first), may side-effect, and returns the method's private
814
+ * state (delivered to `run` as `bag.state`). */
815
+ setup?: (bag: {
816
+ imports: Record<string, unknown>;
817
+ }) => unknown;
818
+ /** `setup`'s dual: releases what setup acquired. Run by `disposeSdk` in
819
+ * reverse dependency order. */
820
+ dispose?: DisposeFn;
821
+ /** Validates `input` before `run` and drives the authoring `input` type. */
822
+ inputSchema?: z.ZodType;
823
+ /** When true, skip the runtime validation/parse of `input`: `run` receives the
824
+ * raw input untouched — no coercion, stripping, or cloning — even if
825
+ * `inputSchema` is set (the schema stays for registry / CLI / MCP projection).
826
+ * For raw methods that own their own validation and must not have their input
827
+ * transformed, e.g. `fetch` passing a `RequestInit` bag through unchanged. */
828
+ skipInputValidation?: boolean;
829
+ /** Descriptive metadata for the registry / CLI / MCP / docs (carry-only at
830
+ * runtime). */
831
+ meta?: LeafMeta;
832
+ /** Per-parameter input resolvers (method attachments). Reached for
833
+ * materialization and bound into the entry at createSdk; a reachability-only
834
+ * edge whose imports never enter this method's `importBindings`. */
835
+ resolvers?: Record<string, Resolver>;
836
+ /** Output formatter (method attachment). Bound into the entry at createSdk. */
837
+ formatter?: Formatter;
838
+ run: (bag: MethodRunBag<any, TInput, any>) => TOutput;
839
+ /** How `run`'s result is shaped into the public surface (see Output in the
840
+ * design doc). Omitted is "raw". Stored loosely; the precise per-mode typing
841
+ * lives on the `defineMethod` overloads. */
842
+ output?: OutputConfig;
843
+ /** Positional projection (see Output): ordered keys of the canonical input
844
+ * that the public surface and imports take as positional arguments. The
845
+ * framework packs them back into `{ input }` before validation, middleware,
846
+ * and `run`, so internals stay canonical. The runtime reads this loose field;
847
+ * the precise names ride the `TPositional` type param for surface typing. */
848
+ positional?: readonly string[];
849
+ /**
850
+ * Phantom: carries the positional names as a tuple type so `BindingsOf` /
851
+ * `ExportSurface` can render the positional signature. Never present at
852
+ * runtime; the loose `positional` field above is the runtime carrier.
853
+ * @internal
854
+ */
855
+ readonly [POSITIONAL_NAMES]?: TPositional;
856
+ }
857
+ /** Phantom-only key (see `MethodPlugin`); never set at runtime. */
858
+ declare const POSITIONAL_NAMES: unique symbol;
859
+ /** A method's output mode: raw passthrough, a `{ data }` item envelope, or a
860
+ * paginated list. */
861
+ type OutputMode = "raw" | "item" | "list";
862
+ /** The authoring value for `output`: a bare mode string, or the object form
863
+ * (which carries list options). */
864
+ type OutputConfig = OutputMode | {
865
+ type: "raw";
866
+ } | {
867
+ type: "item";
868
+ } | {
869
+ type: "list";
870
+ adaptPage?: (response: any) => SdkPage<any>;
871
+ defaultPageSize?: number;
872
+ };
873
+ /** Normalized output config: always the object form with a resolved `type`. */
874
+ interface NormalizedOutput {
875
+ type: OutputMode;
876
+ adaptPage?: (response: any) => SdkPage<any>;
877
+ defaultPageSize?: number;
878
+ }
879
+ /** Framework-injected page controls a list method's `run` receives. */
880
+ type PageFetchInput = {
881
+ cursor?: string;
882
+ pageSize?: number;
883
+ };
884
+ /** Page controls a list method's public caller may pass. */
885
+ type PaginatedCallInput = PageFetchInput & {
886
+ maxItems?: number;
887
+ };
888
+ /**
889
+ * A response whose only own keys are `data` / `nextCursor`. Gates the
890
+ * list-standard overload: a raw envelope with extra keys is not a `StrictPage`
891
+ * and falls through to the adapted overload, where `adaptPage` is required.
892
+ */
893
+ type StrictPage$1<TResponse> = SdkPage<unknown> & {
894
+ [K in Exclude<keyof TResponse, keyof SdkPage<unknown>>]?: never;
895
+ };
896
+ /** Item type sourced from a page-ish response. */
897
+ type ItemOf$1<TResponse> = TResponse extends SdkPage<infer TItem> ? TItem : TResponse extends {
898
+ data: readonly (infer TItem)[];
899
+ } ? TItem : never;
900
+ /**
901
+ * A leaf plugin that is a single value (not a function). `value` is a static
902
+ * constant; `get({ imports })` computes the value from imports. Like a
903
+ * method's `setup`, `get` runs eagerly at createSdk (dependencies first), so a
904
+ * module-level value is built on import. An imported/surfaced property yields
905
+ * the value, not a callable.
906
+ */
907
+ interface PropertyPlugin<TName extends string = string, TValue = unknown> {
908
+ pluginType: "property";
909
+ name: TName;
910
+ namespace?: string;
911
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
912
+ id: string;
913
+ /** True for a `declareProperty` stand-in: a typed reference with no value. A
914
+ * real property under the same id satisfies it. */
915
+ standIn?: boolean;
916
+ /** True for a `declareOptionalProperty` stand-in: an optional reference. If no real
917
+ * property satisfies it, dependents bind `undefined` rather than the build
918
+ * failing on a missing dependency. */
919
+ optional?: boolean;
920
+ imports: readonly AnyPlugin[];
921
+ /** Binding-name to plugin-id edges, normalized from `imports`;
922
+ * what the `imports` bag is built from. */
923
+ importBindings: readonly ImportBinding[];
924
+ /** Optional once-eager constructor (the property twin of a method's `setup`):
925
+ * runs once at createSdk (dependencies first), may side-effect, and returns the
926
+ * private state delivered to `get` as `bag.state`. */
927
+ setup?: (bag: {
928
+ imports: Record<string, unknown>;
929
+ }) => unknown;
930
+ /** `setup`'s dual: releases what setup acquired. Run by `disposeSdk` in
931
+ * reverse dependency order. */
932
+ dispose?: DisposeFn;
933
+ value?: TValue;
934
+ /** A live getter: computes the value from imports and `setup` state on each
935
+ * read (not once). The stored shape is loose; the precise typing lives on the
936
+ * `defineProperty` overloads. */
937
+ get?: (bag: {
938
+ imports: Record<string, unknown>;
939
+ state: unknown;
940
+ }) => TValue;
941
+ /** Descriptive metadata for the registry / CLI / MCP / docs (carry-only). */
942
+ meta?: LeafMeta;
943
+ /** Templated registry members for this property's dynamic sub-surface (e.g. a
944
+ * proxy). Carry-only: normalized at define time, folded into the registry. */
945
+ dynamicMembers?: readonly NormalizedDynamicMember[];
946
+ /** A built-in whose value is the live `SdkContext`, injected at
947
+ * materialization. Reserved for kitcore's own plugins;
948
+ * authors use `value` / `get`. */
949
+ privileged?: boolean;
950
+ }
951
+ /**
952
+ * A middleware function wrapping one of the aggregate's imported methods.
953
+ * `next` invokes the next layer (an inner wrap, ultimately the core method);
954
+ * `imports` is the middleware plugin's own dependency reach; `input` is the
955
+ * canonical call argument. It must preserve the target's contract; the
956
+ * `MiddlewareMap` typing on `definePlugin` enforces that statically.
957
+ */
958
+ type MiddlewareFn = (bag: {
959
+ imports: any;
960
+ next: (input: any) => any;
961
+ input: any;
962
+ state: unknown;
963
+ }) => any;
964
+ /**
965
+ * The authoring type for a hook's `wrap`: a map whose keys are the method
966
+ * bindings among the hook's `imports` (you can only wrap a method you import)
967
+ * and whose values are contract-preserving wraps. `next` and `input` take the
968
+ * target's input and the wrap must return the target's output, so a wrap that
969
+ * changes the public signature, or that targets a non-imported / non-method
970
+ * binding, does not compile. `state` is the hook's `setup` result (one bag
971
+ * shape across run/observe/wrap; `next` is the only variant).
972
+ */
973
+ type MiddlewareMap<TImports, TState = unknown> = {
974
+ [K in keyof TImports as TImports[K] extends (input: any) => any ? K : never]?: TImports[K] extends (input: infer TInput) => infer TOutput ? (bag: {
975
+ imports: TImports;
976
+ next: (input: TInput) => TOutput;
977
+ input: TInput;
978
+ state: TState;
979
+ }) => TOutput : never;
980
+ };
981
+ /** The export record one array element contributes: a leaf under its own name,
982
+ * a module under each of its export bindings. */
983
+ type ElementExports<E> = E extends MethodPlugin<infer N, any, any, any> ? {
984
+ [K in N]: E;
985
+ } : E extends PropertyPlugin<infer N, any> ? {
986
+ [K in N]: E;
987
+ } : E extends AggregatePlugin<string, infer TE> ? TE : never;
988
+ /**
989
+ * The canonical export record an aggregate stores: each array element's
990
+ * bindings merged, so every downstream consumer sees a `Record<binding, leaf>`.
991
+ */
992
+ type ArrayExports<T extends readonly (AnyLeafPlugin | AnyAggregatePlugin)[]> = T extends readonly [] ? Record<never, never> : UnionToIntersection<{
993
+ [I in keyof T]: ElementExports<T[I]>;
994
+ }[number]>;
995
+ interface AggregatePlugin<TName extends string = string, TExports extends Record<string, AnyLeafPlugin> = Record<string, AnyLeafPlugin>> {
996
+ pluginType: "aggregate";
997
+ name: TName;
998
+ namespace?: string;
999
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
1000
+ id: string;
1001
+ /** True for a `declarePlugin` stand-in: a typed reference to a whole module
1002
+ * with no implementation. A real aggregate under the same id satisfies it. */
1003
+ standIn?: boolean;
1004
+ imports: readonly AnyPlugin[];
1005
+ /** Binding-name to plugin-id edges, normalized from `imports`; what a
1006
+ * wrap's `imports` is built from, and how a wrap target
1007
+ * binding resolves to a method id. */
1008
+ importBindings: readonly ImportBinding[];
1009
+ exports: TExports;
1010
+ }
1011
+ type AnyAggregatePlugin = AggregatePlugin<string, Record<string, any>>;
1012
+ /**
1013
+ * A legacy bridge plugin: wraps an old function plugin
1014
+ * (`(sdk) => provides`) so it materializes inside the new graph. At
1015
+ * materialization it runs `run` against a live compat view, merges the
1016
+ * returned context contributions into the shared `SdkContext`, and synthesizes
1017
+ * a `context.plugins` entry per root key. `TSurface` is the surfaced shape (the
1018
+ * provides minus `context`). This is the single shape `createPluginStack()
1019
+ * .toPlugin()` emits; there is no separate interim definition format.
1020
+ */
1021
+ interface LegacyPlugin<TSurface = Record<string, unknown>> {
1022
+ pluginType: "legacy";
1023
+ name: string;
1024
+ namespace?: string;
1025
+ /** `namespace/name`, or bare `name`. The `context.plugins` key. */
1026
+ id: string;
1027
+ imports: readonly AnyPlugin[];
1028
+ importBindings: readonly ImportBinding[];
1029
+ run: (sdk: any) => PluginProvides;
1030
+ /** Type-only carrier for the surfaced shape; never set at runtime. */
1031
+ readonly __surface?: TSurface;
1032
+ }
1033
+ type AnyLegacyPlugin = LegacyPlugin<any>;
1034
+ /**
1035
+ * A patch over an already-defined method's descriptive fields. It carries no
1036
+ * `run`: it names an existing method by id (`target`) and, after that method
1037
+ * materializes, merges its `meta` (the same public {@link LeafMetaFields} an
1038
+ * author sets on `defineMethod`) onto the method's entry, so the surface
1039
+ * registry / CLI / MCP / docs project the patched values. For surface-specific
1040
+ * tweaks a base method should not carry (e.g. a CLI that deprecates `fetch`
1041
+ * while the SDK does not, or a host that hides a method via `packages`).
1042
+ *
1043
+ * Distinct from a *replacement* (`addPlugin(..., { override: true })`), which
1044
+ * swaps the whole implementation and forces re-declaring `run`. An override
1045
+ * inherits the target's implementation untouched and only patches meta.
1046
+ */
1047
+ interface MethodOverridePlugin {
1048
+ pluginType: "method-override";
1049
+ name: string;
1050
+ id: string;
1051
+ /** The id of the method whose meta is patched (its bare name if the method is
1052
+ * namespace-less). */
1053
+ target: string;
1054
+ imports: readonly AnyPlugin[];
1055
+ importBindings: readonly ImportBinding[];
1056
+ meta?: LeafMeta;
1057
+ }
1058
+ /**
1059
+ * A method-lifecycle hook leaf (`defineHook`). `observe` contributes
1060
+ * fire-and-forget observers (`onMethodStart` / `onMethodEnd`) that the method
1061
+ * boundary fires around every method; they run defensively (an observer error
1062
+ * never breaks the observed call). `setup` runs once and owns the hook's state
1063
+ * (e.g. a telemetry queue), delivered to the observers.
1064
+ * Each observer bag mirrors a method's: `{ imports, input, state }` — `input` is
1065
+ * the lifecycle context, and there is no `next` (observers don't participate in
1066
+ * the call). The module-model replacement for a legacy plugin that contributed
1067
+ * `context.hooks`.
1068
+ */
1069
+ interface HookPlugin<TName extends string = string> {
1070
+ pluginType: "hook";
1071
+ name: TName;
1072
+ namespace?: string;
1073
+ id: string;
1074
+ imports: readonly AnyPlugin[];
1075
+ importBindings: readonly ImportBinding[];
1076
+ setup?: (bag: {
1077
+ imports: any;
1078
+ }) => unknown;
1079
+ /** `setup`'s dual: releases what setup acquired. Run by `disposeSdk` in
1080
+ * reverse dependency order. */
1081
+ dispose?: DisposeFn;
1082
+ /** Contract-preserving wraps around imported methods (the middleware onion,
1083
+ * folded dependents-outermost in topological order). Keyed by the target's
1084
+ * binding among this hook's `imports`. */
1085
+ wrap?: Record<string, MiddlewareFn>;
1086
+ observe?: {
1087
+ onMethodStart?: (bag: {
1088
+ imports: any;
1089
+ input: OnMethodStartContext;
1090
+ state: unknown;
1091
+ }) => void;
1092
+ onMethodEnd?: (bag: {
1093
+ imports: any;
1094
+ input: OnMethodEndContext;
1095
+ state: unknown;
1096
+ }) => void;
1097
+ };
1098
+ }
1099
+ type AnyPlugin = AnyLeafPlugin | AnyAggregatePlugin | AnyLegacyPlugin | HookPlugin | MethodOverridePlugin;
1100
+ /**
1101
+ * A transitional root that merges a legacy function-plugin stack with the
1102
+ * module-model plugins migrated off it (see Migration order). At `createSdk` it
1103
+ * lifts and runs the legacy stack (like `fromFunctionPlugin`), materializes the
1104
+ * module-model `plugin`, and surfaces the union: the legacy stack's methods plus
1105
+ * the module plugin's exports. The migrated plugins live in one `plugin`
1106
+ * aggregate, so each migration only edits that aggregate's exports, not the
1107
+ * heads. Deleted once every plugin is module-model.
1108
+ */
1109
+ interface LegacyMergePlugin<TProvides extends PluginProvides = PluginProvides, TPlugin extends AnyPlugin = AnyPlugin> {
1110
+ pluginType: "legacy-merge";
1111
+ name: string;
1112
+ namespace?: string;
1113
+ id: string;
1114
+ /** The lifted legacy stack (one node). */
1115
+ legacy: LegacyPlugin<TProvides & {
1116
+ getRegistry: (options?: {
1117
+ package?: string;
1118
+ }) => RegistryResult;
1119
+ }>;
1120
+ /** The module-model plugins migrated off the legacy stack. */
1121
+ plugin: TPlugin;
1122
+ }
1123
+ /** One middleware layer on a method's chain: the wrap and its owning hook
1124
+ * (whose `imports` the wrap receives, built live at call time). */
1125
+ interface MiddlewareWrap {
1126
+ run: MiddlewareFn;
1127
+ owner: HookPlugin;
1128
+ }
1129
+ /** A materialized method: a stable callable `value` that folds `chain` around
1130
+ * the core at call time. The chain is ordered dependents-outermost; it is
1131
+ * mutable so post-seal `addPlugin` middleware can append. */
1132
+ interface MethodEntry {
1133
+ pluginType: "method";
1134
+ name: string;
1135
+ value: (input: any) => any;
1136
+ /** The import-facing twin of `value`: the same boundary, called with the
1137
+ * internal-call sentinel so surface-only concerns (the deprecation signal)
1138
+ * don't fire when a sibling plugin delegates. `buildImports` and
1139
+ * `resolvePlugin` bind this; the surface and registry bind `value`. Absent
1140
+ * on legacy graph entries (they bind `value`). */
1141
+ internalValue?: (input: any) => any;
1142
+ chain: MiddlewareWrap[];
1143
+ /** Carried from the descriptor for the registry / CLI / MCP / docs. */
1144
+ inputSchema?: z.ZodType;
1145
+ meta?: LeafMeta;
1146
+ /** Resolved output mode; the registry derives presentation from it. */
1147
+ output?: NormalizedOutput;
1148
+ /** Positional input projection (see Output): ordered canonical-input keys the
1149
+ * public callable / imports take as positional args. */
1150
+ positional?: readonly string[];
1151
+ /** Bound input resolvers (their imports captured at materialization), keyed by
1152
+ * param name. The CLI calls these with input only, no sdk. */
1153
+ resolvers?: Record<string, BoundResolver>;
1154
+ /** Bound output formatter (imports captured at materialization). */
1155
+ formatter?: BoundFormatter;
1156
+ }
1157
+ /** A materialized property: a static `value`, or a live `getValue` thunk that
1158
+ * re-derives the value per read (consumers install it as a getter on the surface
1159
+ * and on `imports`). Exactly one of `value` / `getValue` is set. */
1160
+ interface PropertyEntry {
1161
+ pluginType: "property";
1162
+ name: string;
1163
+ value?: any;
1164
+ getValue?: () => any;
1165
+ /** Carried from the descriptor for the registry / CLI / MCP / docs. */
1166
+ meta?: LeafMeta;
1167
+ /** Carried from the descriptor: templated registry members for this
1168
+ * property's dynamic sub-surface (folded into the registry by getRegistry). */
1169
+ dynamicMembers?: readonly NormalizedDynamicMember[];
1170
+ }
1171
+ /** A materialized aggregate: its resolved export bindings to child values
1172
+ * (a method's callable or a property's value). */
1173
+ interface AggregateEntry {
1174
+ pluginType: "aggregate";
1175
+ name: string;
1176
+ exports: Record<string, any>;
1177
+ }
1178
+ /** An entry in `context.plugins`. The `value`
1179
+ * of a method entry is its callable; of a property entry, its value. */
1180
+ type PluginEntry = MethodEntry | PropertyEntry | AggregateEntry;
1181
+ /**
1182
+ * The materialization substrate: every reachable plugin keyed by
1183
+ * id, plus the legacy-compat surface used during migration. The
1184
+ * compat fields let adapted function plugins read/write `context` exactly as
1185
+ * they do on the shipped stack: `meta` is the per-method registry source, `hooks`
1186
+ * the composed lifecycle hooks, and the index signature covers arbitrary legacy
1187
+ * fields a function plugin contributes (`api`, `options`, `manifest` helpers,
1188
+ * ...). A pure module-model SDK leaves `meta`/`hooks` empty and uses entry-level
1189
+ * metadata instead.
1190
+ */
1191
+ interface SdkContext {
1192
+ plugins: Record<string, PluginEntry>;
1193
+ meta: Record<string, PluginMeta>;
1194
+ hooks: MethodHooks;
1195
+ /** The SDK surface: each callable/value binding name mapped to the leaf plugin
1196
+ * id it resolves to. This is what the consumer actually calls (the root's
1197
+ * re-exports plus `addPlugin` additions), so the registry reports entries by
1198
+ * binding (with meta from the leaf) rather than dumping `plugins` by id. An
1199
+ * aliased re-export (`{ hi: greet }`) appears here as `hi -> "greet"`. */
1200
+ surface: Record<string, string>;
1201
+ /** Teardown callbacks recorded at materialization, in build order
1202
+ * (dependencies first); `disposeSdk` walks them in reverse. */
1203
+ disposers?: SdkDisposer[];
1204
+ /** The first `disposeSdk` call's settled result; later calls return it
1205
+ * (idempotent, first input wins). */
1206
+ disposed?: Promise<void>;
1207
+ [key: string]: any;
1208
+ }
1209
+ /** One leaf's recorded teardown: built at materialization (closing over the
1210
+ * leaf's imports + setup state), run by `disposeSdk`. */
1211
+ interface SdkDisposer {
1212
+ id: string;
1213
+ dispose: (input?: unknown) => void | Promise<void>;
1214
+ }
1215
+ /** The teardown callback a leaf declares beside `setup`, releasing what setup
1216
+ * acquired. `input` is whatever the caller passed to `disposeSdk` (untyped:
1217
+ * the framework does not bless a shape; each dispose narrows what it reads). */
1218
+ type DisposeFn = (bag: {
1219
+ imports: any;
1220
+ state: unknown;
1221
+ input?: unknown;
1222
+ }) => void | Promise<void>;
1223
+ /** The surfaced shape of one re-exported child: a method's callable or a
1224
+ * property's value. */
1225
+ type ExportSurface<TChild extends AnyLeafPlugin> = TChild extends MethodPlugin<any, infer TInput, infer TOutput, infer TPositional> ? SurfaceCall<TInput, TOutput, TPositional> : TChild extends PropertyPlugin<any, infer TValue> ? TValue : never;
1226
+ /**
1227
+ * The SDK surface a plugin contributes, derived from its descriptor: a
1228
+ * method's callable or a property's value under its name, or an aggregate's
1229
+ * export bindings. No `SdkInternals` — this is the plugin's own slice, not a
1230
+ * whole SDK. The inference replacement for a hand-written
1231
+ * `<Name>PluginProvides` interface:
1232
+ *
1233
+ * export type ListAppsPluginProvides = PluginSurface<typeof listAppsPlugin>;
1234
+ *
1235
+ * "Surface", not "Provides": `PluginProvides` is the legacy function-plugin
1236
+ * bag and `ProvidesOf` is the completeness ledger's phantom ids — both
1237
+ * different concepts.
1238
+ */
1239
+ type PluginSurface<P extends AnyPlugin> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPositional> ? {
1240
+ [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1241
+ } : P extends PropertyPlugin<infer TName, infer TValue> ? {
1242
+ [K in TName]: TValue;
1243
+ } : P extends AggregatePlugin<string, infer TExports> ? {
1244
+ [K in keyof TExports]: ExportSurface<TExports[K]>;
1245
+ } : never;
1246
+ /**
1247
+ * The framework-owned access an SDK carries beyond its string surface: the
1248
+ * legacy `context` string key (back-compat, narrows away later). The off-surface
1249
+ * `[CONTEXT]` symbol is attached at runtime (reach it via `getContext`) but kept
1250
+ * out of this type so it never leaks into a consumer's emitted declarations.
1251
+ */
1252
+ type SdkInternals = {
1253
+ context: SdkContext;
1254
+ };
1255
+ /**
1256
+ * The materialized SDK for a leaf root: the root's callable (method) or value
1257
+ * (property) under its name, plus framework access.
1258
+ */
1259
+ type Sdk$1<TName extends string, TInput, TOutput, TPositional extends readonly string[] = readonly []> = {
1260
+ [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1261
+ } & SdkInternals;
1262
+ /** The materialized SDK for a property root: the value under its name. */
1263
+ type PropertySdk<TName extends string, TValue> = {
1264
+ [K in TName]: TValue;
1265
+ } & SdkInternals;
1266
+ /**
1267
+ * The materialized SDK for an aggregate root: each export binding becomes a
1268
+ * surface entry, typed from the re-exported child (callable for a method,
1269
+ * value for a property).
1270
+ */
1271
+ type AggregateSdk<TExports extends Record<string, AnyLeafPlugin>> = {
1272
+ [K in keyof TExports]: ExportSurface<TExports[K]>;
1273
+ } & SdkInternals;
1274
+ /**
1275
+ * The surface a plugin adds to an SDK when passed to `addPlugin`: a method
1276
+ * under its name, a property's value, an aggregate's export bindings, or a
1277
+ * legacy function plugin's root provides (minus `context`).
1278
+ */
1279
+ type AddedSurface<P> = [P] extends [AnyPlugin] ? [
1280
+ PluginSurface<P>
1281
+ ] extends [never] ? Record<never, never> : PluginSurface<P> : P extends (sdk: any) => infer TProvides ? TProvides extends PluginProvides ? Omit<TProvides, "context"> : Record<never, never> : Record<never, never>;
1282
+ /** `T` when it is a specific string literal, else `never`. Used on a stand-in's
1283
+ * `name` so the id is always captured as a literal: a widened `string` (or the
1284
+ * stale `declareMethod<TInput, TOutput>(...)` call shape, where the contract
1285
+ * lands in the name slot) is rejected at the call rather than silently
1286
+ * weakening the requirements ledger. */
1287
+ type LiteralString<T extends string> = string extends T ? never : T;
1288
+ declare const REQUIRES: unique symbol;
1289
+ declare const PROVIDES: unique symbol;
1290
+ /** Phantom carriers for the requirements ledger; never present at runtime. */
1291
+ interface PluginSummary<TRequires extends string = never, TProvides extends string = never> {
1292
+ /** Declaration ids the plugin's subgraph still needs. @internal */
1293
+ readonly [REQUIRES]?: TRequires;
1294
+ /** Ids the plugin and its subgraph provide. @internal */
1295
+ readonly [PROVIDES]?: TProvides;
1296
+ }
1297
+ /** The declaration ids a plugin still needs (reads the phantom carrier). */
1298
+ type RequiresOf<P> = P extends {
1299
+ readonly [REQUIRES]?: infer R;
1300
+ } ? Extract<R, string> : never;
1301
+ /** The ids a plugin and its subgraph provide (reads the phantom carrier). */
1302
+ type ProvidesOf$1<P> = P extends {
1303
+ readonly [PROVIDES]?: infer R;
1304
+ } ? Extract<R, string> : never;
1305
+ /** Union the requires / provides across an inline imports or exports tuple. */
1306
+ type RequiresIn<T extends readonly unknown[]> = RequiresOf<T[number]>;
1307
+ type ProvidesIn<T extends readonly unknown[]> = ProvidesOf$1<T[number]>;
1308
+ /**
1309
+ * Reject an `imports` / `exports` value whose type widened to a non-tuple
1310
+ * `Plugin[]`: a literal tuple has a literal `length`, a widened array has
1311
+ * `length: number`. Identity in the good (tuple) case, so `T & StaticList<T>`
1312
+ * infers `T` unchanged; an error brand in the bad case, which the passed array
1313
+ * is not assignable to.
1314
+ */
1315
+ type StaticList<T extends readonly unknown[]> = number extends T["length"] ? {
1316
+ readonly __kitcoreError: "must be a fixed inline list of plugins, not a widened Plugin[]; declare them inline so the dependency graph stays statically known";
1317
+ } : T;
1318
+ /** A leaf provides its own name plus whatever its imports provide. */
1319
+ type LeafProvides<TName extends string, TImports extends readonly unknown[]> = TName | ProvidesIn<TImports>;
1320
+ /** A leaf requires its imports' requirements, minus what it provides. */
1321
+ type LeafRequires<TName extends string, TImports extends readonly unknown[]> = Exclude<RequiresIn<TImports>, LeafProvides<TName, TImports>>;
1322
+ /** An aggregate provides its own name plus its imports' and exports' provides. */
1323
+ type AggregateProvides<TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = TName | ProvidesIn<TImports> | ProvidesIn<TExports>;
1324
+ /** An aggregate requires its imports' and exports' requirements, minus provides. */
1325
+ type AggregateRequires<TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = Exclude<RequiresIn<TImports> | RequiresIn<TExports>, AggregateProvides<TName, TImports, TExports>>;
1326
+ /** A plugin's id as a type: `namespace/name`, or bare `name` when the namespace
1327
+ * is empty. The ledger keys on this (matching runtime id resolution), not the
1328
+ * bare name, so same-named plugins in different namespaces stay distinct. */
1329
+ type IdOf<TNamespace extends string, TName extends string> = TNamespace extends "" ? TName : `${TNamespace}/${TName}`;
1330
+ /** The binding name of an id: its last `/`-separated segment. The inverse view
1331
+ * of `IdOf`, used by `declare*` to derive the bare binding from a full id. */
1332
+ type LastSegment<TId extends string> = TId extends `${string}/${infer Rest}` ? LastSegment<Rest> : TId;
1333
+ /** The `PluginSummary` a leaf carries, keyed on its full id. */
1334
+ type LeafSummary<TNamespace extends string, TName extends string, TImports extends readonly unknown[]> = PluginSummary<LeafRequires<IdOf<TNamespace, TName>, TImports>, LeafProvides<IdOf<TNamespace, TName>, TImports>>;
1335
+ /** The `PluginSummary` an aggregate carries, keyed on its full id. */
1336
+ type AggregateSummary<TNamespace extends string, TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = PluginSummary<AggregateRequires<IdOf<TNamespace, TName>, TImports, TExports>, AggregateProvides<IdOf<TNamespace, TName>, TImports, TExports>>;
1337
+ /**
1338
+ * The runtime-input channel for `createSdk`. `configuration` maps plugin ids to
1339
+ * immutable values; each entry materializes as a static value property under
1340
+ * that id, satisfying a `declareProperty` / `declareOptionalProperty` stand-in exactly
1341
+ * as a registered provider would (DI value injection). Strict at build time:
1342
+ * an id must resolve to a property stand-in reachable from the root, so
1343
+ * unknown ids, non-property targets, and collisions with a registered real
1344
+ * provider all throw. kitcore keeps the map untyped; a head's factory is the
1345
+ * typed wrapper (`createMySdk(options)` passes
1346
+ * `{ configuration: { "my/config": options } }`).
1347
+ */
1348
+ interface CreateSdkOptions {
1349
+ configuration?: Record<string, unknown>;
1350
+ }
1351
+ /** Surfaced by `createSdk` when reachable declarations have no provider. */
1352
+ interface MissingDependencies<TIds extends string> {
1353
+ readonly __kitcoreError: "Missing concrete provider(s) for required declaration id(s)";
1354
+ readonly missing: TIds;
1355
+ }
1356
+ /**
1357
+ * `unknown` when every reachable declaration is provided, otherwise a
1358
+ * `MissingDependencies` brand. `createSdk` takes `root: P & CompletenessOf<P>`,
1359
+ * so a complete root infers `P` unchanged (intersect `unknown`) while an
1360
+ * incomplete one fails to assign (the argument lacks `missing`).
1361
+ */
1362
+ type CompletenessOf<P> = [
1363
+ Exclude<RequiresOf<P>, ProvidesOf$1<P>>
1364
+ ] extends [never] ? unknown : MissingDependencies<Exclude<RequiresOf<P>, ProvidesOf$1<P>>>;
1365
+ /** Recover the materialized SDK type for a checked root (the summary that
1366
+ * rides on the `define*` return is transparent to these). */
1367
+ type MethodSdkOf<P> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPos> ? Sdk$1<TName, TInput, TOutput, TPos> : never;
1368
+ type PropertySdkOf<P> = P extends PropertyPlugin<infer TName, infer TValue> ? PropertySdk<TName, TValue> : never;
1369
+ type AggregateSdkOf<P> = P extends AggregatePlugin<string, infer TExports> ? AggregateSdk<TExports> : never;
1370
+
1371
+ /**
1372
+ * Declaration for a registry category (a bucket grouping related functions).
1373
+ * Plugins reference categories in their `meta.categories` field, as either a
1374
+ * bare key (auto-derive title and plural) or this object (override either).
1375
+ *
1376
+ * Examples (with auto-derive rules):
1377
+ * - `{ key: "app" }` → title "App", plural "Apps"
1378
+ * - `{ key: "client-credentials" }` → title "Client Credentials", plural "Client Credentials"
1379
+ * - `{ key: "utility" }` → title "Utility", plural "Utilities"
1380
+ * - `{ key: "http", title: "HTTP Request" }` → plural "HTTP Requests"
1381
+ */
1382
+ interface CategoryDefinition {
1383
+ key: string;
1384
+ /** Display title for the category. Auto-derived from `key` if omitted. */
1385
+ title?: string;
1386
+ /** Plural form of `title`. Auto-derived from the resolved title if omitted. */
1387
+ titlePlural?: string;
1388
+ }
1389
+ interface FunctionRegistryEntry<TSdk = any> {
1390
+ name: string;
1391
+ /**
1392
+ * Human-readable description of the function. Surfaced wherever the
1393
+ * registry is consumed (command help, tool/RPC descriptions, generated
1394
+ * documentation). Prefer providing this directly rather than relying
1395
+ * solely on inputSchema.describe().
1396
+ */
1397
+ description?: string;
1398
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
1399
+ itemType?: string;
1400
+ returnType?: string;
1401
+ inputSchema?: z.ZodSchema;
1402
+ inputParameters?: Array<{
1403
+ name: string;
1404
+ schema: z.ZodSchema;
1405
+ }>;
1406
+ outputSchema?: z.ZodSchema;
1407
+ /**
1408
+ * Ordered input keys the public surface projects onto positional arguments
1409
+ * (the method's `positional` declaration). Absent when the method takes only
1410
+ * the canonical single bag. Lifted off the materialized method entry by the
1411
+ * surface builder, like `boundResolvers` — a runtime projection, not
1412
+ * descriptive meta.
1413
+ */
1414
+ positional?: readonly string[];
1415
+ categories: string[];
1416
+ resolvers?: Record<string, ResolverMetadata<TSdk, any, any>>;
1417
+ /**
1418
+ * Per-parameter bound resolvers from the new model (imports already captured,
1419
+ * called with `input` only, no sdk). Parallel to the legacy `resolvers` field
1420
+ * and `formatter`: the surface builder lifts these off the materialized method
1421
+ * entry. Additive bridge — populated for migrated `defineMethod` plugins; the
1422
+ * legacy `resolvers` field above stays the source for unmigrated ones.
1423
+ */
1424
+ boundResolvers?: Record<string, BoundResolver>;
1425
+ packages?: string[];
1426
+ /**
1427
+ * True if the plugin is registered only in the experimental SDK
1428
+ * factory. See `PluginMeta.experimental`.
1429
+ */
1430
+ experimental?: boolean;
1431
+ /** Confirmation prompt type - prompts user before executing */
1432
+ confirm?: "create-secret" | "delete";
1433
+ /**
1434
+ * Optional deprecation metadata for commands.
1435
+ */
1436
+ deprecation?: FunctionDeprecation;
1437
+ /**
1438
+ * Short aliases for parameter names (e.g., { request: "X", header: "H" }).
1439
+ * Consumers that render the function as a flag-style command surface use
1440
+ * these as short forms.
1441
+ */
1442
+ aliases?: Record<string, string>;
1443
+ /**
1444
+ * Output formatter, normalized to the bound runtime shape (its imports/sdk
1445
+ * already captured), so consumers call `getContext`/`format` with no sdk.
1446
+ * The surface builder produces this from the method entry — `entry.formatter`
1447
+ * for a migrated plugin, or the legacy `meta.formatter` adapted — so vintage
1448
+ * is invisible here.
1449
+ */
1450
+ formatter?: BoundFormatter;
1451
+ /** Defaults to true. Set to false to suppress --json (e.g. login/logout/init). */
1452
+ supportsJsonOutput: boolean;
1453
+ }
1454
+ interface FunctionDeprecation {
1455
+ /** User-facing deprecation message for why/how to migrate */
1456
+ message: string;
1457
+ }
1458
+ interface RegistryResult<TSdk = any> {
1459
+ functions: FunctionRegistryEntry<TSdk>[];
1460
+ categories: {
1461
+ key: string;
1462
+ title: string;
1463
+ titlePlural: string;
1464
+ functions: string[];
1465
+ }[];
1466
+ }
1467
+
1468
+ /**
1469
+ * ------------------------------
1470
+ * Plugin Type System
1471
+ * ------------------------------
1472
+ *
1473
+ * Plugins receive the sdk as a positional parameter. sdk.context holds shared
1474
+ * internal state (api client, event emission, meta, options, etc.). SDK methods
1475
+ * live at the root, context nests under .context.
1476
+ *
1477
+ * A plugin is (sdk) => partialSdk. `createPluginStack()` accumulates plugins
1478
+ * and materializes a built `Sdk` via `.toSdk()`; `addPlugin(sdk, plugin)`
1479
+ * extends an already-built SDK in place with one more plugin.
1480
+ */
1481
+
1482
+ interface PluginProvides extends Record<string, any> {
1483
+ context?: {
1484
+ meta?: Record<string, PluginMeta<any>>;
1485
+ hooks?: MethodHooks;
1486
+ [key: string]: any;
1487
+ };
1488
+ }
1489
+ interface PluginMeta<TSdk = unknown> {
1490
+ /**
1491
+ * Human-readable description of the plugin function. Used by the CLI (help text),
1492
+ * MCP (tool description), and README generators. When omitted, falls back to
1493
+ * the inputSchema's `.describe()` value or a generic placeholder.
1494
+ */
1495
+ description?: string;
1496
+ /**
1497
+ * Buckets this function belongs to in `getRegistry()` output. Each entry is
1498
+ * either a bare key (`"app"`) for auto-derived titles or a {@link CategoryDefinition}
1499
+ * object to override the title or plural. Only one plugin needs to supply
1500
+ * the object form per category key; object refs win over string refs, so
1501
+ * other plugins in the same bucket can stay on bare strings.
1502
+ */
1503
+ categories?: (string | CategoryDefinition)[];
1504
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
1505
+ itemType?: string;
1506
+ returnType?: string;
1507
+ inputSchema?: z.ZodSchema;
1508
+ outputSchema?: z.ZodSchema;
1509
+ /**
1510
+ * Item formatter that the registry hands to the CLI/MCP renderer. The
1511
+ * `sdk` param on `fetch` is typed to the plugin's own declared SDK
1512
+ * surface (`TRequires & TProvides`); reaching into another plugin's
1513
+ * method requires adding it to `TRequires` explicitly.
1514
+ */
1515
+ formatter?: OutputFormatter<TSdk, any, any, any>;
1516
+ /**
1517
+ * Per-parameter resolver metadata. Same `TSdk` surfaces in each
1518
+ * resolver's `fetch`/`tryResolveWithoutPrompt` callbacks.
1519
+ */
1520
+ resolvers?: Record<string, ResolverMetadata<TSdk, any, any>>;
1521
+ /** Confirmation prompt type - prompts user before executing */
1522
+ confirm?: "create-secret" | "delete";
1523
+ /**
1524
+ * Marks this plugin as experimental — wrappers can keep it out of
1525
+ * their stable build (typically by gating it behind an
1526
+ * `experimental` subpath import) and the registry can badge it in
1527
+ * generated docs / CLI help. No runtime capability check.
1528
+ */
1529
+ experimental?: boolean;
1530
+ [key: string]: any;
1531
+ }
1532
+ /**
1533
+ * Plugin interface — 2 type params:
1534
+ *
1535
+ * TSdk = what this plugin needs (the SDK shape including context)
1536
+ * TProvides = what this plugin returns (a partial SDK shape)
1537
+ *
1538
+ * The sdk param always includes context.meta, even if TSdk doesn't declare it.
1539
+ */
1540
+ interface Plugin<TSdk = {}, TProvides extends PluginProvides = PluginProvides> {
1541
+ (sdk: TSdk & {
1542
+ context: {
1543
+ meta: Record<string, PluginMeta<any>>;
1544
+ hooks: MethodHooks;
1545
+ };
1546
+ }): TProvides;
1547
+ }
1548
+ /**
1549
+ * A built SDK. Carries the plugins' contributions plus the
1550
+ * `getRegistry` accessor over `context.meta`. No `addPlugin` method
1551
+ * on the shape: extension after build goes through the top-level
1552
+ * `addPlugin(sdk, plugin)` function, which mutates the sdk in place
1553
+ * and narrows the caller's binding via TypeScript's assertion
1554
+ * functions.
1555
+ */
1556
+ type Sdk<T = {
1557
+ context: {
1558
+ meta: Record<string, PluginMeta<any>>;
1559
+ hooks: MethodHooks;
1560
+ };
1561
+ }> = T & {
1562
+ getRegistry(options?: {
1563
+ package?: string;
1564
+ }): RegistryResult<T>;
1565
+ };
1566
+
1567
+ /**
1568
+ * ------------------------------
1569
+ * Plugin authoring helpers
1570
+ * ------------------------------
1571
+ *
1572
+ * - `createPluginMethod` / `createPaginatedPluginMethod`: per-method
1573
+ * primitives that sit inside a `definePlugin` callback and build the
1574
+ *
1575
+ * { [name]: wrappedFn, context: { meta: { [name]: meta } } }
1576
+ *
1577
+ * fragment a plugin returns for a single method, wiring up
1578
+ * `createFunction` / `createPaginatedFunction`, the method-call hooks,
1579
+ * and the doubled `name` (function key + meta key) in one place.
1580
+ *
1581
+ * Two method helpers (rather than one with a `paginated: true` discriminant)
1582
+ * because the handler signature changes shape across pagination, and
1583
+ * discriminated unions on optional booleans produce noisy TS errors.
1584
+ *
1585
+ * @deprecated The module model replaces this exit; it logs a runtime
1586
+ * deprecation and will be removed in a release after this warning ships.
1587
+ */
1588
+
1589
+ /**
1590
+ * Method-level meta fields. Mirrors `PluginMeta` minus `inputSchema`, which is
1591
+ * passed at the top level alongside the handler and merged into the meta by
1592
+ * the helpers themselves.
1593
+ *
1594
+ * @deprecated The module model replaces this exit; it logs a runtime
1595
+ * deprecation and will be removed in a release after this warning ships.
1596
+ */
1597
+ type MethodMeta<TSdk> = Omit<PluginMeta<TSdk>, "inputSchema">;
1598
+ /**
1599
+ * The plugin's own method signature, synthesized from the method config.
1600
+ * Mixed into the resolver-side SDK so a resolver may freely reference the
1601
+ * host plugin's own method (e.g. `appKeyResolver` calling `sdk.getApp`)
1602
+ * without forcing the plugin to declare a circular dependency on itself.
1603
+ *
1604
+ * Uses `any` for options and return: we only need to assert the method
1605
+ * exists on `sdk`, not pin its full signature. Using `TInput`/`TResult`
1606
+ * here would create a circular inference (TSdk depends on TInput/TResult
1607
+ * via the resolvers slot, TInput/TResult are inferred from the handler
1608
+ * which depends on TSdk), and TS resolves the cycle by widening to
1609
+ * `unknown`. With `any`, the resolver check still verifies the method's
1610
+ * presence on the SDK; signature precision for self is the plugin
1611
+ * author's responsibility.
1612
+ *
1613
+ * Not mixed into the handler's `sdk`: handlers run against the SDK that
1614
+ * existed when the plugin was added to the stack (closure-captured), so
1615
+ * self-method access there would be a lie at runtime.
1616
+ *
1617
+ * @deprecated The module model replaces this exit; it logs a runtime
1618
+ * deprecation and will be removed in a release after this warning ships.
1619
+ */
1620
+ type SelfMethod<TName extends string> = {
1621
+ [K in TName]: (options?: any) => any;
1622
+ };
1623
+ interface PluginMethodConfig<TSdk, TInput, TResult, TName extends string, TResolvers> extends Omit<MethodMeta<TSdk>, "resolvers"> {
1624
+ name: TName;
1625
+ /**
1626
+ * Schema for runtime input validation; drives the handler's `options`
1627
+ * type. For plugins that accept deprecated parameter aliases this is a
1628
+ * `z.union([CanonicalSchema, DeprecatedSchema])` — the registry
1629
+ * unwraps unions and exposes only the first variant (canonical) to
1630
+ * documentation and downstream consumer surfaces.
1631
+ *
1632
+ * @deprecated The module model replaces this exit; it logs a runtime
1633
+ * deprecation and will be removed in a release after this warning ships.
1634
+ */
1635
+ inputSchema?: z.ZodSchema<TInput>;
1636
+ handler: (args: {
1637
+ sdk: TSdk;
1638
+ options: TInput;
1639
+ }) => Promise<TResult>;
1640
+ /**
1641
+ * Per-parameter resolvers. Each entry's `TSdk` requirement is checked
1642
+ * against the plugin's own `TSdk` (plus the plugin's own method via
1643
+ * {@link SelfMethod}) using {@link ValidResolvers}; mismatches surface
1644
+ * at the offending key. `NoInfer` pins `TSdk` to the `sdk` argument so
1645
+ * resolver entries don't widen the inferred `TSdk`.
1646
+ *
1647
+ * @deprecated The module model replaces this exit; it logs a runtime
1648
+ * deprecation and will be removed in a release after this warning ships.
1649
+ */
1650
+ resolvers?: ValidResolvers<NoInfer<TSdk & SelfMethod<TName>>, TResolvers> & TResolvers;
1651
+ }
1652
+ type PluginMethodReturn<TName extends string, TInput, TResult> = {
1653
+ [K in TName]: (options?: TInput) => Promise<TResult>;
1654
+ } & {
1655
+ context: {
1656
+ meta: {
1657
+ [K in TName]: PluginMeta;
1658
+ };
1659
+ };
1660
+ };
1661
+ /**
1662
+ * Build the method fragment for a non-paginated SDK method. Used inside a
1663
+ * `definePlugin(...)` callback:
1664
+ *
1665
+ * export const getProfilePlugin = definePlugin(
1666
+ * (sdk: ApiPluginProvides & EventEmissionProvides) =>
1667
+ * createPluginMethod(sdk, {
1668
+ * name: "getProfile",
1669
+ * categories: ["account"],
1670
+ * inputSchema: GetProfileSchema,
1671
+ * handler: async ({ sdk }) => { ... },
1672
+ * }),
1673
+ * );
1674
+ *
1675
+ * @deprecated The module model replaces this exit; it logs a runtime
1676
+ * deprecation and will be removed in a release after this warning ships.
1677
+ */
1678
+ declare function createPluginMethod<const TName extends string, TSdk extends {
1679
+ context: unknown;
1680
+ }, TInput, TResult, const TResolvers extends Record<string, ResolverMetadata<any, any, any>> = {}>(sdk: TSdk, config: PluginMethodConfig<TSdk, TInput, TResult, TName, TResolvers>): PluginMethodReturn<TName, TInput, TResult>;
1681
+ interface PaginatedPluginMethodConfigBase<TSdk, TInput, TName extends string, TResolvers> extends Omit<MethodMeta<TSdk>, "resolvers"> {
1682
+ name: TName;
1683
+ /** Same semantics as `createPluginMethod`'s `inputSchema`. */
1684
+ inputSchema?: z.ZodSchema<TInput>;
1685
+ /**
1686
+ * Optional default page size when the caller doesn't pass one. Mirrors
1687
+ * `createPaginatedFunction`'s `defaultPageSize` arg.
1688
+ */
1689
+ defaultPageSize?: number;
1690
+ /** See {@link PluginMethodConfig.resolvers}. */
1691
+ resolvers?: ValidResolvers<NoInfer<TSdk & SelfMethod<TName>>, TResolvers> & TResolvers;
1692
+ }
1693
+ /**
1694
+ * A page whose *only* own keys are `data` / `nextCursor`. Used to constrain
1695
+ * the Standard overload: a raw envelope with extra keys (a JSON:API
1696
+ * `links`/`meta`, a top-level `next`, etc.) is NOT a `StrictPage`, so it falls
1697
+ * through to the Adapted overload and `adaptPage` becomes required. Each excess
1698
+ * key is mapped to `?: never`, which a real value (e.g. `links: {...}`) can't
1699
+ * satisfy — that's what a plain `SdkPage` assignability check (which allows
1700
+ * excess keys structurally) misses.
1701
+ */
1702
+ type StrictPage<TResponse> = SdkPage<unknown> & {
1703
+ [K in Exclude<keyof TResponse, keyof SdkPage<unknown>>]?: never;
1704
+ };
1705
+ /**
1706
+ * Config for a paginated method whose handler already returns a clean page
1707
+ * (`{ data, nextCursor? }` and nothing else — see `StrictPage`, enforced on
1708
+ * the overload). No `adaptPage` needed; `TItem` is sourced from the handler's
1709
+ * `data`. Interface extension keeps this a single flattened object type (not
1710
+ * an intersection), preserving clean inference of the `resolvers` /
1711
+ * `TResolvers` slot.
1712
+ */
1713
+ interface PaginatedPluginMethodConfigStandard<TSdk, TInput, TResponse, TName extends string, TResolvers> extends PaginatedPluginMethodConfigBase<TSdk, TInput, TName, TResolvers> {
1714
+ handler: (args: {
1715
+ sdk: TSdk;
1716
+ options: TInput & {
1717
+ cursor?: string;
1718
+ pageSize?: number;
1719
+ };
1720
+ }) => Promise<TResponse>;
1721
+ /** No adapter: the handler already returns a page. */
1722
+ adaptPage?: undefined;
1723
+ }
1724
+ /**
1725
+ * Config for a paginated method whose handler returns a raw upstream shape
1726
+ * (`TResponse`, e.g. a JSON:API `links.next` envelope). `adaptPage` is required
1727
+ * to translate it into a page. `TItem` is sourced from `TResponse` (`ItemOf`),
1728
+ * not the adapter — the adapter is item-agnostic (relocates the cursor; items
1729
+ * are finalized in the handler's `data`), hence `NoInfer`, so a generic adapter
1730
+ * (e.g. `<T>(r) => SdkPage<T>`) doesn't collapse `TItem` to `unknown`.
1731
+ */
1732
+ interface PaginatedPluginMethodConfigAdapted<TSdk, TInput, TResponse, TItem, TName extends string, TResolvers> extends PaginatedPluginMethodConfigBase<TSdk, TInput, TName, TResolvers> {
1733
+ handler: (args: {
1734
+ sdk: TSdk;
1735
+ options: TInput & {
1736
+ cursor?: string;
1737
+ pageSize?: number;
1738
+ };
1739
+ }) => Promise<TResponse>;
1740
+ adaptPage: (response: TResponse) => SdkPage<NoInfer<TItem>>;
1741
+ }
1742
+ type ItemOf<TResponse> = TResponse extends SdkPage<infer TItem> ? TItem : TResponse extends {
1743
+ data: readonly (infer TItem)[];
1744
+ } ? TItem : never;
1745
+ type PaginatedPluginMethodReturn<TName extends string, TInput, TItem> = {
1746
+ [K in TName]: (options?: TInput & {
1747
+ cursor?: string;
1748
+ pageSize?: number;
1749
+ maxItems?: number;
1750
+ }) => PaginatedSdkResult<TItem>;
1751
+ } & {
1752
+ context: {
1753
+ meta: {
1754
+ [K in TName]: PluginMeta;
1755
+ };
1756
+ };
1757
+ };
1758
+ /**
1759
+ * Paginated variant of `createPluginMethod`. Two overloads enforce the
1760
+ * response contract at compile time:
1761
+ *
1762
+ * - **Standard** — the handler returns a strict `SdkPage<TItem>`
1763
+ * (`{ data, nextCursor? }` and nothing else); no `adaptPage`.
1764
+ * - **Adapted** — the handler returns a raw upstream shape and `adaptPage` is
1765
+ * *required* to translate it.
1766
+ *
1767
+ * A handler that returns neither a page-like shape nor pairs a raw shape with
1768
+ * `adaptPage` matches no overload and is a compile error.
1769
+ *
1770
+ * createPaginatedPluginMethod(sdk, {
1771
+ * name: "listThings",
1772
+ * inputSchema: ListThingsSchema,
1773
+ * adaptPage: (res) => ({ data: res.items, nextCursor: res.next }),
1774
+ * handler: ({ sdk, options }) => sdk.context.api.get("/things", { ... }),
1775
+ * });
1776
+ *
1777
+ * @deprecated The module model replaces this exit; it logs a runtime
1778
+ * deprecation and will be removed in a release after this warning ships.
1779
+ */
1780
+ declare function createPaginatedPluginMethod<const TName extends string, TSdk extends {
1781
+ context: unknown;
1782
+ }, TInput, TResponse extends StrictPage<TResponse>, TItem = ItemOf<TResponse>, const TResolvers extends Record<string, ResolverMetadata<any, any, any>> = {}>(sdk: TSdk, config: PaginatedPluginMethodConfigStandard<TSdk, TInput, TResponse, TName, TResolvers>): PaginatedPluginMethodReturn<TName, TInput, TItem>;
1783
+ declare function createPaginatedPluginMethod<const TName extends string, TSdk extends {
1784
+ context: unknown;
1785
+ }, TInput, TResponse, TItem = ItemOf<TResponse>, const TResolvers extends Record<string, ResolverMetadata<any, any, any>> = {}>(sdk: TSdk, config: PaginatedPluginMethodConfigAdapted<TSdk, TInput, TResponse, TItem, TName, TResolvers>): PaginatedPluginMethodReturn<TName, TInput, TItem>;
1786
+ /**
1787
+ * Maps a tuple of plugins to a tuple of their TSdk requirement types.
1788
+ *
1789
+ * SdkRequirementsOf<[Plugin<{ api }, _>, Plugin<{ options }, _>]>
1790
+ * = [{ api }, { options }]
1791
+ */
1792
+ type SdkRequirementsOf<T extends readonly Plugin<any, any>[]> = {
1793
+ [K in keyof T]: T[K] extends Plugin<infer Sdk, any> ? Sdk : never;
1794
+ };
1795
+ /**
1796
+ * Maps a tuple of plugins to a tuple of their TProvides output types.
1797
+ *
1798
+ * ProvidesOf<[Plugin<_, { hello }>, Plugin<_, { goodbye }>]>
1799
+ * = [{ hello }, { goodbye }]
1800
+ */
1801
+ type ProvidesOf<T extends readonly Plugin<any, any>[]> = {
1802
+ [K in keyof T]: T[K] extends Plugin<any, infer Provides> ? Provides : never;
1803
+ };
1804
+ /**
1805
+ * Intersects every member of a tuple into a single combined type. The
1806
+ * result is an object that has every property of every member at once.
1807
+ *
1808
+ * IntersectAll<[{ api }, { options }]> = { api } & { options }
1809
+ * IntersectAll<[]> = {}
1810
+ *
1811
+ * Walks recursively: head & IntersectAll<tail>, base case is the empty
1812
+ * tuple. Why intersection (`&`) and not union (`|`): the composed plugin
1813
+ * must require ALL of the sub-plugins' needs at once — an SDK that has
1814
+ * both `api` AND `options` — not "either api or options."
1815
+ */
1816
+ type IntersectAll<T extends readonly unknown[]> = T extends readonly [
1817
+ infer Head,
1818
+ ...infer Tail
1819
+ ] ? Head & IntersectAll<Tail> : {};
1820
+ /**
1821
+ * The TSdk a composed plugin requires: every sub-plugin's TSdk requirement,
1822
+ * all at once. Composing a plugin that needs `{ api }` with one that needs
1823
+ * `{ options }` yields a composed plugin that needs `{ api } & { options }`.
1824
+ */
1825
+ type ComposeSdk<T extends readonly Plugin<any, any>[]> = IntersectAll<SdkRequirementsOf<T>>;
1826
+ /**
1827
+ * What a composed plugin provides: every sub-plugin's TProvides combined.
1828
+ * Composing a plugin that provides `{ hello }` with one that provides
1829
+ * `{ goodbye }` yields `{ hello } & { goodbye }`.
1830
+ */
1831
+ type ComposeProvides<T extends readonly Plugin<any, any>[]> = IntersectAll<ProvidesOf<T>>;
1832
+ /**
1833
+ * @deprecated Use {@link createPluginStack} instead. It carries the same
1834
+ * collision-detection and hook-composition behavior and supports
1835
+ * per-step `{ override: true }` for intentional duplicates. Migration
1836
+ * (note the stack emits a definition, not a bare function):
1837
+ *
1838
+ * composePlugins(a, b, c)
1839
+ * // →
1840
+ * createPluginStack().use(a).use(b).use(c).toPlugin({ name: "bundle" })
1841
+ *
1842
+ * Bundles N plugins into a single plugin so a consumer can call
1843
+ * `.use(combined)` once on a stack. Bag mode: sub-plugins must not
1844
+ * depend on each other; TSdk on sub-plugins is the intersection of
1845
+ * every sub-plugin's requirements (so the type system never exposes
1846
+ * one sub-plugin's contributions to another).
1847
+ */
1848
+ declare function composePlugins<const Ts extends readonly Plugin<any, any>[]>(...plugins: Ts): Plugin<ComposeSdk<Ts>, ComposeProvides<Ts>>;
1849
+ /**
1850
+ * A typed builder that accumulates plugins into an immutable linked list.
1851
+ * Each `.use` returns a new stack instance (cons-style); the original
1852
+ * stack stays usable for branching. Call `toPlugin()` to collapse the
1853
+ * accumulated chain into a single `Plugin<TRequires, TProvides>`.
1854
+ *
1855
+ * Type params: `TRequires` is the external surface declared on
1856
+ * `createPluginStack<TRequires>()` (what the outer sdk will provide);
1857
+ * `TProvides` accumulates every registration's provides.
1858
+ */
1859
+ interface PluginStack<TRequires, TProvides extends PluginProvides> {
1860
+ /**
1861
+ * Register a bare plugin function. Its required surface is constrained
1862
+ * to `TRequires & TProvides` (the external requirements plus everything
1863
+ * provided by earlier `.use` calls), so registration order is enforced
1864
+ * per step: a plugin that reads a dependency at construction can only be
1865
+ * registered after a plugin that provides it. This stack collapses to a
1866
+ * single function plugin and runs its entries in registration order, so
1867
+ * the type-level order matches the runtime order.
1868
+ *
1869
+ * `{ override: true }` lets a registration replace an earlier root/meta
1870
+ * key it would otherwise collide with.
1871
+ */
1872
+ use<TNewProvides extends PluginProvides>(plugin: Plugin<TRequires & TProvides, TNewProvides>, options?: {
1873
+ override?: boolean;
1874
+ }): PluginStack<TRequires, TProvides & TNewProvides>;
1875
+ /**
1876
+ * Collapse the accumulated registrations into a single bare function
1877
+ * plugin. Its TSdk is `TRequires` (the declared external surface);
1878
+ * in-stack inter-plugin dependencies are resolved when its setup runs.
1879
+ * A head lifts it into the module model with `fromFunctionPlugin`.
1880
+ */
1881
+ toPlugin(): Plugin<TRequires, TProvides>;
1882
+ /**
1883
+ * Build the stack into a sealed, ready-to-use SDK. Eagerly applies the
1884
+ * resolved order: each plugin runs once during `toSdk`, contributions
1885
+ * merge into a single accumulator, and the result is wrapped as an
1886
+ * `Sdk<TRequires & TProvides>`. The returned SDK has `context` and
1887
+ * `getRegistry`, but no plugin-registration method.
1888
+ * To extend a built SDK, use the top-level {@link addPlugin}.
1889
+ */
1890
+ toSdk(): Sdk<TRequires & TProvides>;
1891
+ }
1892
+ /**
1893
+ * Create an empty plugin stack. Pass a type parameter to declare external
1894
+ * SDK requirements that every plugin in the stack can rely on:
1895
+ *
1896
+ * const tablesPlugin = createPluginStack<FetchPluginProvides>()
1897
+ * .use(apiPlugin)
1898
+ * .use(listTablesPlugin)
1899
+ * .use(getTablePlugin)
1900
+ * .toPlugin({ name: "tables" });
1901
+ *
1902
+ * const sdk = createPluginStack()
1903
+ * .use(fetchPlugin) // provides FetchPluginProvides
1904
+ * .use(tablesPlugin) // PluginDefinition<FetchPluginProvides, ...>
1905
+ * .toSdk();
1906
+ *
1907
+ * The stack itself is immutable: calling `.use` returns a new stack
1908
+ * without mutating the original, so you can branch off a base stack for
1909
+ * different consumers. Until the stack materializes, no plugin functions
1910
+ * run.
1911
+ */
1912
+ /**
1913
+ * @deprecated The module model replaces this exit; it logs a runtime
1914
+ * deprecation and will be removed in a release after this warning ships.
1915
+ */
1916
+ declare function createPluginStack<TRequires = object>(): PluginStack<TRequires, {
1917
+ context: {
1918
+ meta: Record<string, PluginMeta>;
1919
+ hooks: MethodHooks;
1920
+ };
1921
+ }>;
1922
+
1923
+ /**
1924
+ * Define a method leaf. The plugin IS the function; `createSdk` (or a
1925
+ * dependent's `imports`) binds it under its bare `name`. `imports` is typed
1926
+ * from the declared `imports` array. `namespace` sets the plugin's id
1927
+ * (`namespace/name`).
1928
+ *
1929
+ * The `output` mode shapes `run`'s result into the public surface and drives
1930
+ * the overload that types the call: raw (default, passthrough), `item`
1931
+ * (`run` returns `T`, surfaced as `Promise<{ data: T }>`), or `list` (`run`
1932
+ * returns one `SdkPage`, surfaced as `PaginatedSdkResult`). See Output.
1933
+ */
1934
+ declare function defineMethod<const TName extends string, TInput, TOutput, const TPositional extends readonly (keyof TInput & string)[] = readonly [], const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1935
+ name: TName;
1936
+ namespace?: TNamespace;
1937
+ imports?: TImports & StaticList<TImports>;
1938
+ /** Validates `input` and drives its type: when given, `input` is the schema's
1939
+ * output and no `run` annotation is needed. */
1940
+ inputSchema?: z.ZodType<TInput>;
1941
+ /** Skip the runtime parse of `input`; `run` gets it untouched (the schema
1942
+ * stays for projection). For raw methods that validate their own input, like
1943
+ * `fetch`. See {@link MethodPlugin.skipInputValidation}. */
1944
+ skipInputValidation?: boolean;
1945
+ resolvers?: Record<string, Resolver>;
1946
+ formatter?: Formatter;
1947
+ output?: "raw" | {
1948
+ type: "raw";
1949
+ };
1950
+ positional?: TPositional;
1951
+ setup?: (bag: {
1952
+ imports: ImportsOf<TImports>;
1953
+ }) => TState;
1954
+ dispose?: (bag: {
1955
+ imports: ImportsOf<TImports>;
1956
+ state: TState;
1957
+ input?: unknown;
1958
+ }) => void | Promise<void>;
1959
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput, TState>) => TOutput;
1960
+ } & LeafMetaFields): MethodPlugin<TName, TInput, TOutput, TPositional> & LeafSummary<TNamespace, TName, TImports>;
1961
+ declare function defineMethod<const TName extends string, TInput, TData, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1962
+ name: TName;
1963
+ namespace?: TNamespace;
1964
+ imports?: TImports & StaticList<TImports>;
1965
+ inputSchema?: z.ZodType<TInput>;
1966
+ resolvers?: Record<string, Resolver>;
1967
+ formatter?: Formatter;
1968
+ output: "item" | {
1969
+ type: "item";
1970
+ };
1971
+ setup?: (bag: {
1972
+ imports: ImportsOf<TImports>;
1973
+ }) => TState;
1974
+ dispose?: (bag: {
1975
+ imports: ImportsOf<TImports>;
1976
+ state: TState;
1977
+ input?: unknown;
1978
+ }) => void | Promise<void>;
1979
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput, TState>) => TData;
1980
+ } & LeafMetaFields): MethodPlugin<TName, TInput, Promise<{
1981
+ data: Awaited<TData>;
1982
+ }>> & LeafSummary<TNamespace, TName, TImports>;
1983
+ declare function defineMethod<const TName extends string, TInput, TResponse extends StrictPage$1<TResponse>, TItem = ItemOf$1<TResponse>, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
1984
+ name: TName;
1985
+ namespace?: TNamespace;
1986
+ imports?: TImports & StaticList<TImports>;
1987
+ inputSchema?: z.ZodType<TInput>;
1988
+ resolvers?: Record<string, Resolver>;
1989
+ formatter?: Formatter;
1990
+ output: "list" | {
1991
+ type: "list";
1992
+ adaptPage?: undefined;
1993
+ defaultPageSize?: number;
1994
+ };
1995
+ setup?: (bag: {
1996
+ imports: ImportsOf<TImports>;
1997
+ }) => TState;
1998
+ dispose?: (bag: {
1999
+ imports: ImportsOf<TImports>;
2000
+ state: TState;
2001
+ input?: unknown;
2002
+ }) => void | Promise<void>;
2003
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput & PageFetchInput, TState>) => TResponse | Promise<TResponse>;
2004
+ } & LeafMetaFields): MethodPlugin<TName, TInput & PaginatedCallInput, PaginatedSdkResult<TItem>> & LeafSummary<TNamespace, TName, TImports>;
2005
+ declare function defineMethod<const TName extends string, TInput, TResponse, TItem, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
2006
+ name: TName;
2007
+ namespace?: TNamespace;
2008
+ imports?: TImports & StaticList<TImports>;
2009
+ inputSchema?: z.ZodType<TInput>;
2010
+ resolvers?: Record<string, Resolver>;
2011
+ formatter?: Formatter;
2012
+ output: {
2013
+ type: "list";
2014
+ adaptPage: (response: TResponse) => SdkPage<TItem>;
2015
+ defaultPageSize?: number;
2016
+ };
2017
+ setup?: (bag: {
2018
+ imports: ImportsOf<TImports>;
2019
+ }) => TState;
2020
+ dispose?: (bag: {
2021
+ imports: ImportsOf<TImports>;
2022
+ state: TState;
2023
+ input?: unknown;
2024
+ }) => void | Promise<void>;
2025
+ run: (bag: MethodRunBag<ImportsOf<TImports>, TInput & PageFetchInput, TState>) => TResponse | Promise<TResponse>;
2026
+ } & LeafMetaFields): MethodPlugin<TName, TInput & PaginatedCallInput, PaginatedSdkResult<TItem>> & LeafSummary<TNamespace, TName, TImports>;
2027
+ /**
2028
+ * Define a method override: a meta-only patch over an already-defined method.
2029
+ * Give it the `target` method's id (its bare name if namespace-less) and any of
2030
+ * the public {@link LeafMetaFields} (`deprecation`, `packages`, `description`,
2031
+ * `categories`, `confirm`, ...); after the SDK materializes, those fields merge
2032
+ * onto the target method's entry so the registry / CLI / MCP / docs project the
2033
+ * patched values. The target's `run` and resolvers are untouched.
2034
+ *
2035
+ * Use it for surface-specific tweaks a base method should not carry (e.g. a CLI
2036
+ * that deprecates `fetch` while the SDK does not). It fails loud at build if the
2037
+ * target does not resolve to a method. Include the override in an aggregate's
2038
+ * `imports` to apply it during `createSdk`, or `addPlugin(sdk, override)` to
2039
+ * apply it to a built SDK.
2040
+ */
2041
+ declare function defineMethodOverride<const TTarget extends string>(config: {
2042
+ target: TTarget;
2043
+ namespace?: string;
2044
+ } & LeafMetaFields): MethodOverridePlugin;
2045
+ /**
2046
+ * Define an input resolver: a method attachment for one of its parameters. Like
2047
+ * `defineMethod` it declares its own `imports`, and its callbacks receive a
2048
+ * narrowed `imports` bag, NOT the whole SDK. The graph reaches its imports
2049
+ * (materialize + dedup) but they never enter the host method's run-bag, so a
2050
+ * resolver may even import its own host method. At createSdk the imports are
2051
+ * captured, so the CLI later calls `listItems(input)` / `tryResolveWithoutPrompt
2052
+ * (input)` with no sdk argument.
2053
+ *
2054
+ * The `type` selects the kind (a {@link Resolver} union member); the config
2055
+ * narrows to it. `requireParameters` names sibling parameters that must resolve
2056
+ * first (it reads their values from `input`), independent of `imports` (the
2057
+ * SDK-capability graph). `object` / `array` resolvers compose nested resolvers;
2058
+ * an import-bearing resolver reached from a built field lives in `definitions`
2059
+ * (reached by `{ ref }`), since it can't be inlined when the field set is built
2060
+ * dynamically.
2061
+ */
2062
+ declare function defineResolver<const TImports extends ImportsInput = readonly [], TItem = unknown, TInput = Record<string, unknown>, TContext = unknown>(config: {
2063
+ type?: "dynamic";
2064
+ imports?: TImports & StaticList<TImports>;
2065
+ requireParameters?: readonly string[];
2066
+ inputType?: "text" | "password" | "email" | "search";
2067
+ placeholder?: string;
2068
+ /** Compute side-context once, before `listItems` (pre-fetch, no items yet),
2069
+ * with the narrowed `imports`. Its result flows into `listItems` and `prompt`
2070
+ * as `context`, so one place resolves what both the fetch and the render need
2071
+ * (e.g. a capability gate). May re-run across re-asks; keep it cheap. */
2072
+ getContext?: (bag: {
2073
+ imports: ImportsOf<TImports>;
2074
+ input: TInput;
2075
+ }) => PromiseLike<TContext>;
2076
+ /** Produce the candidate list. Behaves like an SDK list method (returns a page
2077
+ * / paginated result, never a bare array). `cursor` is the stateless "load
2078
+ * more" re-entry hook. Required: a dynamic resolver IS a candidate-lister;
2079
+ * use `type: "static"` for a free-text field. */
2080
+ listItems: (bag: {
2081
+ imports: ImportsOf<TImports>;
2082
+ input: TInput;
2083
+ /** The value `getContext` returned, if any. */
2084
+ context?: TContext;
2085
+ /** Free-text term the CLI injects for search-mode resolvers; a separate key
2086
+ * from `input`, so it never collides with a parameter named `search`. */
2087
+ search?: string;
2088
+ cursor?: string;
2089
+ }) => ListItemsResult<TItem>;
2090
+ prompt?: (bag: {
2091
+ items: TItem[];
2092
+ input: TInput;
2093
+ /** The value `getContext` returned, if any. */
2094
+ context?: TContext;
2095
+ }) => ResolverPromptConfig;
2096
+ /** Resolve with no user input (e.g. a configured default), skipping the prompt. */
2097
+ tryResolveWithoutPrompt?: (bag: {
2098
+ imports: ImportsOf<TImports>;
2099
+ input: TInput;
2100
+ }) => Promise<{
2101
+ resolvedValue: unknown;
2102
+ } | null>;
2103
+ /** Search-mode exact match: the typed `search` already names a valid value, so
2104
+ * return it and skip the picker. Returns null to fall through to `listItems`. */
2105
+ tryResolveFromSearch?: (bag: {
2106
+ imports: ImportsOf<TImports>;
2107
+ input: TInput;
2108
+ search?: string;
2109
+ }) => Promise<{
2110
+ resolvedValue: unknown;
2111
+ } | null>;
2112
+ }): DynamicResolver;
2113
+ declare function defineResolver(config: {
2114
+ type: "static";
2115
+ requireParameters?: readonly string[];
2116
+ inputType?: "text" | "password" | "email" | "search";
2117
+ placeholder?: string;
2118
+ }): StaticResolver;
2119
+ declare function defineResolver(config: {
2120
+ type: "constant";
2121
+ value: unknown;
2122
+ requireParameters?: readonly string[];
2123
+ }): ConstantResolver;
2124
+ declare function defineResolver(config: {
2125
+ type: "info";
2126
+ text: string;
2127
+ }): InfoResolver;
2128
+ declare function defineResolver<const TImports extends ImportsInput = readonly [], TInput = Record<string, unknown>>(config: {
2129
+ type: "object";
2130
+ imports?: TImports & StaticList<TImports>;
2131
+ requireParameters?: readonly string[];
2132
+ properties?: Record<string, Field>;
2133
+ /** Build the property map when the key set is dynamic (re-invoked as `input`
2134
+ * grow). Returns the map raw, no envelope. */
2135
+ getProperties?: (bag: {
2136
+ imports: ImportsOf<TImports>;
2137
+ input: TInput;
2138
+ }) => PromiseLike<Record<string, Field>>;
2139
+ definitions?: Record<string, Resolver>;
2140
+ }): ObjectResolver;
2141
+ declare function defineResolver(config: {
2142
+ type: "array";
2143
+ requireParameters?: readonly string[];
2144
+ items: Resolver | ResolverRef;
2145
+ minItems?: number;
2146
+ maxItems?: number;
2147
+ /** Coarse value type of each element, so a free-text item answer coerces
2148
+ * (e.g. `"5"` → `5`) like object fields do via `Field.valueType`. */
2149
+ itemValueType?: string;
2150
+ definitions?: Record<string, Resolver>;
2151
+ }): ArrayResolver;
2152
+ /**
2153
+ * Define an output formatter: a method attachment for its output. `getContext`
2154
+ * runs once per rendered page with the narrowed `imports` bag (no sdk); it
2155
+ * receives the items on the page and the context accumulated from prior pages,
2156
+ * and returns the (possibly extended) context — so page-independent context
2157
+ * (e.g. field labels) is fetched once, while per-item context grows as pages
2158
+ * arrive. `format` is pure and synchronous, turning one item + context into a
2159
+ * `FormattedItem`. Anything needing SDK data belongs in `getContext`, not
2160
+ * `format`. Both callbacks get the method's `input` (complete, since the
2161
+ * formatter runs after the method).
2162
+ */
2163
+ declare function defineFormatter<const TImports extends ImportsInput = readonly [], TItem = unknown, TInput = Record<string, unknown>, TContext = unknown>(config: {
2164
+ imports?: TImports & StaticList<TImports>;
2165
+ getContext?: (bag: {
2166
+ imports: ImportsOf<TImports>;
2167
+ items: TItem[];
2168
+ input: TInput;
2169
+ context?: TContext;
2170
+ }) => Promise<TContext>;
2171
+ format: (bag: {
2172
+ item: TItem;
2173
+ input: TInput;
2174
+ context?: TContext;
2175
+ }) => FormattedItem;
2176
+ }): Formatter;
2177
+ /**
2178
+ * Declare a stand-in for a method registered elsewhere (a configured factory
2179
+ * plugin, or just a different module). You reference it by `id` (`namespace/name`,
2180
+ * or a bare name); the binding is the id's last segment, and resolution by id
2181
+ * binds the real implementation at materialization (constraints 3-4). Its `run`
2182
+ * throws, since a stand-in must never be the implementation.
2183
+ */
2184
+ declare function declareMethod<const TId extends string, TInput = unknown, TOutput = unknown>(config: {
2185
+ id: LiteralString<TId>;
2186
+ }): MethodPlugin<LastSegment<TId>, TInput, TOutput> & PluginSummary<TId, never>;
2187
+ /**
2188
+ * Define a property leaf. Either a static `value` or a computed `get` (eager,
2189
+ * dependencies first, like `setup`). `createSdk`, a dependent's `imports`, or
2190
+ * an aggregate's re-export binds it under its bare `name` and yields the value.
2191
+ */
2192
+ declare function defineProperty<const TName extends string, TValue, const TNamespace extends string = "">(config: {
2193
+ name: TName;
2194
+ namespace?: TNamespace;
2195
+ value: TValue;
2196
+ } & LeafMetaFields): PropertyPlugin<TName, TValue> & PluginSummary<never, IdOf<TNamespace, TName>>;
2197
+ declare function defineProperty<const TName extends string, TValue, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
2198
+ name: TName;
2199
+ namespace?: TNamespace;
2200
+ imports?: TImports & StaticList<TImports>;
2201
+ setup?: (bag: {
2202
+ imports: ImportsOf<TImports>;
2203
+ }) => TState;
2204
+ dispose?: (bag: {
2205
+ imports: ImportsOf<TImports>;
2206
+ state: TState;
2207
+ input?: unknown;
2208
+ }) => void | Promise<void>;
2209
+ get: (bag: {
2210
+ imports: ImportsOf<TImports>;
2211
+ state: TState;
2212
+ }) => TValue;
2213
+ /** Templated registry members for this property's dynamic sub-surface (e.g.
2214
+ * a proxy): each a bodyless declaration keyed by `path` instead of `name`. */
2215
+ dynamicMembers?: readonly DynamicMember[];
2216
+ } & LeafMetaFields): PropertyPlugin<TName, TValue> & LeafSummary<TNamespace, TName, TImports>;
2217
+ /**
2218
+ * Declare a stand-in for a property registered elsewhere (a configured factory
2219
+ * plugin, e.g. the api client built from options). Carries only a name and a
2220
+ * provides type; dependents reference it for typing, and resolution by id binds
2221
+ * the real property at materialization (constraints 3-4, the property twin of
2222
+ * `declareMethod`). A stand-in left with no real implementation is a missing
2223
+ * dependency (a runtime error from `createSdk`).
2224
+ */
2225
+ declare function declareProperty<const TId extends string, TValue = unknown>(config: {
2226
+ id: LiteralString<TId>;
2227
+ }): PropertyPlugin<LastSegment<TId>, TValue> & PluginSummary<TId, never>;
2228
+ /**
2229
+ * Declare an OPTIONAL stand-in for a property registered elsewhere. Unlike
2230
+ * `declareProperty`, a `declareOptionalProperty` left unsatisfied is NOT a missing
2231
+ * dependency: dependents bind `undefined` instead of the build failing. The
2232
+ * binding type is therefore `TValue | undefined`, so a consumer must handle the
2233
+ * absent case (typically `{ ...DEFAULTS, ...imports.config }`).
2234
+ *
2235
+ * This lets a plugin own its own defaults and treat a provider as override-only:
2236
+ * it builds standalone (no provider registered -> `undefined` -> defaults), and
2237
+ * a registered provider layers on top. Used for the SDK's static config
2238
+ * (defaults live with each consumer; `createZapierSdk` registers an override)
2239
+ * and for framework capabilities a method can run without (e.g. hooks).
2240
+ */
2241
+ declare function declareOptionalProperty<const TId extends string, TValue = unknown>(config: {
2242
+ id: LiteralString<TId>;
2243
+ }): PropertyPlugin<LastSegment<TId>, TValue | undefined> & PluginSummary<never, never>;
2244
+ /**
2245
+ * Define a method-lifecycle hook: a leaf whose `observe` contributes
2246
+ * fire-and-forget observers (`onMethodStart` / `onMethodEnd`) the method
2247
+ * boundary fires around every method, and whose `wrap` contributes
2248
+ * contract-preserving middleware around imported methods. This is how a
2249
+ * MODULE plugin provides cross-cutting behavior (the module-model successor
2250
+ * to a legacy plugin writing `context.hooks` and to `definePlugin`'s
2251
+ * deleted `middleware` map).
2252
+ *
2253
+ * `setup` runs once and owns the hook's state (e.g. a telemetry queue),
2254
+ * delivered to the observers. Each observer's bag
2255
+ * mirrors a method's `run` bag minus `next`: `{ imports, input, state }`, where
2256
+ * `input` is the lifecycle context (`{ methodName, args, depth, ... }`). The
2257
+ * boundary runs observers defensively, so an observer error never breaks the
2258
+ * observed call.
2259
+ */
2260
+ declare function defineHook<const TImports extends ImportsInput = readonly [], TState = undefined>(config: {
2261
+ name: string;
2262
+ namespace?: string;
2263
+ imports?: TImports & StaticList<TImports>;
2264
+ setup?: (bag: {
2265
+ imports: ImportsOf<TImports>;
2266
+ }) => TState;
2267
+ dispose?: (bag: {
2268
+ imports: ImportsOf<TImports>;
2269
+ state: TState;
2270
+ input?: unknown;
2271
+ }) => void | Promise<void>;
2272
+ /** Contract-preserving wraps around imported methods, keyed by the target's
2273
+ * binding among `imports` (the middleware onion: dependents-outermost in
2274
+ * topological order). One bag shape with `run`/`observe`; `next` is the
2275
+ * only variant. */
2276
+ wrap?: MiddlewareMap<ImportsOf<TImports>, TState>;
2277
+ observe?: {
2278
+ onMethodStart?: (bag: {
2279
+ imports: ImportsOf<TImports>;
2280
+ input: OnMethodStartContext;
2281
+ state: TState;
2282
+ }) => void;
2283
+ onMethodEnd?: (bag: {
2284
+ imports: ImportsOf<TImports>;
2285
+ input: OnMethodEndContext;
2286
+ state: TState;
2287
+ }) => void;
2288
+ };
2289
+ }): HookPlugin;
2290
+ /**
2291
+ * Declare a stand-in for a whole aggregate (module) registered elsewhere: the
2292
+ * aggregate twin of `declareMethod` / `declareProperty`. `exports` is an array
2293
+ * of leaf stand-ins describing the module's surface, so dependents that import
2294
+ * it get typed bindings; resolution by id binds the real aggregate at
2295
+ * materialization, and a stand-in left with no implementation is a missing
2296
+ * dependency. Use it to depend on a module abstractly and provide the concrete
2297
+ * one at the composition root (the tree-shakeable / swappable shape).
2298
+ */
2299
+ declare function declarePlugin<const TId extends string, const TExports extends readonly AnyLeafPlugin[] = readonly []>(config: {
2300
+ id: LiteralString<TId>;
2301
+ exports?: TExports & StaticList<TExports>;
2302
+ }): AggregatePlugin<LastSegment<TId>, ArrayExports<TExports>> & PluginSummary<TId, never>;
2303
+ /**
2304
+ * Function form — the legacy function-plugin identity wrapper: it returns the
2305
+ * function unchanged but constrains its return to `PluginProvides` and
2306
+ * preserves the narrow inferred shape, so callers derive `*PluginProvides` via
2307
+ * `ReturnType<typeof plugin>`. Such a plugin runs through the legacy bridge
2308
+ * (`fromFunctionPlugin` / `createPluginStack`), deprecated with it.
2309
+ *
2310
+ * @deprecated Author plugins with `defineMethod` / `defineProperty` /
2311
+ * object-form `definePlugin` instead. This form logs a runtime deprecation and
2312
+ * will be removed in a release after the warning ships.
2313
+ */
2314
+ declare function definePlugin<TSdk, TProvides extends PluginProvides>(fn: (sdk: TSdk & {
2315
+ context: {
2316
+ meta: Record<string, PluginMeta>;
2317
+ };
2318
+ }) => TProvides): (sdk: TSdk & {
2319
+ context: {
2320
+ meta: Record<string, PluginMeta>;
2321
+ };
2322
+ }) => TProvides;
2323
+ /**
2324
+ * Define a plugin module: an aggregate that re-exports child plugins.
2325
+ * `exports` mirrors `imports`: an array where a leaf binds under its own name
2326
+ * (`[greet]` binds "greet"), a module spreads its bindings, and
2327
+ * `selectExports(dep, { hi: "greet" })` subsets/renames. It is optional, so an
2328
+ * imports-only module can omit it. Re-exporting implies a dependency on the
2329
+ * child. To wrap imported methods, export a `defineHook` with `wrap`.
2330
+ */
2331
+ declare function definePlugin<const TName extends string, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", const TExports extends readonly (AnyLeafPlugin | AnyAggregatePlugin)[] = readonly []>(config: {
2332
+ name: TName;
2333
+ namespace?: TNamespace;
2334
+ imports?: TImports & StaticList<TImports>;
2335
+ exports?: TExports & StaticList<TExports>;
2336
+ }): AggregatePlugin<TName, ArrayExports<TExports>> & AggregateSummary<TNamespace, TName, TImports, TExports>;
2337
+
2338
+ /**
2339
+ * A `selectExports` spec: a bare export name to keep (`"getApp"`), or a rename
2340
+ * map whose key is the resulting binding and value the source export name
2341
+ * (`{ getUser: "getProfile" }` is `export { getProfile as getUser }`).
2342
+ */
2343
+ type SelectSpec<TExports> = (keyof TExports & string) | {
2344
+ [newName: string]: keyof TExports & string;
2345
+ };
2346
+ /** The export record one spec contributes: a kept name maps to its own leaf; a
2347
+ * rename map keys each new name to the leaf at the source name. */
2348
+ type ResolveSpec<TExports extends Record<string, AnyLeafPlugin>, S> = S extends string | number ? S extends keyof TExports ? {
2349
+ [K in S]: TExports[S];
2350
+ } : never : {
2351
+ [K in keyof S]: S[K] extends keyof TExports ? TExports[S[K]] : never;
2352
+ };
2353
+ /** Ensure the computed export record satisfies the `AggregatePlugin` constraint
2354
+ * (an empty/degenerate selection collapses to a bare exports record). */
2355
+ type AsExports<T> = T extends Record<string, AnyLeafPlugin> ? T : Record<string, AnyLeafPlugin>;
2356
+ /**
2357
+ * Select (and optionally rename) a subset of a module's exports, the ES
2358
+ * `{ a, b, c as d }` clause. Works the same in `imports` (import) and
2359
+ * `exports` (re-export): each spec is a bare name to keep or a `{ new: "old" }`
2360
+ * rename map. An unknown source name throws. Returns a re-export descriptor (a
2361
+ * synthetic aggregate over the chosen bindings) that drops straight into either
2362
+ * array; the selected bindings keep the source module's identity.
2363
+ */
2364
+ declare function selectExports<TExports extends Record<string, AnyLeafPlugin>, const TSpecs extends readonly SelectSpec<TExports>[]>(source: AggregatePlugin<string, TExports>, ...specs: TSpecs): AggregatePlugin<string, AsExports<UnionToIntersection<{
2365
+ [I in keyof TSpecs]: ResolveSpec<TExports, TSpecs[I]>;
2366
+ }[number]>>>;
2367
+ /**
2368
+ * Re-export all of a module's exports EXCEPT the named ones, the denylist
2369
+ * complement to {@link selectExports}'s allowlist (think TS `Omit` vs `Pick`).
2370
+ * The argument is a list of SOURCE export names to drop (not resulting
2371
+ * bindings), so there is no key-semantics ambiguity. An unknown name throws.
2372
+ *
2373
+ * The omitted leaves stay in the graph (the synthetic aggregate still `imports`
2374
+ * the source, so it materializes) and remain addressable by id — they are just
2375
+ * not surfaced under a binding. That lets a head replace an export's binding
2376
+ * with its own plugin while still depending on the original by id.
2377
+ */
2378
+ declare function omitExports<TExports extends Record<string, AnyLeafPlugin>, const TOmit extends readonly (keyof TExports & string)[]>(source: AggregatePlugin<string, TExports>, omit: TOmit): AggregatePlugin<string, Omit<TExports, TOmit[number]>>;
2379
+
2380
+ /**
2381
+ * Lift a legacy function plugin into the module model. The
2382
+ * returned plugin runs `fn` at materialization and surfaces its root methods;
2383
+ * `createPluginStack().toPlugin()` is built on this, and `addPlugin` uses it for
2384
+ * external function plugins. `fn`'s `context` contributions merge into the live
2385
+ * `SdkContext`; its other root keys become the surface.
2386
+ *
2387
+ * @deprecated The module model replaces this exit; it logs a runtime
2388
+ * deprecation and will be removed in a release after this warning ships.
2389
+ */
2390
+ declare function fromFunctionPlugin<TProvides extends PluginProvides>(fn: (sdk: any) => TProvides, config: {
2391
+ name: string;
2392
+ namespace?: string;
2393
+ }): LegacyPlugin<TProvides & {
2394
+ getRegistry: (options?: {
2395
+ package?: string;
2396
+ }) => RegistryResult;
2397
+ }>;
2398
+ /**
2399
+ * Build a {@link LegacyMergePlugin}: pass the collapsed legacy stack
2400
+ * (`stack.toPlugin()`) as `legacy` and the migrated module-model plugins as
2401
+ * `plugin`. `createSdk(defineLegacyMerge({...}))` surfaces both.
2402
+ *
2403
+ * @deprecated Build directly with `createSdk(root, { configuration })`
2404
+ * instead; it logs a runtime deprecation and will be removed in a release
2405
+ * after this warning ships.
2406
+ */
2407
+ declare function defineLegacyMerge<TProvides extends PluginProvides, const TPlugin extends AnyPlugin>(args: {
2408
+ name: string;
2409
+ namespace?: string;
2410
+ legacy: (sdk: any) => TProvides;
2411
+ plugin: TPlugin;
2412
+ }): LegacyMergePlugin<TProvides, TPlugin>;
2413
+
2414
+ /**
2415
+ * Core error machinery.
2416
+ *
2417
+ * kitcore constructs errors at two internal throw sites: input
2418
+ * validation (`utils/validation.ts`) and non-Error normalization
2419
+ * (`utils/function-utils.ts`'s `normalizeError`). Heads supply a
2420
+ * `adaptError` factory via `createCorePlugin` to map kitcore's abstract
2421
+ * `CoreErrorCode` values onto their own branded error classes; if
2422
+ * no factory is supplied, kitcore falls back to constructing a plain
2423
+ * `CoreError`. Either way, every kitcore-thrown error is brand-stamped
2424
+ * with `CORE_ERROR_SYMBOL` and `coreCode` (non-enumerable),
2425
+ * so consumers can recognize core errors via `isCoreError`
2426
+ * without knowing the head's class identity.
2427
+ */
2428
+ /**
2429
+ * Cross-package brand for kitcore-constructed errors. `Symbol.for(key)`
2430
+ * reads from the engine-global registry, so the same value resolves
2431
+ * across realms and across multiple copies of kitcore (e.g. when one
2432
+ * package bundles kitcore and another installs it standalone). Use
2433
+ * `isCoreError` for cross-package checks.
2434
+ */
2435
+ declare const CORE_ERROR_SYMBOL: unique symbol;
2436
+ /**
2437
+ * Abstract codes for the errors kitcore can produce. Heads receive these
2438
+ * via `AdaptErrorOptions.code` and map them onto their own named
2439
+ * error classes (e.g. `VALIDATION_ERROR` → the head's branded
2440
+ * `<Prefix>ValidationError`).
2441
+ */
2442
+ declare const CoreErrorCode: {
2443
+ readonly Validation: "VALIDATION_ERROR";
2444
+ readonly Unknown: "UNKNOWN_ERROR";
2445
+ };
2446
+ type CoreErrorCode = (typeof CoreErrorCode)[keyof typeof CoreErrorCode];
2447
+ /**
2448
+ * Standard error envelope. kitcore doesn't generate these
2449
+ * itself; heads set `errors?: CoreApiError[]` on their error constructor
2450
+ * options when surfacing structured upstream failures.
2451
+ */
2452
+ interface CoreApiError {
2453
+ status: number;
2454
+ code: string;
2455
+ title: string;
2456
+ detail: string;
2457
+ source?: unknown;
2458
+ meta?: unknown;
2459
+ }
2460
+ /**
2461
+ * Base options for the default `CoreError` fallback. Heads' own error
2462
+ * classes typically accept a richer options bag.
2463
+ */
2464
+ interface CoreErrorOptions {
2465
+ statusCode?: number;
2466
+ errors?: CoreApiError[];
2467
+ cause?: unknown;
2468
+ response?: unknown;
2469
+ }
2470
+ /**
2471
+ * What `adaptError` factories receive. `code` is the abstract error
2472
+ * code; `details` carries type-specific extras (validation issues for
2473
+ * `VALIDATION_ERROR`, etc.).
2474
+ */
2475
+ interface AdaptErrorOptions {
2476
+ code: CoreErrorCode;
2477
+ message: string;
2478
+ cause?: unknown;
2479
+ details?: unknown;
2480
+ }
2481
+ type AdaptError = (options: AdaptErrorOptions) => Error;
2482
+ /**
2483
+ * Default error class kitcore constructs when no `adaptError` is
2484
+ * supplied. Heads typically provide their own branded classes via
2485
+ * `adaptError` and never see this. Exported so the rare head-less
2486
+ * caller (tests, scratch scripts) can recognize the fallback.
2487
+ */
2488
+ declare class CoreError extends Error {
2489
+ readonly name: string;
2490
+ statusCode?: number;
2491
+ errors?: CoreApiError[];
2492
+ cause?: unknown;
2493
+ response?: unknown;
2494
+ constructor(message: string, options?: CoreErrorOptions);
2495
+ }
2496
+ /**
2497
+ * Construct a core error, optionally via a head-supplied factory.
2498
+ * Stamps the core brand and the abstract `coreCode` on the
2499
+ * returned instance (non-enumerable, so they don't pollute JSON
2500
+ * serialization). The `instanceof <HeadErrorClass>` check on the
2501
+ * result works as expected; `isCoreError` is the cross-package
2502
+ * recognizer that survives bundled/standalone splits.
2503
+ */
2504
+ declare function createCoreError(options: AdaptErrorOptions, adaptError?: AdaptError): Error;
2505
+ /**
2506
+ * Cross-package-safe check that `value` was produced by kitcore's
2507
+ * error construction path (i.e. through `createCoreError`). Use
2508
+ * this in code that needs to distinguish "kitcore threw this" from
2509
+ * "a handler threw an unrelated `Error` subclass" — `instanceof` checks
2510
+ * on specific head classes also work, but `isCoreError` is the
2511
+ * neutral recognizer.
2512
+ */
2513
+ declare function isCoreError(value: unknown): boolean;
2514
+ /**
2515
+ * Abstract `CoreErrorCode` for an error produced via
2516
+ * `createCoreError`. Returns `undefined` for non-kitcore values.
2517
+ */
2518
+ declare function getCoreErrorCode(value: unknown): CoreErrorCode | undefined;
2519
+ /**
2520
+ * `cause` field accessor that doesn't trip the type system. Same as
2521
+ * `(value as { cause?: unknown }).cause` for kitcore-produced errors;
2522
+ * returns `undefined` for non-kitcore values.
2523
+ */
2524
+ declare function getCoreErrorCause(value: unknown): unknown;
2525
+
2526
+ /**
2527
+ * Framework options (`CoreOptions`) and their well-known configuration id.
2528
+ * Heads inject the bag under `CORE_OPTIONS_ID` via `createSdk`'s
2529
+ * `configuration`; the method boundary resolves it by id at every invocation
2530
+ * (`resolveCoreOptions`), and `coreOptionsPluginRef` (model/builtins) is the
2531
+ * importable stand-in for plugins that need the same options.
2532
+ */
2533
+
2534
+ /**
2535
+ * What the boundary reports when a deprecated method is called: the method
2536
+ * plus its declared `deprecation` meta, whole, so future declaration fields
2537
+ * ride along without a signature change. `type` makes the record
2538
+ * self-describing (the shape a future unified event channel would carry;
2539
+ * see docs/design/2026-06-04-unified-event-bus.md).
2540
+ */
2541
+ interface DeprecationWarning {
2542
+ type: "deprecation";
2543
+ methodName: string;
2544
+ deprecation: FunctionDeprecation;
2545
+ }
2546
+ /**
2547
+ * The default `logDeprecation` handler: format the one-line warning and pass
2548
+ * it through kitcore's deduping logger, so the built-in policy is
2549
+ * once-per-process per message.
2550
+ */
2551
+ declare function defaultLogDeprecation({ methodName, deprecation, }: DeprecationWarning): void;
2552
+ /**
2553
+ * The well-known id for framework options: heads inject a `CoreOptions` bag
2554
+ * under it via `createSdk`'s `configuration` (or register a property plugin),
2555
+ * and the method boundary resolves it by id at every invocation, falling back
2556
+ * to the legacy `context.core` write while the deprecated `createCorePlugin`
2557
+ * path still exists.
2558
+ */
2559
+ declare const CORE_OPTIONS_ID = "kitcore/coreOptions";
2560
+ /**
2561
+ * Head-supplied configuration for kitcore-managed behavior. All fields are
2562
+ * optional; absent fields fall back to kitcore's built-in behavior.
2563
+ */
2564
+ interface CoreOptions {
2565
+ /**
2566
+ * Construct the head's branded error class for kitcore-thrown errors
2567
+ * (validation failures, non-Error normalization). Receives the
2568
+ * abstract `CoreErrorCode`, message, optional cause, and
2569
+ * type-specific details; returns the head's `Error` subclass. The
2570
+ * returned instance is automatically brand-stamped via
2571
+ * `createCoreError` so `isCoreError(err)` still recognizes
2572
+ * it across package boundaries. If absent, kitcore throws a plain
2573
+ * `CoreError`.
2574
+ */
2575
+ adaptError?: AdaptError;
2576
+ /**
2577
+ * The deprecation HANDLER (adaptError's sibling, not an observer): the
2578
+ * framework signals every call of a method declaring `deprecation` meta,
2579
+ * and this gate decides what happens — policy (how often to tell; the
2580
+ * deduping deprecation loggers make once-per-process one line) and
2581
+ * presentation. Exactly one: absent falls back to
2582
+ * {@link defaultLogDeprecation}, supplied replaces it. Runs isolated, so a
2583
+ * throwing handler never breaks the observed call. Additive observation
2584
+ * (many subscribers, e.g. telemetry counting hits) is a different concept
2585
+ * reserved for an `on*`-named observer when the unified event bus lands.
2586
+ */
2587
+ logDeprecation?: (warning: DeprecationWarning) => void;
2588
+ }
2589
+
2590
+ /**
2591
+ * The optional stand-in for the framework-options bag (`kitcore/coreOptions`).
2592
+ * The method boundary resolves the same id internally (for `adaptError`); a
2593
+ * plugin that needs the options imports this ref, binding
2594
+ * `CoreOptions | undefined` (absent means kitcore's built-in behavior). Heads
2595
+ * supply the value via `createSdk`'s `configuration` or a registered property.
2596
+ */
2597
+ declare const coreOptionsPluginRef: PropertyPlugin<"coreOptions", CoreOptions | undefined> & PluginSummary<never, never>;
2598
+ /**
2599
+ * Escape hatch. A built-in privileged plugin whose value is the live
2600
+ * `SdkContext` (the raw plugin graph). Importing it (`imports.context`) lets a
2601
+ * body reach internals the model otherwise keeps private.
2602
+ *
2603
+ * Prefer not to depend on this. The `SdkContext` shape is an implementation
2604
+ * detail and may change without notice; import the specific plugins you need,
2605
+ * use `getRegistryPlugin` for surface introspection, and `resolvePlugin` for
2606
+ * out-of-graph access to a binding. Its value is injected at materialization,
2607
+ * not authored.
2608
+ */
2609
+ declare const dangerousContextPlugin: PropertyPlugin<"context", SdkContext>;
2610
+ /**
2611
+ * A built-in that reports the live SDK surface as the canonical
2612
+ * {@link RegistryResult}. It is just a method depending on `dangerousContextPlugin` (no
2613
+ * new privilege): re-export it to put `getRegistry()` on the SDK surface. Reads
2614
+ * `context.surface` at call time, so it reflects any post-seal `addPlugin`
2615
+ * additions, and produces the same registry shape the heads (CLI / MCP / docs)
2616
+ * consume.
2617
+ */
2618
+ declare const getRegistryPlugin: MethodPlugin<"getRegistry", {
2619
+ package?: string | undefined;
2620
+ } | undefined, RegistryResult<any>, readonly []> & LeafSummary<"kitcore", "getRegistry", readonly [PropertyPlugin<"context", SdkContext>]>;
2621
+
2622
+ /**
2623
+ * The external escape-hatch key for an SDK's context. A Symbol,
2624
+ * not a string, so it stays off the string surface (which is exactly the root's
2625
+ * exports) and is collision-free and clearly internal. It is attached at
2626
+ * runtime but kept OUT of the public SDK type (a `unique symbol` in an exported
2627
+ * type can't be named in a consumer's emitted `.d.ts`); reach it through the
2628
+ * typed `getContext(sdk)` accessor.
2629
+ *
2630
+ * `Symbol.for`, not `Symbol()`: heads bundle kitcore (tsup `noExternal`), so
2631
+ * an sdk built by one bundle's copy must still be readable by another copy's
2632
+ * `getContext` / `resolvePlugin` (e.g. a CLI sdk inspected with helpers
2633
+ * imported from `@zapier/zapier-sdk`). The global symbol registry makes every
2634
+ * copy agree on the key.
2635
+ */
2636
+ declare const CONTEXT: unique symbol;
2637
+ /** The off-surface escape hatch to an SDK's `SdkContext`. */
2638
+ declare function getContext(sdk: unknown): SdkContext;
2639
+ /**
2640
+ * Resolve a plugin's materialized value against a built SDK: a method's
2641
+ * callable or a property's value (the same thing an importer receives), NOT
2642
+ * the plugin descriptor. For head infrastructure that builds the SDK and
2643
+ * needs one of its own internals; consumers use the SDK surface, and in-graph
2644
+ * code keeps using `imports`. Read-only against the built graph; nothing
2645
+ * materializes. A missing required ref throws; an unsatisfied optional ref
2646
+ * resolves `undefined` (matching import behavior); a live `get` property
2647
+ * re-reads per call (a read-time snapshot — hold the function, not the value,
2648
+ * for liveness). Aggregate refs are not one-ref-one-binding and are
2649
+ * unsupported.
2650
+ */
2651
+ declare function resolvePlugin<TRef extends AnyLeafPlugin>(sdk: unknown, ref: TRef): ExportSurface<TRef>;
2652
+ /**
2653
+ * Thrown by {@link disposeSdk} when one or more dispose callbacks failed.
2654
+ * Every dispose was still attempted; `errors` holds the failures in teardown
2655
+ * order.
2656
+ */
2657
+ declare class CoreDisposeError extends Error {
2658
+ readonly name: string;
2659
+ readonly errors: unknown[];
2660
+ constructor(errors: unknown[]);
2661
+ }
2662
+ /**
2663
+ * Tear down a built SDK: run every recorded `dispose` (a leaf's `setup` dual)
2664
+ * in reverse build order, so dependents release before their dependencies.
2665
+ * Each dispose is awaited and run defensively; all are attempted even after a
2666
+ * failure, then the failures reject together as {@link CoreDisposeError}.
2667
+ * Idempotent: the first call's `input` wins and later calls return the same
2668
+ * settled result. A top-level function like `addPlugin`, reaching internals
2669
+ * through the `CONTEXT` symbol, so anyone holding the sdk can call it.
2670
+ */
2671
+ declare function disposeSdk(sdk: unknown, input?: unknown): Promise<void>;
2672
+ /**
2673
+ * Materialize one plugin into an SDK whose surface is that plugin's exports.
2674
+ * A method root surfaces its callable under its bare name; a property root its
2675
+ * value; an aggregate root its export bindings. `options.configuration`
2676
+ * injects runtime values by plugin id (see {@link CreateSdkOptions}).
2677
+ */
2678
+ declare function createSdk<P extends AnyMethodPlugin>(root: P & CompletenessOf<P>, options?: CreateSdkOptions): MethodSdkOf<P>;
2679
+ declare function createSdk<P extends AnyPropertyPlugin>(root: P & CompletenessOf<P>, options?: CreateSdkOptions): PropertySdkOf<P>;
2680
+ declare function createSdk<P extends AnyAggregatePlugin>(root: P & CompletenessOf<P>, options?: CreateSdkOptions): AggregateSdkOf<P>;
2681
+ declare function createSdk<TSurface>(root: LegacyPlugin<TSurface>, options?: CreateSdkOptions): TSurface & SdkInternals;
2682
+ declare function createSdk<TProvides extends PluginProvides, TPlugin extends AnyPlugin>(root: LegacyMergePlugin<TProvides, TPlugin>, options?: CreateSdkOptions): TProvides & {
2683
+ getRegistry: (options?: {
2684
+ package?: string;
2685
+ }) => RegistryResult;
2686
+ } & AddedSurface<TPlugin> & SdkInternals;
2687
+ /**
2688
+ * Extend an already-built SDK in place with one more plugin (the post-seal
2689
+ * extension path). Dispatches on shape: a module-model plugin (`defineMethod` /
2690
+ * `defineProperty` / `definePlugin`) is materialized incrementally into the live
2691
+ * graph; a legacy function plugin runs through the legacy merge. Either way the
2692
+ * caller's `sdk` binding is narrowed to include the addition.
2693
+ */
2694
+ declare function addPlugin<TSdk extends object, P>(sdk: TSdk, plugin: P, options?: {
2695
+ override?: boolean;
2696
+ }): asserts sdk is TSdk & AddedSurface<P>;
2697
+
2698
+ /**
2699
+ * Public types for the resolution engine: the serializable protocol a host
2700
+ * drives (`start` / `step`), the in-process `resolve` sugar's answerer, and the
2701
+ * reflection shapes (`listMethods` / `getMethod` / `listChoices`). The engine
2702
+ * turns a method's partial input into a complete, validated input by resolving
2703
+ * each parameter, interacting with the host only when it must. See the kitcore
2704
+ * README's "Resolving inputs: controllers" section for worked host examples.
2705
+ */
2706
+ /** A candidate value the host renders; the host composes its own display label
2707
+ * from `label`/`hint`. `value` is what flows back in a `choose` action. */
2708
+ interface ControllerChoice {
2709
+ label: string;
2710
+ value: string;
2711
+ hint?: string;
2712
+ }
2713
+ /**
2714
+ * A move the host can make in response to a question, self-described so an agent
2715
+ * can follow it without the type definitions (HATEOAS-lite). `description` says
2716
+ * what it does; `supply` names the single payload field to include when sending
2717
+ * the action (absent = no payload). Enriching an affordance with a full field
2718
+ * schema later is additive and never changes the {@link ControllerAction} it
2719
+ * produces.
2720
+ */
2721
+ interface ControllerAffordance {
2722
+ action: ControllerAction["type"];
2723
+ description: string;
2724
+ supply?: "value" | "term";
2725
+ }
2726
+ /** A question the host renders. Discriminated on `type`; the available moves are
2727
+ * the self-describing `actions` list (single source of truth, no flags).
2728
+ * `actions` is emitted in recommended presentation order — answer directly
2729
+ * (`choose`/`custom`/`add`), refine (`search`), paginate (`more`), decline
2730
+ * (`skip`/`done`), and failure questions offer `retry` then `cancel` — so a
2731
+ * minimal host can render the list verbatim, top to bottom. Hosts with richer
2732
+ * widgets (windowed lists, filter state) may reorder. */
2733
+ type ControllerQuestion = {
2734
+ type: "select";
2735
+ message: string;
2736
+ /** What this field is, for an agent that lacks the schema. */
2737
+ description?: string;
2738
+ choices: ControllerChoice[];
2739
+ actions: ControllerAffordance[];
2740
+ /** The active search term these `choices` were fetched for, when the
2741
+ * resolver is search-mode and a `search` action has run. Absent means no
2742
+ * search yet (the initial state of a search-mode resolver): a host leads
2743
+ * with a term prompt rather than an unfiltered list. Local
2744
+ * type-to-filter is for bounded loaded lists; search-mode does discrete
2745
+ * server queries. */
2746
+ search?: string;
2747
+ /** A multi-select (the resolver's `prompt` returned `type: "checkbox"`);
2748
+ * the `choose` action then carries an array. */
2749
+ multiple?: boolean;
2750
+ /** Informational, non-selectable lines (`PromptConfig.notes`), e.g. a
2751
+ * capability hint. A host renders them dimmed, after the choices. */
2752
+ notes?: string[];
2753
+ /** The resolver's `placeholder`, carried so a search-mode host can show it
2754
+ * in its lead-with-term prompt (e.g. "Enter or search app (e.g. 'slack')").
2755
+ * Only meaningful before a search has run. */
2756
+ placeholder?: string;
2757
+ } | {
2758
+ type: "input";
2759
+ message: string;
2760
+ description?: string;
2761
+ inputType: "text" | "password" | "email";
2762
+ placeholder?: string;
2763
+ actions: ControllerAffordance[];
2764
+ } | {
2765
+ type: "collection";
2766
+ message: string;
2767
+ description?: string;
2768
+ /** Which container kind this decision gates. `array` is the add-another
2769
+ * loop; `object` is the entry gate on an optional object, fired BEFORE
2770
+ * its fields are fetched (`add` descends into the fields, `done` skips
2771
+ * the container). A host that renders `message` + `actions` generically
2772
+ * needs nothing else; this is additive metadata for hosts that render
2773
+ * containers specially. */
2774
+ container: "array" | "object";
2775
+ /** Object optionals gate only: the fields the `add` action would walk
2776
+ * (key + display label + coarse value type), so a smart host can render
2777
+ * them (or a form section) instead of a blind yes/no. Dumb hosts keep
2778
+ * rendering `message`. Absent on the entry gate: its fields aren't
2779
+ * fetched until the gate is accepted. */
2780
+ fields?: {
2781
+ key: string;
2782
+ label?: string;
2783
+ valueType?: string;
2784
+ }[];
2785
+ /** Array only: items so far. */
2786
+ count?: number;
2787
+ /** Array only: `minItems`. */
2788
+ min?: number;
2789
+ /** Absent when the array is unbounded (no `maxItems`); a finite cap
2790
+ * otherwise. Omitted rather than `Infinity` so the question stays JSON. */
2791
+ max?: number;
2792
+ actions: ControllerAffordance[];
2793
+ };
2794
+ /** The host's response to a question. The wire shape is frozen: a fuller
2795
+ * HATEOAS affordance schema would still produce exactly these. */
2796
+ type ControllerAction = {
2797
+ type: "choose";
2798
+ value: string | string[];
2799
+ } | {
2800
+ type: "search";
2801
+ term: string;
2802
+ } | {
2803
+ type: "more";
2804
+ } | {
2805
+ type: "custom";
2806
+ value: string;
2807
+ } | {
2808
+ type: "skip";
2809
+ } | {
2810
+ type: "add";
2811
+ } | {
2812
+ type: "done";
2813
+ } | {
2814
+ type: "cancel";
2815
+ } | {
2816
+ type: "retry";
2817
+ };
2818
+ /** What `start` / `step` return alongside the next state. `ask` carries a
2819
+ * question to answer; `done` the fully resolved input; `invalid` the validation
2820
+ * issues; `failed` a thrown lookup error plus a question offering retry/cancel. */
2821
+ type ControllerResult = {
2822
+ status: "ask";
2823
+ question: ControllerQuestion;
2824
+ /** The prior answer's validation failure (`PromptConfig.validate`), when
2825
+ * this is a re-ask. About the last transition, not the question itself. */
2826
+ error?: string;
2827
+ } | {
2828
+ status: "done";
2829
+ value: Record<string, unknown>;
2830
+ } | {
2831
+ status: "invalid";
2832
+ issues: ControllerIssue[];
2833
+ } | {
2834
+ status: "failed";
2835
+ error: ControllerError;
2836
+ question: ControllerQuestion;
2837
+ } | {
2838
+ status: "cancelled";
2839
+ };
2840
+ /** A thrown lookup failure, normalized to plain data at the wall. The engine
2841
+ * catches an arbitrary throwable; a raw `Error` loses its message under
2842
+ * `JSON.stringify` (and a circular/custom value can break transport), so a
2843
+ * `failed` result carries this DTO instead, which a remote host can render. */
2844
+ interface ControllerError {
2845
+ name: string;
2846
+ message: string;
2847
+ code?: string;
2848
+ }
2849
+ /** A single validation problem, keyed to the offending parameter when known. */
2850
+ interface ControllerIssue {
2851
+ parameter?: string;
2852
+ message: string;
2853
+ }
2854
+ /**
2855
+ * The serializable, caller-held progress of a resolution. The host carries it
2856
+ * forward and passes it back into the next `step`; it round-trips across a
2857
+ * client/server boundary unchanged (no closures, no live iterators). It carries
2858
+ * the method id, so `step` needs nothing else.
2859
+ */
2860
+ interface ControllerState {
2861
+ method: string;
2862
+ /** The growing input, as a nested tree of *real values only* — objects build
2863
+ * in place (`resolved.inputs.channel`), so a leaf value lives at its {@link ControllerPath}. */
2864
+ resolved: Record<string, unknown>;
2865
+ /** Dotted path-keys the engine is done with: a resolved leaf (value in
2866
+ * `resolved`), a skipped leaf (no value), or a finished array. Objects derive
2867
+ * doneness from their children. The "touched" analog from form libraries. */
2868
+ settled: string[];
2869
+ /** The path of the parameter (or nested field) currently being asked. */
2870
+ current?: ControllerPath;
2871
+ /** Which container decision the outstanding `collection` question is, when
2872
+ * `current` points at one: the array add/done loop, an optional object's
2873
+ * entry gate, or an object's optionals gate. Recorded explicitly so `step`'s
2874
+ * add/done handling never infers the decision from value presence or
2875
+ * resolver shape. Absent when `current` is a plain leaf question. */
2876
+ gate?: "array" | "entry" | "optionals";
2877
+ /** Listing progress for the current dynamic leaf (serializable: items +
2878
+ * cursor, never a live iterator). */
2879
+ listing?: ControllerListing;
2880
+ /** Whether the host will prompt. Interactive (the default) always asks;
2881
+ * non-interactive runs `tryResolveWithoutPrompt` to auto-fill what it can
2882
+ * (e.g. configured defaults) before asking for the rest. */
2883
+ interactive: boolean;
2884
+ }
2885
+ /** A location in the input tree: top-level `["app"]`, a nested object field
2886
+ * `["inputs", "channel"]`, or (later) an array item `["records", 0, "id"]`. */
2887
+ type ControllerPath = (string | number)[];
2888
+ /** Accumulated candidate items for the current dynamic parameter, plus the
2889
+ * serializable cursor for "load more" and the active search term. */
2890
+ interface ControllerListing {
2891
+ items: unknown[];
2892
+ cursor?: string;
2893
+ search?: string;
2894
+ /** True when the source reported no further pages. */
2895
+ exhausted: boolean;
2896
+ }
2897
+ /**
2898
+ * The one pluggable seam for the in-process `resolve` sugar. It receives the
2899
+ * same `{ state, result }` pair `start`/`step` return (so an answer callback
2900
+ * sees exactly what a host driving the protocol directly would) and produces
2901
+ * the next action. `result` is a question-bearing result — `ask` (the question
2902
+ * plus any prior-answer `error`) or `failed` (a lookup threw; the question
2903
+ * offers `retry`/`cancel`, `error` is the thrown value). `state` is read-only
2904
+ * context (e.g. an agent can inspect `state.resolved`); mutating it is
2905
+ * unsupported. Modality-agnostic — inquirer/DOM, an LLM agent, an auto-select
2906
+ * policy, or a test script all satisfy it. The `start`/`step` protocol needs no
2907
+ * answer callback.
2908
+ */
2909
+ type ControllerAnswerFn = (turn: {
2910
+ state: ControllerState;
2911
+ result: Extract<ControllerResult, {
2912
+ status: "ask" | "failed";
2913
+ }>;
2914
+ }) => Promise<ControllerAction>;
2915
+ /** Per-parameter metadata for reflection (agents / MCP / docs / previews). The
2916
+ * static, no-I/O view, complementing the in-the-moment `question`. */
2917
+ interface ControllerParameterDescription {
2918
+ required: boolean;
2919
+ /** True when values come from a fetch (`listItems`) rather than a static set. */
2920
+ dynamic: boolean;
2921
+ /** True when the resolver accepts a free-text search term. */
2922
+ searchable?: boolean;
2923
+ /** The field's serialized type (`z.toJSONSchema` of its input schema). Absent
2924
+ * for a dynamically-shaped field (`getProperties`) with no static schema, or
2925
+ * when the schema can't be represented as JSON Schema. zod never crosses the
2926
+ * wall; this is its plain-data projection. */
2927
+ schema?: Record<string, unknown>;
2928
+ /** Statically known labeled values, when the parameter is a fixed enum. Richer
2929
+ * than `schema.enum` (carries label/hint), so kept alongside `schema`. */
2930
+ choices?: ControllerChoice[];
2931
+ /** Sibling parameters this one depends on (`requireParameters`). A form host
2932
+ * reads this to know which fields are independent (render together) and which
2933
+ * to re-fetch when a dependency changes. */
2934
+ requireParameters?: readonly string[];
2935
+ }
2936
+ /** A method's lightweight index entry: enough to render a menu or tool list
2937
+ * without the full per-parameter detail. The list face of {@link Controller}. */
2938
+ interface ControllerMethodSummary {
2939
+ name: string;
2940
+ description?: string;
2941
+ categories?: string[];
2942
+ }
2943
+ /** A method's full static contract, serialized: its parameters as a named bag
2944
+ * (mirroring the canonical single-object input), the positional projection if
2945
+ * the surface declares one, and the output type. All plain JSON — the
2946
+ * serializable projection of the registry entry, never its live zod. */
2947
+ interface ControllerMethodDescription {
2948
+ name: string;
2949
+ description?: string;
2950
+ categories?: string[];
2951
+ /** Keyed by parameter name (the input bag's shape), not an ordered array:
2952
+ * named-first, since MCP/web/agent hosts fill named slots. Order, when it
2953
+ * matters, lives in `positional`. */
2954
+ parameters: Record<string, ControllerParameterDescription>;
2955
+ /** Ordered input keys the public surface takes as positional args, when the
2956
+ * method declares a positional projection. Absent for a pure single-bag call. */
2957
+ positional?: readonly string[];
2958
+ /** The output type (`z.toJSONSchema` of the output schema), when known. */
2959
+ output?: Record<string, unknown>;
2960
+ }
2961
+ /**
2962
+ * Drives parameter resolution over a built SDK, reading its registry for the
2963
+ * method's input schema and bound resolvers. Created from an SDK with
2964
+ * `createController(sdk)`; transport-agnostic, so a remote implementation
2965
+ * (browser → server) satisfies the same interface.
2966
+ */
2967
+ interface Controller {
2968
+ /** In-process sugar: loop `start`/`step` against an answer callback, return
2969
+ * the resolved input (ready to pass to the SDK method). Throws on cancel. */
2970
+ resolve(opts: {
2971
+ method: string;
2972
+ input?: Record<string, unknown>;
2973
+ answer: ControllerAnswerFn;
2974
+ /** Defaults to true. Pass false for an agent/headless answer callback that
2975
+ * wants configured defaults auto-filled (`tryResolveWithoutPrompt`) rather
2976
+ * than prompted. */
2977
+ interactive?: boolean;
2978
+ }): Promise<Record<string, unknown>>;
2979
+ /** Start resolving: seed from `input`, auto-resolve what needs no interaction,
2980
+ * return the first result (an `ask`, or `done`). */
2981
+ start(opts: {
2982
+ method: string;
2983
+ input?: Record<string, unknown>;
2984
+ /** Defaults to true (always prompt). Pass false for headless/agent hosts to
2985
+ * auto-fill via `tryResolveWithoutPrompt` before asking. */
2986
+ interactive?: boolean;
2987
+ }): Promise<{
2988
+ state: ControllerState;
2989
+ result: ControllerResult;
2990
+ }>;
2991
+ /** Advance with the user's action; return the next state and result. */
2992
+ step(opts: {
2993
+ state: ControllerState;
2994
+ action: ControllerAction;
2995
+ }): Promise<{
2996
+ state: ControllerState;
2997
+ result: ControllerResult;
2998
+ }>;
2999
+ /** Reflection (list): the lightweight index of every method (no I/O). The
3000
+ * `nextCursor` slot mirrors `listChoices` and leaves room for paging a future
3001
+ * dynamic/large method set; unpaged today. */
3002
+ listMethods(): {
3003
+ data: ControllerMethodSummary[];
3004
+ nextCursor?: string;
3005
+ };
3006
+ /** Reflection (item): one method's full static contract, serialized (no I/O).
3007
+ * Named `getMethod` to mirror the SDK's `getApp`/`listApps` resource pair;
3008
+ * returns the method's *description*, not the callable. */
3009
+ getMethod(opts: {
3010
+ method: string;
3011
+ }): {
3012
+ data: ControllerMethodDescription;
3013
+ };
3014
+ /** Reflection: enumerate legal values for one dynamic parameter. */
3015
+ listChoices(opts: {
3016
+ method: string;
3017
+ parameter: string;
3018
+ input?: Record<string, unknown>;
3019
+ search?: string;
3020
+ cursor?: string;
3021
+ }): Promise<{
3022
+ data: ControllerChoice[];
3023
+ nextCursor?: string;
3024
+ }>;
3025
+ }
3026
+
3027
+ /** The slice of a built SDK the driver needs: its registry accessor. */
3028
+ interface ControllerSdk {
3029
+ getRegistry: (options?: {
3030
+ package?: string;
3031
+ }) => RegistryResult;
3032
+ }
3033
+ /**
3034
+ * Build a {@link Controller} over a built SDK. Reads `sdk.getRegistry()`
3035
+ * at call time (so post-build `addPlugin` additions are visible) to find each
3036
+ * method's canonical input schema and bound resolvers, then drives the engine.
3037
+ * The SDK surface itself is untouched; this is a sibling layer.
3038
+ */
3039
+ declare function createController(sdk: ControllerSdk): Controller;
3040
+
3041
+ /**
3042
+ * Generic utility functions for creating SDK-method wrappers.
3043
+ *
3044
+ * Both `createFunction` and `createPaginatedFunction` accept the SDK
3045
+ * as a parameter and read framework state (`hooks`, `core.adaptError`)
3046
+ * live from `sdk.context.*` at method-invocation time. Plugins registered
3047
+ * after a method is built still observe and configure it; ordering of
3048
+ * plugin registration doesn't change runtime semantics. (Pagination's
3049
+ * `adaptPage` is passed in per method, not read from context.)
3050
+ */
3051
+
3052
+ /**
3053
+ * Minimal SDK shape the function wrappers accept. The wrappers only
3054
+ * touch `context.hooks` and the resolved core options, but we keep
3055
+ * `context` typed as `unknown` so any kitcore-built SDK (whose context type
3056
+ * widens unpredictably as plugins layer on) flows through without
3057
+ * upstream type narrowing. Each read inside is asserted at the use
3058
+ * site against the small slice we actually need.
3059
+ */
3060
+ type FunctionSdk = {
3061
+ context: unknown;
3062
+ };
3063
+ /**
3064
+ * Wrap a core async function with input validation, error normalization,
3065
+ * and method-call lifecycle hooks. Hooks and `adaptError` are read live
3066
+ * from `sdk.context.*` at every invocation, so a plugin registered
3067
+ * after this method is built still observes and configures it.
3068
+ *
3069
+ * @param coreFn - the underlying async function to wrap
3070
+ * @param options.sdk - the SDK (or sub-SDK view) providing `context.hooks`
3071
+ * and `context.core`
3072
+ * @param options.schema - optional Zod schema for input validation
3073
+ */
3074
+ declare function createFunction<TOptions, TResult, TSchemaOptions extends TOptions = TOptions>(coreFn: (options: TOptions) => Promise<TResult>, options: {
3075
+ sdk: FunctionSdk;
3076
+ schema?: z.ZodSchema<TSchemaOptions>;
3077
+ name?: string;
3078
+ /** Live read of the method's deprecation meta (see signalDeprecation). */
3079
+ getDeprecation?: () => FunctionDeprecation | undefined;
3080
+ }): (callOptions?: TOptions) => Promise<TResult>;
3081
+ /**
3082
+ * Higher-order function that creates a paginated function that wraps
3083
+ * results in `SdkPage<TItem>`.
3084
+ *
3085
+ * @param coreFn - Function that returns T directly or throws errors
3086
+ * @returns A function that normalizes errors and wraps results in `SdkPage`
3087
+ */
3088
+ /**
3089
+ * Extract the item type from a page handler's return shape. The handler
3090
+ * may return a flat `{ data: TItem[] }` (or single `data: TItem`), a bare
3091
+ * array, or anything else; in all cases the wrapper normalizes to
3092
+ * `SdkPage<TItem>` and this resolves the right `TItem`.
3093
+ */
3094
+ type ItemType<TResult> = TResult extends {
3095
+ data: infer TData;
3096
+ } ? TData extends readonly (infer TItem)[] ? TItem : TData : TResult extends readonly (infer TItem)[] ? TItem : TResult;
3097
+ declare function createPaginatedFunction<TUserOptions, TResponse, TItem = ItemType<TResponse>>(coreFn: (options: TUserOptions & {
3098
+ cursor?: string;
3099
+ pageSize?: number;
3100
+ }) => Promise<TResponse>, options: {
3101
+ sdk: FunctionSdk;
3102
+ schema?: z.ZodSchema<TUserOptions>;
3103
+ name?: string;
3104
+ defaultPageSize?: number;
3105
+ /**
3106
+ * Translate the handler's raw `TResponse` into `SdkPage<TItem>`. `TItem`
3107
+ * is wrapped in `NoInfer`: it is sourced from `TResponse` (via the
3108
+ * `ItemType` default), not from this adapter, which is item-agnostic (it
3109
+ * relocates the cursor; items are finalized in the handler's `data`).
3110
+ * Without `NoInfer`, a generic adapter (e.g. `<T>(r) => SdkPage<T>`)
3111
+ * would collapse `TItem` to `unknown`.
3112
+ */
3113
+ adaptPage?: (response: TResponse) => SdkPage<NoInfer<TItem>>;
3114
+ /** Live read of the method's deprecation meta (see signalDeprecation). */
3115
+ getDeprecation?: () => FunctionDeprecation | undefined;
3116
+ }): (options?: TUserOptions & {
3117
+ cursor?: string;
3118
+ pageSize?: number;
3119
+ maxItems?: number;
3120
+ }) => PaginatedSdkResult<TItem>;
3121
+
3122
+ /**
3123
+ * Register kitcore-level configuration by writing the options to
3124
+ * `context.core`; the method boundary falls back to that path when no
3125
+ * `kitcore/coreOptions` configuration value exists.
3126
+ *
3127
+ * @deprecated Inject the `CoreOptions` bag under `CORE_OPTIONS_ID` via
3128
+ * `createSdk(root, { configuration })` instead. This factory logs a runtime
3129
+ * deprecation and will be removed in a release after the warning ships.
3130
+ */
3131
+ declare function createCorePlugin(options: CoreOptions): Plugin<object, {
3132
+ context: {
3133
+ core: CoreOptions;
3134
+ };
3135
+ }>;
3136
+
3137
+ /**
3138
+ * Per-invocation scope for SDK method calls. Each top-level SDK method call
3139
+ * runs in its own AsyncLocalStorage scope (via `runInMethodScope`), isolating
3140
+ * its depth counter and any plugin-specific state from concurrent calls.
3141
+ *
3142
+ * The toolkit reserves the `depth` field; anything else on the scope is
3143
+ * opaque key/value storage that plugins can use (e.g. eventEmission stores
3144
+ * its `MethodMetadata` under its own key).
3145
+ */
3146
+ /**
3147
+ * The per-call scope object held in ALS. Toolkit owns `depth`; everything
3148
+ * else is open for plugin-specific use.
3149
+ */
3150
+ interface MethodScope {
3151
+ depth: number;
3152
+ [key: string]: unknown;
3153
+ }
3154
+ /**
3155
+ * Read the current scope object, or `undefined` if no scope is active or
3156
+ * AsyncLocalStorage isn't available. Plugins use this to read/write their
3157
+ * own scoped state under their own key.
3158
+ */
3159
+ declare function getCurrentScope(): MethodScope | undefined;
3160
+ /**
3161
+ * Current depth of the SDK method-call stack. 0 = outermost call,
3162
+ * 1+ = invoked from inside another SDK method. Returns 0 when no scope
3163
+ * is active (e.g. raw callers outside the framework).
3164
+ */
3165
+ declare function getCurrentDepth(): number;
3166
+ /**
3167
+ * True when the current call is nested inside another SDK method.
3168
+ * Preserves the legacy "no store = nested" fallback used by browser
3169
+ * builds to suppress hook firing when async_hooks isn't available.
3170
+ */
3171
+ declare function isNestedMethodCall(): boolean;
3172
+ /**
3173
+ * Run `fn` inside a new method scope. Nested invocations see an incremented
3174
+ * `depth`. When no scope store is available (e.g. browsers without
3175
+ * async_hooks), `fn` is called directly with no scope tracking.
3176
+ */
3177
+ declare function runInMethodScope<T>(fn: () => T): T;
3178
+ declare const runWithTelemetryContext: typeof runInMethodScope;
3179
+ declare const isTelemetryNested: typeof isNestedMethodCall;
3180
+
3181
+ /**
3182
+ * A typed wrapper around a single `AsyncLocalStorage` instance. Centralizes the
3183
+ * `node:async_hooks` plumbing (bundler-safe static import, browser fallback) so
3184
+ * consumers don't each hand-roll it and drift apart.
3185
+ *
3186
+ * The wrapper holds no merge or depth policy: `run` simply activates `store`
3187
+ * for the duration of `fn`, and `get` returns whatever is active. Consumers
3188
+ * layer their own semantics (e.g. depth counting, parent merging) on top.
3189
+ */
3190
+ interface AsyncContext<T> {
3191
+ /** Run `fn` with `store` active. Returns whatever `fn` returns; `fn`'s errors propagate. */
3192
+ run<R>(store: T, fn: () => R): R;
3193
+ /** The active store, or `undefined` if no scope is active or ALS is unavailable. */
3194
+ get(): T | undefined;
3195
+ /**
3196
+ * `false` only where `node:async_hooks` could not be loaded (e.g. browsers),
3197
+ * leaving the context inert. Lets callers distinguish "ALS unavailable" from
3198
+ * the also-`undefined` "ALS available but no active scope".
3199
+ */
3200
+ readonly available: boolean;
3201
+ }
3202
+ /** Create an isolated {@link AsyncContext} backed by one `AsyncLocalStorage`. */
3203
+ declare function createAsyncContext<T>(): AsyncContext<T>;
3204
+
3205
+ /**
3206
+ * Deferred form: bind a schema (and `adaptError`) once, get a reusable
3207
+ * validator. Its input is `unknown` so it can validate values wider than the
3208
+ * schema's own type (e.g. paginated options that carry cursor / pageSize
3209
+ * alongside the schema-typed fields).
3210
+ */
3211
+ declare function createValidator<TSchema extends z.ZodSchema>(schema: TSchema, { adaptError }?: {
3212
+ adaptError?: AdaptError;
3213
+ }): (input: unknown) => z.infer<TSchema>;
3214
+ /**
3215
+ * Eager form: validate `options` now and return the parsed value. The
3216
+ * `TSchemaOptions extends TOptions` generics let the call site check that the
3217
+ * value being validated matches the schema's type, which `createValidator`
3218
+ * (input `unknown`) can't.
3219
+ */
3220
+ declare const validateOptions: <TOptions, TSchemaOptions extends TOptions>(schema: z.ZodSchema<TSchemaOptions>, options: TOptions, { adaptError }?: {
3221
+ adaptError?: AdaptError;
3222
+ }) => TSchemaOptions;
3223
+
3224
+ /**
3225
+ * Translates a paginated handler's raw response into a normalized
3226
+ * `SdkPage<TItem>`. Supplied per method as the `adaptPage` on
3227
+ * `createPaginatedPluginMethod` (and forwarded to `createPaginatedFunction`).
3228
+ */
3229
+ type AdaptPage<TResponse = unknown, TItem = unknown> = (response: TResponse) => SdkPage<TItem>;
3230
+ type TPageOptions<TOptions> = TOptions extends undefined ? {
3231
+ cursor?: string;
3232
+ maxItems?: number;
3233
+ pageSize?: number;
3234
+ } : TOptions & {
3235
+ cursor?: string;
3236
+ maxItems?: number;
3237
+ pageSize?: number;
3238
+ };
3239
+ declare function decodeIncomingCursor(incoming?: string): {
3240
+ offset: number;
3241
+ cursor: string | undefined;
3242
+ };
3243
+ declare function createPrefixedCursor(prefix: string, cursor: string | undefined): string;
3244
+ declare function splitPrefixedCursor(cursor: string | undefined, prefixes?: string[]): [string | undefined, string | undefined];
3245
+ /**
3246
+ * Utility for paginating through API endpoints that return cursor-based pages.
3247
+ * Accepts and yields SDK-encoded cursor envelopes. Any incoming cursor is decoded
3248
+ * before being passed to the page function; all outgoing cursors are encoded.
3249
+ *
3250
+ * @param pageFunction - Function that fetches a single page with {data, nextCursor} structure
3251
+ * @param pageOptions - Options to pass to the page function (cursor will be managed automatically)
3252
+ * @returns Async iterator that yields pages with encoded cursors
3253
+ */
3254
+ declare function paginateMaxItems<TOptions, TPage extends {
3255
+ data: any[];
3256
+ nextCursor?: string;
3257
+ }>(pageFunction: (options: TOptions & {
3258
+ cursor?: string;
3259
+ maxItems?: number;
3260
+ pageSize?: number;
3261
+ }) => Promise<TPage>, pageOptions?: TPageOptions<TOptions>): AsyncIterableIterator<TPage>;
3262
+ declare function paginateBuffered<TOptions, TPage extends {
3263
+ data: any[];
3264
+ nextCursor?: string;
3265
+ }>(pageFunction: (options: TOptions & {
3266
+ cursor?: string;
3267
+ maxItems?: number;
3268
+ pageSize?: number;
3269
+ }) => Promise<TPage>, pageOptions?: TPageOptions<TOptions>): AsyncIterableIterator<TPage>;
3270
+ declare const paginate: typeof paginateBuffered;
3271
+ interface PaginatedResult<TItem> {
3272
+ data: TItem[];
3273
+ nextCursor?: string;
3274
+ }
3275
+ type PaginatedSource<TItem> = () => PromiseLike<PaginatedResult<TItem>> & AsyncIterable<PaginatedResult<TItem>>;
3276
+ /**
3277
+ * Concatenate multiple paginated SDK results into a single paginated stream.
3278
+ * Each source is a function returning a dual Promise+AsyncIterable (as SDK
3279
+ * paginated methods return). Sources are drained in order.
3280
+ *
3281
+ * The optional `dedupe` key extractor filters items from source N against
3282
+ * all items seen in sources 0 through N-1.
3283
+ *
3284
+ * Uses paginateBuffered internally to normalize page sizes across source
3285
+ * boundaries — e.g. if the first source only has 2 items, they'll be
3286
+ * buffered with items from the next source into a full page.
3287
+ *
3288
+ * Returns the same dual Promise+AsyncIterable shape that resolvers expect.
3289
+ */
3290
+ declare function concatPaginated<TItem>({ sources, dedupe, pageSize, }: {
3291
+ sources: PaginatedSource<TItem>[];
3292
+ dedupe?: (item: TItem) => string;
3293
+ pageSize?: number;
3294
+ }): PromiseLike<PaginatedResult<TItem>> & AsyncIterable<PaginatedResult<TItem>>;
3295
+ /**
3296
+ * Strip the PromiseLike from an async iterable, returning a plain
3297
+ * AsyncIterable. This prevents async functions from unwrapping the
3298
+ * iterable (since async only unwraps PromiseLike, not AsyncIterable).
3299
+ */
3300
+ declare function toIterable<T>(source: AsyncIterable<T>): AsyncIterable<T>;
3301
+
3302
+ /**
3303
+ * Generic string utilities used by the plugin framework.
3304
+ */
3305
+ /**
3306
+ * Converts a string to title case, handling various input formats:
3307
+ * - camelCase: "firstName" → "First Name"
3308
+ * - snake_case: "first_name" → "First Name"
3309
+ * - kebab-case: "first-name" → "First Name"
3310
+ * - mixed formats: "first_name-value" → "First Name Value"
3311
+ */
3312
+ declare function toTitleCase(input: string): string;
3313
+ /**
3314
+ * Converts a string to snake_case, handling various input formats:
3315
+ * - camelCase: "firstName" → "first_name"
3316
+ * - kebab-case: "first-name" → "first_name"
3317
+ * - title case: "First Name" → "first_name"
3318
+ * - mixed formats: "first-Name Value" → "first_name_value"
3319
+ * - starts with number: "123abc" → "_123abc"
3320
+ */
3321
+ declare function toSnakeCase(input: string): string;
3322
+
3323
+ interface DeprecationLogger {
3324
+ logDeprecation(message: string): void;
3325
+ resetDeprecationWarnings(): void;
3326
+ }
3327
+ /**
3328
+ * Create a package-tagged deprecation logger. Each logger tracks its own
3329
+ * once-per-process message Set, so package heads can keep independent warning
3330
+ * channels while sharing the implementation.
3331
+ */
3332
+ declare function createDeprecationLogger(tag: string): DeprecationLogger;
3333
+
3334
+ /**
3335
+ * Core signal machinery.
3336
+ *
3337
+ * Signals are intentional control-flow throws — not failures. They're the
3338
+ * sibling of {@link CoreError}: where an error means "something went wrong," a
3339
+ * signal means "stop and do this on purpose." The first (and currently only)
3340
+ * one is {@link CoreCancelledSignal}, thrown by `Controller.resolve` when the
3341
+ * host cancels resolution (its answer callback returned `{ type: "cancel" }`).
3342
+ *
3343
+ * Like errors, every signal is brand-stamped with {@link CORE_SIGNAL_SYMBOL} so
3344
+ * a consumer can recognize one via {@link isCoreSignal} without sharing class
3345
+ * identity — important across the bundled-vs-standalone kitcore boundary.
3346
+ */
3347
+ /**
3348
+ * Cross-package brand for kitcore signals. `Symbol.for(key)` reads the
3349
+ * engine-global registry, so the same value resolves across realms and across
3350
+ * multiple copies of kitcore. Use {@link isCoreSignal} for cross-package checks.
3351
+ */
3352
+ declare const CORE_SIGNAL_SYMBOL: unique symbol;
3353
+ /**
3354
+ * Base class for kitcore signals. A signal is intentional control flow, not an
3355
+ * error, so it does NOT extend any error hierarchy that failure-handling code
3356
+ * sweeps up via `instanceof CoreError`. Subclasses declare a stable `name` and
3357
+ * `code`. (Mirrors the head convention, e.g. zapier-sdk's `ZapierSignal`.)
3358
+ */
3359
+ declare abstract class CoreSignal extends Error {
3360
+ abstract readonly name: string;
3361
+ abstract readonly code: string;
3362
+ constructor(message?: string);
3363
+ }
3364
+ /**
3365
+ * Cross-package-safe check that `value` is a kitcore signal (an intentional
3366
+ * control-flow throw), as opposed to a real error. Survives the
3367
+ * bundled/standalone kitcore split, where `instanceof CoreSignal` may not.
3368
+ */
3369
+ declare function isCoreSignal(value: unknown): boolean;
3370
+ /**
3371
+ * Thrown by `Controller.resolve` when the host cancels resolution (the answer
3372
+ * callback returned `{ type: "cancel" }`). The lower-level `start`/`step`
3373
+ * protocol instead returns a `{ status: "cancelled" }` result, so a host
3374
+ * driving it directly never sees this throw; `resolve` raises it because its
3375
+ * contract is "the resolved input, or nothing."
3376
+ */
3377
+ declare class CoreCancelledSignal extends CoreSignal {
3378
+ readonly name = "CoreCancelledSignal";
3379
+ readonly code: "CANCELLED";
3380
+ constructor(message?: string);
3381
+ }
3382
+
3383
+ export { type AdaptError, type AdaptErrorOptions, type AdaptPage, type AggregatePlugin, type ArrayResolver$1 as ArrayResolver, type AsyncContext, type BoundFormatter, type BoundResolver, CONTEXT, CORE_ERROR_SYMBOL, CORE_OPTIONS_ID, CORE_SIGNAL_SYMBOL, type CategoryDefinition, type ConstantResolver$1 as ConstantResolver, type Controller, type ControllerAction, type ControllerAffordance, type ControllerAnswerFn, type ControllerChoice, type ControllerError, type ControllerIssue, type ControllerListing, type ControllerMethodDescription, type ControllerMethodSummary, type ControllerParameterDescription, type ControllerPath, type ControllerQuestion, type ControllerResult, type ControllerSdk, type ControllerState, type CoreApiError, CoreCancelledSignal, CoreDisposeError, CoreError, CoreErrorCode, type CoreErrorOptions, type CoreOptions, CoreSignal, type CreateSdkOptions, type DeprecatedPromptConfigChoice, type DeprecationLogger, type DeprecationWarning, type DisposeFn, type DynamicListResolver, type DynamicMember, type DynamicResolver$1 as DynamicResolver, type DynamicSearchResolver, type FieldsResolver, type FormattedItem, type Formatter, type FunctionDeprecation, type FunctionRegistryEntry, type HookPlugin, type LeafMeta, type LeafSummary, type LegacyMergePlugin, type LegacyPlugin, type ListItemsResult, type ListPromptConfig, type MethodAttachment, type MethodHooks, type MethodOverridePlugin, type MethodPlugin, type MethodScope, type Resolver as ModelResolver, type OnMethodEnd, type OnMethodEndContext, type OnMethodStart, type OnMethodStartContext, type OutputFormatter, type PaginatedSdkFunction, type PaginatedSdkResult, type Plugin, type PluginMeta, type PluginProvides, type PluginStack, type PluginSummary, type PluginSurface, type PositionalMetadata, type PromptConfig, type PromptConfigChoice, type PropertyPlugin, type RegistryResult, type RequiredSdkOf, type Resolver$1 as Resolver, type ResolverConfig, type ResolverFieldItem, type ResolverMetadata, type ResolverPromptConfig, type ResolverType, type Sdk, type SdkContext, type SdkPage, type StaticResolver$1 as StaticResolver, type ValidResolvers, addPlugin, composePlugins, concatPaginated, coreOptionsPluginRef, createAsyncContext, createController, createCoreError, createCorePlugin, createDeprecationLogger, createFunction, createPaginatedFunction, createPaginatedPluginMethod, createPluginMethod, createPluginStack, createPrefixedCursor, createSdk, createValidator, dangerousContextPlugin, declareMethod, declareOptionalProperty, declarePlugin, declareProperty, decodeIncomingCursor, defaultLogDeprecation, defineFormatter, defineHook, defineLegacyMerge, defineMethod, defineMethodOverride, definePlugin, defineProperty, defineResolver, disposeSdk, fromFunctionPlugin, getContext, getCoreErrorCause, getCoreErrorCode, getCurrentDepth, getCurrentScope, getFieldDescriptions, getOutputSchema, getRegistryPlugin, getSchemaDescription, isCoreError, isCoreSignal, isNestedMethodCall, isPositional, isTelemetryNested, omitExports, openEnum, paginate, paginateBuffered, paginateMaxItems, resolvePlugin, runInMethodScope, runWithTelemetryContext, selectExports, splitPrefixedCursor, toIterable, toSnakeCase, toTitleCase, validateOptions, withOutputSchema, withPositional, withResolver };