@zapier/kitcore 0.19.0 → 0.21.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.
package/dist/index.d.ts CHANGED
@@ -8,6 +8,139 @@ declare module "zod" {
8
8
  }
9
9
  }
10
10
 
11
+ /**
12
+ * Per-call context threaded explicitly through the method boundary in place of
13
+ * ambient AsyncLocalStorage. It carries call identity, nesting depth, and a
14
+ * per-invocation annotation bag. Because it travels as data, correlation and
15
+ * nested-call dedup work without `async_hooks` — including in browsers, where
16
+ * the old ALS store was inert and nested calls all looked top-level.
17
+ *
18
+ * Framework-neutral: heads surface `callId` under their own name (e.g. a
19
+ * correlation id) and own their annotation field names.
20
+ */
21
+ /**
22
+ * A private brand (a fresh `Symbol()`, never `Symbol.for`) makes a CallContext
23
+ * unforgeable: no outside code can name the symbol to synthesize an id-bearing
24
+ * context, and the brand never collides across bundled copies. This is the same
25
+ * unforgeability the `INTERNAL_CALL` sentinel relies on.
26
+ */
27
+ declare const CALL_CONTEXT_BRAND: unique symbol;
28
+ /**
29
+ * The per-invocation annotation bag: an open string-keyed map a head fills with
30
+ * telemetry-shaping fields (via the boundary annotator, a method's pre-run
31
+ * `annotator`, or the run bag's mid-`run` `annotate`) and reads back on the
32
+ * method-lifecycle hook context. Framework-neutral: kitcore does not know or
33
+ * constrain the keys.
34
+ */
35
+ type Annotations = Record<string, unknown>;
36
+ /**
37
+ * Origin of a call's root. `"surface"` = entered through the SDK surface, or a
38
+ * parent-less runtime delegation that still represents real user work;
39
+ * `"internal"` = a framework-internal root minted by kitcore's own machinery,
40
+ * which a head can suppress from telemetry.
41
+ */
42
+ type CallOrigin = "surface" | "internal";
43
+ interface CallContext {
44
+ /**
45
+ * Minted once at the root call; copied verbatim to every nested (child) call.
46
+ * `readonly`: method code owns only the `annotations` bag. A child copies this
47
+ * off the live parent when the delegated call fires, so mutating it mid-run
48
+ * would corrupt the child's correlation id.
49
+ */
50
+ readonly callId: string | null;
51
+ /**
52
+ * 0 at the outermost call; `parent.depth + 1` for a delegated call. `readonly`
53
+ * for the same reason as `callId` — a mutated depth would mis-nest children
54
+ * and, where ALS can't correct it (browsers), duplicate telemetry.
55
+ */
56
+ readonly depth: number;
57
+ /**
58
+ * Per-invocation scratch space. Never forwarded to callees — a child call
59
+ * gets a fresh bag — so annotations describe one method's own invocation.
60
+ * Method `run` code contributes through the run bag's `annotate` function
61
+ * rather than writing here directly; the bag reference is fixed, only its
62
+ * contents change.
63
+ */
64
+ readonly annotations: Annotations;
65
+ /**
66
+ * Origin of the call's root, copied verbatim to every child. `"surface"`
67
+ * (the default) marks a surface-origin root — a call that entered through the
68
+ * SDK surface, or a parent-less runtime delegation that still represents real
69
+ * user work (e.g. a delegation proxy reaching another method). `"internal"`
70
+ * marks a framework-internal root minted by kitcore's own build-time machinery
71
+ * (resolver/formatter/dispose/observer twins, `resolvePlugin`), which a head
72
+ * can suppress from telemetry. Orthogonal to `depth`: an internal root is
73
+ * still `depth 0`. `readonly` so a child can't inherit a mutated origin.
74
+ */
75
+ readonly callOrigin: CallOrigin;
76
+ readonly [CALL_CONTEXT_BRAND]: true;
77
+ }
78
+
79
+ /**
80
+ * Method-call lifecycle hooks. Plugins contribute `onMethodStart` and/or
81
+ * `onMethodEnd` observers, plus an optional pre-run `annotator` that returns
82
+ * fields merged into the call's annotation bag; `buildHooks` composes each
83
+ * across plugins so multiple contributors coexist. Composition is right-additive
84
+ * (newer plugins fire — and `annotator` fields win — after earlier ones); a
85
+ * method triggers the hooks only when its boundary fires them, which is every
86
+ * `item` / `list` method and any raw method that opts in.
87
+ */
88
+
89
+ interface OnMethodStartContext {
90
+ methodName: string;
91
+ args: unknown[];
92
+ isPaginated: boolean;
93
+ /**
94
+ * Depth of this method invocation in the SDK call tree. 0 = outermost
95
+ * (user-initiated) call; 1+ = called from inside another SDK method.
96
+ * Observers can use this to ignore nested calls if they only want
97
+ * top-level events.
98
+ */
99
+ depth: number;
100
+ /** The call's correlation id, copied from the per-call context; `null` where
101
+ * id minting was unavailable. */
102
+ callId: string | null;
103
+ /**
104
+ * Origin of the call's root, copied from the per-call context. `"surface"` =
105
+ * surface-origin (an SDK-surface call or a runtime delegation — real user
106
+ * work); `"internal"` = a framework-internal call minted by kitcore's own
107
+ * machinery (resolver/formatter/dispose/observer twins, `resolvePlugin`).
108
+ * Orthogonal to `depth` (an internal call is still `depth 0`); a head can drop
109
+ * internal-origin calls from telemetry.
110
+ */
111
+ callOrigin: CallOrigin;
112
+ /**
113
+ * The call's annotation bag, carried live from the per-call context. At
114
+ * `onMethodStart` it holds the early-knowable fields (boundary annotator +
115
+ * a method's pre-run `annotator`); by `onMethodEnd` any mid-`run` writes
116
+ * are visible too (same object reference throughout the call).
117
+ */
118
+ annotations: Annotations;
119
+ }
120
+ type OnMethodStart = (ctx: OnMethodStartContext) => void;
121
+ interface OnMethodEndContext extends OnMethodStartContext {
122
+ durationMs: number;
123
+ error?: Error;
124
+ }
125
+ type OnMethodEnd = (ctx: OnMethodEndContext) => void;
126
+ /**
127
+ * A composed pre-run annotator: given a call's method name and (normalized,
128
+ * pre-validation) input, it returns {@link Annotations} the boundary merges into
129
+ * the call's bag before `onMethodStart`. Unlike the `void` lifecycle observers,
130
+ * this one returns a value; composition merges the returned bags rather than
131
+ * chaining side effects. A contributor with nothing to add returns an empty bag,
132
+ * so absence is modelled by no annotator rather than an `undefined` return.
133
+ */
134
+ type ComposedAnnotator = (ctx: {
135
+ methodName: string;
136
+ input: unknown;
137
+ }) => Annotations;
138
+ interface MethodHooks {
139
+ onMethodStart?: OnMethodStart;
140
+ onMethodEnd?: OnMethodEnd;
141
+ annotator?: ComposedAnnotator;
142
+ }
143
+
11
144
  /**
12
145
  * What the framework reports about the output it produced.
13
146
  *
@@ -140,292 +273,73 @@ interface PaginatedSdkResult<TItem> extends Promise<SdkPage<TItem>> {
140
273
  type PaginatedSdkFunction<TOptions, TItem> = (options: TOptions) => PaginatedSdkResult<TItem>;
141
274
 
142
275
  /**
143
- * The external escape-hatch key for an SDK's context. A Symbol,
144
- * not a string, so it stays off the string surface (which is exactly the root's
145
- * exports) and is collision-free and clearly internal. It is attached at
146
- * runtime but kept OUT of the public SDK type (a `unique symbol` in an exported
147
- * type can't be named in a consumer's emitted `.d.ts`); reach it through the
148
- * typed `getContext(sdk)` accessor.
149
- *
150
- * `Symbol.for`, not `Symbol()`: heads bundle kitcore (tsup `noExternal`), so
151
- * an sdk built by one bundle's copy must still be readable by another copy's
152
- * `getContext` / `resolvePlugin` (e.g. a CLI sdk inspected with helpers
153
- * imported from `@zapier/zapier-sdk`). The global symbol registry makes every
154
- * copy agree on the key.
155
- */
156
- declare const CONTEXT: unique symbol;
157
-
158
- /**
159
- * Per-call context threaded explicitly through the method boundary in place of
160
- * ambient AsyncLocalStorage. It carries call identity, nesting depth, and a
161
- * per-invocation annotation bag. Because it travels as data, correlation and
162
- * nested-call dedup work without `async_hooks` — including in browsers, where
163
- * the old ALS store was inert and nested calls all looked top-level.
276
+ * Plugins with a required-parameter rename declare two schemas: a canonical one
277
+ * (new names only, carrying `.meta({ aliases })`) and a `z.union([canonical,
278
+ * deprecated])` for runtime input parsing (so callers passing old names still
279
+ * validate). The union has no object shape, so everything that reads parameter
280
+ * shape/requiredness the registry projection, generated docs, and the
281
+ * resolution planner — must read the canonical variant, not the union.
164
282
  *
165
- * Framework-neutral: heads surface `callId` under their own name (e.g. a
166
- * correlation id) and own their annotation field names.
167
- */
168
- /**
169
- * A private brand (a fresh `Symbol()`, never `Symbol.for`) makes a CallContext
170
- * unforgeable: no outside code can name the symbol to synthesize an id-bearing
171
- * context, and the brand never collides across bundled copies. This is the same
172
- * unforgeability the `INTERNAL_CALL` sentinel relies on.
173
- */
174
- declare const CALL_CONTEXT_BRAND: unique symbol;
175
- /**
176
- * The per-invocation annotation bag: an open string-keyed map a head fills with
177
- * telemetry-shaping fields (via the boundary annotator, a method's pre-run
178
- * `annotator`, or the run bag's mid-`run` `annotate`) and reads back on the
179
- * method-lifecycle hook context. Framework-neutral: kitcore does not know or
180
- * constrain the keys.
283
+ * Convention: the FIRST union variant is the canonical schema. Every plugin
284
+ * that uses unions follows this; it's explicit and needs no extra metadata.
285
+ * Runtime validation still uses the full union; only shape reading canonicalizes.
181
286
  */
182
- type Annotations = Record<string, unknown>;
287
+ declare function canonicalInputSchema(schema: z.ZodSchema | undefined): z.ZodSchema | undefined;
288
+ /** Strip optional/default/nullable wrappers to the inner schema, tracking
289
+ * whether the wrappers made the field non-required. */
290
+ declare function unwrapSchema(schema: z.ZodType): {
291
+ inner: z.ZodType;
292
+ required: boolean;
293
+ };
183
294
  /**
184
- * Origin of a call's root. `"surface"` = entered through the SDK surface, or a
185
- * parent-less runtime delegation that still represents real user work;
186
- * `"internal"` = a framework-internal root minted by kitcore's own machinery,
187
- * which a head can suppress from telemetry.
295
+ * The object shape of a method's input schema, or undefined when the schema is
296
+ * absent or not a plain object. A required-rename union (`z.union([canonical,
297
+ * deprecated])`) is canonicalized to its first variant first, and
298
+ * optional/default/nullable wrappers are stripped, so a schema whose fields are
299
+ * readable at all is read rather than treated as shapeless.
188
300
  */
189
- type CallOrigin = "surface" | "internal";
190
- interface CallContext {
191
- /**
192
- * Minted once at the root call; copied verbatim to every nested (child) call.
193
- * `readonly`: method code owns only the `annotations` bag. A child copies this
194
- * off the live parent when the delegated call fires, so mutating it mid-run
195
- * would corrupt the child's correlation id.
196
- */
197
- readonly callId: string | null;
301
+ declare function objectShapeOf(schema: z.ZodSchema | undefined): Record<string, z.ZodType> | undefined;
302
+ interface FormattedItem {
303
+ title: string;
198
304
  /**
199
- * 0 at the outermost call; `parent.depth + 1` for a delegated call. `readonly`
200
- * for the same reason as `callId` a mutated depth would mis-nest children
201
- * and, where ALS can't correct it (browsers), duplicate telemetry.
305
+ * Secondary identifying context shown dimmed after the title (ids, keys,
306
+ * slugs, ...). A dumb visual string a renderer shows verbatim, never
307
+ * structured data it has to interpret; the same role as a prompt choice's
308
+ * `hint`. An array is joined with ", ". Structured fields live on the
309
+ * response / `outputSchema`, not here, so the renderer stays dumb.
202
310
  */
203
- readonly depth: number;
311
+ hint?: string | string[];
312
+ /** @deprecated Use `hint` (the renderer no longer interprets ids). */
313
+ id?: string;
314
+ /** @deprecated Use `hint`. */
315
+ key?: string;
316
+ /** @deprecated Use `hint`. */
317
+ keys?: string[];
318
+ description?: string;
319
+ /** If provided, the renderer shows this raw (verbatim) instead of `details`. */
320
+ raw?: unknown;
321
+ details: Array<{
322
+ label?: string;
323
+ text: string;
324
+ style: "normal" | "dim" | "accent" | "warning" | "success";
325
+ }>;
326
+ }
327
+ declare function getOutputSchema(inputSchema: z.ZodType): z.ZodType | undefined;
328
+ declare function withOutputSchema<T extends z.ZodType>(inputSchema: T, outputSchema: z.ZodType): T & {
329
+ _def: T["_def"] & {
330
+ outputSchema: z.ZodType;
331
+ };
332
+ };
333
+ /** A selectable option in a prompt. `label` is the display text; `value` is
334
+ * what the resolver returns when picked. */
335
+ interface PromptConfigChoice {
336
+ label: string;
337
+ value: unknown;
204
338
  /**
205
- * Per-invocation scratch space. Never forwarded to callees a child call
206
- * gets a fresh bag so annotations describe one method's own invocation.
207
- * Method `run` code contributes through the run bag's `annotate` function
208
- * rather than writing here directly; the bag reference is fixed, only its
209
- * contents change.
210
- */
211
- readonly annotations: Annotations;
212
- /**
213
- * Origin of the call's root, copied verbatim to every child. `"surface"`
214
- * (the default) marks a surface-origin root — a call that entered through the
215
- * SDK surface, or a parent-less runtime delegation that still represents real
216
- * user work (e.g. a delegation proxy reaching another method). `"internal"`
217
- * marks a framework-internal root minted by kitcore's own build-time machinery
218
- * (resolver/formatter/dispose/observer twins, `resolvePlugin`), which a head
219
- * can suppress from telemetry. Orthogonal to `depth`: an internal root is
220
- * still `depth 0`. `readonly` so a child can't inherit a mutated origin.
221
- */
222
- readonly callOrigin: CallOrigin;
223
- readonly [CALL_CONTEXT_BRAND]: true;
224
- }
225
-
226
- /**
227
- * Method-call lifecycle hooks. Plugins contribute `onMethodStart` and/or
228
- * `onMethodEnd` observers, plus an optional pre-run `annotator` that returns
229
- * fields merged into the call's annotation bag; `buildHooks` composes each
230
- * across plugins so multiple contributors coexist. Composition is right-additive
231
- * (newer plugins fire — and `annotator` fields win — after earlier ones); only
232
- * opt-in methods built through `createPluginMethod` /
233
- * `createPaginatedPluginMethod` trigger the hooks.
234
- */
235
-
236
- interface OnMethodStartContext {
237
- methodName: string;
238
- args: unknown[];
239
- isPaginated: boolean;
240
- /**
241
- * Depth of this method invocation in the SDK call tree. 0 = outermost
242
- * (user-initiated) call; 1+ = called from inside another SDK method.
243
- * Observers can use this to ignore nested calls if they only want
244
- * top-level events.
245
- */
246
- depth: number;
247
- /** The call's correlation id, copied from the per-call context; `null` where
248
- * id minting was unavailable. */
249
- callId: string | null;
250
- /**
251
- * Origin of the call's root, copied from the per-call context. `"surface"` =
252
- * surface-origin (an SDK-surface call or a runtime delegation — real user
253
- * work); `"internal"` = a framework-internal call minted by kitcore's own
254
- * machinery (resolver/formatter/dispose/observer twins, `resolvePlugin`).
255
- * Orthogonal to `depth` (an internal call is still `depth 0`); a head can drop
256
- * internal-origin calls from telemetry.
257
- */
258
- callOrigin: CallOrigin;
259
- /**
260
- * The call's annotation bag, carried live from the per-call context. At
261
- * `onMethodStart` it holds the early-knowable fields (boundary annotator +
262
- * a method's pre-run `annotator`); by `onMethodEnd` any mid-`run` writes
263
- * are visible too (same object reference throughout the call).
264
- */
265
- annotations: Annotations;
266
- }
267
- type OnMethodStart = (ctx: OnMethodStartContext) => void;
268
- interface OnMethodEndContext extends OnMethodStartContext {
269
- durationMs: number;
270
- error?: Error;
271
- }
272
- type OnMethodEnd = (ctx: OnMethodEndContext) => void;
273
- /**
274
- * A composed pre-run annotator: given a call's method name and (normalized,
275
- * pre-validation) input, it returns {@link Annotations} the boundary merges into
276
- * the call's bag before `onMethodStart`. Unlike the `void` lifecycle observers,
277
- * this one returns a value; composition merges the returned bags rather than
278
- * chaining side effects. A contributor with nothing to add returns an empty bag,
279
- * so absence is modelled by no annotator rather than an `undefined` return.
280
- */
281
- type ComposedAnnotator = (ctx: {
282
- methodName: string;
283
- input: unknown;
284
- }) => Annotations;
285
- interface MethodHooks {
286
- onMethodStart?: OnMethodStart;
287
- onMethodEnd?: OnMethodEnd;
288
- annotator?: ComposedAnnotator;
289
- }
290
-
291
- /**
292
- * API stability tiers.
293
- *
294
- * A plugin declares exactly one level via `PluginMeta.stability`; tier
295
- * membership (which subpath aggregate exports the plugin) is structural,
296
- * so nothing here compares levels ordinally. The array is the single
297
- * source of truth: it derives the {@link StabilityLevel} type, gives the
298
- * ladder tests their adjacent-tier iteration order, and gives docs a
299
- * render order.
300
- */
301
- declare const STABILITY_LEVELS: readonly ["stable", "beta", "experimental"];
302
- type StabilityLevel = (typeof STABILITY_LEVELS)[number];
303
- /**
304
- * Title-case display names for each level, for section-level badges in
305
- * generated docs (e.g. `Code Workflows (Beta)`). Inline description
306
- * labels go through {@link applyStabilityLabel} instead.
307
- */
308
- declare const STABILITY_TITLES: {
309
- readonly stable: "Stable";
310
- readonly beta: "Beta";
311
- readonly experimental: "Experimental";
312
- };
313
- /**
314
- * Normalize authored meta to a concrete level: absent means `"stable"`,
315
- * and the deprecated `experimental: true` boolean means `"experimental"`.
316
- * The registry projection runs every entry through this, so
317
- * `FunctionRegistryEntry.stability` is always concrete and consumers
318
- * never branch on `undefined`.
319
- *
320
- * The declared value can cross a JSON boundary from a hand-written
321
- * plugin, so at runtime it may be any string. An unrecognized level
322
- * clamps to `"experimental"` — the author declared the method not
323
- * stable, and clamping keeps the raw string out of notices and labels.
324
- * It doesn't throw because this also runs in the `getStability` live
325
- * read on the call path, where a throw would break the observed call.
326
- */
327
- declare function normalizeStability(meta: {
328
- stability?: StabilityLevel;
329
- experimental?: boolean;
330
- }): StabilityLevel;
331
- /**
332
- * The shared label renderer: every consumer that renders a registry
333
- * entry's description (CLI help, MCP tool descriptions) labels it
334
- * through this function, so a new consumer cannot silently drop the
335
- * label. `stability` stays structured data on the registry entry — the
336
- * label is applied at render time, never baked into the stored
337
- * description (docs badge at the section level, so baking it in would
338
- * double-badge).
339
- *
340
- * The label follows the plugin's declared level, not the subpath that
341
- * surfaced it: a beta method surfaced through an experimental-tier
342
- * consumer still reads "(beta)".
343
- */
344
- declare function applyStabilityLabel({ description, stability, placement, }: {
345
- description: string;
346
- /** Absent means stable (the value may arrive from outside the
347
- * normalized registry projection, e.g. hand-built JSON). */
348
- stability: StabilityLevel | undefined;
349
- /**
350
- * `"suffix"` renders `<description> (beta)` (CLI help);
351
- * `"prefix"` renders `[Beta] <description>` (MCP tool descriptions,
352
- * where the front of the string is what an LLM reads first).
353
- */
354
- placement?: "suffix" | "prefix";
355
- }): string;
356
-
357
- /**
358
- * Plugins with a required-parameter rename declare two schemas: a canonical one
359
- * (new names only, carrying `.meta({ aliases })`) and a `z.union([canonical,
360
- * deprecated])` for runtime input parsing (so callers passing old names still
361
- * validate). The union has no object shape, so everything that reads parameter
362
- * shape/requiredness — the registry projection, generated docs, and the
363
- * resolution planner — must read the canonical variant, not the union.
364
- *
365
- * Convention: the FIRST union variant is the canonical schema. Every plugin
366
- * that uses unions follows this; it's explicit and needs no extra metadata.
367
- * Runtime validation still uses the full union; only shape reading canonicalizes.
368
- */
369
- declare function canonicalInputSchema(schema: z.ZodSchema | undefined): z.ZodSchema | undefined;
370
- /** Strip optional/default/nullable wrappers to the inner schema, tracking
371
- * whether the wrappers made the field non-required. */
372
- declare function unwrapSchema(schema: z.ZodType): {
373
- inner: z.ZodType;
374
- required: boolean;
375
- };
376
- /**
377
- * The object shape of a method's input schema, or undefined when the schema is
378
- * absent or not a plain object. A required-rename union (`z.union([canonical,
379
- * deprecated])`) is canonicalized to its first variant first, and
380
- * optional/default/nullable wrappers are stripped, so a schema whose fields are
381
- * readable at all is read rather than treated as shapeless.
382
- */
383
- declare function objectShapeOf(schema: z.ZodSchema | undefined): Record<string, z.ZodType> | undefined;
384
- interface FormattedItem {
385
- title: string;
386
- /**
387
- * Secondary identifying context shown dimmed after the title (ids, keys,
388
- * slugs, ...). A dumb visual string a renderer shows verbatim, never
389
- * structured data it has to interpret; the same role as a prompt choice's
390
- * `hint`. An array is joined with ", ". Structured fields live on the
391
- * response / `outputSchema`, not here, so the renderer stays dumb.
392
- */
393
- hint?: string | string[];
394
- /** @deprecated Use `hint` (the renderer no longer interprets ids). */
395
- id?: string;
396
- /** @deprecated Use `hint`. */
397
- key?: string;
398
- /** @deprecated Use `hint`. */
399
- keys?: string[];
400
- description?: string;
401
- /** If provided, the renderer shows this raw (verbatim) instead of `details`. */
402
- raw?: unknown;
403
- details: Array<{
404
- label?: string;
405
- text: string;
406
- style: "normal" | "dim" | "accent" | "warning" | "success";
407
- }>;
408
- }
409
- interface OutputFormatter<TSdk, TItem = unknown, TParams = Record<string, unknown>, TContext = unknown> {
410
- fetch?: (sdk: TSdk, params: TParams, item: TItem, context: TContext | undefined) => Promise<TContext>;
411
- format: (item: TItem, context?: TContext) => FormattedItem;
412
- }
413
- declare function getOutputSchema(inputSchema: z.ZodType): z.ZodType | undefined;
414
- declare function withOutputSchema<T extends z.ZodType>(inputSchema: T, outputSchema: z.ZodType): T & {
415
- _def: T["_def"] & {
416
- outputSchema: z.ZodType;
417
- };
418
- };
419
- /** A selectable option in a prompt. `label` is the display text; `value` is
420
- * what the resolver returns when picked. */
421
- interface PromptConfigChoice {
422
- label: string;
423
- value: unknown;
424
- /**
425
- * Optional secondary info shown after the label. The CLI wraps it in
426
- * dimmed parens; an array is joined with ", ". Use for keys, ids, or
427
- * other context that's useful but shouldn't compete visually with
428
- * the primary label.
339
+ * Optional secondary info shown after the label. The CLI wraps it in
340
+ * dimmed parens; an array is joined with ", ". Use for keys, ids, or
341
+ * other context that's useful but shouldn't compete visually with
342
+ * the primary label.
429
343
  */
430
344
  hint?: string | string[];
431
345
  }
@@ -681,69 +595,288 @@ declare function openEnum<const T extends readonly [string, ...string[]]>(values
681
595
  }>, z.ZodString]>;
682
596
 
683
597
  /**
684
- * Descriptive metadata a leaf carries for the registry / CLI / MCP / docs:
685
- * description, categories, type, formatter, resolvers, etc.
686
- * Reuses the shipped `PluginMeta` minus `inputSchema`, which is a first-class
687
- * descriptor field (it also drives `input` typing and runtime validation).
598
+ * The external escape-hatch key for an SDK's context. A Symbol,
599
+ * not a string, so it stays off the string surface (which is exactly the root's
600
+ * exports) and is collision-free and clearly internal. It is attached at
601
+ * runtime but kept OUT of the public SDK type (a `unique symbol` in an exported
602
+ * type can't be named in a consumer's emitted `.d.ts`); reach it through the
603
+ * typed `getContext(sdk)` accessor.
604
+ *
605
+ * `Symbol.for`, not `Symbol()`: heads bundle kitcore (tsup `noExternal`), so
606
+ * an sdk built by one bundle's copy must still be readable by another copy's
607
+ * `getContext` / `resolvePlugin` (e.g. a CLI sdk inspected with helpers
608
+ * imported from `@zapier/zapier-sdk`). The global symbol registry makes every
609
+ * copy agree on the key.
688
610
  */
