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