apps 0.0.1-beta.5 → 0.0.1-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +65 -43
  2. package/framework-reference.json +1 -1
  3. package/js/{chunk-FWQC6I3C.js → chunk-5T57N25Q.js} +13 -1
  4. package/js/{chunk-67EVWIGJ.js → chunk-6BSSI67S.js} +4 -4
  5. package/js/{chunk-DQAZTA4I.js → chunk-B3EOZTK3.js} +212 -19
  6. package/js/{chunk-TDNYXSIX.js → chunk-ECQFRCH4.js} +21 -9
  7. package/js/{chunk-UDDE5KOR.js → chunk-ITM77QPO.js} +26 -7
  8. package/js/{chunk-G7T27IWB.js → chunk-MKWZPDR6.js} +1 -1
  9. package/js/chunk-MNMNLXBL.js +507 -0
  10. package/js/{chunk-CYYBFC2K.js → chunk-NKLWZJLE.js} +1 -1
  11. package/js/{chunk-C3VAOK5B.js → chunk-OE3QQTSB.js} +33 -26
  12. package/js/{chunk-YEPYT6SD.js → chunk-R3EV5FTO.js} +12 -0
  13. package/js/{chunk-XHO2ZX6W.js → chunk-RFVIONFX.js} +27 -10
  14. package/js/{chunk-LUVSFETN.js → chunk-SB4HEPNJ.js} +72 -228
  15. package/js/chunk-T7GKZBLP.js +209 -0
  16. package/js/client.js +1 -1
  17. package/js/contracts.js +24 -11
  18. package/js/effect.js +9 -11
  19. package/js/graphql.js +25 -32
  20. package/js/host.js +9 -11
  21. package/js/index.js +184 -173
  22. package/js/mcp/effect.js +11 -13
  23. package/js/mcp/stdio.js +15 -17
  24. package/js/mcp.js +50 -36
  25. package/js/openapi.js +166 -108
  26. package/js/skills.js +6 -7
  27. package/package.json +1 -1
  28. package/runtime.json +1 -1
  29. package/types/apps/src/contracts/app.d.ts +2 -5
  30. package/types/apps/src/contracts/host.d.ts +11 -7
  31. package/types/apps/src/contracts/mcp.d.ts +16 -0
  32. package/types/apps/src/contracts/openapi.d.ts +4 -0
  33. package/types/apps/src/contracts/operations.d.ts +0 -5
  34. package/types/apps/src/contracts/protocol-version.d.ts +2 -2
  35. package/types/apps/src/contracts/protocols/4.d.ts +1229 -0
  36. package/types/apps/src/contracts/router.d.ts +59 -0
  37. package/types/apps/src/graphql.d.ts +1 -3
  38. package/types/apps/src/implementation/account-router.d.ts +12 -0
  39. package/types/apps/src/implementation/app.d.ts +5 -4
  40. package/types/apps/src/implementation/catalog-cache.d.ts +9 -2
  41. package/types/apps/src/implementation/graphql-catalog.d.ts +1 -4
  42. package/types/apps/src/implementation/mcp-catalog.d.ts +1 -4
  43. package/types/apps/src/implementation/mcp-client.d.ts +35 -19
  44. package/types/apps/src/implementation/mcp.d.ts +35 -19
  45. package/types/apps/src/implementation/openapi-compile.d.ts +2 -1
  46. package/types/apps/src/implementation/openapi-source.d.ts +2 -6
  47. package/types/apps/src/implementation/operations.d.ts +26 -3
  48. package/types/apps/src/implementation/protocol-operations.d.ts +3 -4
  49. package/types/apps/src/implementation/router-catalog.d.ts +225 -0
  50. package/types/apps/src/implementation/router.d.ts +59 -0
  51. package/types/apps/src/implementation/schema.d.ts +5 -1
  52. package/types/apps/src/implementation/workflow-context.d.ts +1 -1
  53. package/types/apps/src/index.d.ts +3 -2
  54. package/types/apps/src/mcp-stdio.d.ts +2 -5
  55. package/types/apps/src/mcp.d.ts +5 -4
  56. package/types/apps/src/openapi.d.ts +6 -6
  57. package/js/chunk-3XKZDQLM.js +0 -93
  58. package/js/chunk-4M277YTM.js +0 -136
  59. package/js/chunk-SB3V4YVR.js +0 -18
  60. package/js/chunk-W4DMKWAB.js +0 -35
  61. package/types/apps/src/contracts/dynamic-tools.d.ts +0 -13
  62. package/types/apps/src/implementation/account-operations.d.ts +0 -151
  63. package/types/apps/src/implementation/dynamic-tools.d.ts +0 -8