689
- type LeafMeta = Omit<PluginMeta, "inputSchema">;
611
+ declare const CONTEXT: unique symbol;
612
+
690
613
  /**
691
- * The descriptive registry fields a `defineMethod` / `defineProperty` author
692
- * sets directly on the config (hoisted, not nested under a `meta` wrapper).
693
- * The impl folds whichever are present back into the stored `LeafMeta`. This is
694
- * the strict, explicit subset of `PluginMeta` (no `[key: string]: any` escape
695
- * hatch, no `inputSchema` / `formatter` / `resolvers` those are first-class
696
- * config fields of their own).
614
+ * API stability tiers.
615
+ *
616
+ * A plugin declares exactly one level via `MethodMeta.stability`; tier
617
+ * membership (which subpath aggregate exports the plugin) is structural,
618
+ * so nothing here compares levels ordinally. The array is the single
619
+ * source of truth: it derives the {@link StabilityLevel} type, gives the
620
+ * ladder tests their adjacent-tier iteration order, and gives docs a
621
+ * render order.
697
622
  */
698
- interface LeafMetaFields {
699
- description?: string;
700
- categories?: (string | CategoryDefinition)[];
701
- type?: "list" | "item" | "create" | "update" | "delete" | "function";
702
- itemType?: string;
703
- returnType?: string;
704
- outputSchema?: z.ZodSchema;
705
- /** Behavioral opt-out that rides on this config for every `defineMethod`
706
- * overload (all merge `LeafMetaFields`), the partner of `outputSchema`: when
707
- * true, the materializer skips validating/stripping the output. It is
708
- * consumed at build time and stored as a first-class plugin field, NOT folded
709
- * into the projected meta (hence absent from `LEAF_META_KEYS`), so it stays
710
- * off the registry / CLI / MCP surface, exactly like `skipInputValidation`. */
711
- skipOutputValidation?: boolean;
712
- packages?: string[];
713
- stability?: StabilityLevel;
714
- /** @deprecated Use `stability: "experimental"` instead. */
715
- experimental?: boolean;
716
- confirm?: "create-secret" | "delete";
717
- deprecation?: FunctionDeprecation;
718
- aliases?: Record<string, string>;
719
- supportsJsonOutput?: boolean;
720
- }
623
+ declare const STABILITY_LEVELS: readonly ["stable", "beta", "experimental"];
624
+ type StabilityLevel = (typeof STABILITY_LEVELS)[number];
721
625
  /**
722
- * The meta an override may patch onto an already-built method.
723
- *
724
- * An allow-list, so a field added to {@link LeafMetaFields} later is refused
725
- * until someone decides it is safe. Naming the dangerous fields instead would
726
- * hand every future field to overrides by default, and the default has to be
727
- * the safe one: an override changes how a surface PRESENTS a method, never what
728
- * runs, what input is accepted, or what safety gate fires. Nothing re-checks
729
- * the method's declared TypeScript type after `defineMethod` fixes it.
730
- *
731
- * What that rule rules out, and why each is dangerous rather than merely
732
- * unused:
733
- *
734
- * - `outputSchema` decides what output validation enforces. Patching it makes
735
- * a call fail against a contract its own return type says it satisfies.
736
- * - `confirm` gates a host's confirmation prompt. Patching it can drop the
737
- * prompt in front of a destructive call.
626
+ * Title-case display names for each level, for section-level badges in
627
+ * generated docs (e.g. `Code Workflows (Beta)`). Inline description
628
+ * labels go through {@link applyStabilityLabel} instead.
629
+ */
630
+ declare const STABILITY_TITLES: {
631
+ readonly stable: "Stable";
632
+ readonly beta: "Beta";
633
+ readonly experimental: "Experimental";
634
+ };
635
+ /**
636
+ * Normalize authored meta to a concrete level: absent means `"stable"`,
637
+ * and the deprecated `experimental: true` boolean means `"experimental"`.
638
+ * The registry projection runs every entry through this, so
639
+ * `FunctionRegistryEntry.stability` is always concrete and consumers
640
+ * never branch on `undefined`.
641
+ *
642
+ * The declared value can cross a JSON boundary from a hand-written
643
+ * plugin, so at runtime it may be any string. An unrecognized level
644
+ * clamps to `"experimental"` — the author declared the method not
645
+ * stable, and clamping keeps the raw string out of notices and labels.
646
+ * It doesn't throw because this also runs in the `getStability` live
647
+ * read on the call path, where a throw would break the observed call.
648
+ */
649
+ declare function normalizeStability(meta: {
650
+ stability?: StabilityLevel;
651
+ experimental?: boolean;
652
+ }): StabilityLevel;
653
+ /**
654
+ * The shared label renderer: every consumer that renders a registry
655
+ * entry's description (CLI help, MCP tool descriptions) labels it
656
+ * through this function, so a new consumer cannot silently drop the
657
+ * label. `stability` stays structured data on the registry entry — the
658
+ * label is applied at render time, never baked into the stored
659
+ * description (docs badge at the section level, so baking it in would
660
+ * double-badge).
661
+ *
662
+ * The label follows the plugin's declared level, not the subpath that
663
+ * surfaced it: a beta method surfaced through an experimental-tier
664
+ * consumer still reads "(beta)".
665
+ */
666
+ declare function applyStabilityLabel({ description, stability, placement, }: {
667
+ description: string;
668
+ /** Absent means stable (the value may arrive from outside the
669
+ * normalized registry projection, e.g. hand-built JSON). */
670
+ stability: StabilityLevel | undefined;
671
+ /**
672
+ * `"suffix"` renders `<description> (beta)` (CLI help);
673
+ * `"prefix"` renders `[Beta] <description>` (MCP tool descriptions,
674
+ * where the front of the string is what an LLM reads first).
675
+ */
676
+ placement?: "suffix" | "prefix";
677
+ }): string;
678
+
679
+ /**
680
+ * Declaration for a registry category (a bucket grouping related functions).
681
+ * Plugins reference categories in their `meta.categories` field, as either a
682
+ * bare key (auto-derive title and plural) or this object (override either).
683
+ *
684
+ * Examples (with auto-derive rules):
685
+ * - `{ key: "app" }` → title "App", plural "Apps"
686
+ * - `{ key: "client-credentials" }` → title "Client Credentials", plural "Client Credentials"
687
+ * - `{ key: "utility" }` → title "Utility", plural "Utilities"
688
+ * - `{ key: "http", title: "HTTP Request" }` → plural "HTTP Requests"
689
+ */
690
+ interface CategoryDefinition {
691
+ key: string;
692
+ /** Display title for the category. Auto-derived from `key` if omitted. */
693
+ title?: string;
694
+ /** Plural form of `title`. Auto-derived from the resolved title if omitted. */
695
+ titlePlural?: string;
696
+ }
697
+ interface FunctionRegistryEntry {
698
+ name: string;
699
+ /**
700
+ * Human-readable description of the function. Surfaced wherever the
701
+ * registry is consumed (command help, tool/RPC descriptions, generated
702
+ * documentation). Prefer providing this directly rather than relying
703
+ * solely on inputSchema.describe().
704
+ */
705
+ description?: string;
706
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
707
+ itemType?: string;
708
+ returnType?: string;
709
+ inputSchema?: z.ZodSchema;
710
+ /**
711
+ * When true, the method owns its input validation and its boundary passes the
712
+ * input through unparsed. The resolution controller reads this to skip its
713
+ * final `safeParse` (it still uses `inputSchema` to plan/prompt parameters),
714
+ * so a method routed through the controller isn't re-validated against a
715
+ * schema it deliberately opts out of. Lifted off the materialized entry.
716
+ */
717
+ skipInputValidation?: boolean;
718
+ outputSchema?: z.ZodSchema;
719
+ /**
720
+ * Ordered input keys the public surface projects onto positional arguments
721
+ * (the method's `positional` declaration). Absent when the method takes only
722
+ * the canonical single bag. Lifted off the materialized method entry by the
723
+ * surface builder, like `resolvers` — a runtime projection, not
724
+ * descriptive meta.
725
+ */
726
+ positional?: readonly string[];
727
+ categories: string[];
728
+ /**
729
+ * Per-parameter bound resolvers (imports already captured, called with
730
+ * `input` only, no sdk). Lifted off the materialized method entry by the
731
+ * surface builder.
732
+ */
733
+ resolvers?: Record<string, BoundResolver>;
734
+ packages?: string[];
735
+ /**
736
+ * API stability tier of the plugin, normalized from `MethodMeta.stability`
737
+ * (absent means `"stable"`; the legacy `experimental: true` boolean means
738
+ * `"experimental"`). Always concrete here, so consumers never branch on
739
+ * `undefined`.
740
+ */
741
+ stability: StabilityLevel;
742
+ /**
743
+ * @deprecated Read `stability` instead. Derived as
744
+ * `stability === "experimental"` — literal by name, so beta reads
745
+ * `false`; the not-stable warning duty lives in `stability` and the
746
+ * runtime stability notice.
747
+ */
748
+ experimental?: boolean;
749
+ /** Confirmation prompt type - prompts user before executing */
750
+ confirm?: "create-secret" | "delete";
751
+ /**
752
+ * Optional deprecation metadata for commands.
753
+ */
754
+ deprecation?: FunctionDeprecation;
755
+ /**
756
+ * Short aliases for parameter names (e.g., { request: "X", header: "H" }).
757
+ * Consumers that render the function as a flag-style command surface use
758
+ * these as short forms.
759
+ */
760
+ aliases?: Record<string, string>;
761
+ /**
762
+ * Output formatter, normalized to the bound runtime shape (its imports
763
+ * already captured), so consumers call `getContext`/`format` with no sdk.
764
+ * The surface builder lifts this off the method entry, where `defineFormatter`
765
+ * bound it at materialization.
766
+ */
767
+ formatter?: BoundFormatter;
768
+ /** Defaults to true. Set to false to suppress --json (e.g. login/logout/init). */
769
+ supportsJsonOutput: boolean;
770
+ }
771
+ interface FunctionDeprecation {
772
+ /** User-facing deprecation message for why/how to migrate */
773
+ message: string;
774
+ }
775
+ interface RegistryResult {
776
+ functions: FunctionRegistryEntry[];
777
+ categories: {
778
+ key: string;
779
+ title: string;
780
+ titlePlural: string;
781
+ functions: string[];
782
+ }[];
783
+ }
784
+
785
+ /**
786
+ * ------------------------------
787
+ * Plugin Metadata
788
+ * ------------------------------
789
+ *
790
+ * The description fields a method or property carries for the registry, the
791
+ * CLI, MCP, and the docs generators. An author sets them directly on a
792
+ * `defineMethod` / `defineProperty` config, the descriptor carries them as its
793
+ * own fields, a `defineOverride` patches a subset onto the entry, and the
794
+ * registry projection merges the two.
795
+ * Nothing here changes what a method does. The two schemas are not here: they
796
+ * drive typing and validation, so they are fields of the method itself.
797
+ */
798
+
799
+ interface PropertyMeta {
800
+ /**
801
+ * Human-readable description. Used by the CLI (help text), MCP (tool
802
+ * description), and README generators. For a method, falls back to the
803
+ * inputSchema's `.describe()` value when omitted.
804
+ */
805
+ description?: string;
806
+ /**
807
+ * Buckets this plugin belongs to in `getRegistry()` output. Each entry is
808
+ * either a bare key (`"app"`) for auto-derived titles or a {@link CategoryDefinition}
809
+ * object to override the title or plural. Only one plugin needs to supply
810
+ * the object form per category key; object refs win over string refs, so
811
+ * other plugins in the same bucket can stay on bare strings.
812
+ */
813
+ categories?: (string | CategoryDefinition)[];
814
+ /** Which package surfaces (`"sdk"`, `"cli"`, `"mcp"`) include it. */
815
+ packages?: string[];
816
+ /**
817
+ * API stability tier this plugin belongs to. Absent means `"stable"`;
818
+ * the registry projection normalizes it, so registry consumers always
819
+ * read a concrete {@link StabilityLevel}. Wrappers keep non-stable
820
+ * plugins out of their stable build (by gating them behind a `beta` /
821
+ * `experimental` subpath import) and consumers badge the level in
822
+ * generated docs, CLI help, and MCP tool descriptions. No runtime
823
+ * capability check.
824
+ */
825
+ stability?: StabilityLevel;
826
+ /**
827
+ * @deprecated Use `stability: "experimental"` instead. Kept as an
828
+ * input for external authors; `true` normalizes to
829
+ * `stability: "experimental"` in the registry projection.
830
+ */
831
+ experimental?: boolean;
832
+ deprecation?: FunctionDeprecation;
833
+ }
834
+ /**
835
+ * A method's description fields: everything a property has, plus what only a
836
+ * callable can carry. A `defineOverride` patches the safe subset of these, see
837
+ * `OverridableMetaFields`.
838
+ */
839
+ interface MethodMeta extends PropertyMeta {
840
+ type?: "list" | "item" | "create" | "update" | "delete" | "function";
841
+ itemType?: string;
842
+ returnType?: string;
843
+ /** Confirmation prompt type - prompts user before executing */
844
+ confirm?: "create-secret" | "delete";
845
+ /** Parameter name to CLI flag name. */
846
+ aliases?: Record<string, string>;
847
+ supportsJsonOutput?: boolean;
848
+ }
849
+ /** @deprecated Use {@link MethodMeta} or {@link PropertyMeta}. */
850
+ type PluginMeta = MethodMeta;
851
+
852
+ /** @deprecated Use {@link MethodMeta} or {@link PropertyMeta}. */
853
+ type LeafMeta = MethodMeta;
854
+ /**
855
+ * The description fields an override may patch onto an already-built method.
856
+ * One list serves both sides: `defineOverride` refuses any other key at
857
+ * runtime, and `OverridableMetaFields` is derived from it, so the type and the
858
+ * runtime guard cannot drift.
859
+ *
860
+ * An allow-list, so a field added to {@link MethodMeta} later is refused
861
+ * until someone decides it is safe. Naming the dangerous fields instead would
862
+ * hand every future field to overrides by default, and the default has to be
863
+ * the safe one: an override changes how a surface PRESENTS a method, never what
864
+ * runs, what input is accepted, or what safety gate fires. Nothing re-checks
865
+ * the method's declared TypeScript type after `defineMethod` fixes it.
866
+ *
867
+ * What that rule rules out, and why each is dangerous rather than merely
868
+ * unused:
869
+ *
870
+ * - `confirm` gates a host's confirmation prompt. Patching it can drop the
871
+ * prompt in front of a destructive call.
738
872
  * - `type` reaches `confirm` indirectly: the registry derives
739
873
  * `confirm: m.confirm ?? (m.type === "delete" ? "delete" : undefined)`, so
740
874
  * moving a method off `"delete"` removes the same prompt quietly.
741
875
  * - `aliases` maps a parameter to a CLI flag, so patching it changes which
742
876
  * input a caller can pass.
743
- * - `skipOutputValidation` is already unreachable, being absent from
744
- * `LEAF_META_KEYS` and never folded into the projected meta.
745
877
  */
746
- type OverridableMetaFields = Pick<LeafMetaFields, "description" | "categories" | "itemType" | "returnType" | "packages" | "experimental" | "deprecation" | "supportsJsonOutput">;
878
+ declare const OVERRIDABLE_META_KEYS: readonly ["description", "categories", "itemType", "returnType", "packages", "experimental", "deprecation", "supportsJsonOutput"];
879
+ type OverridableMetaFields = Pick<MethodMeta, (typeof OVERRIDABLE_META_KEYS)[number]>;
747
880
  /** One segment of a {@link DynamicMember} path: a literal binding/segment name,
748
881
  * or a `{ param }` placeholder for an open-ended key (rendered `{param}`). */
