apps 1.0.0-beta.2 → 1.0.0-beta.3

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 (41) hide show
  1. package/dist/authoring/index.d.ts +222 -34
  2. package/dist/authoring/index.js +11 -1
  3. package/dist/{chunk-NFLNA2SC.js → chunk-4OZFMCTT.js} +7 -1
  4. package/dist/{chunk-LWKQDDLZ.js → chunk-A3H32P2J.js} +46 -1
  5. package/dist/chunk-F7GZYEAC.js +41 -0
  6. package/dist/{chunk-OGCPVWAZ.js → chunk-MUFMJRXR.js} +130 -13
  7. package/dist/chunk-S5KFP4JQ.js +20 -0
  8. package/dist/{chunk-646MS7DD.js → chunk-Y6LLTN7W.js} +7 -7
  9. package/dist/chunk-YUZ4TXOY.js +27 -0
  10. package/dist/http/index.d.ts +9 -0
  11. package/dist/http/index.js +6 -0
  12. package/dist/index.d.ts +3 -0
  13. package/dist/index.js +23 -1
  14. package/dist/manifest/contract.d.ts +8 -0
  15. package/dist/manifest/index.js +3 -3
  16. package/dist/mcp/client.d.ts +9 -0
  17. package/dist/mcp/index.d.ts +11 -0
  18. package/dist/mcp/index.js +7 -0
  19. package/dist/openapi/index.d.ts +14 -0
  20. package/dist/openapi/index.js +7 -0
  21. package/dist/openapi/mapper.d.ts +7 -0
  22. package/dist/runner/index.js +29 -15
  23. package/dist/runner/protocol.d.ts +18 -5
  24. package/dist/runner/protocol.js +5 -3
  25. package/dist/runtime/index.d.ts +42 -5
  26. package/dist/runtime/index.js +3 -1
  27. package/dist/workerd/index.d.ts +1 -1
  28. package/dist/workerd/index.js +1 -1
  29. package/package.json +13 -6
  30. package/src/authoring/index.ts +362 -44
  31. package/src/http/index.ts +26 -0
  32. package/src/index.ts +3 -0
  33. package/src/manifest/contract.ts +9 -0
  34. package/src/mcp/client.ts +59 -0
  35. package/src/mcp/index.ts +42 -0
  36. package/src/openapi/index.ts +70 -0
  37. package/src/openapi/mapper.ts +25 -0
  38. package/src/runner/index.ts +35 -12
  39. package/src/runner/protocol.ts +32 -7
  40. package/src/runtime/index.ts +209 -22
  41. package/src/workerd/index.ts +2 -0
@@ -3,6 +3,18 @@
3
3
  * Authored modules record plain claims without I/O or user context; the
4
4
  * manifest loader owns execution, validation, and effects.
5
5
  */
6
+ /** A single opaque credential with RFC 6750 bearer semantics. */
7
+ export interface BearerMethod {
8
+ readonly kind: "bearer";
9
+ readonly label: string;
10
+ readonly help?: string;
11
+ }
12
+ /** An RFC 7617 username/password pair. */
13
+ export interface BasicMethod {
14
+ readonly kind: "basic";
15
+ readonly label: string;
16
+ readonly help?: string;
17
+ }
6
18
  export interface SecretsMethod<F extends Readonly<Record<string, SecretField>> = Readonly<Record<string, SecretField>>> {
7
19
  readonly kind: "secrets";
8
20
  readonly label: string;
@@ -17,7 +29,7 @@ export interface SecretField {
17
29
  readonly secret: boolean;
18
30
  }
19
31
  /**
20
- * An oauth auth method is a secrets-shaped auth method with acquisition strategies
32
+ * An oauth auth method is a bearer method with acquisition strategies
21
33
  * layered on: the material contract is always {token, refresh_token?,
22
34
  * expires_at?}, and the host fills it by the best strategy it can offer
23
35
  * — authorization-code ceremony, device-code ceremony, or paste. Paste
@@ -41,7 +53,15 @@ export interface OAuthMethod {
41
53
  * (audience-bound tokens, DPoP). Stated, never inferred. */
42
54
  readonly paste?: false;
43
55
  }