@@ -0,0 +1,59 @@
1
+ /** Routers group operations. Keys form tool paths; each operation keeps its own kind. */
2
+ import { Schema, type Effect } from "effect";
3
+ import type { HostedTool, HostedToolSummary } from "./host.js";
4
+ import type { AppOperation } from "./operations.js";
5
+ /** Object keys that JavaScript gives special meaning, so no router may use them. */
6
+ export declare const reservedRouterKeys: ReadonlySet<string>;
7
+ /** One static path segment. Dots separate segments, so a key never contains one. */
8
+ export declare const RouterKey: Schema.String;
9
+ /** An image a client may show beside a router, such as an MCP server's own icon. Models never read it. */
10
+ export declare const RouterIcon: Schema.Struct<{
11
+ readonly src: Schema.NonEmptyString;
12
+ readonly mimeType: Schema.optionalKey<Schema.String>;
13
+ readonly sizes: Schema.optionalKey<Schema.$Array<Schema.String>>;
14
+ readonly theme: Schema.optionalKey<Schema.Literals<readonly ["light", "dark"]>>;
15
+ }>;
16
+ export type RouterIcon = typeof RouterIcon.Type;
17
+ /**
18
+ * What an agent should know about a group of tools. `instructions` is published as a skill;
19
+ * `tags` describes labels that tools in this router carry, such as OpenAPI tags.
20
+ */
21
+ export declare const RouterMeta: Schema.Struct<{
22
+ readonly title: Schema.optionalKey<Schema.String>;
23
+ readonly description: Schema.optionalKey<Schema.String>;
24
+ readonly instructions: Schema.optionalKey<Schema.String>;
25
+ readonly icons: Schema.optionalKey<Schema.$Array<Schema.Struct<{
26
+ readonly src: Schema.NonEmptyString;
27
+ readonly mimeType: Schema.optionalKey<Schema.String>;
28
+ readonly sizes: Schema.optionalKey<Schema.$Array<Schema.String>>;
29
+ readonly theme: Schema.optionalKey<Schema.Literals<readonly ["light", "dark"]>>;
30
+ }>>>;
31
+ readonly tags: Schema.optionalKey<Schema.$Record<Schema.NonEmptyString, Schema.String>>;
32
+ }>;
33
+ export type RouterMeta = typeof RouterMeta.Type;
34
+ /** A statically declared router. Children are operations or further routers. */
35
+ export interface AppRouter {
36
+ readonly kind: "router";
37
+ readonly meta?: RouterMeta;
38
+ readonly children: Readonly<Record<string, AppNode>>;
39
+ }
40
+ /**
41
+ * A router whose tools are discovered when read, such as an MCP server or OpenAPI document.
42
+ * Names are relative to the router and may contain dots. `readOnly: true` marks a query;
43
+ * anything else is a mutation. Resolution never requires listing.
44
+ */
45
+ export interface DynamicRouter {
46
+ readonly kind: "dynamic";
47
+ /** Metadata supplied by the source. Author metadata on the router takes precedence. */
48
+ readonly meta?: () => Effect.Effect<RouterMeta, unknown>;
49
+ readonly list: () => Effect.Effect<readonly HostedTool[], unknown>;
50
+ readonly resolve: (name: string) => Effect.Effect<AppOperation | undefined, unknown>;
51
+ /** Names and descriptions without schemas. Omitted sources reduce list(). */
52
+ readonly summaries?: () => Effect.Effect<readonly HostedToolSummary[], unknown>;
53
+ /** One tool's full metadata without listing. Omitted sources search list(). */
54
+ readonly describe?: (name: string) => Effect.Effect<HostedTool | undefined, unknown>;
55
+ /** Static author metadata, merged over the source's metadata. */
56
+ readonly overrides?: RouterMeta;
57
+ }
58
+ /** Anything a router can contain. */
59
+ export type AppNode = AppOperation | AppRouter | DynamicRouter;
@@ -4,7 +4,5 @@ import { type GraphqlCatalogOptions } from "./implementation/graphql-catalog.js"
4
4
  export { GraphqlError, type GraphqlToolsOptions } from "./contracts/graphql.js";
5
5
  export type { GraphqlCatalogOptions } from "./implementation/graphql-catalog.js";
6
6
  /** Lazy tools with optional persistent metadata caching for the selected account. */
7
- export declare const graphqlOperations: (options: GraphqlCatalogOptions, kinds?: OperationKinds) => Promise<{
8
- dynamicTools: import("./contracts/dynamic-tools.js").DynamicTools;
9
- }>;
7
+ export declare const graphqlRouter: (options: GraphqlCatalogOptions, kinds?: OperationKinds) => Promise<import("./index.js").RouterDeclaration<unknown, unknown>>;
10
8
  export type { OperationKinds } from "./implementation/protocol-operations.js";