749
882
  type DynamicMemberSegment = string | {
@@ -754,22 +887,25 @@ type DynamicMemberSegment = string | {
754
887
  * (e.g. `apps.{appKey}.{actionType}.{actionKey}`), backed at runtime by a proxy.
755
888
  * It is a bodyless declaration — the same descriptive fields an author sets on a
756
889
  * leaf, keyed by a `path` instead of a `name`. The framework derives the
757
- * registry name by joining the path (params rendered `{param}`) and folds these
758
- * fields into a `PluginMeta` for the registry / CLI / MCP / docs projection.
890
+ * registry name by joining the path (params rendered `{param}`) and projects
891
+ * these fields into the registry / CLI / MCP / docs like a method's.
759
892
  * `path[0]` must be a literal that resolves to a real surfaced binding (the
760
893
  * owning member).
761
894
  */
762
895
  type DynamicMember = {
763
896
  path: readonly DynamicMemberSegment[];
764
- /** Projection-only input schema (no runtime; the proxy validates its own). */
897
+ /** Projection-only schemas (no runtime; the proxy validates its own). */
765
898
  inputSchema?: z.ZodType;
766
- } & LeafMetaFields;
899
+ outputSchema?: z.ZodSchema;
900
+ } & MethodMeta;
767
901
  /** A {@link DynamicMember} normalized at define time: the derived registry name,
768
- * the literal root segment (validated against the surface), and the folded meta. */
769
- interface NormalizedDynamicMember {
902
+ * the literal root segment (validated against the surface), and its description. */
903
+ interface NormalizedDynamicMember extends MethodMeta {
770
904
  name: string;
771
905
  rootBinding: string;
772
- meta: PluginMeta;
906
+ /** Projection-only, like the schemas a method entry carries. */
907
+ inputSchema?: z.ZodType;
908
+ outputSchema?: z.ZodSchema;
773
909
  }
774
910
  type AnyMethodPlugin = MethodPlugin<string, any, any, readonly string[]>;
775
911
  type AnyPropertyPlugin = PropertyPlugin<string, any>;
@@ -781,7 +917,7 @@ type AnyLeafPlugin = AnyMethodPlugin | AnyPropertyPlugin;
781
917
  * `selectExports(...)` element contributes its chosen bindings. To rename or
782
918
  * subset, wrap an element in `selectExports`; there is no alias-map form.
783
919
  */
784
- type ImportsInput = readonly AnyPlugin[];
920
+ type ImportsInput = readonly Plugin[];
785
921
  /** A resolved import edge: the local binding name and the plugin id it reads
786
922
  * from `context.plugins` (id, not identity, so a swap stays transparent). */
787
923
  interface ImportBinding {
@@ -838,7 +974,7 @@ type SurfaceCall<TInput, TOutput, TPositional extends readonly string[]> = TPosi
838
974
  * its own name (method callable or property value), an aggregate under each of
839
975
  * its export names — exactly the dependency's {@link PluginSurface}.
840
976
  */
841
- type BindingsOf<TDep extends AnyPlugin> = PluginSurface<TDep>;
977
+ type BindingsOf<TDep extends Plugin> = PluginSurface<TDep>;
842
978
  /**
843
979
  * The `imports` a body receives. Each element contributes its bindings
844
980
  * (`BindingsOf`); empty imports yield an empty object.
@@ -888,7 +1024,7 @@ type HookAnnotator<TState = unknown> = (bag: {
888
1024
  /** Shared plumbing for the method attachments: each declares its own
889
1025
  * dependencies. Resolvers and formatters are otherwise separate concepts. */
890
1026
  interface MethodAttachment {
891
- imports: readonly AnyPlugin[];
1027
+ imports: readonly Plugin[];
892
1028
  /** Binding-name to plugin-id edges, normalized from `imports`; what the
893
1029
  * narrowed bag captured at materialization is built from. */
894
1030
  importBindings: readonly ImportBinding[];
@@ -1261,29 +1397,43 @@ interface BoundFormatter<TItem = unknown, TInput = Record<string, unknown>, TCon
1261
1397
  * `run` is loosely typed for `imports` (the precise type lives on the
1262
1398
  * `defineMethod` authoring surface, like the shipped definePlugin).
1263
1399
  */
1264
- interface MethodPlugin<TName extends string = string, TInput = unknown, TOutput = unknown, TPositional extends readonly string[] = readonly [],
1400
+ /** Every `pluginType` the model builds. */
1401
+ type PluginType = "method" | "property" | "aggregate" | "hook" | "method-override";
1265
1402
  /**
1266
- * What `run` receives, when that differs from what a CALLER may pass.
1267
- *
1268
- * They part company for item and list, whose call type mixes in
1269
- * {@link CallOutputOptions} and {@link PaginatedCallInput}. Those are the
1270
- * framework's, peeled off before `run`, so folding them into one parameter
1271
- * told a consumer reading `Parameters<typeof plugin.run>[0]` that `run` gets
1272
- * a flag the runtime always removes.
1273
- *
1274
- * Defaults to `TInput`, since raw's caller and `run` see the same object.
1403
+ * What every plugin descriptor carries, whatever its kind. `pluginType` is the
1404
+ * discriminant, and each kind narrows it. `imports` and `importBindings` are on
1405
+ * every kind so the graph walk treats them alike (an override's are empty).
1275
1406
  */
1276
- TRunInput = TInput> {
1277
- pluginType: "method";
1407
+ interface PluginBase<TName extends string = string> {
1408
+ pluginType: PluginType;
1278
1409
  name: TName;
1279
1410
  namespace?: string;
1280
1411
  /** `namespace/name`, or bare `name`. The `context.plugins` key. */
1281
1412
  id: string;
1282
- /** True for a `declareMethod` stand-in: a typed reference with no real
1413
+ imports: readonly Plugin[];
1414
+ /** Binding-name to plugin-id edges, normalized from `imports`; what the
1415
+ * `imports` bag is built from. */
1416
+ importBindings: readonly ImportBinding[];
1417
+ }
1418
+ /** `setup` runs once at build, dependencies first, and returns the plugin's
1419
+ * private state. `dispose` releases what it acquired, in reverse build order. */
1420
+ interface PluginLifecycle {
1421
+ setup?: (bag: {
1422
+ imports: Record<string, unknown>;
1423
+ }) => unknown;
1424
+ dispose?: DisposeFn;
1425
+ }
1426
+ /**
1427
+ * A method or property. A `declare*` stand-in wears the same shape with no
1428
+ * implementation, and a `declareDefault` wrapper marks the fallback provider
1429
+ * for an id.
1430
+ */
1431
+ interface LeafBase<TName extends string = string> extends PluginBase<TName>, PluginLifecycle {
1432
+ /** True for a `declare*` stand-in: a typed reference with no real
1283
1433
  * implementation. A real plugin under the same id satisfies it. */
1284
1434
  standIn?: boolean;
1285
- /** True for a `declareOptionalMethod` stand-in: dependents bind `undefined` if
1286
- * no real plugin satisfies it, and `PluginSurface` types the binding
1435
+ /** True for a `declareOptional*` stand-in: dependents bind `undefined` if no
1436
+ * real plugin satisfies it, and `PluginSurface` types the binding
1287
1437
  * `| undefined`. */
1288
1438
  optional?: boolean;
1289
1439
  /** Present on a `declareDefault` wrapper: this entry is the DEFAULT provider
@@ -1291,34 +1441,37 @@ TRunInput = TInput> {
1291
1441
  * plugin, so two defaults for one id dedup (same source) or conflict
1292
1442
  * (different source). */
1293
1443
  defaultSource?: AnyLeafPlugin;
1294
- imports: readonly AnyPlugin[];
1295
- /** Binding-name to plugin-id edges, normalized from `imports`;
1296
- * what the `imports` bag is built from. */
1297
- importBindings: readonly ImportBinding[];
1298
- /** Optional per-materialization constructor: runs once at createSdk
1299
- * (dependencies first), may side-effect, and returns the method's private
1300
- * state (delivered to `run` as `bag.state`). */
1301
- setup?: (bag: {
1302
- imports: Record<string, unknown>;
1303
- }) => unknown;
1304
- /** `setup`'s dual: releases what setup acquired. Run by `disposeSdk` in
1305
- * reverse dependency order. */
1306
- dispose?: DisposeFn;
1307
- /** Validates `input` before `run` and drives the authoring `input` type. */
1308
- inputSchema?: z.ZodType;
1309
- /** When true, skip the runtime validation/parse of `input`: `run` receives the
1310
- * raw input untouched — no coercion, stripping, or cloning — even if
1311
- * `inputSchema` is set (the schema stays for registry / CLI / MCP projection).
1312
- * For raw methods that own their own validation and must not have their input
1313
- * transformed, e.g. `fetch` passing a `RequestInit` bag through unchanged. */
1314
- skipInputValidation?: boolean;
1315
- /** When true, the materializer skips validating/stripping `run`'s output
1316
- * against `meta.outputSchema` (the schema stays for projection). The output
1317
- * partner of {@link MethodPlugin.skipInputValidation}. */
1318
- skipOutputValidation?: boolean;
1319
- /** Descriptive metadata for the registry / CLI / MCP / docs (carry-only at
1320
- * runtime). */
1321
- meta?: LeafMeta;
1444
+ }
1445
+ interface MethodPlugin<TName extends string = string, TInput = unknown, TOutput = unknown, TPositional extends readonly string[] = readonly [],
1446
+ /**
1447
+ * What `run` receives, when that differs from what a CALLER may pass.
1448
+ *
1449
+ * They part company for item and list, whose call type mixes in
1450
+ * {@link CallOutputOptions} and {@link PaginatedCallInput}. Those are the
1451
+ * framework's, peeled off before `run`, so folding them into one parameter
1452
+ * told a consumer reading `Parameters<typeof plugin.run>[0]` that `run` gets
1453
+ * a flag the runtime always removes.
1454
+ *
1455
+ * Defaults to `TInput`, since raw's caller and `run` see the same object.
1456
+ */
1457
+ TRunInput = TInput> extends LeafBase<TName>, MethodMeta {
1458
+ pluginType: "method";
1459
+ /** Validates `input` before `run` and drives the authoring `input` type. */
1460
+ inputSchema?: z.ZodType;
1461
+ /** When true, skip the runtime validation/parse of `input`: `run` receives the
1462
+ * raw input untouched no coercion, stripping, or cloning even if
1463
+ * `inputSchema` is set (the schema stays for registry / CLI / MCP projection).
1464
+ * For raw methods that own their own validation and must not have their input
1465
+ * transformed, e.g. `fetch` passing a `RequestInit` bag through unchanged. */
1466
+ skipInputValidation?: boolean;
1467
+ /** Validates and strips `run`'s output, and describes it for the registry. */
1468
+ outputSchema?: z.ZodSchema;
1469
+ /** When true, the materializer skips validating/stripping `run`'s output
1470
+ * against `outputSchema` (the schema stays for projection). The output
1471
+ * partner of {@link MethodPlugin.skipInputValidation}. */
1472
+ skipOutputValidation?: boolean;
1473
+ /** Descriptive metadata for the registry / CLI / MCP / docs (carry-only at
1474
+ * runtime). */
1322
1475
  /** Per-parameter input resolvers (method attachments). Reached for
1323
1476
  * materialization and bound into the entry at createSdk; a reachability-only
1324
1477
  * edge whose imports never enter this method's `importBindings`. */
@@ -1427,11 +1580,11 @@ type CallOutputOptions = {
1427
1580
  * list-standard overload: a raw envelope with extra keys is not a `StrictPage`
1428
1581
  * and falls through to the adapted overload, where `adaptPage` is required.
1429
1582
  */
1430
- type StrictPage$1<TResponse> = SdkPage<unknown> & {
1583
+ type StrictPage<TResponse> = SdkPage<unknown> & {
1431
1584
  [K in Exclude<keyof TResponse, keyof SdkPage<unknown>>]?: never;
1432
1585
  };
1433
1586
  /** Item type sourced from a page-ish response. */
1434
- type ItemOf$1<TResponse> = TResponse extends SdkPage<infer TItem> ? TItem : TResponse extends {
1587
+ type ItemOf<TResponse> = TResponse extends SdkPage<infer TItem> ? TItem : TResponse extends {
1435
1588
  data: readonly (infer TItem)[];
1436
1589
  } ? TItem : never;
1437
1590
  /**
@@ -1456,37 +1609,8 @@ type DataOf<TResponse> = TResponse extends {
1456
1609
  * eagerly at createSdk (dependencies first, like a method's `setup`) to build
1457
1610
  * that state. An imported/surfaced property yields the value, not a callable.
1458
1611
  */
1459
- interface PropertyPlugin<TName extends string = string, TValue = unknown> {
1612
+ interface PropertyPlugin<TName extends string = string, TValue = unknown> extends LeafBase<TName>, PropertyMeta {
1460
1613
  pluginType: "property";
1461
- name: TName;
1462
- namespace?: string;
1463
- /** `namespace/name`, or bare `name`. The `context.plugins` key. */
1464
- id: string;
1465
- /** True for a `declareProperty` stand-in: a typed reference with no value. A
1466
- * real property under the same id satisfies it. */
1467
- standIn?: boolean;
1468
- /** True for a `declareOptionalProperty` stand-in: an optional reference. If no real
1469
- * property satisfies it, dependents bind `undefined` rather than the build
1470
- * failing on a missing dependency. */
1471
- optional?: boolean;
1472
- /** Present on a `declareDefault` wrapper: this entry is the DEFAULT provider
1473
- * for its id (preempted by any explicit provider). Its value is the wrapped
1474
- * plugin, so two defaults for one id dedup (same source) or conflict
1475
- * (different source). */
1476
- defaultSource?: AnyLeafPlugin;
1477
- imports: readonly AnyPlugin[];
1478
- /** Binding-name to plugin-id edges, normalized from `imports`;
1479
- * what the `imports` bag is built from. */
1480
- importBindings: readonly ImportBinding[];
1481
- /** Optional once-eager constructor (the property twin of a method's `setup`):
1482
- * runs once at createSdk (dependencies first), may side-effect, and returns the
1483
- * private state delivered to `get` as `bag.state`. */
1484
- setup?: (bag: {
1485
- imports: Record<string, unknown>;
1486
- }) => unknown;
1487
- /** `setup`'s dual: releases what setup acquired. Run by `disposeSdk` in
1488
- * reverse dependency order. */
1489
- dispose?: DisposeFn;
1490
1614
  value?: TValue;
1491
1615
  /** A live getter: computes the value from imports and `setup` state on each
1492
1616
  * read (not once). The stored shape is loose; the precise typing lives on the
@@ -1496,8 +1620,6 @@ interface PropertyPlugin<TName extends string = string, TValue = unknown> {
1496
1620
  state: unknown;
1497
1621
  callContext?: CallContext;
1498
1622
  }) => TValue;
1499
- /** Descriptive metadata for the registry / CLI / MCP / docs (carry-only). */
1500
- meta?: LeafMeta;
1501
1623
  /** Templated registry members for this property's dynamic sub-surface (e.g. a
1502
1624
  * proxy). Carry-only: normalized at define time, folded into the registry. */
1503
1625
  dynamicMembers?: readonly NormalizedDynamicMember[];
@@ -1536,6 +1658,21 @@ type MiddlewareMap<TImports, TState = unknown> = {
1536
1658
  state: TState;
1537
1659
  }) => TOutput : never;
1538
1660
  };
1661
+ /**
1662
+ * An aggregate plugin: it re-exports child plugins under binding names. Has no
1663
+ * body of its own; composition is "declare what to re-export".
1664
+ * `exports` keys are binding names; re-exporting a child implies a dependency
1665
+ * on it (it is pulled into the graph). `imports` lists extra internal
1666
+ * plugins to materialize that are not re-exported. `middleware` wraps imported
1667
+ * methods, keyed by the target's binding name.
1668
+ */
1669
+ /**
1670
+ * How a module declares its `exports`: an array, mirroring {@link ImportsInput}. A
1671
+ * leaf binds under its own `name`; a module (or `selectExports(...)`)
1672
+ * contributes each of its export bindings (spread). A binding-name collision
1673
+ * throws (wrap one in `selectExports` to rename).
1674
+ */
1675
+ type ExportsInput = readonly (AnyLeafPlugin | AnyAggregatePlugin)[];
1539
1676
  /** The export record one array element contributes: a leaf under its own name,
1540
1677
  * a module under each of its export bindings. */
1541
1678
  type ElementExports<E> = E extends MethodPlugin<infer N, any, any, any> ? {
@@ -1550,49 +1687,36 @@ type ElementExports<E> = E extends MethodPlugin<infer N, any, any, any> ? {
1550
1687
  type ArrayExports<T extends readonly (AnyLeafPlugin | AnyAggregatePlugin)[]> = T extends readonly [] ? Record<never, never> : UnionToIntersection<{
1551
1688
  [I in keyof T]: ElementExports<T[I]>;
1552
1689
  }[number]>;
1553
- interface AggregatePlugin<TName extends string = string, TExports extends Record<string, AnyLeafPlugin> = Record<string, AnyLeafPlugin>> {
1690
+ /**
1691
+ * Coerce a computed export record to the shape {@link AggregatePlugin} requires.
1692
+ * `ArrayExports` folds with `UnionToIntersection`, whose result the checker
1693
+ * cannot prove satisfies the constraint, so name the fallback rather than
1694
+ * asserting at each use.
1695
+ */
1696
+ type AsExports<T> = T extends Record<string, AnyLeafPlugin> ? T : Record<string, AnyLeafPlugin>;
1697
+ /**
1698
+ * Reject an `exports` entry that is not a plugin: identity in the good case, an
1699
+ * error brand in the bad case. A deferred conditional rather than a constraint
1700
+ * on the type parameter, because a plugin-shaped constraint contextually types
1701
+ * the array literal and an inline `define*` call then infers `input` as `any`.
1702
+ * `declarePlugin`'s `exports` and every `imports` still carry the constraint;
1703
+ * move them here when something writes an inline `define*` there.
1704
+ */
1705
+ type PluginList<T extends readonly unknown[]> = Exclude<T[number], AnyLeafPlugin | AnyAggregatePlugin> extends never ? unknown : {
1706
+ readonly __kitcoreError: "every exports entry must be a plugin built by define*, declare*, selectExports, or omitExports";
1707
+ };
1708
+ interface AggregatePlugin<TName extends string = string, TExports extends Record<string, AnyLeafPlugin> = Record<string, AnyLeafPlugin>> extends PluginBase<TName> {
1554
1709
  pluginType: "aggregate";
1555
- name: TName;
1556
- namespace?: string;
1557
- /** `namespace/name`, or bare `name`. The `context.plugins` key. */
1558
- id: string;
1559
1710
  /** True for a `declarePlugin` stand-in: a typed reference to a whole module
1560
1711
  * with no implementation. A real aggregate under the same id satisfies it. */
1561
1712
  standIn?: boolean;
1562
- imports: readonly AnyPlugin[];
1563
- /** Binding-name to plugin-id edges, normalized from `imports`; what a
1564
- * wrap's `imports` is built from, and how a wrap target
1565
- * binding resolves to a method id. */
1566
- importBindings: readonly ImportBinding[];
1567
1713
  exports: TExports;
1568
1714
  }
1569
1715
  type AnyAggregatePlugin = AggregatePlugin<string, Record<string, any>>;
1570
- /**
1571
- * A legacy bridge plugin: wraps an old function plugin
1572
- * (`(sdk) => provides`) so it materializes inside the new graph. At
1573
- * materialization it runs `run` against a live compat view, merges the
1574
- * returned context contributions into the shared `SdkContext`, and synthesizes
1575
- * a `context.plugins` entry per root key. `TSurface` is the surfaced shape (the
1576
- * provides minus `context`). This is the single shape `createPluginStack()
1577
- * .toPlugin()` emits; there is no separate interim definition format.
1578
- */
1579
- interface LegacyPlugin<TSurface = Record<string, unknown>> {
1580
- pluginType: "legacy";
1581
- name: string;
1582
- namespace?: string;
1583
- /** `namespace/name`, or bare `name`. The `context.plugins` key. */
1584
- id: string;
1585
- imports: readonly AnyPlugin[];
1586
- importBindings: readonly ImportBinding[];
1587
- run: (sdk: any) => PluginProvides;
1588
- /** Type-only carrier for the surfaced shape; never set at runtime. */
1589
- readonly __surface?: TSurface;
1590
- }
1591
- type AnyLegacyPlugin = LegacyPlugin<any>;
1592
1716
  /**
1593
1717
  * A patch over an already-defined method's descriptive fields. It carries no
1594
1718
  * `run`: it names an existing method by id (`target`) and, after that method
1595
- * materializes, merges its `meta` (the same public {@link LeafMetaFields} an
1719
+ * materializes, merges its `meta` (the same public {@link MethodMeta} an
1596
1720
  * author sets on `defineMethod`) onto the method's entry, so the surface
1597
1721
  * registry / CLI / MCP / docs project the patched values. For surface-specific
1598
1722
  * tweaks a base method should not carry (e.g. a CLI that deprecates `fetch`
@@ -1602,16 +1726,13 @@ type AnyLegacyPlugin = LegacyPlugin<any>;
1602
1726
  * swaps the whole implementation and forces re-declaring `run`. An override
1603
1727
  * inherits the target's implementation untouched and only patches meta.
1604
1728
  */
1605
- interface MethodOverridePlugin {
1729
+ interface MethodOverridePlugin extends PluginBase {
1606
1730
  pluginType: "method-override";
1607
- name: string;
1608
- id: string;
1609
1731
  /** The id of the method whose meta is patched (its bare name if the method is
1610
1732
  * namespace-less). */
1611
1733
  target: string;
1612
- imports: readonly AnyPlugin[];
1613
- importBindings: readonly ImportBinding[];
1614
- meta?: LeafMeta;
1734
+ /** The description fields this override sets on its target. */
1735
+ patch: OverridableMetaFields;
1615
1736
  }
1616
1737
  /**
1617
1738
  * A method-lifecycle hook leaf (`defineHook`). `observe` contributes
@@ -1621,22 +1742,10 @@ interface MethodOverridePlugin {
1621
1742
  * (e.g. a telemetry queue), delivered to the observers.
1622
1743
  * Each observer bag mirrors a method's: `{ imports, input, state }` — `input` is
1623
1744
  * the lifecycle context, and there is no `next` (observers don't participate in
1624
- * the call). The module-model replacement for a legacy plugin that contributed
1625
- * `context.hooks`.
1745
+ * the call).
1626
1746
  */
1627
- interface HookPlugin<TName extends string = string> {
1747
+ interface HookPlugin<TName extends string = string> extends PluginBase<TName>, PluginLifecycle {
1628
1748
  pluginType: "hook";
1629
- name: TName;
1630
- namespace?: string;
1631
- id: string;
1632
- imports: readonly AnyPlugin[];
1633
- importBindings: readonly ImportBinding[];
1634
- setup?: (bag: {
1635
- imports: any;
1636
- }) => unknown;
1637
- /** `setup`'s dual: releases what setup acquired. Run by `disposeSdk` in
1638
- * reverse dependency order. */
1639
- dispose?: DisposeFn;
1640
1749
  /** Contract-preserving wraps around imported methods (the middleware onion,
1641
1750
  * folded dependents-outermost in topological order). Keyed by the target's
1642
1751
  * binding among this hook's `imports`. */
@@ -1657,30 +1766,13 @@ interface HookPlugin<TName extends string = string> {
1657
1766
  * bag before `onMethodStart`. Coexists with other hooks' annotators. */
1658
1767
  annotator?: HookAnnotator;
1659
1768
  }
1660
- type AnyPlugin = AnyLeafPlugin | AnyAggregatePlugin | AnyLegacyPlugin | HookPlugin | MethodOverridePlugin;
1661
- /**
1662
- * A transitional root that merges a legacy function-plugin stack with the
1663
- * module-model plugins migrated off it (see Migration order). At `createSdk` it
1664
- * lifts and runs the legacy stack (like `fromFunctionPlugin`), materializes the
1665
- * module-model `plugin`, and surfaces the union: the legacy stack's methods plus
1666
- * the module plugin's exports. The migrated plugins live in one `plugin`
1667
- * aggregate, so each migration only edits that aggregate's exports, not the
1668
- * heads. Deleted once every plugin is module-model.
1669
- */
1670
- interface LegacyMergePlugin<TProvides extends PluginProvides = PluginProvides, TPlugin extends AnyPlugin = AnyPlugin> {
1671
- pluginType: "legacy-merge";
1672
- name: string;
1673
- namespace?: string;
1674
- id: string;
1675
- /** The lifted legacy stack (one node). */
1676
- legacy: LegacyPlugin<TProvides & {
1677
- getRegistry: (options?: {
1678
- package?: string;
1679
- }) => RegistryResult;
1680
- }>;
1681
- /** The module-model plugins migrated off the legacy stack. */
1682
- plugin: TPlugin;
1683
- }
1769
+ /**
1770
+ * A plugin: the descriptor any `define*` call returns, what `createSdk` builds
1771
+ * and `addPlugin` adds, and the type a host gives a slot that accepts plugins.
1772
+ * A `declare*` stand-in matches structurally, so both entry points refuse one
1773
+ * by name at runtime.
1774
+ */
1775
+ type Plugin = AnyLeafPlugin | AnyAggregatePlugin | HookPlugin | MethodOverridePlugin;
1684
1776
  /** One middleware layer on a method's chain: the wrap and its owning hook
1685
1777
  * (whose `imports` the wrap receives, built live at call time). */
1686
1778
  interface MiddlewareWrap {
@@ -1689,25 +1781,33 @@ interface MiddlewareWrap {
1689
1781
  }
1690
1782
  /** A materialized method: a stable callable `value` that folds `chain` around
1691
1783
  * the core at call time. The chain is ordered dependents-outermost; it is
1692
- * mutable so post-seal `addPlugin` middleware can append. */
1693
- interface MethodEntry {
1784
+ * mutable so post-seal `addPlugin` middleware can append.
1785
+ *
1786
+ * The description fields are copied off the descriptor at build, like the
1787
+ * runtime fields, and a `defineOverride` writes into them. `descriptor` keeps
1788
+ * what the author wrote. */
1789
+ interface MethodEntry extends MethodMeta {
1694
1790
  pluginType: "method";
1695
1791
  name: string;
1792
+ /** The plugin object this entry was built from. Identity for `addPlugin`:
1793
+ * re-adding this object is a no-op, a different object under the same id is
1794
+ * refused. */
1795
+ descriptor: AnyMethodPlugin;
1696
1796
  value: (input: any) => any;
1697
1797
  /** The import-facing twin of `value`: the same boundary, called with the
1698
1798
  * internal-call sentinel so surface-only concerns (the deprecation signal)
1699
1799
  * don't fire when a sibling plugin delegates. `buildImports` and
1700
- * `resolvePlugin` bind this; the surface and registry bind `value`. Absent
1701
- * on legacy graph entries (they bind `value`). */
1702
- internalValue?: (input: any) => any;
1800
+ * `resolvePlugin` bind this through `bindInternal`; the surface and registry
1801
+ * bind `value`. */
1802
+ internalValue: (input: any) => any;
1703
1803
  /** Produce the import-facing twin for a given call context: with a context,
1704
1804
  * the twin mints a fresh child per invocation (callee inherits `callId`, its
1705
1805
  * origin, and sits one level deeper); without one it is parent-less — the
1706
1806
  * surface-origin `internalValue` by default, or a framework-internal root when
1707
1807
  * `frameworkOrigin` is set (kitcore's own build-time passes request it, so
1708
1808
  * their delegated calls can be dropped from telemetry). `buildImports` binds
1709
- * this. Absent on legacy graph entries. */
1710
- bindInternal?: (opts: {
1809
+ * this. */
1810
+ bindInternal: (opts: {
1711
1811
  ctx?: CallContext;
1712
1812
  frameworkOrigin?: boolean;
1713
1813
  }) => (...args: any[]) => any;
@@ -1718,7 +1818,9 @@ interface MethodEntry {
1718
1818
  * through unparsed; carried so the controller skips its final `safeParse` too
1719
1819
  * (it still uses `inputSchema` to plan/prompt parameters). */
1720
1820
  skipInputValidation?: boolean;
1721
- meta?: LeafMeta;
1821
+ /** Carried from the descriptor: validates the output, and the registry
1822
+ * projects it. */
1823
+ outputSchema?: z.ZodSchema;
1722
1824
  /** Resolved output mode; the registry derives presentation from it. */
1723
1825
  output?: NormalizedOutput;
1724
1826
  /** Positional input projection (see Output): ordered canonical-input keys the
@@ -1733,16 +1835,16 @@ interface MethodEntry {
1733
1835
  /** A materialized property: a static `value`, or a live `getValue` thunk that
1734
1836
  * re-derives the value per read (consumers install it as a getter on the surface
1735
1837
  * and on `imports`). Exactly one of `value` / `getValue` is set. */
1736
- interface PropertyEntry {
1838
+ interface PropertyEntry extends PropertyMeta {
1737
1839
  pluginType: "property";
1738
1840
  name: string;
1841
+ descriptor: AnyPropertyPlugin;
1739
1842
  value?: any;
1740
1843
  /** Re-derives the value per read. Receives the live per-call `CallContext`
1741
1844
  * when installed on a method's `imports` bag with a threaded context, and
1742
1845
  * nothing on a surface / build-time read. */
1743
1846
  getValue?: (callContext?: CallContext) => any;
1744
1847
  /** Carried from the descriptor for the registry / CLI / MCP / docs. */
1745
- meta?: LeafMeta;
1746
1848
  /** Carried from the descriptor: templated registry members for this
1747
1849
  * property's dynamic sub-surface (folded into the registry by getRegistry). */
1748
1850
  dynamicMembers?: readonly NormalizedDynamicMember[];
@@ -1752,27 +1854,42 @@ interface PropertyEntry {
1752
1854
  interface AggregateEntry {
1753
1855
  pluginType: "aggregate";
1754
1856
  name: string;
1857
+ descriptor: AnyAggregatePlugin;
1755
1858
  exports: Record<string, any>;
1756
1859
  }
1757
- /** An entry in `context.plugins`. The `value`
1758
- * of a method entry is its callable; of a property entry, its value. */
1759
- type PluginEntry = MethodEntry | PropertyEntry | AggregateEntry;
1760
- /**
1761
- * The materialization substrate: every reachable plugin keyed by
1762
- * id, plus the legacy-compat surface used during migration. The
1763
- * compat fields let adapted function plugins read/write `context` exactly as
1764
- * they do on the shipped stack: `meta` is the per-method registry source, `hooks`
1765
- * the composed lifecycle hooks, and the index signature covers arbitrary legacy
1766
- * fields a function plugin contributes (`api`, `options`, `manifest` helpers,
1767
- * ...). A pure module-model SDK leaves `meta`/`hooks` empty and uses entry-level
1768
- * metadata instead.
1860
+ /** A materialized hook. It has no value: its wraps sit on other methods'
1861
+ * chains and its observers in `context.hooks`. The entry records that the
1862
+ * hook is in the graph. */
1863
+ interface HookEntry {
1864
+ pluginType: "hook";
1865
+ name: string;
1866
+ descriptor: HookPlugin;
1867
+ }
1868
+ /** A materialized `defineOverride`. No value: its patch is on the target
1869
+ * method's `meta`. The entry records that the override is in the graph. */
1870
+ interface OverrideEntry {
1871
+ pluginType: "method-override";
1872
+ name: string;
1873
+ descriptor: MethodOverridePlugin;
1874
+ }
1875
+ /** An entry in `context.plugins`, one per plugin in the graph. A method's
1876
+ * `value` is its callable, a property's its value, an aggregate's `exports`
1877
+ * its bindings. A hook and an override have no value. */
1878
+ type PluginEntry = MethodEntry | PropertyEntry | AggregateEntry | HookEntry | OverrideEntry;
1879
+ /**
1880
+ * The materialization substrate: every reachable plugin keyed by id, plus the
1881
+ * ambient state the method boundary reads. Exhaustive, with no index signature:
1882
+ * a plugin keeps its state in `setup` and reads values through `imports`.
1769
1883
  */
1770
1884
  interface SdkContext {
1885
+ /** Every reachable plugin by id. Created with `Object.create(null)`, as is
1886
+ * `surface`, because the keys are names an author chose: on a `{}` a lookup
1887
+ * of `"toString"` finds `Object.prototype.toString` and a `"__proto__"` write
1888
+ * replaces the prototype instead of adding a key. */
1771
1889
  plugins: Record<string, PluginEntry>;
1772
- meta: Record<string, PluginMeta>;
1773
1890
  hooks: MethodHooks;
1774
1891
  /** The SDK surface: each callable/value binding name mapped to the leaf plugin
1775
- * id it resolves to. This is what the consumer actually calls (the root's
1892
+ * id it resolves to. No prototype, for the reason given on `plugins`. This is what the consumer actually calls (the root's
1776
1893
  * re-exports plus `addPlugin` additions), so the registry reports entries by
1777
1894
  * binding (with meta from the leaf) rather than dumping `plugins` by id. An
1778
1895
  * aliased re-export (`{ hi: greet }`) appears here as `hi -> "greet"`. */
@@ -1783,7 +1900,6 @@ interface SdkContext {
1783
1900
  /** The first `disposeSdk` call's settled result; later calls return it
1784
1901
  * (idempotent, first input wins). */
1785
1902
  disposed?: Promise<void>;
1786
- [key: string]: any;
1787
1903
  }
1788
1904
  /** One leaf's recorded teardown: built at materialization (closing over the
1789
1905
  * leaf's imports + setup state), run by `disposeSdk`. */
@@ -1799,757 +1915,367 @@ type DisposeFn = (bag: {
1799
1915
  state: unknown;
1800
1916
  input?: unknown;
1801
1917
  }) => void | Promise<void>;
1802
- /** The surfaced shape of one re-exported child: a method's callable or a
1803
- * property's value. */
1804
- 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;
1805
- /**
1806
- * The SDK surface a plugin contributes, derived from its descriptor: a
1807
- * method's callable or a property's value under its name, or an aggregate's
1808
- * export bindings. No `SdkInternals` — this is the plugin's own slice, not a
1809
- * whole SDK. The inference replacement for a hand-written
1810
- * `<Name>PluginProvides` interface:
1811
- *
1812
- * export type ListAppsPluginProvides = PluginSurface<typeof listAppsPlugin>;
1813
- *
1814
- * "Surface", not "Provides": `PluginProvides` is the legacy function-plugin
1815
- * bag and `ProvidesOf` is the completeness ledger's phantom ids — both
1816
- * different concepts.
1817
- */
1818
- type PluginSurface<P extends AnyPlugin> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPositional> ? P extends {
1819
- optional: true;
1820
- } ? {
1821
- [K in TName]: SurfaceCall<TInput, TOutput, TPositional> | undefined;
1822
- } : {
1823
- [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1824
- } : P extends PropertyPlugin<infer TName, infer TValue> ? {
1825
- [K in TName]: TValue;
1826
- } : P extends AggregatePlugin<string, infer TExports> ? {
1827
- [K in keyof TExports]: ExportSurface<TExports[K]>;
1828
- } : never;
1829
- /**
1830
- * The framework-owned access an SDK carries beyond its string surface.
1831
- *
1832
- * Both keys, because the value has both. `[CONTEXT]` is what materialization
1833
- * writes and what `getContext` reads, so declaring it is the type telling the
1834
- * truth. `context` is the legacy string key, kept for back-compat and narrowing
1835
- * away later.
1836
- *
1837
- * The symbol used to be omitted so it would not reach a consumer's emitted
1838
- * declarations. It is exported from the package root, so it is nameable there,
1839
- * and hiding it cost more than it saved: `ControllerSdk` had to check the
1840
- * legacy string key as a stand-in for the real one.
1841
- */
1842
- interface SdkContextCarrier {
1843
- readonly [CONTEXT]: SdkContext;
1844
- }
1845
- type SdkInternals = {
1846
- context: SdkContext;
1847
- } & SdkContextCarrier;
1848
- /**
1849
- * The materialized SDK for a leaf root: the root's callable (method) or value
1850
- * (property) under its name, plus framework access.
1851
- */
1852
- type Sdk$1<TName extends string, TInput, TOutput, TPositional extends readonly string[] = readonly []> = {
1853
- [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1854
- } & SdkInternals;
1855
- /** The materialized SDK for a property root: the value under its name. */
1856
- type PropertySdk<TName extends string, TValue> = {
1857
- [K in TName]: TValue;
1858
- } & SdkInternals;
1859
- /**
1860
- * The materialized SDK for an aggregate root: each export binding becomes a
1861
- * surface entry, typed from the re-exported child (callable for a method,
1862
- * value for a property).
1863
- */
1864
- type AggregateSdk<TExports extends Record<string, AnyLeafPlugin>> = {
1865
- [K in keyof TExports]: ExportSurface<TExports[K]>;
1866
- } & SdkInternals;
1867
- /**
1868
- * The surface a plugin adds to an SDK when passed to `addPlugin`: a method
1869
- * under its name, a property's value, an aggregate's export bindings, or a
1870
- * legacy function plugin's root provides (minus `context`).
1871
- */
1872
- type AddedSurface<P> = [P] extends [AnyPlugin] ? [
1873
- PluginSurface<P>
1874
- ] 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>;
1875
- /** `T` when it is a specific string literal, else `never`. Used on a stand-in's
1876
- * `name` so the id is always captured as a literal: a widened `string` (or the
1877
- * stale `declareMethod<TInput, TOutput>(...)` call shape, where the contract
1878
- * lands in the name slot) is rejected at the call rather than silently
1879
- * weakening the requirements ledger. */
1880
- type LiteralString<T extends string> = string extends T ? never : T;
1881
- declare const REQUIRES: unique symbol;
1882
- declare const PROVIDES: unique symbol;
1883
- /** Phantom carriers for the requirements ledger; never present at runtime. */
1884
- interface PluginSummary<TRequires extends string = never, TProvides extends string = never> {
1885
- /** Declaration ids the plugin's subgraph still needs. @internal */
1886
- readonly [REQUIRES]?: TRequires;
1887
- /** Ids the plugin and its subgraph provide. @internal */
1888
- readonly [PROVIDES]?: TProvides;
1889
- }
1890
- /**
1891
- * The id a stand-in declares, carried separately from the requires ledger.
1892
- *
1893
- * `declareProperty` requires its own id, so the ledger alone would do. A
1894
- * `declareOptionalProperty` requires NOTHING, which is the point of it, so its
1895
- * ledger is empty and the id has nowhere else to live. Reading the id off the
1896
- * ledger meant an optional stand-in handed a by-reference provider `never`,
1897
- * and a `never` in that position stopped `CompletenessOf` reporting anything
1898
- * for the whole graph.
1899
- *
1900
- * A carrier of its own keeps the two facts apart: what a stand-in NEEDS, and
1901
- * what it NAMES.
1902
- */
1903
- interface StandInId<TId extends string = never> {
1904
- /** @internal */
1905
- readonly [DECLARES]?: TId;
1906
- }
1907
- /** Phantom-only key (see `StandInId`); never set at runtime. */
1908
- declare const DECLARES: unique symbol;
1909
- /** The declaration ids a plugin still needs (reads the phantom carrier). */
1910
- type RequiresOf<P> = P extends {
1911
- readonly [REQUIRES]?: infer R;
1912
- } ? Extract<R, string> : never;
1913
- /** The ids a plugin and its subgraph provide (reads the phantom carrier). */
1914
- type ProvidesOf$1<P> = P extends {
1915
- readonly [PROVIDES]?: infer R;
1916
- } ? Extract<R, string> : never;
1917
- /** Union the requires / provides across an inline imports or exports tuple. */
1918
- type RequiresIn<T extends readonly unknown[]> = RequiresOf<T[number]>;
1919
- type ProvidesIn<T extends readonly unknown[]> = ProvidesOf$1<T[number]>;
1920
- /**
1921
- * Reject an `imports` / `exports` value whose type widened to a non-tuple
1922
- * `Plugin[]`: a literal tuple has a literal `length`, a widened array has
1923
- * `length: number`. Identity in the good (tuple) case, so `T & StaticList<T>`
1924
- * infers `T` unchanged; an error brand in the bad case, which the passed array
1925
- * is not assignable to.
1926
- */
1927
- type StaticList<T extends readonly unknown[]> = number extends T["length"] ? {
1928
- readonly __kitcoreError: "must be a fixed inline list of plugins, not a widened Plugin[]; declare them inline so the dependency graph stays statically known";
1929
- } : T;
1930
- /** A leaf provides its own name plus whatever its imports provide. */
1931
- type LeafProvides<TName extends string, TImports extends readonly unknown[]> = TName | ProvidesIn<TImports>;
1932
- /** A leaf requires its imports' requirements, minus what it provides. */
1933
- type LeafRequires<TName extends string, TImports extends readonly unknown[]> = Exclude<RequiresIn<TImports>, LeafProvides<TName, TImports>>;
1934
- /** An aggregate provides its own name plus its imports' and exports' provides. */
1935
- type AggregateProvides<TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = TName | ProvidesIn<TImports> | ProvidesIn<TExports>;
1936
- /** An aggregate requires its imports' and exports' requirements, minus provides. */
1937
- type AggregateRequires<TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = Exclude<RequiresIn<TImports> | RequiresIn<TExports>, AggregateProvides<TName, TImports, TExports>>;
1938
- /** A plugin's id as a type: `namespace/name`, or bare `name` when the namespace
1939
- * is empty. The ledger keys on this (matching runtime id resolution), not the
1940
- * bare name, so same-named plugins in different namespaces stay distinct. */
1941
- type IdOf<TNamespace extends string, TName extends string> = TNamespace extends "" ? TName : `${TNamespace}/${TName}`;
1942
- /** The binding name of an id: its last `/`-separated segment. The inverse view
1943
- * of `IdOf`, used by `declare*` to derive the bare binding from a full id. */
1944
- type LastSegment<TId extends string> = TId extends `${string}/${infer Rest}` ? LastSegment<Rest> : TId;
1945
- /** The `PluginSummary` a leaf carries, keyed on its full id. */
1946
- type LeafSummary<TNamespace extends string, TName extends string, TImports extends readonly unknown[]> = PluginSummary<LeafRequires<IdOf<TNamespace, TName>, TImports>, LeafProvides<IdOf<TNamespace, TName>, TImports>>;
1947
- /** The `PluginSummary` an aggregate carries, keyed on its full id. */
1948
- 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>>;
1949
- /**
1950
- * The runtime-input channel for `createSdk`. `configuration` maps plugin ids to
1951
- * immutable values; each entry materializes as a static value property under
1952
- * that id, satisfying a `declareProperty` / `declareOptionalProperty` stand-in exactly
1953
- * as a registered provider would (DI value injection). Strict at build time:
1954
- * an id must resolve to a property stand-in reachable from the root, so
1955
- * unknown ids, non-property targets, and collisions with a registered real
1956
- * provider all throw. kitcore keeps the map untyped; a head's factory is the
1957
- * typed wrapper (`createMySdk(options)` passes
1958
- * `{ configuration: { "my/config": options } }`).
1959
- */
1960
- interface CreateSdkOptions {
1961
- configuration?: Record<string, unknown>;
1962
- }
1963
- /** Surfaced by `createSdk` when reachable declarations have no provider. */
1964
- interface MissingDependencies<TIds extends string> {
1965
- readonly __kitcoreError: "Missing concrete provider(s) for required declaration id(s)";
1966
- readonly missing: TIds;
1967
- }
1968
- /**
1969
- * `unknown` when every reachable declaration is provided, otherwise a
1970
- * `MissingDependencies` brand. `createSdk` takes `root: P & CompletenessOf<P>`,
1971
- * so a complete root infers `P` unchanged (intersect `unknown`) while an
1972
- * incomplete one fails to assign (the argument lacks `missing`).
1973
- */
1974
- type CompletenessOf<P> = [
1975
- Exclude<RequiresOf<P>, ProvidesOf$1<P>>
1976
- ] extends [never] ? unknown : MissingDependencies<Exclude<RequiresOf<P>, ProvidesOf$1<P>>>;
1977
- /** Recover the materialized SDK type for a checked root (the summary that
1978
- * rides on the `define*` return is transparent to these). */
1979
- type MethodSdkOf<P> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPos> ? Sdk$1<TName, TInput, TOutput, TPos> : never;
1980
- type PropertySdkOf<P> = P extends PropertyPlugin<infer TName, infer TValue> ? PropertySdk<TName, TValue> : never;
1981
- type AggregateSdkOf<P> = P extends AggregatePlugin<string, infer TExports> ? AggregateSdk<TExports> : never;
1982
-
1983
- /**
1984
- * Declaration for a registry category (a bucket grouping related functions).
1985
- * Plugins reference categories in their `meta.categories` field, as either a
1986
- * bare key (auto-derive title and plural) or this object (override either).
1987
- *
1988
- * Examples (with auto-derive rules):
1989
- * - `{ key: "app" }` → title "App", plural "Apps"
1990
- * - `{ key: "client-credentials" }` → title "Client Credentials", plural "Client Credentials"
1991
- * - `{ key: "utility" }` → title "Utility", plural "Utilities"
1992
- * - `{ key: "http", title: "HTTP Request" }` → plural "HTTP Requests"
1993
- */
1994
- interface CategoryDefinition {
1995
- key: string;
1996
- /** Display title for the category. Auto-derived from `key` if omitted. */
1997
- title?: string;
1998
- /** Plural form of `title`. Auto-derived from the resolved title if omitted. */
1999
- titlePlural?: string;
2000
- }
2001
- interface FunctionRegistryEntry {
2002
- name: string;
2003
- /**
2004
- * Human-readable description of the function. Surfaced wherever the
2005
- * registry is consumed (command help, tool/RPC descriptions, generated
2006
- * documentation). Prefer providing this directly rather than relying
2007
- * solely on inputSchema.describe().
2008
- */
2009
- description?: string;
2010
- type?: "list" | "item" | "create" | "update" | "delete" | "function";
2011
- itemType?: string;
2012
- returnType?: string;
2013
- inputSchema?: z.ZodSchema;
2014
- /**
2015
- * When true, the method owns its input validation and its boundary passes the
2016
- * input through unparsed. The resolution controller reads this to skip its
2017
- * final `safeParse` (it still uses `inputSchema` to plan/prompt parameters),
2018
- * so a method routed through the controller isn't re-validated against a
2019
- * schema it deliberately opts out of. Lifted off the materialized entry.
2020
- */
2021
- skipInputValidation?: boolean;
2022
- outputSchema?: z.ZodSchema;
2023
- /**
2024
- * Ordered input keys the public surface projects onto positional arguments
2025
- * (the method's `positional` declaration). Absent when the method takes only
2026
- * the canonical single bag. Lifted off the materialized method entry by the
2027
- * surface builder, like `resolvers` — a runtime projection, not
2028
- * descriptive meta.
2029
- */
2030
- positional?: readonly string[];
2031
- categories: string[];
2032
- /**
2033
- * Per-parameter bound resolvers (imports already captured, called with
2034
- * `input` only, no sdk). Lifted off the materialized method entry by the
2035
- * surface builder.
2036
- */
2037
- resolvers?: Record<string, BoundResolver>;
2038
- packages?: string[];
2039
- /**
2040
- * API stability tier of the plugin, normalized from `PluginMeta.stability`
2041
- * (absent means `"stable"`; the legacy `experimental: true` boolean means
2042
- * `"experimental"`). Always concrete here, so consumers never branch on
2043
- * `undefined`.
2044
- */
2045
- stability: StabilityLevel;
2046
- /**
2047
- * @deprecated Read `stability` instead. Derived as
2048
- * `stability === "experimental"` — literal by name, so beta reads
2049
- * `false`; the not-stable warning duty lives in `stability` and the
2050
- * runtime stability notice.
2051
- */
2052
- experimental?: boolean;
2053
- /** Confirmation prompt type - prompts user before executing */
2054
- confirm?: "create-secret" | "delete";
2055
- /**
2056
- * Optional deprecation metadata for commands.
2057
- */
2058
- deprecation?: FunctionDeprecation;
2059
- /**
2060
- * Short aliases for parameter names (e.g., { request: "X", header: "H" }).
2061
- * Consumers that render the function as a flag-style command surface use
2062
- * these as short forms.
2063
- */
2064
- aliases?: Record<string, string>;
2065
- /**
2066
- * Output formatter, normalized to the bound runtime shape (its imports/sdk
2067
- * already captured), so consumers call `getContext`/`format` with no sdk.
2068
- * The surface builder produces this from the method entry — `entry.formatter`
2069
- * for a migrated plugin, or the legacy `meta.formatter` adapted — so vintage
2070
- * is invisible here.
2071
- */
2072
- formatter?: BoundFormatter;
2073
- /** Defaults to true. Set to false to suppress --json (e.g. login/logout/init). */
2074
- supportsJsonOutput: boolean;
2075
- }
2076
- interface FunctionDeprecation {
2077
- /** User-facing deprecation message for why/how to migrate */
2078
- message: string;
2079
- }
2080
- interface RegistryResult {
2081
- functions: FunctionRegistryEntry[];
2082
- categories: {
2083
- key: string;
2084
- title: string;
2085
- titlePlural: string;
2086
- functions: string[];
2087
- }[];
2088
- }
2089
-
2090
- /**
2091
- * ------------------------------
2092
- * Plugin Type System
2093
- * ------------------------------
2094
- *
2095
- * Plugins receive the sdk as a positional parameter. sdk.context holds shared
2096
- * internal state (api client, event emission, meta, options, etc.). SDK methods
2097
- * live at the root, context nests under .context.
2098
- *
2099
- * A plugin is (sdk) => partialSdk. `createPluginStack()` accumulates plugins
2100
- * and materializes a built `Sdk` via `.toSdk()`; `addPlugin(sdk, plugin)`
2101
- * extends an already-built SDK in place with one more plugin.
2102
- */
2103
-
2104
- interface PluginProvides extends Record<string, any> {
2105
- context?: {
2106
- meta?: Record<string, PluginMeta<any>>;
2107
- hooks?: MethodHooks;
2108
- [key: string]: any;
2109
- };
2110
- }
2111
- interface PluginMeta<TSdk = unknown> {
2112
- /**
2113
- * Human-readable description of the plugin function. Used by the CLI (help text),
2114
- * MCP (tool description), and README generators. When omitted, falls back to
2115
- * the inputSchema's `.describe()` value or a generic placeholder.
2116
- */
2117
- description?: string;
2118
- /**
2119
- * Buckets this function belongs to in `getRegistry()` output. Each entry is
2120
- * either a bare key (`"app"`) for auto-derived titles or a {@link CategoryDefinition}
2121
- * object to override the title or plural. Only one plugin needs to supply
2122
- * the object form per category key; object refs win over string refs, so
2123
- * other plugins in the same bucket can stay on bare strings.
2124
- */
2125
- categories?: (string | CategoryDefinition)[];
2126
- type?: "list" | "item" | "create" | "update" | "delete" | "function";
2127
- itemType?: string;
2128
- returnType?: string;
2129
- inputSchema?: z.ZodSchema;
2130
- outputSchema?: z.ZodSchema;
2131
- /**
2132
- * Item formatter that the registry hands to the CLI/MCP renderer. The
2133
- * `sdk` param on `fetch` is typed to the plugin's own declared SDK
2134
- * surface (`TRequires & TProvides`); reaching into another plugin's
2135
- * method requires adding it to `TRequires` explicitly.
2136
- */
2137
- formatter?: OutputFormatter<TSdk, any, any, any>;
2138
- /**
2139
- * Per-parameter resolver metadata. Same `TSdk` surfaces in each
2140
- * resolver's `fetch`/`tryResolveWithoutPrompt` callbacks.
2141
- */
2142
- resolvers?: Record<string, ResolverMetadata<TSdk, any, any>>;
2143
- /** Confirmation prompt type - prompts user before executing */
2144
- confirm?: "create-secret" | "delete";
2145
- /**
2146
- * API stability tier this plugin belongs to. Absent means `"stable"`;
2147
- * the registry projection normalizes it, so registry consumers always
2148
- * read a concrete {@link StabilityLevel}. Wrappers keep non-stable
2149
- * plugins out of their stable build (by gating them behind a `beta` /
2150
- * `experimental` subpath import) and consumers badge the level in
2151
- * generated docs, CLI help, and MCP tool descriptions. No runtime
2152
- * capability check.
2153
- */
2154
- stability?: StabilityLevel;
2155
- /**
2156
- * @deprecated Use `stability: "experimental"` instead. Kept as an
2157
- * input for external authors; `true` normalizes to
2158
- * `stability: "experimental"` in the registry projection.
2159
- */
2160
- experimental?: boolean;
2161
- [key: string]: any;
2162
- }
2163
- /**
2164
- * Plugin interface — 2 type params:
2165
- *
2166
- * TSdk = what this plugin needs (the SDK shape including context)
2167
- * TProvides = what this plugin returns (a partial SDK shape)
2168
- *
2169
- * The sdk param always includes context.meta, even if TSdk doesn't declare it.
2170
- */
2171
- interface Plugin<TSdk = {}, TProvides extends PluginProvides = PluginProvides> {
2172
- (sdk: TSdk & {
2173
- context: {
2174
- meta: Record<string, PluginMeta<any>>;
2175
- hooks: MethodHooks;
2176
- };
2177
- }): TProvides;
2178
- }
2179
- /**
2180
- * A built SDK. Carries the plugins' contributions plus the
2181
- * `getRegistry` accessor over `context.meta`. No `addPlugin` method
2182
- * on the shape: extension after build goes through the top-level
2183
- * `addPlugin(sdk, plugin)` function, which mutates the sdk in place
2184
- * and narrows the caller's binding via TypeScript's assertion
2185
- * functions.
2186
- */
2187
- type Sdk<T = {
2188
- context: {
2189
- meta: Record<string, PluginMeta<any>>;
2190
- hooks: MethodHooks;
2191
- };
2192
- }> = T & {
2193
- getRegistry(options?: {
2194
- package?: string;
2195
- }): RegistryResult;
2196
- };
2197
-
2198
- /**
2199
- * ------------------------------
2200
- * Plugin authoring helpers
2201
- * ------------------------------
2202
- *
2203
- * - `createPluginMethod` / `createPaginatedPluginMethod`: per-method
2204
- * primitives that sit inside a `definePlugin` callback and build the
2205
- *
2206
- * { [name]: wrappedFn, context: { meta: { [name]: meta } } }
2207
- *
2208
- * fragment a plugin returns for a single method, wiring up
2209
- * `createFunction` / `createPaginatedFunction`, the method-call hooks,
2210
- * and the doubled `name` (function key + meta key) in one place.
2211
- *
2212
- * Two method helpers (rather than one with a `paginated: true` discriminant)
2213
- * because the handler signature changes shape across pagination, and
2214
- * discriminated unions on optional booleans produce noisy TS errors.
2215
- *
2216
- * @deprecated The module model replaces this exit; it logs a runtime
2217
- * deprecation and will be removed in a release after this warning ships.
2218
- */
2219
-
2220
- /**
2221
- * Method-level meta fields. Mirrors `PluginMeta` minus `inputSchema`, which is
2222
- * passed at the top level alongside the handler and merged into the meta by
2223
- * the helpers themselves.
2224
- *
2225
- * @deprecated The module model replaces this exit; it logs a runtime
2226
- * deprecation and will be removed in a release after this warning ships.
2227
- */
2228
- type MethodMeta<TSdk> = Omit<PluginMeta<TSdk>, "inputSchema">;
1918
+ /** The surfaced shape of one re-exported child: a method's callable or a
1919
+ * property's value. */
1920
+ 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;
1921
+ /** The bindings a module surfaces: each export under its binding name. */
1922
+ type AggregateBindings<TExports extends Record<string, AnyLeafPlugin>> = {
1923
+ [K in keyof TExports]: ExportSurface<TExports[K]>;
1924
+ };
2229
1925
  /**
2230
- * The plugin's own method signature, synthesized from the method config.
2231
- * Mixed into the resolver-side SDK so a resolver may freely reference the
2232
- * host plugin's own method (e.g. `appKeyResolver` calling `sdk.getApp`)
2233
- * without forcing the plugin to declare a circular dependency on itself.
2234
- *
2235
- * Uses `any` for options and return: we only need to assert the method
2236
- * exists on `sdk`, not pin its full signature. Using `TInput`/`TResult`
2237
- * here would create a circular inference (TSdk depends on TInput/TResult
2238
- * via the resolvers slot, TInput/TResult are inferred from the handler
2239
- * which depends on TSdk), and TS resolves the cycle by widening to
2240
- * `unknown`. With `any`, the resolver check still verifies the method's
2241
- * presence on the SDK; signature precision for self is the plugin
2242
- * author's responsibility.
1926
+ * The SDK surface a plugin contributes, derived from its descriptor: a
1927
+ * method's callable or a property's value under its name, or an aggregate's
1928
+ * export bindings. No `SdkInternals` — this is the plugin's own slice, not a
1929
+ * whole SDK. Derive a package's provides type from it rather than hand-writing
1930
+ * the shape:
2243
1931
  *
2244
- * Not mixed into the handler's `sdk`: handlers run against the SDK that
2245
- * existed when the plugin was added to the stack (closure-captured), so
2246
- * self-method access there would be a lie at runtime.
1932
+ * export type ListAppsPluginProvides = PluginSurface<typeof listAppsPlugin>;
2247
1933
  *
2248
- * @deprecated The module model replaces this exit; it logs a runtime
2249
- * deprecation and will be removed in a release after this warning ships.
1934
+ * "Surface", not "Provides": `ProvidesOf` already names the completeness
1935
+ * ledger's phantom ids, which is a different concept.
2250
1936
  */
2251
- type SelfMethod<TName extends string> = {
2252
- [K in TName]: (options?: any) => any;
2253
- };
2254
- interface PluginMethodConfig<TSdk, TInput, TResult, TName extends string, TResolvers> extends Omit<MethodMeta<TSdk>, "resolvers"> {
2255
- name: TName;
2256
- /**
2257
- * Schema for runtime input validation; drives the handler's `options`
2258
- * type. For plugins that accept deprecated parameter aliases this is a
2259
- * `z.union([CanonicalSchema, DeprecatedSchema])` the registry
2260
- * unwraps unions and exposes only the first variant (canonical) to
2261
- * documentation and downstream consumer surfaces.
2262
- *
2263
- * @deprecated The module model replaces this exit; it logs a runtime
2264
- * deprecation and will be removed in a release after this warning ships.
2265
- */
2266
- inputSchema?: z.ZodSchema<TInput>;
2267
- handler: (args: {
2268
- sdk: TSdk;
2269
- options: TInput;
2270
- }) => Promise<TResult>;
2271
- /**
2272
- * Per-parameter resolvers. Each entry's `TSdk` requirement is checked
2273
- * against the plugin's own `TSdk` (plus the plugin's own method via
2274
- * {@link SelfMethod}) using {@link ValidResolvers}; mismatches surface
2275
- * at the offending key. `NoInfer` pins `TSdk` to the `sdk` argument so
2276
- * resolver entries don't widen the inferred `TSdk`.
2277
- *
2278
- * @deprecated The module model replaces this exit; it logs a runtime
2279
- * deprecation and will be removed in a release after this warning ships.
2280
- */
2281
- resolvers?: ValidResolvers<NoInfer<TSdk & SelfMethod<TName>>, TResolvers> & TResolvers;
2282
- }
2283
- type PluginMethodReturn<TName extends string, TInput, TResult> = {
2284
- [K in TName]: (options?: TInput) => Promise<TResult>;
2285
- } & {
2286
- context: {
2287
- meta: {
2288
- [K in TName]: PluginMeta;
2289
- };
2290
- };
2291
- };
1937
+ type PluginSurface<P extends Plugin> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPositional> ? P extends {
1938
+ optional: true;
1939
+ } ? {
1940
+ [K in TName]: SurfaceCall<TInput, TOutput, TPositional> | undefined;
1941
+ } : {
1942
+ [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1943
+ } : P extends PropertyPlugin<infer TName, infer TValue> ? {
1944
+ [K in TName]: TValue;
1945
+ } : P extends AggregatePlugin<string, infer TExports> ? AggregateBindings<TExports> : never;
2292
1946
  /**
2293
- * Build the method fragment for a non-paginated SDK method. Used inside a
2294
- * `definePlugin(...)` callback:
1947
+ * The framework-owned access an SDK carries beyond its string surface.
2295
1948
  *
2296
- * export const getProfilePlugin = definePlugin(
2297
- * (sdk: ApiPluginProvides & EventEmissionProvides) =>
2298
- * createPluginMethod(sdk, {
2299
- * name: "getProfile",
2300
- * categories: ["account"],
2301
- * inputSchema: GetProfileSchema,
2302
- * handler: async ({ sdk }) => { ... },
2303
- * }),
2304
- * );
1949
+ * Both keys, because the value has both. `[CONTEXT]` is what materialization
1950
+ * writes and what `getContext` reads, so declaring it is the type telling the
1951
+ * truth. `context` is the legacy string key, kept for back-compat and narrowing
1952
+ * away later.
2305
1953
  *
2306
- * @deprecated The module model replaces this exit; it logs a runtime
2307
- * deprecation and will be removed in a release after this warning ships.
1954
+ * The symbol used to be omitted so it would not reach a consumer's emitted
1955
+ * declarations. It is exported from the package root, so it is nameable there,
1956
+ * and hiding it cost more than it saved: `ControllerSdk` had to check the
1957
+ * legacy string key as a stand-in for the real one.
2308
1958
  */
2309
- declare function createPluginMethod<const TName extends string, TSdk extends {
2310
- context: unknown;
2311
- }, TInput, TResult, const TResolvers extends Record<string, ResolverMetadata<any, any, any>> = {}>(sdk: TSdk, config: PluginMethodConfig<TSdk, TInput, TResult, TName, TResolvers>): PluginMethodReturn<TName, TInput, TResult>;
2312
- interface PaginatedPluginMethodConfigBase<TSdk, TInput, TName extends string, TResolvers> extends Omit<MethodMeta<TSdk>, "resolvers"> {
2313
- name: TName;
2314
- /** Same semantics as `createPluginMethod`'s `inputSchema`. */
2315
- inputSchema?: z.ZodSchema<TInput>;
2316
- /**
2317
- * Optional default page size when the caller doesn't pass one. Mirrors
2318
- * `createPaginatedFunction`'s `defaultPageSize` arg.
2319
- */
2320
- defaultPageSize?: number;
2321
- /** See {@link PluginMethodConfig.resolvers}. */
2322
- resolvers?: ValidResolvers<NoInfer<TSdk & SelfMethod<TName>>, TResolvers> & TResolvers;
1959
+ interface SdkContextCarrier {
1960
+ readonly [CONTEXT]: SdkContext;
2323
1961
  }
1962
+ type SdkInternals = {
1963
+ context: SdkContext;
1964
+ } & SdkContextCarrier;
2324
1965
  /**
2325
- * A page whose *only* own keys are `data` / `nextCursor`. Used to constrain
2326
- * the Standard overload: a raw envelope with extra keys (a JSON:API
2327
- * `links`/`meta`, a top-level `next`, etc.) is NOT a `StrictPage`, so it falls
2328
- * through to the Adapted overload and `adaptPage` becomes required. Each excess
2329
- * key is mapped to `?: never`, which a real value (e.g. `links: {...}`) can't
2330
- * satisfy — that's what a plain `SdkPage` assignability check (which allows
2331
- * excess keys structurally) misses.
1966
+ * The materialized SDK for a leaf root: the root's callable (method) or value
1967
+ * (property) under its name, plus framework access.
2332
1968
  */
2333
- type StrictPage<TResponse> = SdkPage<unknown> & {
2334
- [K in Exclude<keyof TResponse, keyof SdkPage<unknown>>]?: never;
2335
- };
2336
- /**
2337
- * Config for a paginated method whose handler already returns a clean page
2338
- * (`{ data, nextCursor? }` and nothing else — see `StrictPage`, enforced on
2339
- * the overload). No `adaptPage` needed; `TItem` is sourced from the handler's
2340
- * `data`. Interface extension keeps this a single flattened object type (not
2341
- * an intersection), preserving clean inference of the `resolvers` /
2342
- * `TResolvers` slot.
2343
- */
2344
- interface PaginatedPluginMethodConfigStandard<TSdk, TInput, TResponse, TName extends string, TResolvers> extends PaginatedPluginMethodConfigBase<TSdk, TInput, TName, TResolvers> {
2345
- handler: (args: {
2346
- sdk: TSdk;
2347
- options: TInput & {
2348
- cursor?: string;
2349
- pageSize?: number;
2350
- };
2351
- }) => Promise<TResponse>;
2352
- /** No adapter: the handler already returns a page. */
2353
- adaptPage?: undefined;
2354
- }
2355
- /**
2356
- * Config for a paginated method whose handler returns a raw upstream shape
2357
- * (`TResponse`, e.g. a JSON:API `links.next` envelope). `adaptPage` is required
2358
- * to translate it into a page. `TItem` is sourced from `TResponse` (`ItemOf`),
2359
- * not the adapter — the adapter is item-agnostic (relocates the cursor; items
2360
- * are finalized in the handler's `data`), hence `NoInfer`, so a generic adapter
2361
- * (e.g. `<T>(r) => SdkPage<T>`) doesn't collapse `TItem` to `unknown`.
2362
- */
2363
- interface PaginatedPluginMethodConfigAdapted<TSdk, TInput, TResponse, TItem, TName extends string, TResolvers> extends PaginatedPluginMethodConfigBase<TSdk, TInput, TName, TResolvers> {
2364
- handler: (args: {
2365
- sdk: TSdk;
2366
- options: TInput & {
2367
- cursor?: string;
2368
- pageSize?: number;
2369
- };
2370
- }) => Promise<TResponse>;
2371
- adaptPage: (response: TResponse) => SdkPage<NoInfer<TItem>>;
2372
- }
2373
- type ItemOf<TResponse> = TResponse extends SdkPage<infer TItem> ? TItem : TResponse extends {
2374
- data: readonly (infer TItem)[];
2375
- } ? TItem : never;
2376
- type PaginatedPluginMethodReturn<TName extends string, TInput, TItem> = {
2377
- [K in TName]: (options?: TInput & {
2378
- cursor?: string;
2379
- pageSize?: number;
2380
- maxItems?: number;
2381
- }) => PaginatedSdkResult<TItem>;
2382
- } & {
2383
- context: {
2384
- meta: {
2385
- [K in TName]: PluginMeta;
2386
- };
2387
- };
2388
- };
1969
+ type Sdk<TName extends string, TInput, TOutput, TPositional extends readonly string[] = readonly []> = {
1970
+ [K in TName]: SurfaceCall<TInput, TOutput, TPositional>;
1971
+ } & SdkInternals;
1972
+ /** The materialized SDK for a property root: the value under its name. */
1973
+ type PropertySdk<TName extends string, TValue> = {
1974
+ [K in TName]: TValue;
1975
+ } & SdkInternals;
2389
1976
  /**
2390
- * Paginated variant of `createPluginMethod`. Two overloads enforce the
2391
- * response contract at compile time:
2392
- *
2393
- * - **Standard** — the handler returns a strict `SdkPage<TItem>`
2394
- * (`{ data, nextCursor? }` and nothing else); no `adaptPage`.
2395
- * - **Adapted** — the handler returns a raw upstream shape and `adaptPage` is
2396
- * *required* to translate it.
2397
- *
2398
- * A handler that returns neither a page-like shape nor pairs a raw shape with
2399
- * `adaptPage` matches no overload and is a compile error.
2400
- *
2401
- * createPaginatedPluginMethod(sdk, {
2402
- * name: "listThings",
2403
- * inputSchema: ListThingsSchema,
2404
- * adaptPage: (res) => ({ data: res.items, nextCursor: res.next }),
2405
- * handler: ({ sdk, options }) => sdk.context.api.get("/things", { ... }),
2406
- * });
2407
- *
2408
- * @deprecated The module model replaces this exit; it logs a runtime
2409
- * deprecation and will be removed in a release after this warning ships.
1977
+ * The materialized SDK for an aggregate root: each export binding becomes a
1978
+ * surface entry, typed from the re-exported child (callable for a method,
1979
+ * value for a property).
2410
1980
  */
2411
- declare function createPaginatedPluginMethod<const TName extends string, TSdk extends {
2412
- context: unknown;
2413
- }, 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>;
2414
- declare function createPaginatedPluginMethod<const TName extends string, TSdk extends {
2415
- context: unknown;
2416
- }, 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>;
1981
+ type AggregateSdk<TExports extends Record<string, AnyLeafPlugin>> = AggregateBindings<TExports> & SdkInternals;
2417
1982
  /**
2418
- * Maps a tuple of plugins to a tuple of their TSdk requirement types.
2419
- *
2420
- * SdkRequirementsOf<[Plugin<{ api }, _>, Plugin<{ options }, _>]>
2421
- * = [{ api }, { options }]
1983
+ * The surface a plugin adds to an SDK when passed to `addPlugin`: a method
1984
+ * under its name, a property's value, or an aggregate's export bindings.
2422
1985
  */
2423
- type SdkRequirementsOf<T extends readonly Plugin<any, any>[]> = {
2424
- [K in keyof T]: T[K] extends Plugin<infer Sdk, any> ? Sdk : never;
2425
- };
1986
+ type AddedSurface<P> = [P] extends [Plugin] ? [
1987
+ PluginSurface<P>
1988
+ ] extends [never] ? Record<never, never> : PluginSurface<P> : Record<never, never>;
1989
+ /** `T` when it is a specific string literal, else `never`. Used on a stand-in's
1990
+ * `name` so the id is always captured as a literal: a widened `string` (or the
1991
+ * stale `declareMethod<TInput, TOutput>(...)` call shape, where the contract
1992
+ * lands in the name slot) is rejected at the call rather than silently
1993
+ * weakening the requirements ledger. */
1994
+ type LiteralString<T extends string> = string extends T ? never : T;
1995
+ declare const REQUIRES: unique symbol;
1996
+ declare const PROVIDES: unique symbol;
1997
+ declare const REQUIRED_CONTRACTS: unique symbol;
1998
+ declare const PROVIDED_CONTRACTS: unique symbol;
2426
1999
  /**
2427
- * Maps a tuple of plugins to a tuple of their TProvides output types.
2000
+ * One id's contract, as the ledger compares it: the binding a consumer of that
2001
+ * id sees. A method's is its {@link SurfaceCall}, a property's is its value, an
2002
+ * aggregate's is its export-bindings record.
2428
2003
  *
2429
- * ProvidesOf<[Plugin<_, { hello }>, Plugin<_, { goodbye }>]>
2430
- * = [{ hello }, { goodbye }]
2004
+ * The surfaced binding, not the raw `run`, is the thing compared, because that
2005
+ * is what a consumer actually calls. Under `strictFunctionTypes` that gives the
2006
+ * useful rule: a provider may accept WIDER input and must return a SUBTYPE of
2007
+ * the declared output.
2431
2008
  */
2432
- type ProvidesOf<T extends readonly Plugin<any, any>[]> = {
2433
- [K in keyof T]: T[K] extends Plugin<any, infer Provides> ? Provides : never;
2434
- };
2009
+ interface ContractEntry<TId extends string = string, TBinding = unknown> {
2010
+ readonly id: TId;
2011
+ readonly binding: TBinding;
2012
+ }
2013
+ /**
2014
+ * The input a contract compares on. A `void` input means "the caller passes
2015
+ * nothing", and the only value that expresses is `undefined`. Comparing the
2016
+ * literal `void` would reject nearly every provider, because `void` is
2017
+ * assignable to almost nothing, so a provider taking an optional argument
2018
+ * would fail a declaration it serves perfectly. A provider that demands real
2019
+ * input is still rejected: `undefined` is not assignable to it.
2020
+ */
2021
+ type ContractInput<TInput> = [TInput] extends [void] ? undefined : TInput;
2022
+ /** The contract binding a method contributes: its surfaced call signature. */
2023
+ type MethodContract<TInput, TOutput, TPositional extends readonly string[] = readonly []> = SurfaceCall<ContractInput<TInput>, TOutput, TPositional>;
2024
+ /**
2025
+ * The contract input of a method whose surfaced call carries framework keys on
2026
+ * top of the author's own (`item` adds `CallOutputOptions`, `list` adds those
2027
+ * plus `PaginatedCallInput`).
2028
+ *
2029
+ * A `run` that declares no input infers `unknown`, and intersecting `unknown`
2030
+ * with those keys collapses it to an all-optional object. Comparing against
2031
+ * THAT rejects any declared input sharing no key with it (TypeScript's
2032
+ * weak-type rule), even though the provider reads no input at all and serves
2033
+ * every caller. Keep it `unknown` in that case.
2034
+ */
2035
+ type CallContractInput<TInput, TFrameworkInput> = [unknown] extends [
2036
+ TInput
2037
+ ] ? unknown : TInput & TFrameworkInput;
2038
+ /** Phantom carriers for the requirements and contract ledgers; never present at
2039
+ * runtime. The contract parameters default to `never`, so a summary written
2040
+ * with two arguments carries no contract and is unchanged. */
2041
+ interface PluginSummary<TRequires extends string = never, TProvides extends string = never, TRequiredContracts extends ContractEntry = never, TProvidedContracts extends ContractEntry = never> {
2042
+ /** Declaration ids the plugin's subgraph still needs. @internal */
2043
+ readonly [REQUIRES]?: TRequires;
2044
+ /** Ids the plugin and its subgraph provide. @internal */
2045
+ readonly [PROVIDES]?: TProvides;
2046
+ /** Contracts the plugin's subgraph declared, by id. @internal */
2047
+ readonly [REQUIRED_CONTRACTS]?: TRequiredContracts;
2048
+ /** Contracts the plugin's subgraph implements, by id. @internal */
2049
+ readonly [PROVIDED_CONTRACTS]?: TProvidedContracts;
2050
+ }
2435
2051
  /**
2436
- * Intersects every member of a tuple into a single combined type. The
2437
- * result is an object that has every property of every member at once.
2052
+ * The id a stand-in declares, carried separately from the requires ledger.
2438
2053
  *
2439
- * IntersectAll<[{ api }, { options }]> = { api } & { options }
2440
- * IntersectAll<[]> = {}
2054
+ * `declareProperty` requires its own id, so the ledger alone would do. A
2055
+ * `declareOptionalProperty` requires NOTHING, which is the point of it, so its
2056
+ * ledger is empty and the id has nowhere else to live. Reading the id off the
2057
+ * ledger meant an optional stand-in handed a by-reference provider `never`,
2058
+ * and a `never` in that position stopped `CompletenessOf` reporting anything
2059
+ * for the whole graph.
2441
2060
  *
2442
- * Walks recursively: head & IntersectAll<tail>, base case is the empty
2443
- * tuple. Why intersection (`&`) and not union (`|`): the composed plugin
2444
- * must require ALL of the sub-plugins' needs at once — an SDK that has
2445
- * both `api` AND `options` — not "either api or options."
2061
+ * A carrier of its own keeps the two facts apart: what a stand-in NEEDS, and
2062
+ * what it NAMES.
2446
2063
  */
2447
- type IntersectAll<T extends readonly unknown[]> = T extends readonly [
2448
- infer Head,
2449
- ...infer Tail
2450
- ] ? Head & IntersectAll<Tail> : {};
2064
+ interface StandInId<TId extends string = never> {
2065
+ /** @internal */
2066
+ readonly [DECLARES]?: TId;
2067
+ }
2068
+ /** Phantom-only key (see `StandInId`); never set at runtime. */
2069
+ declare const DECLARES: unique symbol;
2070
+ /** The declaration ids a plugin still needs (reads the phantom carrier). */
2071
+ type RequiresOf<P> = P extends {
2072
+ readonly [REQUIRES]?: infer R;
2073
+ } ? Extract<R, string> : never;
2074
+ /** The ids a plugin and its subgraph provide (reads the phantom carrier). */
2075
+ type ProvidesOf<P> = P extends {
2076
+ readonly [PROVIDES]?: infer R;
2077
+ } ? Extract<R, string> : never;
2078
+ /** The contracts a plugin's subgraph declared (reads the phantom carrier). */
2079
+ type RequiredContractsOf<P> = P extends {
2080
+ readonly [REQUIRED_CONTRACTS]?: infer C;
2081
+ } ? Extract<C, ContractEntry> : never;
2082
+ /** The contracts a plugin's subgraph implements (reads the phantom carrier). */
2083
+ type ProvidedContractsOf<P> = P extends {
2084
+ readonly [PROVIDED_CONTRACTS]?: infer C;
2085
+ } ? Extract<C, ContractEntry> : never;
2086
+ /** Union the requires / provides across an inline imports or exports tuple. */
2087
+ type RequiresIn<T extends readonly unknown[]> = RequiresOf<T[number]>;
2088
+ type ProvidesIn<T extends readonly unknown[]> = ProvidesOf<T[number]>;
2089
+ /** Union the contracts across an inline imports or exports tuple. */
2090
+ type RequiredContractsIn<T extends readonly unknown[]> = RequiredContractsOf<T[number]>;
2091
+ type ProvidedContractsIn<T extends readonly unknown[]> = ProvidedContractsOf<T[number]>;
2451
2092
  /**
2452
- * The TSdk a composed plugin requires: every sub-plugin's TSdk requirement,
2453
- * all at once. Composing a plugin that needs `{ api }` with one that needs
2454
- * `{ options }` yields a composed plugin that needs `{ api } & { options }`.
2093
+ * Reject an `imports` / `exports` value whose type widened to a non-tuple
2094
+ * `Plugin[]`: a literal tuple has a literal `length`, a widened array has
2095
+ * `length: number`. Identity in the good (tuple) case, so `T & StaticList<T>`
2096
+ * infers `T` unchanged; an error brand in the bad case, which the passed array
2097
+ * is not assignable to.
2455
2098
  */
2456
- type ComposeSdk<T extends readonly Plugin<any, any>[]> = IntersectAll<SdkRequirementsOf<T>>;
2099
+ type StaticList<T extends readonly unknown[]> = number extends T["length"] ? {
2100
+ readonly __kitcoreError: "must be a fixed inline list of plugins, not a widened Plugin[]; declare them inline so the dependency graph stays statically known";
2101
+ } : T;
2102
+ /** A plugin's id as a type: `namespace/name`, or bare `name` when the namespace
2103
+ * is empty. The ledger keys on this (matching runtime id resolution), not the
2104
+ * bare name, so same-named plugins in different namespaces stay distinct. */
2105
+ type IdOf<TNamespace extends string, TName extends string> = TNamespace extends "" ? TName : `${TNamespace}/${TName}`;
2106
+ /** The binding name of an id: its last `/`-separated segment. The inverse view
2107
+ * of `IdOf`, used by `declare*` to derive the bare binding from a full id. */
2108
+ type LastSegment<TId extends string> = TId extends `${string}/${infer Rest}` ? LastSegment<Rest> : TId;
2109
+ /**
2110
+ * The `PluginSummary` a leaf carries, keyed on its full id. `TBinding` is the
2111
+ * surfaced binding the leaf implements (its call signature or its value).
2112
+ *
2113
+ * `TBinding` is REQUIRED, deliberately. Defaulting it to `never` would make a
2114
+ * three-argument annotation contribute no contract, so a hand-written
2115
+ * annotation would keep compiling and silently drop the leaf out of the
2116
+ * compatibility check.
2117
+ * A missing argument is a compile error instead.
2118
+ */
2119
+ type LeafSummary<TNamespace extends string, TName extends string, TImports extends readonly unknown[], TBinding> = LeafSummaryById<IdOf<TNamespace, TName>, TImports, TBinding>;
2120
+ /** {@link LeafSummary} for a leaf whose full id is already known rather than
2121
+ * composed from a namespace and a name, which is what the by-reference
2122
+ * `define*(ref, config)` forms have: the id comes off the stand-in. */
2123
+ type LeafSummaryById<TId extends string, TImports extends readonly unknown[], TBinding> = LeafSummaryOf<TId, RequiresIn<TImports>, ProvidesIn<TImports>, RequiredContractsIn<TImports>, ProvidedContractsIn<TImports>, TBinding>;
2124
+ /**
2125
+ * {@link LeafSummaryById} with each import ledger already read, so it is read
2126
+ * ONCE per leaf. See the rule on {@link AggregateSummaryOf}.
2127
+ */
2128
+ type LeafSummaryOf<TId extends string, TRequires extends string, TProvides extends string, TRequiredContracts extends ContractEntry, TProvidedContracts extends ContractEntry, TBinding> = PluginSummary<Exclude<TRequires, TId | TProvides>, TId | TProvides, TRequiredContracts, ContractEntry<TId, TBinding> | TProvidedContracts>;
2129
+ /**
2130
+ * The `PluginSummary` an aggregate carries, keyed on its full id.
2131
+ *
2132
+ * It contributes no contract for its own id. A module's contract IS its
2133
+ * exports, and each export already carries one keyed by its own id, so
2134
+ * `declarePlugin` is checked against the real module leaf by leaf. Carrying the
2135
+ * whole export-bindings record as a second entry would only add the binding
2136
+ * NAMES to the comparison, and it costs a mapped type over every export inside
2137
+ * every enclosing summary. That cost grows with the graph, for nothing.
2138
+ */
2139
+ type AggregateSummary<TNamespace extends string, TName extends string, TImports extends readonly unknown[], TExports extends readonly unknown[]> = AggregateSummaryOf<IdOf<TNamespace, TName>, RequiresIn<TImports> | RequiresIn<TExports>, ProvidesIn<TImports> | ProvidesIn<TExports>, RequiredContractsIn<TImports> | RequiredContractsIn<TExports>, ProvidedContractsIn<TImports> | ProvidedContractsIn<TExports>>;
2140
+ /**
2141
+ * {@link AggregateSummary} with each child ledger already read, so it is read
2142
+ * ONCE per aggregate.
2143
+ *
2144
+ * THE RULE FOR EVERY SUMMARY: read each child ledger ONCE, at the call site,
2145
+ * and pass it in. A summary's phantom slots must never contain an expression
2146
+ * that reads the children again.
2147
+ *
2148
+ * Duplicating a read makes the cost grow exponentially with graph depth rather
2149
+ * than linearly, and a deep graph then fails to compile at all. TypeScript has
2150
+ * no way to name an intermediate type, so a helper that takes the ledgers as
2151
+ * parameters is the only way to read each one exactly once.
2152
+ *
2153
+ * So `Exclude<TRequires, TId | TProvides>` is safe here: `TProvides` is a
2154
+ * parameter, already resolved, shared by both slots. Inlining it back to
2155
+ * `Exclude<RequiresIn<TImports>, TId | ProvidesIn<TImports>>` reads the
2156
+ * children twice and brings the exponential back. Do not "simplify" these
2157
+ * helpers away. `composition-depth.test.ts` and `import-chain-depth.test.ts`
2158
+ * are the canaries.
2159
+ */
2160
+ type AggregateSummaryOf<TId extends string, TRequires extends string, TProvides extends string, TRequiredContracts extends ContractEntry, TProvidedContracts extends ContractEntry> = PluginSummary<Exclude<TRequires, TId | TProvides>, TId | TProvides, TRequiredContracts, TProvidedContracts>;
2161
+ /**
2162
+ * The `PluginSummary` a re-export synthetic forwards from its source: the
2163
+ * source's own ledgers, unchanged, since `selectExports` / `omitExports` change
2164
+ * which bindings are visible and never which ids the graph reaches. Each read
2165
+ * appears once, per the rule on {@link AggregateSummaryOf}.
2166
+ *
2167
+ * `TSource` is inferred from an intersection parameter, which is fragile. If it
2168
+ * ever stops binding the source's summary it falls back to `unknown`, these
2169
+ * ledgers come out empty, and every check behind the helper switches off
2170
+ * SILENTLY, with nothing failing to compile. The forwarding case in
2171
+ * `select-exports.test.ts` is the only thing that catches that, so it is
2172
+ * load-bearing rather than illustrative.
2173
+ */
2174
+ type ForwardedSummary<TSource> = PluginSummary<RequiresOf<TSource>, ProvidesOf<TSource>, RequiredContractsOf<TSource>, ProvidedContractsOf<TSource>>;
2175
+ /** The `PluginSummary` a `declarePlugin` declaration carries: its id in the
2176
+ * requirements ledger, plus the contracts its export stand-ins declared, read
2177
+ * once at the call site per the rule on {@link AggregateSummaryOf}. */
2178
+ type AggregateDeclarationSummary<TId extends string, TRequiredContracts extends ContractEntry> = PluginSummary<TId, never, TRequiredContracts, never>;
2179
+ /** The `PluginSummary` a required declaration carries: its id in the
2180
+ * requirements ledger, and the contract every provider of that id must honor. */
2181
+ type DeclarationSummary<TId extends string, TBinding> = PluginSummary<TId, never, ContractEntry<TId, TBinding>, never>;
2182
+ /** The optional twin of {@link DeclarationSummary}: it claims no slot, so it is
2183
+ * never a missing dependency, but a provider that DOES appear under the id
2184
+ * still has to honor the contract. */
2185
+ type OptionalDeclarationSummary<TId extends string, TBinding> = PluginSummary<never, never, ContractEntry<TId, TBinding>, never>;
2457
2186
  /**
2458
- * What a composed plugin provides: every sub-plugin's TProvides combined.
2459
- * Composing a plugin that provides `{ hello }` with one that provides
2460
- * `{ goodbye }` yields `{ hello } & { goodbye }`.
2187
+ * The runtime-input channel for `createSdk`. `configuration` maps plugin ids to
2188
+ * immutable values; each entry materializes as a static value property under
2189
+ * that id, satisfying a `declareProperty` / `declareOptionalProperty` stand-in exactly
2190
+ * as a registered provider would (DI value injection). Strict at build time:
2191
+ * an id must resolve to a property stand-in reachable from the root, so
2192
+ * unknown ids, non-property targets, and collisions with a registered real
2193
+ * provider all throw. kitcore keeps the map untyped; a head's factory is the
2194
+ * typed wrapper (`createMySdk(options)` passes
2195
+ * `{ configuration: { "my/config": options } }`).
2461
2196
  */
2462
- type ComposeProvides<T extends readonly Plugin<any, any>[]> = IntersectAll<ProvidesOf<T>>;
2197
+ interface CreateSdkOptions {
2198
+ configuration?: Record<string, unknown>;
2199
+ }
2463
2200
  /**
2464
- * @deprecated Use {@link createPluginStack} instead. It carries the same
2465
- * collision-detection and hook-composition behavior and supports
2466
- * per-step `{ override: true }` for intentional duplicates. Migration
2467
- * (note the stack emits a definition, not a bare function):
2201
+ * Surfaced by `createSdk` when reachable declarations have no provider.
2468
2202
  *
2469
- * composePlugins(a, b, c)
2470
- * // →
2471
- * createPluginStack().use(a).use(b).use(c).toPlugin({ name: "bundle" })
2472
- *
2473
- * Bundles N plugins into a single plugin so a consumer can call
2474
- * `.use(combined)` once on a stack. Bag mode: sub-plugins must not
2475
- * depend on each other; TSdk on sub-plugins is the intersection of
2476
- * every sub-plugin's requirements (so the type system never exposes
2477
- * one sub-plugin's contributions to another).
2478
- */
2479
- declare function composePlugins<const Ts extends readonly Plugin<any, any>[]>(...plugins: Ts): Plugin<ComposeSdk<Ts>, ComposeProvides<Ts>>;
2480
- /**
2481
- * A typed builder that accumulates plugins into an immutable linked list.
2482
- * Each `.use` returns a new stack instance (cons-style); the original
2483
- * stack stays usable for branching. Call `toPlugin()` to collapse the
2484
- * accumulated chain into a single `Plugin<TRequires, TProvides>`.
2485
- *
2486
- * Type params: `TRequires` is the external surface declared on
2487
- * `createPluginStack<TRequires>()` (what the outer sdk will provide);
2488
- * `TProvides` accumulates every registration's provides.
2203
+ * The guard names the property it checks (`CompletenessOf`) and the brand
2204
+ * names the fault, so the pair shares no root. That is deliberate: "missing"
2205
+ * tells a reader what to do, where "incomplete" only restates the property.
2489
2206
  */
2490
- interface PluginStack<TRequires, TProvides extends PluginProvides> {
2491
- /**
2492
- * Register a bare plugin function. Its required surface is constrained
2493
- * to `TRequires & TProvides` (the external requirements plus everything
2494
- * provided by earlier `.use` calls), so registration order is enforced
2495
- * per step: a plugin that reads a dependency at construction can only be
2496
- * registered after a plugin that provides it. This stack collapses to a
2497
- * single function plugin and runs its entries in registration order, so
2498
- * the type-level order matches the runtime order.
2499
- *
2500
- * `{ override: true }` lets a registration replace an earlier root/meta
2501
- * key it would otherwise collide with.
2502
- */
2503
- use<TNewProvides extends PluginProvides>(plugin: Plugin<TRequires & TProvides, TNewProvides>, options?: {
2504
- override?: boolean;
2505
- }): PluginStack<TRequires, TProvides & TNewProvides>;
2506
- /**
2507
- * Collapse the accumulated registrations into a single bare function
2508
- * plugin. Its TSdk is `TRequires` (the declared external surface);
2509
- * in-stack inter-plugin dependencies are resolved when its setup runs.
2510
- * A head lifts it into the module model with `fromFunctionPlugin`.
2511
- */
2512
- toPlugin(): Plugin<TRequires, TProvides>;
2513
- /**
2514
- * Build the stack into a sealed, ready-to-use SDK. Eagerly applies the
2515
- * resolved order: each plugin runs once during `toSdk`, contributions
2516
- * merge into a single accumulator, and the result is wrapped as an
2517
- * `Sdk<TRequires & TProvides>`. The returned SDK has `context` and
2518
- * `getRegistry`, but no plugin-registration method.
2519
- * To extend a built SDK, use the top-level {@link addPlugin}.
2520
- */
2521
- toSdk(): Sdk<TRequires & TProvides>;
2207
+ interface MissingProviders<TIds extends string> {
2208
+ readonly __kitcoreError: "Missing concrete provider(s) for required declaration id(s)";
2209
+ readonly missing: TIds;
2522
2210
  }
2523
2211
  /**
2524
- * Create an empty plugin stack. Pass a type parameter to declare external
2525
- * SDK requirements that every plugin in the stack can rely on:
2526
- *
2527
- * const tablesPlugin = createPluginStack<FetchPluginProvides>()
2528
- * .use(apiPlugin)
2529
- * .use(listTablesPlugin)
2530
- * .use(getTablePlugin)
2531
- * .toPlugin({ name: "tables" });
2212
+ * `unknown` when every reachable declaration is provided, otherwise a
2213
+ * `MissingProviders` brand. `createSdk` takes `root: P & CompletenessOf<P>`,
2214
+ * so a complete root infers `P` unchanged (intersect `unknown`) while an
2215
+ * incomplete one fails to assign (the argument lacks `missing`).
2216
+ */
2217
+ type CompletenessOf<P> = [
2218
+ Exclude<RequiresOf<P>, ProvidesOf<P>>
2219
+ ] extends [never] ? unknown : MissingProviders<Exclude<RequiresOf<P>, ProvidesOf<P>>>;
2220
+ /** The provided entries registered under one id. */
2221
+ type ProvidersFor<TProvided extends ContractEntry, TId extends string> = Extract<TProvided, {
2222
+ readonly id: TId;
2223
+ }>;
2224
+ /**
2225
+ * The ids whose reachable providers do not all honor the declared contract.
2532
2226
  *
2533
- * const sdk = createPluginStack()
2534
- * .use(fetchPlugin) // provides FetchPluginProvides
2535
- * .use(tablesPlugin) // PluginDefinition<FetchPluginProvides, ...>
2536
- * .toSdk();
2227
+ * EVERY provider under an id must honor it, not just one: `declareDefault` lets
2228
+ * a default coexist with an explicit provider, so "some compatible provider
2229
+ * exists" would pass a good default beside a bad explicit one while the runtime
2230
+ * picks the bad one.
2537
2231
  *
2538
- * The stack itself is immutable: calling `.use` returns a new stack
2539
- * without mutating the original, so you can branch off a base stack for
2540
- * different consumers. Until the stack materializes, no plugin functions
2541
- * run.
2232
+ * An id with no provider yields nothing here. That is `CompletenessOf`'s
2233
+ * report, and two errors for one cause read worse than one.
2542
2234
  */
2235
+ type IncompatibleIds<TRequired extends ContractEntry, TProvided extends ContractEntry> = TRequired extends ContractEntry ? MismatchedProviders<TRequired, ProvidersFor<TProvided, TRequired["id"]>> : never;
2236
+ /** The required id, once per provider of it that fails the contract. An id with
2237
+ * no provider yields `never` here, since a distributive conditional over
2238
+ * `never` is `never`. */
2239
+ type MismatchedProviders<TRequired extends ContractEntry, TCandidate extends ContractEntry> = TCandidate extends ContractEntry ? [TCandidate["binding"]] extends [TRequired["binding"]] ? never : ServesEveryDeclaredCall<TCandidate["binding"], TRequired["binding"]> extends true ? never : TRequired["id"] : never;
2240
+ /** The keys a caller of `T` must supply. */
2241
+ type RequiredKeys<T> = keyof {
2242
+ [K in keyof T as {} extends Pick<T, K> ? never : K]: unknown;
2243
+ };
2543
2244
  /**
2544
- * @deprecated The module model replaces this exit; it logs a runtime
2545
- * deprecation and will be removed in a release after this warning ships.
2245
+ * Rescues a provider that whole-function assignability rejects for a reason
2246
+ * that does not apply here.
2247
+ *
2248
+ * TypeScript's weak-type rule refuses to relate two object types that share no
2249
+ * properties, even when the target needs none of them. So a declaration
2250
+ * promising `{ search: string }` failed against a provider taking
2251
+ * `{ locale?: string }`, though that provider requires nothing and reads
2252
+ * nothing the declaration sends. That contradicts the rule this check is built
2253
+ * on, which is that a provider may accept WIDER input.
2254
+ *
2255
+ * The escape stays sound by demanding all three: the output is still a subtype,
2256
+ * the provider requires no input field, and the two inputs share no key, so
2257
+ * there is no field the provider can read at a type it does not expect.
2258
+ */
2259
+ type ServesEveryDeclaredCall<TProvided, TRequired> = TRequired extends (...args: infer TDeclaredArgs) => infer TDeclaredOut ? TProvided extends (...args: infer TProviderArgs) => infer TProviderOut ? [TProviderOut] extends [TDeclaredOut] ? [TDeclaredArgs] extends [readonly [unknown?]] ? [TProviderArgs] extends [readonly [unknown?]] ? [
2260
+ Extract<keyof NonNullable<TDeclaredArgs[0]>, keyof NonNullable<TProviderArgs[0]>>
2261
+ ] extends [never] ? [RequiredKeys<NonNullable<TProviderArgs[0]>>] extends [never] ? true : false : false : false : false : false : false : false;
2262
+ /** Surfaced by `createSdk` when a provider contradicts its declaration. */
2263
+ interface IncompatibleProviders<TIds extends string> {
2264
+ readonly __kitcoreError: "Provider(s) do not match the contract declared for the id(s); a provider may accept wider input but must return a subtype of the declared output";
2265
+ readonly incompatible: TIds;
2266
+ }
2267
+ /**
2268
+ * `unknown` when every provided id honors the contract declared for it,
2269
+ * otherwise an `IncompatibleProviders` brand. `createSdk` takes
2270
+ * `root: P & CompletenessOf<P> & CompatibilityOf<P>`, so a sound graph infers
2271
+ * `P` unchanged (intersect `unknown`) while an unsound one fails to assign.
2546
2272
  */
2547
- declare function createPluginStack<TRequires = object>(): PluginStack<TRequires, {
2548
- context: {
2549
- meta: Record<string, PluginMeta>;
2550
- hooks: MethodHooks;
2551
- };
2552
- }>;
2273
+ type CompatibilityOf<P> = IncompatibleIds<RequiredContractsOf<P>, ProvidedContractsOf<P>> extends infer TIds extends string ? [TIds] extends [never] ? unknown : IncompatibleProviders<TIds> : never;
2274
+ /** Recover the materialized SDK type for a checked root (the summary that
2275
+ * rides on the `define*` return is transparent to these). */
2276
+ type MethodSdkOf<P> = P extends MethodPlugin<infer TName, infer TInput, infer TOutput, infer TPos> ? Sdk<TName, TInput, TOutput, TPos> : never;
2277
+ type PropertySdkOf<P> = P extends PropertyPlugin<infer TName, infer TValue> ? PropertySdk<TName, TValue> : never;
2278
+ type AggregateSdkOf<P> = P extends AggregatePlugin<string, infer TExports> ? AggregateSdk<TExports> : never;
2553
2279
 
2554
2280
  /**
2555
2281
  * Reject a LIST stand-in from the ref form, at the REF rather than at `run`.
@@ -2609,7 +2335,11 @@ declare function defineMethod<const TName extends string, TInput, TOutput, const
2609
2335
  input?: unknown;
2610
2336
  }) => void | Promise<void>;
2611
2337
  run: (bag: MethodRunBag<ImportsOf<TImports>, TInput, TState>) => TOutput;
2612
- } & LeafMetaFields): MethodPlugin<TName, TInput, TOutput, TPositional> & LeafSummary<TNamespace, TName, TImports>;
2338
+ /** Validates and strips the output, and describes it for the registry. */
2339
+ outputSchema?: z.ZodSchema;
2340
+ /** Skip validating and stripping the output against `outputSchema`. */
2341
+ skipOutputValidation?: boolean;
2342
+ } & MethodMeta): MethodPlugin<TName, TInput, TOutput, TPositional> & LeafSummary<TNamespace, TName, TImports, MethodContract<TInput, TOutput, TPositional>>;
2613
2343
  declare function defineMethod<const TName extends string, TInput, TResponse extends StrictItem<TResponse>, TData = DataOf<TResponse>, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
2614
2344
  name: TName;
2615
2345
  namespace?: TNamespace;
@@ -2630,11 +2360,18 @@ declare function defineMethod<const TName extends string, TInput, TResponse exte
2630
2360
  input?: unknown;
2631
2361
  }) => void | Promise<void>;
2632
2362
  run: (bag: MethodRunBag<ImportsOf<TImports>, TInput, TState>) => TResponse | Promise<TResponse>;
2633
- } & LeafMetaFields): MethodPlugin<TName, TInput & CallOutputOptions, Promise<{
2363
+ /** Validates and strips the output, and describes it for the registry. */
2364
+ outputSchema?: z.ZodSchema;
2365
+ /** Skip validating and stripping the output against `outputSchema`. */
2366
+ skipOutputValidation?: boolean;
2367
+ } & MethodMeta): MethodPlugin<TName, TInput & CallOutputOptions, Promise<{
2634
2368
  data: TData;
2635
2369
  meta?: ResponseMeta;
2636
- }>, readonly [], ItemRunInput<TInput>> & LeafSummary<TNamespace, TName, TImports>;
2637
- 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: {
2370
+ }>, readonly [], ItemRunInput<TInput>> & LeafSummary<TNamespace, TName, TImports, MethodContract<CallContractInput<TInput, CallOutputOptions>, Promise<{
2371
+ data: TData;
2372
+ meta?: ResponseMeta;
2373
+ }>>>;
2374
+ declare function defineMethod<const TName extends string, TInput, TResponse extends StrictPage<TResponse>, TItem = ItemOf<TResponse>, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
2638
2375
  name: TName;
2639
2376
  namespace?: TNamespace;
2640
2377
  imports?: TImports & StaticList<TImports>;
@@ -2656,7 +2393,11 @@ declare function defineMethod<const TName extends string, TInput, TResponse exte
2656
2393
  input?: unknown;
2657
2394
  }) => void | Promise<void>;
2658
2395
  run: (bag: MethodRunBag<ImportsOf<TImports>, TInput & PageFetchInput, TState>) => TResponse | Promise<TResponse>;
2659
- } & LeafMetaFields): MethodPlugin<TName, TInput & PaginatedCallInput & CallOutputOptions, PaginatedSdkResult<TItem>, readonly [], ListRunInput<TInput>> & LeafSummary<TNamespace, TName, TImports>;
2396
+ /** Validates and strips the output, and describes it for the registry. */
2397
+ outputSchema?: z.ZodSchema;
2398
+ /** Skip validating and stripping the output against `outputSchema`. */
2399
+ skipOutputValidation?: boolean;
2400
+ } & MethodMeta): MethodPlugin<TName, TInput & PaginatedCallInput & CallOutputOptions, PaginatedSdkResult<TItem>, readonly [], ListRunInput<TInput>> & LeafSummary<TNamespace, TName, TImports, MethodContract<CallContractInput<TInput, PaginatedCallInput & CallOutputOptions>, PaginatedSdkResult<TItem>>>;
2660
2401
  declare function defineMethod<const TName extends string, TInput, TResponse, TItem, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
2661
2402
  name: TName;
2662
2403
  namespace?: TNamespace;
@@ -2679,7 +2420,11 @@ declare function defineMethod<const TName extends string, TInput, TResponse, TIt
2679
2420
  input?: unknown;
2680
2421
  }) => void | Promise<void>;
2681
2422
  run: (bag: MethodRunBag<ImportsOf<TImports>, TInput & PageFetchInput, TState>) => TResponse | Promise<TResponse>;
2682
- } & LeafMetaFields): MethodPlugin<TName, TInput & PaginatedCallInput & CallOutputOptions, PaginatedSdkResult<TItem>, readonly [], ListRunInput<TInput>> & LeafSummary<TNamespace, TName, TImports>;
2423
+ /** Validates and strips the output, and describes it for the registry. */
2424
+ outputSchema?: z.ZodSchema;
2425
+ /** Skip validating and stripping the output against `outputSchema`. */
2426
+ skipOutputValidation?: boolean;
2427
+ } & MethodMeta): MethodPlugin<TName, TInput & PaginatedCallInput & CallOutputOptions, PaginatedSdkResult<TItem>, readonly [], ListRunInput<TInput>> & LeafSummary<TNamespace, TName, TImports, MethodContract<CallContractInput<TInput, PaginatedCallInput & CallOutputOptions>, PaginatedSdkResult<TItem>>>;
2683
2428
  declare function defineMethod<const TName extends string, TInput, TOutput, const TId extends string, const TImports extends ImportsInput = readonly [], TState = undefined>(ref: MethodPlugin<TName, TInput, TOutput> & StandInId<TId> & RefFormRawOnly<TOutput>, config: {
2684
2429
  imports?: TImports & StaticList<TImports>;
2685
2430
  inputSchema?: z.ZodType<TInput>;
@@ -2695,7 +2440,11 @@ declare function defineMethod<const TName extends string, TInput, TOutput, const
2695
2440
  input?: unknown;
2696
2441
  }) => void | Promise<void>;
2697
2442
  run: (bag: MethodRunBag<ImportsOf<TImports>, NoInfer<TInput>, TState>) => NoInfer<TOutput>;
2698
- } & LeafMetaFields): MethodPlugin<TName, TInput, TOutput> & PluginSummary<LeafRequires<TId, TImports>, LeafProvides<TId, TImports>>;
2443
+ /** Validates and strips the output, and describes it for the registry. */
2444
+ outputSchema?: z.ZodSchema;
2445
+ /** Skip validating and stripping the output against `outputSchema`. */
2446
+ skipOutputValidation?: boolean;
2447
+ } & MethodMeta): MethodPlugin<TName, TInput, TOutput> & LeafSummaryById<TId, TImports, MethodContract<TInput, TOutput>>;
2699
2448
  /**
2700
2449
  * Patch how a surface PRESENTS an already-defined method, by reference. Pass
2701
2450
  * the method (or its `declareMethod` stand-in) and any of
@@ -2885,7 +2634,7 @@ declare function defineFormatter<const TImports extends ImportsInput = readonly
2885
2634
  */
2886
2635
  declare function declareMethod<const TId extends string, TInput = unknown, TOutput = unknown>(config: {
2887
2636
  id: LiteralString<TId>;
2888
- }): MethodPlugin<LastSegment<TId>, TInput, TOutput> & PluginSummary<TId, never> & StandInId<TId>;
2637
+ }): MethodPlugin<LastSegment<TId>, TInput, TOutput> & DeclarationSummary<TId, MethodContract<TInput, TOutput>> & StandInId<TId>;
2889
2638
  /**
2890
2639
  * Declare an OPTIONAL stand-in for a method registered elsewhere: the method twin
2891
2640
  * of `declareOptionalProperty`. Unlike `declareMethod`, an unsatisfied optional
@@ -2898,7 +2647,7 @@ declare function declareOptionalMethod<const TId extends string, TInput = unknow
2898
2647
  id: LiteralString<TId>;
2899
2648
  }): MethodPlugin<LastSegment<TId>, TInput, TOutput> & {
2900
2649
  optional: true;
2901
- } & PluginSummary<never, never> & StandInId<TId>;
2650
+ } & OptionalDeclarationSummary<TId, MethodContract<TInput, TOutput>> & StandInId<TId>;
2902
2651
  /**
2903
2652
  * Define a property leaf. Either a static `value` or a computed `get`, which
2904
2653
  * re-runs live on each read; an optional `setup` runs once at `createSdk`
@@ -2910,7 +2659,7 @@ declare function defineProperty<const TName extends string, TValue, const TNames
2910
2659
  name: TName;
2911
2660
  namespace?: TNamespace;
2912
2661
  value: TValue;
2913
- } & LeafMetaFields): PropertyPlugin<TName, TValue> & PluginSummary<never, IdOf<TNamespace, TName>>;
2662
+ } & PropertyMeta): PropertyPlugin<TName, TValue> & LeafSummary<TNamespace, TName, readonly [], TValue>;
2914
2663
  declare function defineProperty<const TName extends string, TValue, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", TState = undefined>(config: {
2915
2664
  name: TName;
2916
2665
  namespace?: TNamespace;
@@ -2937,7 +2686,7 @@ declare function defineProperty<const TName extends string, TValue, const TImpor
2937
2686
  /** Templated registry members for this property's dynamic sub-surface (e.g.
2938
2687
  * a proxy): each a bodyless declaration keyed by `path` instead of `name`. */
2939
2688
  dynamicMembers?: readonly DynamicMember[];
2940
- } & LeafMetaFields): PropertyPlugin<TName, TValue> & LeafSummary<TNamespace, TName, TImports>;
2689
+ } & PropertyMeta): PropertyPlugin<TName, TValue> & LeafSummary<TNamespace, TName, TImports, TValue>;
2941
2690
  /**
2942
2691
  * Provide a value for a declared property BY REFERENCE: pass the
2943
2692
  * `declareProperty` / `declareOptionalProperty` stand-in instead of respelling
@@ -2948,7 +2697,7 @@ declare function defineProperty<const TName extends string, TValue, const TImpor
2948
2697
  */
2949
2698
  declare function defineProperty<const TName extends string, TValue, const TId extends string>(ref: PropertyPlugin<TName, TValue> & StandInId<TId>, config: {
2950
2699
  value: NoInfer<TValue>;
2951
- } & LeafMetaFields): PropertyPlugin<TName, TValue> & PluginSummary<never, TId>;
2700
+ } & PropertyMeta): PropertyPlugin<TName, TValue> & PluginSummary<never, TId, never, ContractEntry<TId, TValue>>;
2952
2701
  /**
2953
2702
  * Declare a stand-in for a property registered elsewhere (a configured factory
2954
2703
  * plugin, e.g. the api client built from options). Carries only a name and a
@@ -2959,7 +2708,7 @@ declare function defineProperty<const TName extends string, TValue, const TId ex
2959
2708
  */