44
- export type AuthMethod = SecretsMethod | OAuthMethod;
56
+ export type AuthMethod = BearerMethod | BasicMethod | SecretsMethod | OAuthMethod;
57
+ export declare const bearer: (opts: {
58
+ readonly label: string;
59
+ readonly help?: string;
60
+ }) => BearerMethod;
61
+ export declare const basic: (opts: {
62
+ readonly label: string;
63
+ readonly help?: string;
64
+ }) => BasicMethod;
45
65
  export declare const secrets: <const F extends Readonly<Record<string, SecretField>>>(opts: {
46
66
  readonly label: string;
47
67
  /** Markdown shown under this auth method on the connect page, for example:
@@ -82,55 +102,171 @@ export interface RequirementSpec {
82
102
  readonly description?: string;
83
103
  }
84
104
  declare const RequirementKey: unique symbol;
105
+ declare const RequirementPhantom: unique symbol;
106
+ /** Requirement arity, tracked at the type level so handler contexts
107
+ * know whether a role arrives as one entry, maybe-one, or a list. */
108
+ export type RequirementArity = "one" | "optional" | "many";
85
109
  /**
86
110
  * A requirement value in a tool's `requirements` record. A Service IS
87
111
  * a requirement (bare value = arity "one"); .optional()/.array()
88
112
  * return terminal Requirements so nonsense chains do not typecheck.
113
+ * The phantom property is never assigned — it exists so auth-compose
114
+ * callbacks and handler contexts can recover the service's grants, a
115
+ * .grant() pin, and the arity at the type level.
89
116
  */
90
- export interface Requirement<D extends ServiceDecl = ServiceDecl> {
117
+ export interface Requirement<D extends ServiceDecl = ServiceDecl, G extends string | undefined = string | undefined, A extends RequirementArity = RequirementArity> {
91
118
  readonly [RequirementKey]: RequirementSpec;
92
- describe(text: string): Requirement<D>;
119
+ readonly [RequirementPhantom]?: {
120
+ readonly decl: D;
121
+ readonly pinned: G;
122
+ readonly arity: A;
123
+ };
124
+ describe(text: string): Requirement<D, G, A>;
93
125
  }
94
- export interface Service<D extends ServiceDecl = ServiceDecl> extends Requirement<D> {
126
+ export interface Service<D extends ServiceDecl = ServiceDecl, G extends (keyof NonNullable<D["auth"]> & string) | undefined = undefined> extends Requirement<D, G, "one"> {
95
127
  readonly decl: D;
96
- optional(): Requirement<D>;
97
- array(): Requirement<D>;
128
+ optional(): Requirement<D, G, "optional">;
129
+ array(): Requirement<D, G, "many">;
98
130
  /** Pin one auth method: this tool supports only the named grant. */
99
- grant(name: keyof NonNullable<D["auth"]> & string): Service<D>;
100
- describe(text: string): Service<D>;
131
+ grant<N extends keyof NonNullable<D["auth"]> & string>(name: N): Service<D, N>;
132
+ describe(text: string): Service<D, G>;
101
133
  }
102
134
  /** A publish-time authoring problem accumulated without interrupting defines. */
103
135
  export interface Problem {
104
136
  readonly message: string;
105
137
  }
106
- /**
107
- * A dynamic tool-set claim: tools discovered from a live surface (an
108
- * MCP server's tool list, an OpenAPI document) rather than authored one
109
- * file at a time. The claim is recorded at publish time; discovery runs
110
- * later, per connection — an app with zero static tools and one claim
111
- * saves green, and listing never blocks on an upstream.
112
- */
113
- export type DynamicClaimSpec = {
114
- readonly kind: "mcp";
115
- readonly requirement: RequirementSpec;
116
- /** MCP endpoint URL. Absent = the service origin at its root path. */
117
- readonly endpoint?: string;
138
+ /** One connected role, discriminated by the declared auth method kind. */
139
+ export type AuthRoleEntry<D extends ServiceDecl> = {
140
+ [N in keyof NonNullable<D["auth"]> & string]: NonNullable<D["auth"]>[N] extends SecretsMethod<infer F> ? {
141
+ readonly grant: N;
142
+ readonly kind: "secrets";
143
+ readonly secrets: {
144
+ readonly [K in keyof F & string]: string;
145
+ };
146
+ } : NonNullable<D["auth"]>[N] extends BasicMethod ? {
147
+ readonly grant: N;
148
+ readonly kind: "basic";
149
+ readonly username: string;
150
+ readonly password: string;
151
+ } : {
152
+ readonly grant: N;
153
+ readonly kind: "bearer" | "oauth";
154
+ readonly token: string;
155
+ };
156
+ }[keyof NonNullable<D["auth"]> & string];
157
+ /** Kind-discriminated credential material accepted by surface helpers. */
158
+ export type RoleMaterial = {
159
+ readonly kind: "bearer" | "oauth";
160
+ readonly token: string;
118
161
  } | {
119
- readonly kind: "openapi";
120
- readonly requirement: RequirementSpec;
121
- /** OpenAPI document: an absolute URL or an app-relative path. */
122
- readonly spec: string;
162
+ readonly kind: "basic";
163
+ readonly username: string;
164
+ readonly password: string;
165
+ } | {
166
+ readonly kind: "secrets";
167
+ readonly secrets: Readonly<Record<string, string>>;
168
+ };
169
+ /** Recover the connected role type produced by a service requirement. */
170
+ export type RoleOf<S, G extends string | undefined = undefined> = S extends Requirement<infer D, infer Pin> ? [G] extends [string] ? Extract<AuthRoleEntry<D>, {
171
+ grant: G;
172
+ }> : Pin extends string ? Extract<AuthRoleEntry<D>, {
173
+ grant: Pin;
174
+ }> : AuthRoleEntry<D> : never;
175
+ /** Role record received by an authored authentication placement callback. */
176
+ export type AuthRoles<Reqs extends Readonly<Record<string, Requirement>>> = {
177
+ readonly [K in keyof Reqs]: NonNullable<Reqs[K][typeof RequirementPhantom]> extends {
178
+ readonly decl: infer D extends ServiceDecl;
179
+ readonly pinned: infer G;
180
+ } ? G extends string ? Extract<AuthRoleEntry<D>, {
181
+ grant: G;
182
+ }> : AuthRoleEntry<D> : never;
183
+ };
184
+ /** Request placement returned by an authored dynamic auth callback. */
185
+ export interface AuthPlacement {
186
+ readonly headers?: HeadersInit;
187
+ readonly searchParams?: URLSearchParams | Readonly<Record<string, string>>;
188
+ }
189
+ export type AuthComposeFn<Reqs extends Readonly<Record<string, Requirement>> = never> = (roles: AuthRoles<Reqs>) => AuthPlacement | undefined | void;
190
+ export type HasSecretsGrant<D extends ServiceDecl> = true extends (NonNullable<D["auth"]>[keyof NonNullable<D["auth"]>] extends infer M ? M extends SecretsMethod ? true : false : never) ? true : false;
191
+ /** Whether an OpenAPI wrapper must state credential placement explicitly. */
192
+ export type RequiresAuthCompose<Reqs extends Readonly<Record<string, Requirement>>> = true extends {
193
+ [K in keyof Reqs]: NonNullable<Reqs[K][typeof RequirementPhantom]> extends {
194
+ readonly decl: infer D extends ServiceDecl;
195
+ readonly pinned: infer G;
196
+ } ? G extends keyof NonNullable<D["auth"]> & string ? NonNullable<D["auth"]>[G] extends SecretsMethod ? true : false : HasSecretsGrant<D> : never;
197
+ }[keyof Reqs] ? true : false;
198
+ /** Record a wrapper-specific publish problem on the active authored file. @internal */
199
+ export declare const recordAuthoringProblem: (message: string) => void;
200
+ /** Operation curation for a dynamic tool set. Exactly one of allow/block. */
201
+ export type OperationSelection = {
202
+ readonly allow: readonly string[];
203
+ readonly block?: undefined;
204
+ } | {
205
+ readonly block: readonly string[];
206
+ readonly allow?: undefined;
123
207
  };
208
+ /** One tool emitted by a dynamic discovery pass. */
209
+ export interface DiscoveredToolSpec {
210
+ readonly name: string;
211
+ readonly description: string;
212
+ readonly input: SchemaLike;
213
+ readonly annotations?: ToolAnnotations;
214
+ readonly detail?: unknown;
215
+ }
216
+ /**
217
+ * The generic authored shape of a dynamic pair: ctx is inferred from
218
+ * the requirements record exactly as for static tools. Discovered
219
+ * inputs are runtime data (the schema arrives from the upstream at
220
+ * discover time), so `call`'s input is honestly `unknown` — the
221
+ * runtime validates against the discovered descriptor before calling.
222
+ */
223
+ export interface DynamicToolsDecl<Reqs extends Readonly<Record<string, Requirement>> | undefined = Readonly<Record<string, Requirement>> | undefined> {
224
+ readonly description: string;
225
+ readonly requirements?: Reqs;
226
+ discover(ctx: HandlerCtx<Reqs>): Promise<readonly DiscoveredToolSpec[]>;
227
+ call(tool: {
228
+ readonly name: string;
229
+ readonly detail: unknown;
230
+ }, input: unknown, ctx: HandlerCtx<Reqs>): Promise<unknown>;
231
+ }
232
+ /**
233
+ * The erased registry row of a dynamic pair — same storage boundary
234
+ * as ToolSpec. App code: runs where handlers run (in-process locally,
235
+ * inside the isolate on workerd) and places credentials itself from
236
+ * ctx, like any handler. `discover` interrogates the tool source;
237
+ * `call` executes one discovered tool from the identity and detail
238
+ * discover emitted.
239
+ */
240
+ export interface DynamicToolsSpec {
241
+ readonly description: string;
242
+ readonly requirements?: Readonly<Record<string, Requirement>>;
243
+ discover(ctx: never): Promise<readonly DiscoveredToolSpec[]>;
244
+ call(tool: {
245
+ readonly name: string;
246
+ readonly detail: unknown;
247
+ }, input: never, ctx: never): Promise<unknown>;
248
+ }
124
249
  declare const DynamicKey: unique symbol;
125
- /** The value fromMCP/fromOpenAPI return: an opaque claim handle a tool
126
- * file default-exports. The spec is undefined when the claim was
250
+ /** The value defineDynamicTools returns: an opaque handle a tool file
251
+ * default-exports. The spec is undefined when the definition was
127
252
  * invalid (a problem was recorded instead). */
128
253
  export interface DynamicToolSet {
129
- readonly [DynamicKey]: DynamicClaimSpec | undefined;
254
+ readonly [DynamicKey]: DynamicToolsSpec | undefined;
130
255
  }
131
- /** A registered dynamic claim and its source attribution. @internal */
132
- export interface RegisteredDynamic {
133
- readonly spec: DynamicClaimSpec;
256
+ /** Reads a dynamic spec from a tool file's default export. @internal */
257
+ export declare const dynamicSpecOf: (value: unknown) => DynamicToolsSpec | undefined;
258
+ /**
259
+ * The dynamic-tools primitive: an author-written discover/call pair
260
+ * whose tool list is interrogated at runtime, per connection, instead
261
+ * of authored one file at a time. The file's name becomes the address
262
+ * segment (appKey/<stem>/<toolName>); tools land in the catalog after
263
+ * discovery and never block a save. fromMCP/fromOpenAPI are shipped
264
+ * pairs over this same primitive.
265
+ */
266
+ export declare const defineDynamicTools: <const Reqs extends Readonly<Record<string, Requirement>> | undefined = undefined>(decl: DynamicToolsDecl<Reqs>) => DynamicToolSet;
267
+ /** A registered dynamic tool set and its source attribution. @internal */
268
+ export interface DynamicRegistration {
269
+ readonly spec: DynamicToolsSpec;
134
270
  readonly file: string;
135
271
  }
136
272
  /** A registered service declaration and its source attribution. @internal */
@@ -148,7 +284,7 @@ export interface Registry {
148
284
  app: AppManifest | undefined;
149
285
  readonly services: Map<string, RegisteredService>;
150
286
  readonly tools: Map<string, RegisteredTool>;
151
- readonly dynamic: Map<string, RegisteredDynamic>;
287
+ readonly dynamic: Map<string, DynamicRegistration>;
152
288
  readonly problems: Problem[];
153
289
  readonly toolFiles: Map<string, {
154
290
  definitions: number;
@@ -178,14 +314,66 @@ export declare const defineApp: (manifest: {
178
314
  }) => AppManifest;
179
315
  /** Any Standard Schema (zod preferred) or a raw JSON-schema object. */
180
316
  export type SchemaLike = object;
317
+ /**
318
+ * The validated value a Standard Schema produces, recovered from its
319
+ * phantom types (zod 4 and effect Schema both publish them). A raw
320
+ * JSON-schema object carries no phantom, so its input is `unknown` —
321
+ * stated weakness, not silent weakness.
322
+ */
323
+ export type InferSchema<S> = S extends {
324
+ readonly "~standard": {
325
+ readonly types?: infer T;
326
+ };
327
+ } ? NonNullable<T> extends {
328
+ readonly output: infer O;
329
+ } ? O : unknown : unknown;
330
+ /**
331
+ * The capability a handler receives for one connected requirement
332
+ * role: the grant's kind-discriminated material (narrowed by any
333
+ * .grant() pin) plus the spending fetch. Arity shapes the value —
334
+ * `.optional()` may be absent, `.array()` is every connected account.
335
+ */
336
+ export type HandlerRole<R> = R extends Requirement<infer D, infer G, infer A> ? [A] extends ["many"] ? ReadonlyArray<HandlerRoleEntry<D, G>> : [A] extends ["optional"] ? HandlerRoleEntry<D, G> | undefined : HandlerRoleEntry<D, G> : never;
337
+ /** One connected role entry: declared-auth material + capability fetch. */
338
+ export type HandlerRoleEntry<D extends ServiceDecl, G extends string | undefined> = ([G] extends [string] ? Extract<AuthRoleEntry<D>, {
339
+ grant: G;
340
+ }> : AuthRoleEntry<D>) & {
341
+ fetch(path: string, init?: RequestInit): Promise<Response>;
342
+ };
343
+ /** The ctx record a handler receives, keyed by requirement role. */
344
+ export type HandlerCtx<Reqs> = [Reqs] extends [Readonly<Record<string, Requirement>>] ? {
345
+ readonly [K in keyof Reqs]: HandlerRole<Reqs[K]>;
346
+ } : Readonly<Record<never, never>>;
181
347
  export interface ToolAnnotations {
182
348
  readonly readOnly?: boolean;
183
349
  readonly destructive?: boolean;
184
350
  /** Facts, not flow: shortfall surfaces as the scope challenge. */
185
351
  readonly scopes?: readonly string[];
186
352
  }
187
- export interface ToolSpec {
353
+ /**
354
+ * The generic authored shape: input/ctx/output are all inferred — the
355
+ * handler's input from the Standard Schema, ctx from the requirements
356
+ * record (grants, pins, arity), and the return type checked against
357
+ * the output schema when one is stated.
358
+ */
359
+ export interface ToolDecl<Input extends SchemaLike = SchemaLike, Reqs extends Readonly<Record<string, Requirement>> | undefined = Readonly<Record<string, Requirement>> | undefined, Output extends SchemaLike | undefined = SchemaLike | undefined> {
188
360
  /** Address segment. Single-tool files may omit it (filename). */
361
+ readonly name?: string;
362
+ readonly description: string;
363
+ readonly requirements?: Reqs;
364
+ readonly input: Input;
365
+ readonly output?: Output;
366
+ readonly annotations?: ToolAnnotations;
367
+ handler(input: InferSchema<Input>, ctx: HandlerCtx<Reqs>): Promise<Output extends SchemaLike ? InferSchema<Output> : unknown>;
368
+ }
369
+ /**
370
+ * The erased registry row. Registration drops the generics — storage
371
+ * is untyped by design, the same boundary every schema library draws
372
+ * between its typed builders and its runtime representation. The
373
+ * runtime re-establishes safety by validating input before the
374
+ * handler runs and shaping ctx from resolved connections.
375
+ */
376
+ export interface ToolSpec {
189
377
  readonly name?: string;
190
378
  readonly description: string;
191
379
  readonly requirements?: Readonly<Record<string, Requirement>>;
@@ -198,7 +386,7 @@ declare const ToolKey: unique symbol;
198
386
  export interface Tool {
199
387
  readonly [ToolKey]: ToolSpec;
200
388
  }
201
- export declare const defineTool: (spec: ToolSpec) => Tool;
389
+ export declare const defineTool: <const Input extends SchemaLike, const Reqs extends Readonly<Record<string, Requirement>> | undefined = undefined, const Output extends SchemaLike | undefined = undefined>(decl: ToolDecl<Input, Reqs, Output>) => Tool;
202
390
  export declare const toolSpecOf: (value: unknown) => ToolSpec | undefined;
203
391
  /** A tool file's default export. */
204
392
  export type ToolExport = Tool | ReadonlyArray<Tool>;
@@ -1,23 +1,33 @@
1
1
  import {
2
2
  __enterFile,
3
3
  __leaveFile,
4
+ basic,
5
+ bearer,
4
6
  defineApp,
7
+ defineDynamicTools,
5
8
  defineTool,
9
+ dynamicSpecOf,
6
10
  newRegistry,
7
11
  oauth,
12
+ recordAuthoringProblem,
8
13
  requirementSpecOf,
9
14
  secrets,
10
15
  service,
11
16
  setActiveRegistry,
12
17
  toolSpecOf
13
- } from "../chunk-LWKQDDLZ.js";
18
+ } from "../chunk-A3H32P2J.js";
14
19
  export {
15
20
  __enterFile,
16
21
  __leaveFile,
22
+ basic,
23
+ bearer,
17
24
  defineApp,
25
+ defineDynamicTools,
18
26
  defineTool,
27
+ dynamicSpecOf,
19
28
  newRegistry,
20
29
  oauth,
30
+ recordAuthoringProblem,
21
31
  requirementSpecOf,
22
32
  secrets,
23
33
  service,
@@ -5,7 +5,13 @@ var CallError = class extends Data.TaggedError("CallError") {
5
5
  return `${this.target}: ${this.reason}`;
6
6
  }
7
7
  };
8
+ var DiscoverError = class extends Data.TaggedError("DiscoverError") {
9
+ get message() {
10
+ return `${this.segment}: ${this.reason}`;
11
+ }
12
+ };
8
13
 
9
14
  export {
10
- CallError
15
+ CallError,
16
+ DiscoverError
11
17
  };
@@ -1,8 +1,44 @@
1
1
  // src/authoring/index.ts
2
+ var bearer = (opts) => ({ kind: "bearer", ...opts });
3
+ var basic = (opts) => ({ kind: "basic", ...opts });
2
4
  var secrets = (opts) => ({ kind: "secrets", ...opts });
3
5
  var oauth = (opts) => ({ kind: "oauth", ...opts });
4
6
  var RequirementKey = Symbol.for("executor/apps/requirement");
7
+ var recordAuthoringProblem = (message) => {
8
+ const file = sourceFileFor("wrapper");
9
+ activeRegistry.problems.push({ message: `${file}: ${message}` });
10
+ };
5
11
  var DynamicKey = Symbol.for("executor/apps/dynamic");
12
+ var dynamicSpecOf = (value) => typeof value === "object" && value !== null && DynamicKey in value ? value[DynamicKey] : void 0;
13
+ var defineDynamicTools = (decl) => {
14
+ const spec = decl;
15
+ const file = sourceFileFor("defineDynamicTools(...)");
16
+ const problems = [];
17
+ if (typeof spec.description !== "string" || spec.description.trim().length === 0)
18
+ problems.push("dynamic tool set description must not be empty");
19
+ const roles = Object.entries(spec.requirements ?? {});
20
+ if (roles.length > 1) problems.push("a dynamic tool set takes exactly one requirement role");
21
+ else if (roles.length === 1) {
22
+ const [role, value] = roles[0];
23
+ const requirementSpec = requirementSpecOf(value);
24
+ if (requirementSpec === void 0)
25
+ problems.push(`requirement '${role}' is not a service/requirement value`);
26
+ else if (requirementSpec.arity === "many")
27
+ problems.push(
28
+ `requirement '${role}' cannot be .array() \u2014 multiple accounts expand the catalog per connection, never merge one list`
29
+ );
30
+ }
31
+ if (problems.length > 0) {
32
+ activeRegistry.problems.push(...problems.map((message) => ({ message: `${file}: ${message}` })));
33
+ return { [DynamicKey]: void 0 };
34
+ }
35
+ if (activeRegistry.dynamic.has(file))
36
+ activeRegistry.problems.push({
37
+ message: `${file}: one dynamic tool set per file \u2014 its address segment is the file's name`
38
+ });
39
+ else activeRegistry.dynamic.set(file, { spec, file });
40
+ return { [DynamicKey]: spec };
41
+ };
6
42
  var newRegistry = () => ({
7
43
  app: void 0,
8
44
  services: /* @__PURE__ */ new Map(),
@@ -61,7 +97,11 @@ var defineApp = (manifest) => {
61
97
  return value;
62
98
  };
63
99
  var ToolKey = Symbol.for("executor/apps/tool");
64
- var defineTool = (spec) => {
100
+ var defineTool = (decl) => {
101
+ const spec = decl;
102
+ return registerTool(spec);
103
+ };
104
+ var registerTool = (spec) => {
65
105
  const file = sourceFileFor("defineTool(...)");
66
106
  const value = { [ToolKey]: spec };
67
107
  const fileName = file.slice(file.lastIndexOf("/") + 1);
@@ -84,8 +124,13 @@ var isTool = (value) => typeof value === "object" && value !== null && ToolKey i
84
124
  var toolSpecOf = (value) => isTool(value) ? value[ToolKey] : void 0;
85
125
 
86
126
  export {
127
+ bearer,
128
+ basic,
87
129
  secrets,
88
130
  oauth,
131
+ recordAuthoringProblem,
132
+ dynamicSpecOf,
133
+ defineDynamicTools,
89
134
  newRegistry,
90
135
  setActiveRegistry,
91
136
  __enterFile,
@@ -0,0 +1,41 @@
1
+ import {
2
+ defineDynamicTools,
3
+ recordAuthoringProblem,
4
+ requirementSpecOf
5
+ } from "./chunk-A3H32P2J.js";
6
+
7
+ // src/openapi/mapper.ts
8
+ var openapiDiscover = async (_spec, _ctx, _auth, _operations) => {
9
+ throw new Error("openapi mapper not built yet");
10
+ };
11
+ var openapiCall = async (_tool, _input, _ctx, _auth) => {
12
+ throw new Error("openapi mapper not built yet");
13
+ };
14
+
15
+ // src/openapi/index.ts
16
+ var enforceSecretsPlacement = (requirements, auth) => {
17
+ if (auth !== void 0) return;
18
+ for (const value of Object.values(requirements ?? {})) {
19
+ const spec = requirementSpecOf(value);
20
+ const methods = spec?.grant === void 0 ? Object.values(spec?.service.auth ?? {}) : [spec.service.auth?.[spec.grant]].filter((method) => method !== void 0);
21
+ if (methods.some((method) => method.kind === "secrets"))
22
+ recordAuthoringProblem(
23
+ "fromOpenAPI: the service offers a secrets() auth method, so 'auth' must state how the credential rides"
24
+ );
25
+ }
26
+ };
27
+ function fromOpenAPI(spec, options) {
28
+ enforceSecretsPlacement(options?.requirements, options?.auth);
29
+ const auth = options?.auth;
30
+ const operations = options?.operations;
31
+ return defineDynamicTools({
32
+ description: typeof spec === "string" && spec.startsWith("https://") ? `Operations from the OpenAPI document at ${spec}.` : "Operations from an OpenAPI document shipped with the app.",
33
+ ...options?.requirements === void 0 ? {} : { requirements: options.requirements },
34
+ discover: (ctx) => openapiDiscover(spec, ctx, auth, operations),
35
+ call: (tool, input, ctx) => openapiCall(tool, input, ctx, auth)
36
+ });
37
+ }
38
+
39
+ export {
40
+ fromOpenAPI
41
+ };