@@ -0,0 +1,12 @@
1
+ import { type RouterDeclaration } from "./router.js";
2
+ /**
3
+ * Discover each selected account's router and combine matching names.
4
+ * Calls take { accountId, input }; each branch retains its account's input schema,
5
+ * credentials, approval and output validation. Empty selections expose no operations.
6
+ * Discovery is sequential and cancellation follows the caller's signal.
7
+ */
8
+ export declare const accountRouter: <Account extends {
9
+ readonly id: string;
10
+ }>(accounts: readonly Account[], discover: (account: Account) => Promise<RouterDeclaration>, options: {
11
+ readonly signal: AbortSignal;
12
+ }) => Promise<RouterDeclaration>;
@@ -4,7 +4,7 @@ import type { AppRequirements, AppContext, QueryContext, MutationContext, Webhoo
4
4
  import { type PromiseMethods } from "./authoring.js";
5
5
  import { type WorkflowDeclaration } from "./workflows.js";
6
6
  import type { WorkflowContext } from "../contracts/workflows.js";
7
- import { type OperationDeclaration } from "./operations.js";
7
+ import { type RouterDeclaration } from "./router.js";
8
8
  import { type Schema } from "./schema.js";
9
9
  type PromiseCatalog<Catalog> = Catalog extends Readonly<Record<string, object>> ? {
10
10
  readonly [Name in keyof Catalog]: {
@@ -14,15 +14,16 @@ type PromiseCatalog<Catalog> = Catalog extends Readonly<Record<string, object>>
14
14
  /** Author definition projected from native capabilities. Excluding callable objects keeps
15
15
  * factories from being inferred as definitions and preserves contextual handler inference. */
16
16
  export type AppDefinition<Requirements extends AppRequirements> = {
17
- readonly [Key in keyof NativeDefinition<WebhookContext<Requirements>>]: Key extends "workflows" ? Readonly<Record<string, WorkflowDeclaration<WorkflowContext<Requirements>>>> : Key extends "schedules" ? Readonly<Record<string, ScheduleDeclaration<MutationContext<Requirements>>>> : Key extends "queries" ? Readonly<Record<string, OperationDeclaration<"query", QueryContext<Requirements>>>> : Key extends "mutations" ? Readonly<Record<string, OperationDeclaration<"mutation", MutationContext<Requirements>>>> : Key extends "webhooks" ? PromiseCatalog<NonNullable<NativeDefinition<WebhookContext<Requirements>>[Key]>> : NativeDefinition<WebhookContext<Requirements>>[Key];
17
+ readonly [Key in keyof NativeDefinition<WebhookContext<Requirements>>]: Key extends "workflows" ? Readonly<Record<string, WorkflowDeclaration<WorkflowContext<Requirements>>>> : Key extends "schedules" ? Readonly<Record<string, ScheduleDeclaration<MutationContext<Requirements>>>> : Key extends "tools" ? RouterDeclaration<QueryContext<Requirements>, MutationContext<Requirements>> : Key extends "webhooks" ? PromiseCatalog<NonNullable<NativeDefinition<WebhookContext<Requirements>>[Key]>> : NativeDefinition<WebhookContext<Requirements>>[Key];
18
18
  } & {
19
19
  readonly name?: never;
20
- readonly tools?: never;
20
+ readonly queries?: never;
21
+ readonly mutations?: never;
21
22
  readonly call?: never;
22
23
  };
23
24
  /** Adapt operation and webhook catalogs without evaluating their handlers. */
24
25
  export type EffectDefinition<Def> = {
25
- readonly [Key in keyof Def]: Key extends "dynamicTools" ? NonNullable<NativeDefinition<unknown>["dynamicTools"]> : Key extends "workflows" ? Readonly<Record<string, import("../contracts/workflows.js").AppWorkflow>> : Key extends "schedules" ? NonNullable<NativeDefinition<unknown>["schedules"]> : Key extends "queries" | "mutations" ? Readonly<Record<string, import("../contracts/operations.js").AppOperation>> : Key extends "webhooks" ? NonNullable<NativeDefinition<WebhookContext>["webhooks"]> : Key extends "skills" ? NonNullable<NativeDefinition<unknown>["skills"]> : Key extends "dynamicSkills" ? NonNullable<NativeDefinition<unknown>["dynamicSkills"]> : Def[Key];
26
+ readonly [Key in keyof Def]: Key extends "tools" ? NonNullable<NativeDefinition<unknown>["tools"]> : Key extends "workflows" ? Readonly<Record<string, import("../contracts/workflows.js").AppWorkflow>> : Key extends "schedules" ? NonNullable<NativeDefinition<unknown>["schedules"]> : Key extends "webhooks" ? NonNullable<NativeDefinition<WebhookContext>["webhooks"]> : Key extends "skills" ? NonNullable<NativeDefinition<unknown>["skills"]> : Key extends "dynamicSkills" ? NonNullable<NativeDefinition<unknown>["dynamicSkills"]> : Def[Key];
26
27
  };
27
28
  declare const InternalApp: unique symbol;
28
29
  /** Recognize a declaration from this framework instance before host adaptation. */
@@ -1,6 +1,6 @@
1
1
  import { Duration, Effect, Schema } from "effect";
2
2
  import type { AppCache, CacheLoadContext } from "../contracts/cache.js";
3
- import { type JsonValue } from "../contracts/schema.js";
3
+ import { JsonObject, type JsonValue } from "../contracts/schema.js";
4
4
  export interface CatalogCacheOptions {
5
5
  /** App/build scope, optionally narrowed to the current account. */
6
6
  readonly cache?: AppCache;
@@ -11,6 +11,11 @@ export interface CatalogCacheOptions {
11
11
  /** Await a fresh revision at an explicit logical connection or refresh boundary. */
12
12
  readonly revalidate?: boolean;
13
13
  }
14
+ /** One load: the tools, and optionally a record describing the whole catalog. */
15
+ export interface CatalogLoad<A> {
16
+ readonly tools: readonly A[];
17
+ readonly header?: JsonObject;
18
+ }
14
19
  export declare const catalogCache: <A extends {
15
20
  readonly name: string;
16
21
  }, S>(options: CatalogCacheOptions & {
@@ -21,9 +26,11 @@ export declare const catalogCache: <A extends {
21
26
  readonly schema: Schema.Decoder<S>;
22
27
  readonly of: (tool: A) => S;
23
28
  };
24
- readonly load: (context?: CacheLoadContext) => Effect.Effect<readonly A[], unknown>;
29
+ readonly load: (context?: CacheLoadContext) => Effect.Effect<CatalogLoad<A>, unknown>;
25
30
  }) => Effect.Effect<{
26
31
  list: () => Effect.Effect<readonly A[], unknown, never>;
32
+ /** The record stored with the current revision, if the source supplied one. */
33
+ header: () => Effect.Effect<JsonObject | undefined, unknown>;
27
34
  summaries: () => Effect.Effect<S[], unknown, never>;
28
35
  resolve: (name: string) => Effect.Effect<A | undefined, unknown, never>;
29
36
  }, unknown, never>;
@@ -1,10 +1,7 @@
1
1
  import { Effect } from "effect";
2
2
  import { GraphqlToolsOptions } from "../contracts/graphql.js";
3
- import type { DynamicTools } from "../contracts/dynamic-tools.js";
4
3
  import { type CatalogCacheOptions } from "./catalog-cache.js";
5
4
  import { type OperationKinds } from "./protocol-operations.js";
6
5
  export interface GraphqlCatalogOptions extends GraphqlToolsOptions, CatalogCacheOptions {
7
6
  }
8
- export declare const graphqlCatalog: (options: GraphqlCatalogOptions, kinds: OperationKinds) => Effect.Effect<{
9
- dynamicTools: DynamicTools;
10
- }, unknown, never>;
7
+ export declare const graphqlCatalog: (options: GraphqlCatalogOptions, kinds: OperationKinds) => Effect.Effect<import("./operations.js").RouterDeclaration<unknown, unknown>, unknown, never>;
@@ -1,5 +1,4 @@
1
1
  import { Effect } from "effect";
2
- import type { DynamicTools } from "../contracts/dynamic-tools.js";
3
2
  import { McpToolsOptions } from "../contracts/mcp.js";
4
3
  import { type CatalogCacheOptions } from "./catalog-cache.js";
5
4
  import { type OperationKinds } from "./protocol-operations.js";
@@ -7,6 +6,4 @@ import { type OperationKinds } from "./protocol-operations.js";
7
6
  export interface McpCatalogOptions extends McpToolsOptions, CatalogCacheOptions {
8
7
  }
9
8
  /** Construction opens no transport unless explicit revalidation is requested. */
10
- export declare const mcpCatalog: (options: McpCatalogOptions, kinds: OperationKinds) => Effect.Effect<{
11
- dynamicTools: DynamicTools;
12
- }, unknown, never>;
9
+ export declare const mcpCatalog: (options: McpCatalogOptions, kinds: OperationKinds) => Effect.Effect<import("./operations.js").RouterDeclaration<unknown, unknown>, unknown, never>;
@@ -14,26 +14,42 @@ export interface WithMcpClient {
14
14
  /** Shared client operations never cache catalogs or account credentials. */
15
15
  export declare function mcpClient(withClient: WithMcpClient, timeoutMs: number, failure: (phase: McpError["phase"], error: unknown) => McpError | ProviderError): {
16
16
  list: Effect.Effect<{
17
- readonly name: string;
18
- readonly inputSchema: {
19
- readonly [x: string]: Schema.Json;
20
- };
21
- readonly description?: string | undefined;
22
- readonly _meta?: {
23
- readonly [x: string]: Schema.Json;
24
- } | undefined;
25
- readonly title?: string | undefined;
26
- readonly outputSchema?: {
27
- readonly [x: string]: Schema.Json;
28
- } | undefined;
29
- readonly annotations?: {
17
+ tools: {
18
+ readonly name: string;
19
+ readonly inputSchema: {
20
+ readonly [x: string]: Schema.Json;
21
+ };
22
+ readonly description?: string | undefined;
23
+ readonly _meta?: {
24
+ readonly [x: string]: Schema.Json;
25
+ } | undefined;
26
+ readonly title?: string | undefined;
27
+ readonly annotations?: {
28
+ readonly title?: string;
29
+ readonly readOnlyHint?: boolean;
30
+ readonly destructiveHint?: boolean;
31
+ readonly idempotentHint?: boolean;
32
+ readonly openWorldHint?: boolean;
33
+ } | undefined;
34
+ readonly outputSchema?: {
35
+ readonly [x: string]: Schema.Json;
36
+ } | undefined;
37
+ }[];
38
+ server: {
39
+ readonly version?: string;
40
+ readonly name?: string;
41
+ readonly description?: string;
30
42
  readonly title?: string;
31
- readonly readOnlyHint?: boolean;
32
- readonly destructiveHint?: boolean;
33
- readonly idempotentHint?: boolean;
34
- readonly openWorldHint?: boolean;
35
- } | undefined;
36
- }[], ProviderError | McpError, never>;
43
+ readonly instructions?: string;
44
+ readonly icons?: readonly {
45
+ readonly src: string;
46
+ readonly mimeType?: string;
47
+ readonly sizes?: readonly string[];
48
+ readonly theme?: "light" | "dark";
49
+ }[];
50
+ readonly websiteUrl?: string;
51
+ } | {};
52
+ }, ProviderError | McpError, never>;
37
53
  call: (name: string, input: JsonObject, context: McpToolContext) => Effect.Effect<{
38
54
  readonly content: readonly {
39
55
  readonly [x: string]: Schema.Json;
@@ -4,26 +4,42 @@ import { McpError, McpToolsOptions } from "../contracts/mcp.js";
4
4
  /** Discover and call with a fresh selected-account transport for each operation. */
5
5
  export declare const mcpClientEffect: (input: McpToolsOptions, changed?: Effect.Effect<void, unknown>) => Effect.Effect<{
6
6
  list: Effect.Effect<{
7
- readonly name: string;
8
- readonly inputSchema: {
9
- readonly [x: string]: Schema.Json;
10
- };
11
- readonly description?: string | undefined;
12
- readonly _meta?: {
13
- readonly [x: string]: Schema.Json;
14
- } | undefined;
15
- readonly title?: string | undefined;
16
- readonly outputSchema?: {
17
- readonly [x: string]: Schema.Json;
18
- } | undefined;
19
- readonly annotations?: {
7
+ tools: {
8
+ readonly name: string;
9
+ readonly inputSchema: {
10
+ readonly [x: string]: Schema.Json;
11
+ };
12
+ readonly description?: string | undefined;
13
+ readonly _meta?: {
14
+ readonly [x: string]: Schema.Json;
15
+ } | undefined;
16
+ readonly title?: string | undefined;
17
+ readonly annotations?: {
18
+ readonly title?: string;
19
+ readonly readOnlyHint?: boolean;
20
+ readonly destructiveHint?: boolean;
21
+ readonly idempotentHint?: boolean;
22
+ readonly openWorldHint?: boolean;
23
+ } | undefined;
24
+ readonly outputSchema?: {
25
+ readonly [x: string]: Schema.Json;
26
+ } | undefined;
27
+ }[];
28
+ server: {
29
+ readonly version?: string;
30
+ readonly name?: string;
31
+ readonly description?: string;
20
32
  readonly title?: string;
21
- readonly readOnlyHint?: boolean;
22
- readonly destructiveHint?: boolean;
23
- readonly idempotentHint?: boolean;
24
- readonly openWorldHint?: boolean;
25
- } | undefined;
26
- }[], ProviderError | McpError, never>;
33
+ readonly instructions?: string;
34
+ readonly icons?: readonly {
35
+ readonly src: string;
36
+ readonly mimeType?: string;
37
+ readonly sizes?: readonly string[];
38
+ readonly theme?: "light" | "dark";
39
+ }[];
40
+ readonly websiteUrl?: string;
41
+ } | {};
42
+ }, ProviderError | McpError, never>;
27
43
  call: (name: string, input: import("../index.js").JsonObject, context: import("../mcp.js").McpToolContext) => Effect.Effect<{
28
44
  readonly content: readonly {
29
45
  readonly [x: string]: Schema.Json;
@@ -56,7 +56,7 @@ export declare const compileOpenApiDocument: (entry: OpenApiImport, inputDocumen
56
56
  readonly input: {
57
57
  readonly [x: string]: Schema.Json;
58
58
  };
59
- readonly method: "HEAD" | "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS";
59
+ readonly method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
60
60
  readonly securitySchemes: {
61
61
  readonly [x: string]: {
62
62
  readonly [x: string]: Schema.Json;
@@ -67,6 +67,7 @@ export declare const compileOpenApiDocument: (entry: OpenApiImport, inputDocumen
67
67
  readonly outputSchema?: {
68
68
  readonly [x: string]: Schema.Json;
69
69
  };
70
+ readonly tags?: readonly string[];
70
71
  readonly operationId?: string;
71
72
  readonly streaming?: true;
72
73
  readonly errorResponses?: readonly {
@@ -3,8 +3,8 @@ import { Duration } from "effect";
3
3
  import type { AppCache } from "../contracts/cache.js";
4
4
  import { OpenapiOperation, type OpenapiToolsOptions } from "../contracts/openapi.js";
5
5
  import { JsonObject, JsonValue } from "../contracts/schema.js";
6
- import type { DynamicTools } from "../contracts/dynamic-tools.js";
7
6
  import { type OperationKinds } from "./protocol-operations.js";
7
+ import { type RouterDeclaration } from "./router.js";
8
8
  /** Static credential placement and destination are reviewed when the app is authored/imported. */
9
9
  export interface OpenapiSourceOptions extends Omit<OpenapiToolsOptions, "operations" | "definitions"> {
10
10
  readonly cache: AppCache;
@@ -33,8 +33,4 @@ export interface OpenapiSourceOptions extends Omit<OpenapiToolsOptions, "operati
33
33
  /** JSON-object patches are static app configuration and are reapplied to every revision. */
34
34
  export declare function patchOpenapi(root: JsonObject, patches: OpenapiSourceOptions["patches"]): JsonObject;
35
35
  /** No I/O during app construction. All accounts share credential-free compilation. */
36
- export declare const liveOpenapiOperations: (options: OpenapiSourceOptions) => {
37
- readonly queries: {};
38
- readonly mutations: {};
39
- readonly dynamicTools: DynamicTools;
40
- };
36
+ export declare const liveOpenapiRouter: (options: OpenapiSourceOptions) => RouterDeclaration;
@@ -7,16 +7,39 @@ import type { ToolAnnotations } from "../contracts/tools.js";
7
7
  import type { JsonObject } from "../contracts/schema.js";
8
8
  import { type Schema } from "./schema.js";
9
9
  declare const NativeOperation: unique symbol;
10
- declare const HandlerContext: unique symbol;
11
- /** A server-only declaration with its category preserved for catalog validation. */
10
+ declare const QueryHandlerContext: unique symbol;
11
+ declare const MutationHandlerContext: unique symbol;
12
+ /**
13
+ * A server-only declaration with its category preserved for catalog validation. Queries and
14
+ * mutations carry their handler context under different phantom keys, so a router can type a
15
+ * query's handler from its query context alone.
16
+ */
12
17
  export interface OperationDeclaration<Kind extends "query" | "mutation", Context = never> {
13
- readonly [HandlerContext]?: (context: Context) => void;
18
+ readonly [QueryHandlerContext]?: "query" extends Kind ? (context: Context) => void : never;
19
+ readonly [MutationHandlerContext]?: "mutation" extends Kind ? (context: Context) => void : never;
14
20
  readonly kind: Kind;
15
21
  readonly [NativeOperation]: Omit<AppOperation<never>, "kind" | "input"> & {
16
22
  readonly kind: Kind;
17
23
  readonly input: EffectSchema.Decoder<unknown>;
18
24
  };
19
25
  }
26
+ /**
27
+ * A router declaration. The phantom contexts let `defineApp` type inline handlers; protocol
28
+ * routers accept any context because their operations only use the framework's own capabilities.
29
+ * The native router is held under a private key in implementation/router.ts.
30
+ */
31
+ export interface RouterDeclaration<Query = unknown, Mutation = unknown> {
32
+ readonly [QueryHandlerContext]?: (context: Query) => void;
33
+ readonly [MutationHandlerContext]?: (context: Mutation) => void;
34
+ readonly [NativeRouterKey]: unknown;
35
+ }
36
+ /** An operation or nested router under one key. Each child is typed only by its own kind's context. */
37
+ export interface RouterChild<Query, Mutation> {
38
+ readonly [QueryHandlerContext]?: (context: Query) => void;
39
+ readonly [MutationHandlerContext]?: (context: Mutation) => void;
40
+ }
41
+ /** Private key for a router's native definition. */
42
+ export declare const NativeRouterKey: unique symbol;
20
43
  /** Typed operation handles drive browser reference inference without bundling handlers. */
21
44
  export interface Operation<Input, Output, Kind extends "query" | "mutation", Context = AppContext> extends OperationDeclaration<Kind, Context> {
22
45
  readonly [NativeOperation]: AppOperation<Input, Output> & {
@@ -17,8 +17,7 @@ interface ProtocolOperation {
17
17
  readonly run: (context: OperationContext, input: JsonValue) => Effect.Effect<unknown, unknown>;
18
18
  }
19
19
  /** Unknown behavior defaults to mutation. Classification never enforces an external service's behavior. */
20
- export declare const protocolOperations: (operations: Readonly<Record<string, ProtocolOperation>>, kinds?: OperationKinds) => {
21
- queries: Record<string, Operation<Schema.Json, unknown, "query", OperationContext>>;
22
- mutations: Record<string, Operation<Schema.Json, unknown, "mutation", OperationContext>>;
23
- };
20
+ export declare const protocolOperations: (operations: Readonly<Record<string, ProtocolOperation>>, kinds?: OperationKinds) => Record<string, Operation<Schema.Json, unknown, "query" | "mutation", OperationContext>>;
21
+ /** Operations already discovered, as a router keyed by upstream name. */
22
+ export declare const protocolRouter: (operations: Readonly<Record<string, ProtocolOperation>>, kinds?: OperationKinds) => import("./operations.js").RouterDeclaration<unknown, unknown>;
24
23
  export {};
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Read a live router tree into tools, routers and router skills. A nested dynamic router that fails
3
+ * is reported on its own entry; the root failing fails the read, as a single-source app would.
4
+ */
5
+ import { Effect, Schema } from "effect";
6
+ import { HostDeclarationInvalid, HostEvaluationFailed, type HostRouterError } from "../contracts/host.js";
7
+ import { McpError } from "../contracts/mcp.js";
8
+ import type { AppOperation } from "../contracts/operations.js";
9
+ import type { AppRouter, DynamicRouter, RouterMeta } from "../contracts/router.js";
10
+ import { SkillLoadFailed } from "../contracts/skills.js";
11
+ import type { OperationSchedule } from "../contracts/schedules.js";
12
+ /**
13
+ * Keep only a failure's safe fields. Anything unrecognized becomes an evaluation failure with the
14
+ * error's name and bounded message, with the given account secrets replaced.
15
+ */
16
+ export declare const safeFailure: (error: unknown, secrets: readonly string[]) => HostRouterError;
17
+ /**
18
+ * Router skills are named `tools` for the root and `tools-<path>` below it, so a router's
19
+ * instructions never take an authored skill's name by accident.
20
+ */
21
+ export declare const routerSkillPrefix = "tools";
22
+ /**
23
+ * The skill name for a router path. A path of lowercase letters and digits is spelled out:
24
+ * `issues.open` is `tools-issues-open`. Any other path, or one too long, is a readable slug
25
+ * followed by a hash of the exact path, such as `tools-issues-list-0123456789`. Plain segments
26
+ * start with a letter and a hash is all digits, so the two forms never meet, and paths that slug
27
+ * alike, such as `issues_list` and `issues.list`, get different names.
28
+ */
29
+ export declare const routerSkillName: (path: string) => string;
30
+ /** A declared operation's catalog entry without schemas. `router` is its owning router's path. */
31
+ export declare const operationSummary: (name: string, router: string, operation: AppOperation, schedules?: readonly OperationSchedule[]) => Effect.Effect<{
32
+ readonly name: string;
33
+ readonly description: string;
34
+ readonly title?: string;
35
+ readonly annotations?: {
36
+ readonly title?: string;
37
+ readonly readOnlyHint?: boolean;
38
+ readonly destructiveHint?: boolean;
39
+ readonly idempotentHint?: boolean;
40
+ readonly openWorldHint?: boolean;
41
+ };
42
+ readonly schedules?: readonly {
43
+ readonly name: string;
44
+ readonly timing: {
45
+ readonly kind: "interval";
46
+ readonly milliseconds: number;
47
+ } | {
48
+ readonly kind: "cron";
49
+ readonly calendar: {
50
+ readonly expression: string;
51
+ readonly timezone: string;
52
+ };
53
+ };
54
+ readonly input: Schema.Json;
55
+ }[];
56
+ readonly readOnly?: boolean;
57
+ readonly router?: string;
58
+ readonly tags?: readonly string[];
59
+ }, HostDeclarationInvalid, never>;
60
+ /** A declared operation's full description, including rendered schemas. */
61
+ export declare const operationDescription: (name: string, router: string, operation: AppOperation, schedules?: readonly OperationSchedule[]) => Effect.Effect<{
62
+ readonly name: string;
63
+ readonly description: string;
64
+ readonly inputSchema: {
65
+ readonly [x: string]: Schema.Json;
66
+ };
67
+ readonly _meta?: {
68
+ readonly [x: string]: Schema.Json;
69
+ };
70
+ readonly title?: string;
71
+ readonly annotations?: {
72
+ readonly title?: string;
73
+ readonly readOnlyHint?: boolean;
74
+ readonly destructiveHint?: boolean;
75
+ readonly idempotentHint?: boolean;
76
+ readonly openWorldHint?: boolean;
77
+ };
78
+ readonly outputSchema?: {
79
+ readonly [x: string]: Schema.Json;
80
+ };
81
+ readonly schedules?: readonly {
82
+ readonly name: string;
83
+ readonly timing: {
84
+ readonly kind: "interval";
85
+ readonly milliseconds: number;
86
+ } | {
87
+ readonly kind: "cron";
88
+ readonly calendar: {
89
+ readonly expression: string;
90
+ readonly timezone: string;
91
+ };
92
+ };
93
+ readonly input: Schema.Json;
94
+ }[];
95
+ readonly readOnly?: boolean;
96
+ readonly router?: string;
97
+ readonly tags?: readonly string[];
98
+ }, HostDeclarationInvalid, never>;
99
+ /**
100
+ * A dynamic router over operations already discovered, such as an eager OpenAPI document or a
101
+ * stdio server. Upstream names can contain dots, which static router keys cannot.
102
+ */
103
+ export declare const fixedRouter: (operations: Readonly<Record<string, AppOperation>>, meta?: RouterMeta) => DynamicRouter;
104
+ export interface CatalogOptions {
105
+ /** Omit schemas. */
106
+ readonly summary: boolean;
107
+ /** Account secrets that a failure's message must not reveal. */
108
+ readonly secrets: readonly string[];
109
+ /** Only these full tool names. Routers with none of them are not read. */
110
+ readonly wanted?: ReadonlySet<string>;
111
+ /** Schedules that target a declared operation, by full name. */
112
+ readonly schedules: (name: string) => readonly OperationSchedule[];
113
+ /**
114
+ * Only declared operations that have schedules. Schedules never target dynamic routers, and
115
+ * their catalogs can be expensive to discover, so none is read.
116
+ */
117
+ readonly scheduled?: true;
118
+ }
119
+ /**
120
+ * Read a router tree. Every nested router is listed, for grouping; the root only when it has
121
+ * metadata. A nested dynamic source that fails is reported on its router's entry.
122
+ */
123
+ export declare const readCatalog: (root: AppRouter | DynamicRouter | undefined, options: CatalogOptions) => Effect.Effect<{
124
+ tools: ({
125
+ readonly name: string;
126
+ readonly description: string;
127
+ readonly inputSchema: {
128
+ readonly [x: string]: Schema.Json;
129
+ };
130
+ readonly _meta?: {
131
+ readonly [x: string]: Schema.Json;
132
+ };
133
+ readonly title?: string;
134
+ readonly annotations?: {
135
+ readonly title?: string;
136
+ readonly readOnlyHint?: boolean;
137
+ readonly destructiveHint?: boolean;
138
+ readonly idempotentHint?: boolean;
139
+ readonly openWorldHint?: boolean;
140
+ };
141
+ readonly outputSchema?: {
142
+ readonly [x: string]: Schema.Json;
143
+ };
144
+ readonly schedules?: readonly {
145
+ readonly name: string;
146
+ readonly timing: {
147
+ readonly kind: "interval";
148
+ readonly milliseconds: number;
149
+ } | {
150
+ readonly kind: "cron";
151
+ readonly calendar: {
152
+ readonly expression: string;
153
+ readonly timezone: string;
154
+ };
155
+ };
156
+ readonly input: Schema.Json;
157
+ }[];
158
+ readonly readOnly?: boolean;
159
+ readonly router?: string;
160
+ readonly tags?: readonly string[];
161
+ } | {
162
+ readonly name: string;
163
+ readonly description: string;
164
+ readonly title?: string;
165
+ readonly annotations?: {
166
+ readonly title?: string;
167
+ readonly readOnlyHint?: boolean;
168
+ readonly destructiveHint?: boolean;
169
+ readonly idempotentHint?: boolean;
170
+ readonly openWorldHint?: boolean;
171
+ };
172
+ readonly schedules?: readonly {
173
+ readonly name: string;
174
+ readonly timing: {
175
+ readonly kind: "interval";
176
+ readonly milliseconds: number;
177
+ } | {
178
+ readonly kind: "cron";
179
+ readonly calendar: {
180
+ readonly expression: string;
181
+ readonly timezone: string;
182
+ };
183
+ };
184
+ readonly input: Schema.Json;
185
+ }[];
186
+ readonly readOnly?: boolean;
187
+ readonly router?: string;
188
+ readonly tags?: readonly string[];
189
+ })[];
190
+ routers: {
191
+ readonly path: string;
192
+ readonly error?: import("../index.js").ProviderError | SkillLoadFailed | McpError | HostDeclarationInvalid | HostEvaluationFailed;
193
+ readonly description?: string;
194
+ readonly title?: string;
195
+ readonly tags?: {
196
+ readonly [x: string]: string;
197
+ };
198
+ readonly icons?: readonly {
199
+ readonly src: string;
200
+ readonly mimeType?: string;
201
+ readonly sizes?: readonly string[];
202
+ readonly theme?: "light" | "dark";
203
+ }[];
204
+ readonly skill?: string;
205
+ }[];
206
+ }, import("../index.js").ProviderError | SkillLoadFailed | McpError | HostDeclarationInvalid | HostEvaluationFailed, never>;
207
+ /**
208
+ * One skill for each router with instructions. Skills and tools fail independently: a dynamic
209
+ * router whose metadata cannot be read, including the root, contributes no skill and does not
210
+ * fail the others. Metadata comes through each source's catalog cache, like a tool listing.
211
+ */
212
+ export declare const routerSkills: (root: AppRouter | DynamicRouter | undefined) => Effect.Effect<{
213
+ readonly name: string;
214
+ readonly description: string;
215
+ readonly files: readonly {
216
+ readonly path: string;
217
+ readonly content: string;
218
+ }[];
219
+ readonly license?: string;
220
+ readonly compatibility?: string;
221
+ readonly metadata?: {
222
+ readonly [x: string]: string;
223
+ };
224
+ readonly "allowed-tools"?: string;
225
+ }[], never, never>;