2960
2709
  declare function declareProperty<const TId extends string, TValue = unknown>(config: {
2961
2710
  id: LiteralString<TId>;
2962
- }): PropertyPlugin<LastSegment<TId>, TValue> & PluginSummary<TId, never> & StandInId<TId>;
2711
+ }): PropertyPlugin<LastSegment<TId>, TValue> & DeclarationSummary<TId, TValue> & StandInId<TId>;
2963
2712
  /**
2964
2713
  * Declare an OPTIONAL stand-in for a property registered elsewhere. Unlike
2965
2714
  * `declareProperty`, a `declareOptionalProperty` left unsatisfied is NOT a missing
@@ -2975,7 +2724,7 @@ declare function declareProperty<const TId extends string, TValue = unknown>(con
2975
2724
  */
2976
2725
  declare function declareOptionalProperty<const TId extends string, TValue = unknown>(config: {
2977
2726
  id: LiteralString<TId>;
2978
- }): PropertyPlugin<LastSegment<TId>, TValue | undefined> & PluginSummary<never, never> & StandInId<TId>;
2727
+ }): PropertyPlugin<LastSegment<TId>, TValue | undefined> & OptionalDeclarationSummary<TId, TValue | undefined> & StandInId<TId>;
2979
2728
  /**
2980
2729
  * Declare a DEFAULT provider for a dependency you own: import the capability the
2981
2730
  * given plugin provides, and fall back to that plugin when nothing else provides
@@ -2995,10 +2744,8 @@ declare function declareDefault<P extends AnyLeafPlugin>({ plugin, }: {
2995
2744
  * Define a method-lifecycle hook: a leaf whose `observe` contributes
2996
2745
  * fire-and-forget observers (`onMethodStart` / `onMethodEnd`) the method
2997
2746
  * boundary fires around every method, and whose `wrap` contributes
2998
- * contract-preserving middleware around imported methods. This is how a
2999
- * MODULE plugin provides cross-cutting behavior (the module-model successor
3000
- * to a legacy plugin writing `context.hooks` and to `definePlugin`'s
3001
- * deleted `middleware` map).
2747
+ * contract-preserving middleware around imported methods. This is the one way a
2748
+ * plugin provides cross-cutting behavior.
3002
2749
  *
3003
2750
  * `setup` runs once and owns the hook's state (e.g. a telemetry queue),
3004
2751
  * delivered to the observers. Each observer's bag
@@ -3057,27 +2804,7 @@ declare function defineHook<const TImports extends ImportsInput = readonly [], T
3057
2804
  declare function declarePlugin<const TId extends string, const TExports extends readonly AnyLeafPlugin[] = readonly []>(config: {
3058
2805
  id: LiteralString<TId>;
3059
2806
  exports?: TExports & StaticList<TExports>;
3060
- }): AggregatePlugin<LastSegment<TId>, ArrayExports<TExports>> & PluginSummary<TId, never>;
3061
- /**
3062
- * Function form — the legacy function-plugin identity wrapper: it returns the
3063
- * function unchanged but constrains its return to `PluginProvides` and
3064
- * preserves the narrow inferred shape, so callers derive `*PluginProvides` via
3065
- * `ReturnType<typeof plugin>`. Such a plugin runs through the legacy bridge
3066
- * (`fromFunctionPlugin` / `createPluginStack`), deprecated with it.
3067
- *
3068
- * @deprecated Author plugins with `defineMethod` / `defineProperty` /
3069
- * object-form `definePlugin` instead. This form logs a runtime deprecation and
3070
- * will be removed in a release after the warning ships.
3071
- */
3072
- declare function definePlugin<TSdk, TProvides extends PluginProvides>(fn: (sdk: TSdk & {
3073
- context: {
3074
- meta: Record<string, PluginMeta>;
3075
- };
3076
- }) => TProvides): (sdk: TSdk & {
3077
- context: {
3078
- meta: Record<string, PluginMeta>;
3079
- };
3080
- }) => TProvides;
2807
+ }): AggregatePlugin<LastSegment<TId>, ArrayExports<TExports>> & AggregateDeclarationSummary<TId, RequiredContractsIn<TExports>>;
3081
2808
  /**
3082
2809
  * Define a plugin module: an aggregate that re-exports child plugins.
3083
2810
  * `exports` mirrors `imports`: an array where a leaf binds under its own name
@@ -3086,12 +2813,12 @@ declare function definePlugin<TSdk, TProvides extends PluginProvides>(fn: (sdk:
3086
2813
  * imports-only module can omit it. Re-exporting implies a dependency on the
3087
2814
  * child. To wrap imported methods, export a `defineHook` with `wrap`.
3088
2815
  */
3089
- declare function definePlugin<const TName extends string, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", const TExports extends readonly (AnyLeafPlugin | AnyAggregatePlugin)[] = readonly []>(config: {
2816
+ declare function definePlugin<const TName extends string, const TImports extends ImportsInput = readonly [], const TNamespace extends string = "", const TExports extends readonly unknown[] = readonly []>(config: {
3090
2817
  name: TName;
3091
2818
  namespace?: TNamespace;
3092
2819
  imports?: TImports & StaticList<TImports>;
3093
- exports?: TExports & StaticList<TExports>;
3094
- }): AggregatePlugin<TName, ArrayExports<TExports>> & AggregateSummary<TNamespace, TName, TImports, TExports>;
2820
+ exports?: TExports & StaticList<TExports> & PluginList<TExports>;
2821
+ }): AggregatePlugin<TName, AsExports<ArrayExports<Extract<TExports, ExportsInput>>>> & AggregateSummary<TNamespace, TName, TImports, TExports>;
3095
2822
 
3096
2823
  /**
3097
2824
  * A `selectExports` spec: a bare export name to keep (`"getApp"`), or a rename
@@ -3108,9 +2835,6 @@ type ResolveSpec<TExports extends Record<string, AnyLeafPlugin>, S> = S extends
3108
2835
  } : never : {
3109
2836
  [K in keyof S]: S[K] extends keyof TExports ? TExports[S[K]] : never;
3110
2837
  };
3111
- /** Ensure the computed export record satisfies the `AggregatePlugin` constraint
3112
- * (an empty/degenerate selection collapses to a bare exports record). */
3113
- type AsExports<T> = T extends Record<string, AnyLeafPlugin> ? T : Record<string, AnyLeafPlugin>;
3114
2838
  /**
3115
2839
  * Select (and optionally rename) a subset of a module's exports, the ES
3116
2840
  * `{ a, b, c as d }` clause. Works the same in `imports` (import) and
@@ -3119,9 +2843,9 @@ type AsExports<T> = T extends Record<string, AnyLeafPlugin> ? T : Record<string,
3119
2843
  * synthetic aggregate over the chosen bindings) that drops straight into either
3120
2844
  * array; the selected bindings keep the source module's identity.
3121
2845
  */
3122
- declare function selectExports<TExports extends Record<string, AnyLeafPlugin>, const TSpecs extends readonly SelectSpec<TExports>[]>(source: AggregatePlugin<string, TExports>, ...specs: TSpecs): AggregatePlugin<string, AsExports<UnionToIntersection<{
2846
+ declare function selectExports<TExports extends Record<string, AnyLeafPlugin>, const TSpecs extends readonly SelectSpec<TExports>[], TSource = unknown>(source: AggregatePlugin<string, TExports> & TSource, ...specs: TSpecs): AggregatePlugin<string, AsExports<UnionToIntersection<{
3123
2847
  [I in keyof TSpecs]: ResolveSpec<TExports, TSpecs[I]>;
3124
- }[number]>>>;
2848
+ }[number]>>> & ForwardedSummary<TSource>;
3125
2849
  /**
3126
2850
  * Re-export all of a module's exports EXCEPT the named ones, the denylist
3127
2851
  * complement to {@link selectExports}'s allowlist (think TS `Omit` vs `Pick`).
@@ -3133,41 +2857,7 @@ declare function selectExports<TExports extends Record<string, AnyLeafPlugin>, c
3133
2857
  * not surfaced under a binding. That lets a head replace an export's binding
3134
2858
  * with its own plugin while still depending on the original by id.
3135
2859
  */
3136
- 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]>>;
3137
-
3138
- /**
3139
- * Lift a legacy function plugin into the module model. The
3140
- * returned plugin runs `fn` at materialization and surfaces its root methods;
3141
- * `createPluginStack().toPlugin()` is built on this, and `addPlugin` uses it for
3142
- * external function plugins. `fn`'s `context` contributions merge into the live
3143
- * `SdkContext`; its other root keys become the surface.
3144
- *
3145
- * @deprecated The module model replaces this exit; it logs a runtime
3146
- * deprecation and will be removed in a release after this warning ships.
3147
- */
3148
- declare function fromFunctionPlugin<TProvides extends PluginProvides>(fn: (sdk: any) => TProvides, config: {
3149
- name: string;
3150
- namespace?: string;
3151
- }): LegacyPlugin<TProvides & {
3152
- getRegistry: (options?: {
3153
- package?: string;
3154
- }) => RegistryResult;
3155
- }>;
3156
- /**
3157
- * Build a {@link LegacyMergePlugin}: pass the collapsed legacy stack
3158
- * (`stack.toPlugin()`) as `legacy` and the migrated module-model plugins as
3159
- * `plugin`. `createSdk(defineLegacyMerge({...}))` surfaces both.
3160
- *
3161
- * @deprecated Build directly with `createSdk(root, { configuration })`
3162
- * instead; it logs a runtime deprecation and will be removed in a release
3163
- * after this warning ships.
3164
- */
3165
- declare function defineLegacyMerge<TProvides extends PluginProvides, const TPlugin extends AnyPlugin>(args: {
3166
- name: string;
3167
- namespace?: string;
3168
- legacy: (sdk: any) => TProvides;
3169
- plugin: TPlugin;
3170
- }): LegacyMergePlugin<TProvides, TPlugin>;
2860
+ declare function omitExports<TExports extends Record<string, AnyLeafPlugin>, const TOmit extends readonly (keyof TExports & string)[], TSource = unknown>(source: AggregatePlugin<string, TExports> & TSource, omit: TOmit): AggregatePlugin<string, Omit<TExports, TOmit[number]>> & ForwardedSummary<TSource>;
3171
2861
 
3172
2862
  /**
3173
2863
  * Core error machinery.
@@ -3175,7 +2865,7 @@ declare function defineLegacyMerge<TProvides extends PluginProvides, const TPlug
3175
2865
  * kitcore constructs errors at two internal throw sites: input
3176
2866
  * validation (`utils/validation.ts`) and non-Error normalization
3177
2867
  * (`utils/function-utils.ts`'s `normalizeError`). Heads supply a
3178
- * `adaptError` factory via `createCorePlugin` to map kitcore's abstract
2868
+ * `adaptError` factory under `CORE_OPTIONS_ID` to map kitcore's abstract
3179
2869
  * `CoreErrorCode` values onto their own branded error classes; if
3180
2870
  * no factory is supplied, kitcore falls back to constructing a plain
3181
2871
  * `CoreError`. Either way, every kitcore-thrown error is brand-stamped
@@ -3200,6 +2890,13 @@ declare const CORE_ERROR_SYMBOL: unique symbol;
3200
2890
  declare const CoreErrorCode: {
3201
2891
  readonly Validation: "VALIDATION_ERROR";
3202
2892
  readonly Unknown: "UNKNOWN_ERROR";
2893
+ /**
2894
+ * The object handed to a framework reader is not an SDK `createSdk` built, so
2895
+ * there is no plugin graph to read. A code rather than prose because a caller
2896
+ * distinguishing "no registry here" from "the registry failed to build" has to
2897
+ * match on something stable, and the message is not that.
2898
+ */
2899
+ readonly NoSdkContext: "NO_SDK_CONTEXT_ERROR";
3203
2900
  };
3204
2901
  type CoreErrorCode = (typeof CoreErrorCode)[keyof typeof CoreErrorCode];
3205
2902
  /**
@@ -3320,9 +3017,7 @@ interface StabilityNotice {
3320
3017
  /**
3321
3018
  * The well-known id for framework options: heads inject a `CoreOptions` bag
3322
3019
  * under it via `createSdk`'s `configuration` (or register a property plugin),
3323
- * and the method boundary resolves it by id at every invocation, falling back
3324
- * to the legacy `context.core` write while the deprecated `createCorePlugin`
3325
- * path still exists.
3020
+ * and the method boundary resolves it by id at every invocation.
3326
3021
  */
3327
3022
  declare const CORE_OPTIONS_ID = "kitcore/coreOptions";
3328
3023
  /**
@@ -3381,7 +3076,7 @@ interface CoreOptions {
3381
3076
  * `CoreOptions | undefined` (absent means kitcore's built-in behavior). Heads
3382
3077
  * supply the value via `createSdk`'s `configuration` or a registered property.
3383
3078
  */
3384
- declare const coreOptionsPluginRef: PropertyPlugin<"coreOptions", CoreOptions | undefined> & PluginSummary<never, never> & StandInId<"kitcore/coreOptions">;
3079
+ declare const coreOptionsPluginRef: PropertyPlugin<"coreOptions", CoreOptions | undefined> & OptionalDeclarationSummary<"kitcore/coreOptions", CoreOptions | undefined> & StandInId<"kitcore/coreOptions">;
3385
3080
  /**
3386
3081
  * Escape hatch. A built-in privileged plugin whose value is the live
3387
3082
  * `SdkContext` (the raw plugin graph). Importing it (`imports.context`) lets a
@@ -3407,17 +3102,18 @@ declare const getRegistryPlugin: MethodPlugin<"getRegistry", {
3407
3102
  package?: string | undefined;
3408
3103
  } | undefined, RegistryResult, readonly [], {
3409
3104
  package?: string | undefined;
3410
- } | undefined> & LeafSummary<"kitcore", "getRegistry", readonly [PropertyPlugin<"context", SdkContext>]>;
3105
+ } | undefined> & LeafSummary<"kitcore", "getRegistry", readonly [PropertyPlugin<"context", SdkContext>], (input?: {
3106
+ package?: string | undefined;
3107
+ } | undefined) => RegistryResult>;
3411
3108
 
3412
- /** The off-surface escape hatch to an SDK's `SdkContext`. */
3109
+ /** The off-surface reader for an SDK's `SdkContext`. Throws when there is
3110
+ * none, because every caller dereferences the result at once. */
3413
3111
  declare function getContext(sdk: unknown): SdkContext;
3414
3112
  /**
3415
3113
  * Read an SDK's registry from outside its surface, so a head need not re-export
3416
- * `getRegistryPlugin` for a controller to introspect it. Module-model SDKs go
3417
- * through the shared, memoized {@link getCachedRegistry} (context-keyed, so this
3418
- * and a surfaced `getRegistry()` return the same object). A pure-legacy
3419
- * stack-built SDK has no `[CONTEXT]` graph; for those the only path is a
3420
- * surfaced `getRegistry()`, so fall back to it when present. Each package
3114
+ * `getRegistryPlugin` for a controller to introspect it. A `createSdk` build
3115
+ * goes through the shared, memoized {@link getCachedRegistry} (context-keyed, so
3116
+ * this and a surfaced `getRegistry()` return the same object). Each package
3421
3117
  * filter is memoized separately.
3422
3118
  */
3423
3119
  declare function getRegistry(sdk: unknown, packageFilter?: string): RegistryResult;
@@ -3460,23 +3156,17 @@ declare function disposeSdk(sdk: unknown, input?: unknown): Promise<void>;
3460
3156
  * value; an aggregate root its export bindings. `options.configuration`
3461
3157
  * injects runtime values by plugin id (see {@link CreateSdkOptions}).
3462
3158
  */
3463
- declare function createSdk<P extends AnyMethodPlugin>(root: P & CompletenessOf<P>, options?: CreateSdkOptions): MethodSdkOf<P>;
3464
- declare function createSdk<P extends AnyPropertyPlugin>(root: P & CompletenessOf<P>, options?: CreateSdkOptions): PropertySdkOf<P>;
3465
- declare function createSdk<P extends AnyAggregatePlugin>(root: P & CompletenessOf<P>, options?: CreateSdkOptions): AggregateSdkOf<P>;
3466
- declare function createSdk<TSurface>(root: LegacyPlugin<TSurface>, options?: CreateSdkOptions): TSurface & SdkInternals;
3467
- declare function createSdk<TProvides extends PluginProvides, TPlugin extends AnyPlugin>(root: LegacyMergePlugin<TProvides, TPlugin>, options?: CreateSdkOptions): TProvides & {
3468
- getRegistry: (options?: {
3469
- package?: string;
3470
- }) => RegistryResult;
3471
- } & AddedSurface<TPlugin> & SdkInternals;
3159
+ declare function createSdk<P extends AnyMethodPlugin>(root: P & CompletenessOf<P> & CompatibilityOf<P>, options?: CreateSdkOptions): MethodSdkOf<P>;
3160
+ declare function createSdk<P extends AnyPropertyPlugin>(root: P & CompletenessOf<P> & CompatibilityOf<P>, options?: CreateSdkOptions): PropertySdkOf<P>;
3161
+ declare function createSdk<P extends AnyAggregatePlugin>(root: P & CompletenessOf<P> & CompatibilityOf<P>, options?: CreateSdkOptions): AggregateSdkOf<P>;
3162
+ declare function createSdk<P extends Plugin>(root: P & CompletenessOf<P> & CompatibilityOf<P>, options?: CreateSdkOptions): never;
3472
3163
  /**
3473
3164
  * Extend an already-built SDK in place with one more plugin (the post-seal
3474
- * extension path). Dispatches on shape: a module-model plugin (`defineMethod` /
3475
- * `defineProperty` / `definePlugin`) is materialized incrementally into the live
3476
- * graph; a legacy function plugin runs through the legacy merge. Either way the
3477
- * caller's `sdk` binding is narrowed to include the addition.
3165
+ * extension path): the plugin's not-yet-materialized graph is materialized
3166
+ * incrementally into the live graph, and the caller's `sdk` binding is narrowed
3167
+ * to include the addition.
3478
3168
  */
3479
- declare function addPlugin<TSdk extends object, P>(sdk: TSdk, plugin: P, options?: {
3169
+ declare function addPlugin<TSdk extends object, P extends Plugin>(sdk: TSdk, plugin: P, options?: {
3480
3170
  override?: boolean;
3481
3171
  }): asserts sdk is TSdk & AddedSurface<P>;
3482
3172
 
@@ -3873,16 +3563,18 @@ interface Controller {
3873
3563
  * What the driver needs of a built SDK: one of two ways to reach a registry.
3874
3564
  *
3875
3565
  * The registry is read with the free {@link getRegistry}, which finds it on the
3876
- * SDK's context and falls back to a surfaced `getRegistry()` for a legacy
3877
- * stack-built SDK. So demanding the surfaced method alone is wrong: a bare tool
3878
- * SDK does not surface one, and it cannot always add `getRegistryPlugin`
3566
+ * SDK's context and falls back to a surfaced `getRegistry()` for an object that
3567
+ * carries no context. So demanding the surfaced method alone is wrong: a bare
3568
+ * tool SDK does not surface one, and it cannot always add `getRegistryPlugin`
3879
3569
  * either, because a head bundling its own kitcore copy would collide with it on
3880
3570
  * the shared `kitcore/getRegistry` id.
3881
3571
  *
3882
3572
  * A union, because those really are two different shapes. `SdkInternals` is
3883
- * what every `createSdk` result carries, and the structural branch is the
3884
- * legacy one. Anything else can never back a controller, and saying so here
3885
- * beats an internal registry error on the caller's first `listMethods()`.
3573
+ * what every `createSdk` result carries; the structural branch covers whatever
3574
+ * else answers the registry contract, such as a test stub or a host wrapper
3575
+ * projecting someone else's registry. Anything else can never back a
3576
+ * controller, and saying so here beats an internal registry error on the
3577
+ * caller's first `listMethods()`.
3886
3578
  *
3887
3579
  * The context branch is `SdkInternals`, which declares the `[CONTEXT]` symbol
3888
3580
  * materialization actually writes. So this checks the real thing rather than a
@@ -3901,167 +3593,6 @@ type ControllerSdk = SdkInternals | {
3901
3593
  */
3902
3594
  declare function createController(sdk: ControllerSdk): Controller;
3903
3595
 
3904
- /**
3905
- * The floor the framework holds its own call parameters to, and the only
3906
- * statement of their shapes. Which of them a given boundary reads at all is
3907
- * that boundary's {@link FrameworkOptionsPolicy}.
3908
- *
3909
- * MINIMAL on purpose. It rejects what the machinery cannot act on and nothing
3910
- * else, leaving a plugin free to tighten it. `pageSize` is at least 1 because a
3911
- * page loop asking upstream for zero items does not terminate. `maxItems` may
3912
- * be 0, since "return nothing" is a coherent request the loop already handles.
3913
- * `cursor` is any string: its meaning belongs to the head's API, including
3914
- * whatever a reverse-paginating one encodes in it.
3915
- *
3916
- * A plugin that wants a tighter rule writes it in its own `inputSchema`, and
3917
- * both run. See {@link parseCallOptions}.
3918
- */
3919
- declare const CallFrameworkOptionsSchema: z.ZodObject<{
3920
- cursor: z.ZodOptional<z.ZodString>;
3921
- pageSize: z.ZodOptional<z.ZodNumber>;
3922
- maxItems: z.ZodOptional<z.ZodNumber>;
3923
- skipOutputDataValidation: z.ZodOptional<z.ZodBoolean>;
3924
- }, z.core.$strip>;
3925
- type CallFrameworkOptions = z.infer<typeof CallFrameworkOptionsSchema>;
3926
- type CallFrameworkOptionKey = keyof CallFrameworkOptions;
3927
- /**
3928
- * What one boundary does with the framework's call parameters.
3929
- *
3930
- * There is no global answer, because the modes differ. A list call feeds a page
3931
- * loop; an item call has no loop to feed; a legacy handler honors nothing the
3932
- * framework added after it was written.
3933
- *
3934
- * This is a fact about the MODE, decided when the boundary is built. It says
3935
- * nothing about the plugin's schema, which is the difference between this and
3936
- * everything {@link parseCallOptions} used to infer.
3937
- */
3938
- interface FrameworkOptionsPolicy {
3939
- /** The parameters this boundary reads. Each is also held to
3940
- * {@link CallFrameworkOptionsSchema}, whatever the plugin's schema says. */
3941
- claims: readonly CallFrameworkOptionKey[];
3942
- /** The subset handed to `run` even when the plugin's schema dropped it,
3943
- * because `run` cannot do its job without it. A list `run` is asked for one
3944
- * page, so it gets that page. */
3945
- injects: readonly CallFrameworkOptionKey[];
3946
- }
3947
-
3948
- /**
3949
- * Generic utility functions for creating SDK-method wrappers.
3950
- *
3951
- * Both `createFunction` and `createPaginatedFunction` accept the SDK
3952
- * as a parameter and read framework state (`hooks`, `core.adaptError`)
3953
- * live from `sdk.context.*` at method-invocation time. Plugins registered
3954
- * after a method is built still observe and configure it; ordering of
3955
- * plugin registration doesn't change runtime semantics. (Pagination's
3956
- * `adaptPage` is passed in per method, not read from context.)
3957
- */
3958
-
3959
- /**
3960
- * Minimal SDK shape the function wrappers accept. The wrappers only
3961
- * touch `context.hooks` and the resolved core options, but we keep
3962
- * `context` typed as `unknown` so any kitcore-built SDK (whose context type
3963
- * widens unpredictably as plugins layer on) flows through without
3964
- * upstream type narrowing. Each read inside is asserted at the use
3965
- * site against the small slice we actually need.
3966
- */
3967
- type FunctionSdk = {
3968
- context: unknown;
3969
- };
3970
- /**
3971
- * Wrap a core async function with input validation, error normalization,
3972
- * and method-call lifecycle hooks. Hooks and `adaptError` are read live
3973
- * from `sdk.context.*` at every invocation, so a plugin registered
3974
- * after this method is built still observes and configures it.
3975
- *
3976
- * @param coreFn - the underlying async function to wrap
3977
- * @param options.sdk - the SDK (or sub-SDK view) providing `context.hooks`
3978
- * and `context.core`
3979
- * @param options.schema - optional Zod schema for input validation
3980
- */
3981
- declare function createFunction<TOptions, TResult, TSchemaOptions extends TOptions = TOptions>(coreFn: (options: TOptions, context?: CallContext) => Promise<TResult>, options: {
3982
- sdk: FunctionSdk;
3983
- schema?: z.ZodSchema<TSchemaOptions>;
3984
- name?: string;
3985
- /** Pre-run per-method annotator (see applyAnnotations): invoked before
3986
- * onMethodStart with the normalized input, its result merged into the
3987
- * call's annotation bag. */
3988
- annotator?: (input: unknown) => Annotations;
3989
- /** Which framework call parameters this callable reads; see
3990
- * `FrameworkOptionsPolicy`. Omitted means none, which is what a legacy
3991
- * handler wants: nothing there honors a framework parameter, so every key
3992
- * in the call object is the handler's own. */
3993
- frameworkOptions?: FrameworkOptionsPolicy;
3994
- /** Live read of the method's deprecation meta (see signalDeprecation). */
3995
- getDeprecation?: () => FunctionDeprecation | undefined;
3996
- /** Live read of the method's stability level (see signalStability). */
3997
- getStability?: () => StabilityLevel | undefined;
3998
- }): (callOptions?: TOptions) => Promise<TResult>;
3999
- /**
4000
- * Higher-order function that creates a paginated function that wraps
4001
- * results in `SdkPage<TItem>`.
4002
- *
4003
- * @param coreFn - Function that returns T directly or throws errors
4004
- * @returns A function that normalizes errors and wraps results in `SdkPage`
4005
- */
4006
- /**
4007
- * Extract the item type from a page handler's return shape. The handler
4008
- * may return a flat `{ data: TItem[] }` (or single `data: TItem`), a bare
4009
- * array, or anything else; in all cases the wrapper normalizes to
4010
- * `SdkPage<TItem>` and this resolves the right `TItem`.
4011
- */
4012
- type ItemType<TResult> = TResult extends {
4013
- data: infer TData;
4014
- } ? TData extends readonly (infer TItem)[] ? TItem : TData : TResult extends readonly (infer TItem)[] ? TItem : TResult;
4015
- declare function createPaginatedFunction<TUserOptions, TResponse, TItem = ItemType<TResponse>>(coreFn: (options: TUserOptions & {
4016
- cursor?: string;
4017
- pageSize?: number;
4018
- }, context?: CallContext) => Promise<TResponse>, options: {
4019
- sdk: FunctionSdk;
4020
- schema?: z.ZodSchema<TUserOptions>;
4021
- name?: string;
4022
- defaultPageSize?: number;
4023
- /**
4024
- * Translate the handler's raw `TResponse` into `SdkPage<TItem>`. `TItem`
4025
- * is wrapped in `NoInfer`: it is sourced from `TResponse` (via the
4026
- * `ItemType` default), not from this adapter, which is item-agnostic (it
4027
- * relocates the cursor; items are finalized in the handler's `data`).
4028
- * Without `NoInfer`, a generic adapter (e.g. `<T>(r) => SdkPage<T>`)
4029
- * would collapse `TItem` to `unknown`.
4030
- */
4031
- adaptPage?: (response: TResponse) => SdkPage<NoInfer<TItem>>;
4032
- /** Pre-run per-method annotator (see applyAnnotations). */
4033
- annotator?: (input: unknown) => Annotations;
4034
- /** Applied to each canonical page after the shape guard (output validation),
4035
- * with this call's options so it can read per-call controls. */
4036
- finalizePage?: (page: SdkPage<TItem>, callOptions: unknown) => SdkPage<TItem>;
4037
- /** Which framework call parameters this callable reads; see
4038
- * `FrameworkOptionsPolicy`. */
4039
- frameworkOptions?: FrameworkOptionsPolicy;
4040
- /** Live read of the method's deprecation meta (see signalDeprecation). */
4041
- getDeprecation?: () => FunctionDeprecation | undefined;
4042
- /** Live read of the method's stability level (see signalStability). */
4043
- getStability?: () => StabilityLevel | undefined;
4044
- }): (options?: TUserOptions & {
4045
- cursor?: string;
4046
- pageSize?: number;
4047
- maxItems?: number;
4048
- }) => PaginatedSdkResult<TItem>;
4049
-
4050
- /**
4051
- * Register kitcore-level configuration by writing the options to
4052
- * `context.core`; the method boundary falls back to that path when no
4053
- * `kitcore/coreOptions` configuration value exists.
4054
- *
4055
- * @deprecated Inject the `CoreOptions` bag under `CORE_OPTIONS_ID` via
4056
- * `createSdk(root, { configuration })` instead. This factory logs a runtime
4057
- * deprecation and will be removed in a release after the warning ships.
4058
- */
4059
- declare function createCorePlugin(options: CoreOptions): Plugin<object, {
4060
- context: {
4061
- core: CoreOptions;
4062
- };
4063
- }>;
4064
-
4065
3596
  /**
4066
3597
  * Per-invocation scope for SDK method calls. Each top-level SDK method call
4067
3598
  * runs in its own AsyncLocalStorage scope (via `runInMethodScope`), isolating
@@ -4148,12 +3679,6 @@ declare const validateOptions: <TOptions, TSchemaOptions extends TOptions>(schem
4148
3679
  adaptError?: AdaptError;
4149
3680
  }) => TSchemaOptions;
4150
3681
 
4151
- /**
4152
- * Translates a paginated handler's raw response into a normalized
4153
- * `SdkPage<TItem>`. Supplied per method as the `adaptPage` on
4154
- * `createPaginatedPluginMethod` (and forwarded to `createPaginatedFunction`).
4155
- */
4156
- type AdaptPage<TResponse = unknown, TItem = unknown> = (response: TResponse) => SdkPage<TItem>;
4157
3682
  type TPageOptions<TOptions> = TOptions extends undefined ? {
4158
3683
  cursor?: string;
4159
3684
  maxItems?: number;
@@ -4521,14 +4046,14 @@ type SendHttpRequest = (request: HttpRequest) => ReturnType<typeof fetch>;
4521
4046
  * removes the only boundary below `initializeHttpRequest`, and a retry wrap
4522
4047
  * would then re-initialize and mint a fresh `operationId` per attempt.
4523
4048
  */
4524
- declare const attemptHttpRequestPlugin: MethodPlugin<"attemptHttpRequest", AttemptHttpRequestInput, Promise<Response>, readonly [], AttemptHttpRequestInput> & LeafSummary<"kitcore", "attemptHttpRequest", readonly [MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly []>, MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly []>, MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & PluginSummary<never, never> & StandInId<"kitcore/httpFetch">]>, MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly []>]>;
4049
+ declare const attemptHttpRequestPlugin: MethodPlugin<"attemptHttpRequest", AttemptHttpRequestInput, Promise<Response>, readonly [], AttemptHttpRequestInput> & LeafSummary<"kitcore", "attemptHttpRequest", readonly [MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly [], (input: PrepareHttpRequestInput) => Promise<HttpRequest>>, MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly [], (input: AuthorizeHttpRequestInput) => Promise<HttpRequest>>, MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & OptionalDeclarationSummary<"kitcore/httpFetch", typeof fetch | undefined> & StandInId<"kitcore/httpFetch">], (input: DispatchHttpRequestInput) => Promise<Response>>, MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly [], (input: ReceiveHttpResponseInput) => Promise<Response>>], (input: AttemptHttpRequestInput) => Promise<Response>>;
4525
4050
 
4526
4051
  /**
4527
4052
  * Completes the operation context: normalizes the caller's request and records
4528
4053
  * whether its body can be sent again. Everything below this stage reads those
4529
4054
  * two facts off `attempt.operation`, and neither changes across retries.
4530
4055
  */
4531
- declare const initializeHttpRequestPlugin: MethodPlugin<"initializeHttpRequest", InitializeHttpRequestInput, Promise<HttpOperationContext>, readonly [], InitializeHttpRequestInput> & LeafSummary<"kitcore", "initializeHttpRequest", readonly []>;
4056
+ declare const initializeHttpRequestPlugin: MethodPlugin<"initializeHttpRequest", InitializeHttpRequestInput, Promise<HttpOperationContext>, readonly [], InitializeHttpRequestInput> & LeafSummary<"kitcore", "initializeHttpRequest", readonly [], (input: InitializeHttpRequestInput) => Promise<HttpOperationContext>>;
4532
4057
 
4533
4058
  /**
4534
4059
  * Details about a retry the loop has scheduled.
@@ -4602,7 +4127,7 @@ interface RetryHttpRequestOptions {
4602
4127
  onRetry?: (attempt: RetryHttpRequestAttempt) => void;
4603
4128
  }
4604
4129
  declare const RETRY_HTTP_REQUEST_OPTIONS_ID = "kitcore/retryHttpRequestOptions";
4605
- declare const retryHttpRequestOptionsPluginRef: PropertyPlugin<"retryHttpRequestOptions", RetryHttpRequestOptions | undefined> & PluginSummary<never, never> & StandInId<"kitcore/retryHttpRequestOptions">;
4130
+ declare const retryHttpRequestOptionsPluginRef: PropertyPlugin<"retryHttpRequestOptions", RetryHttpRequestOptions | undefined> & OptionalDeclarationSummary<"kitcore/retryHttpRequestOptions", RetryHttpRequestOptions | undefined> & StandInId<"kitcore/retryHttpRequestOptions">;
4606
4131
  /**
4607
4132
  * Re-issue a failed attempt, opt-in by composition.
4608
4133
  *
@@ -4634,9 +4159,9 @@ declare const retryHttpRequestOptionsPluginRef: PropertyPlugin<"retryHttpRequest
4634
4159
  */
4635
4160
  declare const retryHttpRequestPlugin: HookPlugin<string>;
4636
4161
 
4637
- declare const prepareHttpRequestPlugin: MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly []>;
4162
+ declare const prepareHttpRequestPlugin: MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly [], (input: PrepareHttpRequestInput) => Promise<HttpRequest>>;
4638
4163
 
4639
- declare const authorizeHttpRequestPlugin: MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly []>;
4164
+ declare const authorizeHttpRequestPlugin: MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly [], (input: AuthorizeHttpRequestInput) => Promise<HttpRequest>>;
4640
4165
 
4641
4166
  declare const HTTP_FETCH_ID = "kitcore/httpFetch";
4642
4167
  /**
@@ -4645,10 +4170,10 @@ declare const HTTP_FETCH_ID = "kitcore/httpFetch";
4645
4170
  * `dispatchHttpRequest` wrap slot that hosts use to replace dispatch. When
4646
4171
  * absent, dispatch uses `globalThis.fetch`.
4647
4172
  */
4648
- declare const httpFetchPluginRef: PropertyPlugin<"httpFetch", typeof fetch | undefined> & PluginSummary<never, never> & StandInId<"kitcore/httpFetch">;
4649
- declare const dispatchHttpRequestPlugin: MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & PluginSummary<never, never> & StandInId<"kitcore/httpFetch">]>;
4173
+ declare const httpFetchPluginRef: PropertyPlugin<"httpFetch", typeof fetch | undefined> & OptionalDeclarationSummary<"kitcore/httpFetch", typeof fetch | undefined> & StandInId<"kitcore/httpFetch">;
4174
+ declare const dispatchHttpRequestPlugin: MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & OptionalDeclarationSummary<"kitcore/httpFetch", typeof fetch | undefined> & StandInId<"kitcore/httpFetch">], (input: DispatchHttpRequestInput) => Promise<Response>>;
4650
4175
 
4651
- declare const receiveHttpResponsePlugin: MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly []>;
4176
+ declare const receiveHttpResponsePlugin: MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly [], (input: ReceiveHttpResponseInput) => Promise<Response>>;
4652
4177
 
4653
4178
  /**
4654
4179
  * The transport orchestrator: turn an {@link HttpRequestInput} into a native
@@ -4677,7 +4202,7 @@ declare const receiveHttpResponsePlugin: MethodPlugin<"receiveHttpResponse", Rec
4677
4202
  * No retry by default: with nothing composed this runs exactly one attempt.
4678
4203
  * `retryHttpRequestPlugin` is opt-in.
4679
4204
  */
4680
- declare const sendHttpRequestPlugin: MethodPlugin<"sendHttpRequest", HttpRequestInput, Promise<Response>, readonly [], HttpRequestInput> & LeafSummary<"kitcore", "sendHttpRequest", readonly [MethodPlugin<"initializeHttpRequest", InitializeHttpRequestInput, Promise<HttpOperationContext>, readonly [], InitializeHttpRequestInput> & LeafSummary<"kitcore", "initializeHttpRequest", readonly []>, MethodPlugin<"attemptHttpRequest", AttemptHttpRequestInput, Promise<Response>, readonly [], AttemptHttpRequestInput> & LeafSummary<"kitcore", "attemptHttpRequest", readonly [MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly []>, MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly []>, MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & PluginSummary<never, never> & StandInId<"kitcore/httpFetch">]>, MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly []>]>]>;
4205
+ declare const sendHttpRequestPlugin: MethodPlugin<"sendHttpRequest", HttpRequestInput, Promise<Response>, readonly [], HttpRequestInput> & LeafSummary<"kitcore", "sendHttpRequest", readonly [MethodPlugin<"initializeHttpRequest", InitializeHttpRequestInput, Promise<HttpOperationContext>, readonly [], InitializeHttpRequestInput> & LeafSummary<"kitcore", "initializeHttpRequest", readonly [], (input: InitializeHttpRequestInput) => Promise<HttpOperationContext>>, MethodPlugin<"attemptHttpRequest", AttemptHttpRequestInput, Promise<Response>, readonly [], AttemptHttpRequestInput> & LeafSummary<"kitcore", "attemptHttpRequest", readonly [MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly [], (input: PrepareHttpRequestInput) => Promise<HttpRequest>>, MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly [], (input: AuthorizeHttpRequestInput) => Promise<HttpRequest>>, MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & OptionalDeclarationSummary<"kitcore/httpFetch", typeof fetch | undefined> & StandInId<"kitcore/httpFetch">], (input: DispatchHttpRequestInput) => Promise<Response>>, MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly [], (input: ReceiveHttpResponseInput) => Promise<Response>>], (input: AttemptHttpRequestInput) => Promise<Response>>], (input: HttpRequestInput) => Promise<Response>>;
4681
4206
 
4682
4207
  /**
4683
4208
  * `fetch` — native `fetch(url, init)` ergonomics over the transport. It
@@ -4706,7 +4231,7 @@ declare const fetchPlugin: MethodPlugin<"fetch", {
4706
4231
  }, Promise<Response>, readonly ["url", "init"], {
4707
4232
  url: string | URL;
4708
4233
  init?: Omit<HttpRequestInput, "url">;
4709
- }> & LeafSummary<"kitcore", "fetch", readonly [MethodPlugin<"sendHttpRequest", HttpRequestInput, Promise<Response>, readonly [], HttpRequestInput> & LeafSummary<"kitcore", "sendHttpRequest", readonly [MethodPlugin<"initializeHttpRequest", InitializeHttpRequestInput, Promise<HttpOperationContext>, readonly [], InitializeHttpRequestInput> & LeafSummary<"kitcore", "initializeHttpRequest", readonly []>, MethodPlugin<"attemptHttpRequest", AttemptHttpRequestInput, Promise<Response>, readonly [], AttemptHttpRequestInput> & LeafSummary<"kitcore", "attemptHttpRequest", readonly [MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly []>, MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly []>, MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & PluginSummary<never, never> & StandInId<"kitcore/httpFetch">]>, MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly []>]>]>]>;
4234
+ }> & LeafSummary<"kitcore", "fetch", readonly [MethodPlugin<"sendHttpRequest", HttpRequestInput, Promise<Response>, readonly [], HttpRequestInput> & LeafSummary<"kitcore", "sendHttpRequest", readonly [MethodPlugin<"initializeHttpRequest", InitializeHttpRequestInput, Promise<HttpOperationContext>, readonly [], InitializeHttpRequestInput> & LeafSummary<"kitcore", "initializeHttpRequest", readonly [], (input: InitializeHttpRequestInput) => Promise<HttpOperationContext>>, MethodPlugin<"attemptHttpRequest", AttemptHttpRequestInput, Promise<Response>, readonly [], AttemptHttpRequestInput> & LeafSummary<"kitcore", "attemptHttpRequest", readonly [MethodPlugin<"prepareHttpRequest", PrepareHttpRequestInput, Promise<HttpRequest>, readonly [], PrepareHttpRequestInput> & LeafSummary<"kitcore", "prepareHttpRequest", readonly [], (input: PrepareHttpRequestInput) => Promise<HttpRequest>>, MethodPlugin<"authorizeHttpRequest", AuthorizeHttpRequestInput, Promise<HttpRequest>, readonly [], AuthorizeHttpRequestInput> & LeafSummary<"kitcore", "authorizeHttpRequest", readonly [], (input: AuthorizeHttpRequestInput) => Promise<HttpRequest>>, MethodPlugin<"dispatchHttpRequest", DispatchHttpRequestInput, Promise<Response>, readonly [], DispatchHttpRequestInput> & LeafSummary<"kitcore", "dispatchHttpRequest", readonly [PropertyPlugin<"httpFetch", typeof fetch | undefined> & OptionalDeclarationSummary<"kitcore/httpFetch", typeof fetch | undefined> & StandInId<"kitcore/httpFetch">], (input: DispatchHttpRequestInput) => Promise<Response>>, MethodPlugin<"receiveHttpResponse", ReceiveHttpResponseInput, Promise<Response>, readonly [], ReceiveHttpResponseInput> & LeafSummary<"kitcore", "receiveHttpResponse", readonly [], (input: ReceiveHttpResponseInput) => Promise<Response>>], (input: AttemptHttpRequestInput) => Promise<Response>>], (input: HttpRequestInput) => Promise<Response>>], (arg: string | URL, arg_1?: Omit<HttpRequestInput, "url"> | undefined) => Promise<Response>>;
4710
4235
 
4711
4236
  /**
4712
4237
  * Headers with every credential value masked, as a plain object a logger can
@@ -4752,9 +4277,9 @@ interface NormalizedConnection {
4752
4277
  value: string;
4753
4278
  }
4754
4279
 
4755
- declare const defaultConnectionSchemePlugin: MethodPlugin<"defaultConnectionScheme", DefaultConnectionSchemeInput, string | undefined, readonly [], DefaultConnectionSchemeInput> & LeafSummary<"kitcore", "defaultConnectionScheme", readonly []>;
4280
+ declare const defaultConnectionSchemePlugin: MethodPlugin<"defaultConnectionScheme", DefaultConnectionSchemeInput, string | undefined, readonly [], DefaultConnectionSchemeInput> & LeafSummary<"kitcore", "defaultConnectionScheme", readonly [], (input: DefaultConnectionSchemeInput) => string | undefined>;
4756
4281
 
4757
- declare const normalizeConnectionPlugin: MethodPlugin<"normalizeConnection", NormalizeConnectionInput, NormalizedConnection | undefined, readonly [], NormalizeConnectionInput> & LeafSummary<"kitcore", "normalizeConnection", readonly [MethodPlugin<"defaultConnectionScheme", DefaultConnectionSchemeInput, string | undefined, readonly [], DefaultConnectionSchemeInput> & LeafSummary<"kitcore", "defaultConnectionScheme", readonly []>]>;
4282
+ declare const normalizeConnectionPlugin: MethodPlugin<"normalizeConnection", NormalizeConnectionInput, NormalizedConnection | undefined, readonly [], NormalizeConnectionInput> & LeafSummary<"kitcore", "normalizeConnection", readonly [MethodPlugin<"defaultConnectionScheme", DefaultConnectionSchemeInput, string | undefined, readonly [], DefaultConnectionSchemeInput> & LeafSummary<"kitcore", "defaultConnectionScheme", readonly [], (input: DefaultConnectionSchemeInput) => string | undefined>], (input?: NormalizeConnectionInput | undefined) => NormalizedConnection | undefined>;
4758
4283
 
4759
4284
  /**
4760
4285
  * SELECT which connection REFERENCE a call should use: the explicit one if the
@@ -4772,6 +4297,6 @@ declare const normalizeConnectionPlugin: MethodPlugin<"normalizeConnection", Nor
4772
4297
  * fatal depends on what the caller declared it needs, which this stage cannot
4773
4298
  * see, so this stays policy-free.
4774
4299
  */
4775
- declare const resolveConnectionPlugin: MethodPlugin<"resolveConnection", ResolveConnectionInput, string | undefined, readonly [], ResolveConnectionInput> & LeafSummary<"kitcore", "resolveConnection", readonly []>;
4300
+ declare const resolveConnectionPlugin: MethodPlugin<"resolveConnection", ResolveConnectionInput, string | undefined, readonly [], ResolveConnectionInput> & LeafSummary<"kitcore", "resolveConnection", readonly [], (input: ResolveConnectionInput) => string | undefined>;
4776
4301
 
4777
- export { type AdaptError, type AdaptErrorOptions, type AdaptPage, type AggregatePlugin, type Annotations, type ArrayResolver$1 as ArrayResolver, type AsyncContext, type AttemptHttpRequestInput, type AuthorizeHttpRequestInput, type BoundFormatter, type BoundResolver, CONTEXT, CORE_ERROR_SYMBOL, CORE_OPTIONS_ID, CORE_SIGNAL_SYMBOL, type CallContext, type CallOrigin, type CategoryDefinition, type ComposedAnnotator, type ConstantResolver$1 as ConstantResolver, type Controller, type ControllerAction, type ControllerAffordance, type ControllerAnswerFn, type ControllerChoice, type ControllerError, type ControllerIssue, type ControllerListingPage, type ControllerListingPosition, type ControllerMethodDescription, type ControllerMethodSummary, type ControllerPagination, type ControllerParameterDescription, type ControllerPath, type ControllerQuestion, type ControllerResult, type ControllerSdk, type ControllerSelectPage, type ControllerState, type CoreApiError, CoreCancelledSignal, CoreDisposeError, CoreError, CoreErrorCode, type CoreErrorOptions, type CoreOptions, CoreSignal, type CreateSdkOptions, type DefaultConnectionSchemeInput, type DeprecatedPromptConfigChoice, type DeprecationLogger, type DeprecationWarning, type DispatchHttpRequestInput, type DisposeFn, type DynamicListResolver, type DynamicMember, type DynamicResolver$1 as DynamicResolver, type DynamicSearchResolver, type FieldsResolver, type FormattedItem, type Formatter, type FunctionDeprecation, type FunctionRegistryEntry, HTTP_FETCH_ID, type HookAnnotator, type HookPlugin, type HttpAttemptContext, type HttpFetchInit, type HttpOperationContext, type HttpOperationStart, type HttpPipelineState, type HttpRequest, type HttpRequestInput, type HttpResponse, type InitializeHttpRequestInput, type LeafMeta, type LeafSummary, type LegacyMergePlugin, type LegacyPlugin, type ListItemsResult, type ListPromptConfig, type MethodAnnotator, type MethodAttachment, type MethodHooks, type MethodOverridePlugin, type MethodPlugin, type MethodScope, type Resolver as ModelResolver, type NegatableMetadata, type NormalizeConnectionInput, type NormalizedConnection, type OnMethodEnd, type OnMethodEndContext, type OnMethodStart, type OnMethodStartContext, type OutputDataValidationReport, type OutputFormatter, type OverridableMetaFields, type PaginatedSdkFunction, type PaginatedSdkResult, type Plugin, type PluginMeta, type PluginProvides, type PluginStack, type PluginSummary, type PluginSurface, type PositionalMetadata, type PrepareHttpRequestInput, type PromptConfig, type PromptConfigChoice, type PropertyPlugin, RETRY_HTTP_REQUEST_OPTIONS_ID, type ReceiveHttpResponseInput, type RegistryResult, type RequiredSdkOf, type ResolveConnectionInput, type Resolver$1 as Resolver, type ResolverConfig, type ResolverFieldItem, type ResolverMetadata, type ResolverPromptConfig, type ResolverRequirement, type ResolverType, type ResponseMeta, type RetryHttpRequestAttempt, type RetryHttpRequestOptions, STABILITY_LEVELS, STABILITY_TITLES, type Sdk, type SdkContext, type SdkContextCarrier, type SdkPage, type SendHttpRequest, type StabilityLevel, type StabilityNotice, type StabilityNoticeLogger, type StandInId, type StaticResolver$1 as StaticResolver, type ValidResolvers, addPlugin, applyStabilityLabel, attemptHttpRequestPlugin, authorizeHttpRequestPlugin, canonicalInputSchema, composePlugins, concatLists, concatPaginated, coreOptionsPluginRef, createAsyncContext, createController, createCoreError, createCorePlugin, createDeprecationLogger, createFunction, createPaginatedFunction, createPaginatedPluginMethod, createPluginMethod, createPluginStack, createPrefixedCursor, createSdk, createStabilityNoticeLogger, createValidator, dangerousContextPlugin, declareDefault, declareMethod, declareOptionalMethod, declareOptionalProperty, declarePlugin, declareProperty, decodeIncomingCursor, defaultConnectionSchemePlugin, defaultLogDeprecation, defineFormatter, defineHook, defineLegacyMerge, defineMethod, defineMethodOverride, defineOverride, definePlugin, defineProperty, defineResolver, dispatchHttpRequestPlugin, disposeSdk, fetchPlugin, fromFunctionPlugin, getContext, getCoreErrorCause, getCoreErrorCode, getCurrentDepth, getCurrentScope, getFieldDescriptions, getNegatable, getOutputSchema, getRegistry, getRegistryPlugin, getSchemaDescription, httpFetchPluginRef, initializeHttpRequestPlugin, isCoreCancelledSignal, isCoreError, isCoreSignal, isNestedMethodCall, isPositional, isTelemetryNested, normalizeConnectionPlugin, normalizeStability, objectShapeOf, omitExports, openEnum, paginate, paginateBuffered, paginateMaxItems, prepareHttpRequestPlugin, receiveHttpResponsePlugin, redactHeaders, redactHttpRequest, resolveConnectionPlugin, resolvePlugin, retryHttpRequestOptionsPluginRef, retryHttpRequestPlugin, runInMethodScope, runWithTelemetryContext, selectExports, sendHttpRequestPlugin, splitPrefixedCursor, toIterable, toSnakeCase, toTitleCase, unwrapSchema, validateOptions, withOutputSchema, withPositional, withResolver };
4302
+ export { type AdaptError, type AdaptErrorOptions, type AggregatePlugin, type Annotations, type ArrayResolver$1 as ArrayResolver, type AsyncContext, type AttemptHttpRequestInput, type AuthorizeHttpRequestInput, type BoundFormatter, type BoundResolver, CONTEXT, CORE_ERROR_SYMBOL, CORE_OPTIONS_ID, CORE_SIGNAL_SYMBOL, type CallContext, type CallOrigin, type CategoryDefinition, type ComposedAnnotator, type ConstantResolver$1 as ConstantResolver, type ContractEntry, type Controller, type ControllerAction, type ControllerAffordance, type ControllerAnswerFn, type ControllerChoice, type ControllerError, type ControllerIssue, type ControllerListingPage, type ControllerListingPosition, type ControllerMethodDescription, type ControllerMethodSummary, type ControllerPagination, type ControllerParameterDescription, type ControllerPath, type ControllerQuestion, type ControllerResult, type ControllerSdk, type ControllerSelectPage, type ControllerState, type CoreApiError, CoreCancelledSignal, CoreDisposeError, CoreError, CoreErrorCode, type CoreErrorOptions, type CoreOptions, CoreSignal, type CreateSdkOptions, type DeclarationSummary, type DefaultConnectionSchemeInput, type DeprecatedPromptConfigChoice, type DeprecationLogger, type DeprecationWarning, type DispatchHttpRequestInput, type DisposeFn, type DynamicListResolver, type DynamicMember, type DynamicResolver$1 as DynamicResolver, type DynamicSearchResolver, type FieldsResolver, type FormattedItem, type Formatter, type FunctionDeprecation, type FunctionRegistryEntry, HTTP_FETCH_ID, type HookAnnotator, type HookPlugin, type HttpAttemptContext, type HttpFetchInit, type HttpOperationContext, type HttpOperationStart, type HttpPipelineState, type HttpRequest, type HttpRequestInput, type HttpResponse, type InitializeHttpRequestInput, type LeafBase, type LeafMeta, type LeafSummary, type ListItemsResult, type ListPromptConfig, type MethodAnnotator, type MethodAttachment, type MethodContract, type MethodHooks, type MethodMeta, type MethodOverridePlugin, type MethodPlugin, type MethodScope, type Resolver as ModelResolver, type NegatableMetadata, type NormalizeConnectionInput, type NormalizedConnection, type OnMethodEnd, type OnMethodEndContext, type OnMethodStart, type OnMethodStartContext, type OptionalDeclarationSummary, type OutputDataValidationReport, type OverridableMetaFields, type PaginatedSdkFunction, type PaginatedSdkResult, type Plugin, type PluginBase, type PluginLifecycle, type PluginMeta, type PluginSummary, type PluginSurface, type PluginType, type PositionalMetadata, type PrepareHttpRequestInput, type PromptConfig, type PromptConfigChoice, type PropertyMeta, type PropertyPlugin, RETRY_HTTP_REQUEST_OPTIONS_ID, type ReceiveHttpResponseInput, type RegistryResult, type RequiredSdkOf, type ResolveConnectionInput, type Resolver$1 as Resolver, type ResolverConfig, type ResolverFieldItem, type ResolverMetadata, type ResolverPromptConfig, type ResolverRequirement, type ResolverType, type ResponseMeta, type RetryHttpRequestAttempt, type RetryHttpRequestOptions, STABILITY_LEVELS, STABILITY_TITLES, type SdkContext, type SdkContextCarrier, type SdkPage, type SendHttpRequest, type StabilityLevel, type StabilityNotice, type StabilityNoticeLogger, type StandInId, type StaticResolver$1 as StaticResolver, type ValidResolvers, addPlugin, applyStabilityLabel, attemptHttpRequestPlugin, authorizeHttpRequestPlugin, canonicalInputSchema, concatLists, concatPaginated, coreOptionsPluginRef, createAsyncContext, createController, createCoreError, createDeprecationLogger, createPrefixedCursor, createSdk, createStabilityNoticeLogger, createValidator, dangerousContextPlugin, declareDefault, declareMethod, declareOptionalMethod, declareOptionalProperty, declarePlugin, declareProperty, decodeIncomingCursor, defaultConnectionSchemePlugin, defaultLogDeprecation, defineFormatter, defineHook, defineMethod, defineMethodOverride, defineOverride, definePlugin, defineProperty, defineResolver, dispatchHttpRequestPlugin, disposeSdk, fetchPlugin, getContext, getCoreErrorCause, getCoreErrorCode, getCurrentDepth, getCurrentScope, getFieldDescriptions, getNegatable, getOutputSchema, getRegistry, getRegistryPlugin, getSchemaDescription, httpFetchPluginRef, initializeHttpRequestPlugin, isCoreCancelledSignal, isCoreError, isCoreSignal, isNestedMethodCall, isPositional, isTelemetryNested, normalizeConnectionPlugin, normalizeStability, objectShapeOf, omitExports, openEnum, paginate, paginateBuffered, paginateMaxItems, prepareHttpRequestPlugin, receiveHttpResponsePlugin, redactHeaders, redactHttpRequest, resolveConnectionPlugin, resolvePlugin, retryHttpRequestOptionsPluginRef, retryHttpRequestPlugin, runInMethodScope, runWithTelemetryContext, selectExports, sendHttpRequestPlugin, splitPrefixedCursor, toIterable, toSnakeCase, toTitleCase, unwrapSchema, validateOptions, withOutputSchema, withPositional, withResolver };