gemi 0.181.0 → 0.183.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.
Files changed (56) hide show
  1. package/dist/auth/AuthController.d.ts.map +1 -1
  2. package/dist/auth/AuthManager.d.ts +2 -1
  3. package/dist/auth/AuthManager.d.ts.map +1 -1
  4. package/dist/auth/config.d.ts +93 -10
  5. package/dist/auth/config.d.ts.map +1 -1
  6. package/dist/auth/oauth/providers.d.ts +8 -3
  7. package/dist/auth/oauth/providers.d.ts.map +1 -1
  8. package/dist/auth/oneTimeCode.d.ts +15 -4
  9. package/dist/auth/oneTimeCode.d.ts.map +1 -1
  10. package/dist/auth/routes.d.ts +1 -1
  11. package/dist/auth/routes.d.ts.map +1 -1
  12. package/dist/{chunk-1mz16fsz.js → chunk-0hr6k996.js} +1 -1
  13. package/dist/chunk-f54p1qc9.js +117 -0
  14. package/dist/{chunk-px7yzba8.js.map → chunk-f54p1qc9.js.map} +9 -9
  15. package/dist/{chunk-28mrg70g.js → chunk-jmjq2cjx.js} +2 -2
  16. package/dist/{chunk-28mrg70g.js.map → chunk-jmjq2cjx.js.map} +1 -1
  17. package/dist/{chunk-m3ncxcw8.js → chunk-qzycygkz.js} +1 -1
  18. package/dist/{chunk-n5gvv25q.js → chunk-synh1gad.js} +1 -1
  19. package/dist/chunks/{RealtimeClient-CHNbqDr7.js → RealtimeClient-v3orUDdN.js} +2 -2
  20. package/dist/chunks/{RealtimeClient-CHNbqDr7.js.map → RealtimeClient-v3orUDdN.js.map} +1 -1
  21. package/dist/chunks/{ThemeProvider-Bkc6A9Nn.js → ThemeProvider-CDm5TXZC.js} +12 -5
  22. package/dist/chunks/ThemeProvider-CDm5TXZC.js.map +1 -0
  23. package/dist/chunks/{fetchFileRequest-BGEW4Wd7.js → fetchFileRequest-B6tFA-uV.js} +2 -2
  24. package/dist/chunks/{fetchFileRequest-BGEW4Wd7.js.map → fetchFileRequest-B6tFA-uV.js.map} +1 -1
  25. package/dist/chunks/{live-l4vtaqXd.js → live-JhGCkWuM.js} +3 -3
  26. package/dist/chunks/{live-l4vtaqXd.js.map → live-JhGCkWuM.js.map} +1 -1
  27. package/dist/chunks/{mutationExtras-C7UPW9XP.js → mutationExtras-BnDYKenf.js} +2 -2
  28. package/dist/chunks/{mutationExtras-C7UPW9XP.js.map → mutationExtras-BnDYKenf.js.map} +1 -1
  29. package/dist/chunks/{subscriptionStream-CULcRbx0.js → subscriptionStream-BdxPsTI_.js} +16 -4
  30. package/dist/chunks/subscriptionStream-BdxPsTI_.js.map +1 -0
  31. package/dist/client/index.js +7 -6
  32. package/dist/client/index.js.map +1 -1
  33. package/dist/client/retryPolicy.d.ts +6 -0
  34. package/dist/client/retryPolicy.d.ts.map +1 -1
  35. package/dist/client/subscriptionStream.d.ts +10 -1
  36. package/dist/client/subscriptionStream.d.ts.map +1 -1
  37. package/dist/client/useSubscription.d.ts +3 -2
  38. package/dist/client/useSubscription.d.ts.map +1 -1
  39. package/dist/facades/Auth.d.ts +2 -1
  40. package/dist/facades/Auth.d.ts.map +1 -1
  41. package/dist/facades/index.js +1 -1
  42. package/dist/http/index.js +1 -1
  43. package/dist/i18n/index.js +1 -1
  44. package/dist/kernel/index.js +1 -1
  45. package/dist/server/index.js +1 -1
  46. package/dist/services/index.d.ts +2 -2
  47. package/dist/services/index.d.ts.map +1 -1
  48. package/dist/services/index.js +1 -1
  49. package/dist/testing/index.js +2 -2
  50. package/package.json +1 -1
  51. package/dist/chunk-px7yzba8.js +0 -117
  52. package/dist/chunks/ThemeProvider-Bkc6A9Nn.js.map +0 -1
  53. package/dist/chunks/subscriptionStream-CULcRbx0.js.map +0 -1
  54. /package/dist/{chunk-1mz16fsz.js.map → chunk-0hr6k996.js.map} +0 -0
  55. /package/dist/{chunk-m3ncxcw8.js.map → chunk-qzycygkz.js.map} +0 -0
  56. /package/dist/{chunk-n5gvv25q.js.map → chunk-synh1gad.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"AuthController.d.ts","sourceRoot":"","sources":["../../auth/AuthController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AuthController.d.ts","sourceRoot":"","sources":["../../auth/AuthController.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,8 @@ export declare class AuthManager {
26
26
  constructor(config?: AuthConfig, provider?: UserProvider<any>);
27
27
  /**
28
28
  * The OAuth sign-in provider `name` names, or `null` when there is none or
29
- * its `feature` is off for this request (#885) — the two answer alike.
29
+ * its `feature` (#885) or `enabled` (#1135) is off for this request — they
30
+ * answer alike.
30
31
  */
31
32
  oauthProvider(name: string): Promise<OAuthProvider | null>;
32
33
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"AuthManager.d.ts","sourceRoot":"","sources":["../../auth/AuthManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AuthManager.d.ts","sourceRoot":"","sources":["../../auth/AuthManager.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,26 @@ import type { ConnectionStore } from "./connections/ConnectionStore";
6
6
  import type { ProviderConnection } from "./connections/ConnectionManager";
7
7
  import type { OAuthConnectionProvider } from "./connections/OAuthConnectionProvider";
8
8
  import type { AuthRateLimitKey, CodeRateLimits } from "./oneTimeCode";
9
+ /** What a per-request switch (`AuthSwitch`) is handed (#1135). */
10
+ export interface AuthSwitchContext {
11
+ req: HttpRequest<any, any>;
12
+ }
13
+ /**
14
+ * An auth flow switch: a boolean, or a function of the request for an app
15
+ * whose flows differ by host or tenant (#1135). The function is asked on each
16
+ * request the switch guards, before the body is read; a throw fails the
17
+ * request (500).
18
+ *
19
+ * password: ({ req }) => req.headers.get("host") !== "app.example.com",
20
+ */
21
+ export type AuthSwitch = boolean | ((ctx: AuthSwitchContext) => boolean | Promise<boolean>);
22
+ /**
23
+ * Whether `value` is on for `req`. A function is asked; anything else is read
24
+ * as a boolean (the config check refuses what is not one at boot).
25
+ */
26
+ export declare function authSwitchOn(value: AuthSwitch | undefined, req: HttpRequest<any, any>): Promise<boolean>;
27
+ /** Whether `value` can be on for some request: `true`, or a function. */
28
+ export declare function authSwitchMayBeOn(value: AuthSwitch | undefined): boolean;
9
29
  /** What `emailCode.send` is handed. */
10
30
  export interface EmailCodeSendArgs {
11
31
  /** Normalized: trimmed and lowercased. */
@@ -29,8 +49,12 @@ export interface EmailCodeSendArgs {
29
49
  * are for `POST /auth/email-code` and `/auth/email-code/verify` only.
30
50
  */
31
51
  export interface EmailCodeConfig {
32
- /** Serves `/auth/email-code` and `/auth/email-code/verify`. Default `false`: both answer 404. */
33
- enabled?: boolean;
52
+ /**
53
+ * Serves `/auth/email-code` and `/auth/email-code/verify`. Default `false`:
54
+ * both answer 404. A function of the request turns them on per request
55
+ * (#1135); off, they answer the same 404.
56
+ */
57
+ enabled?: AuthSwitch;
34
58
  /**
35
59
  * Sign-up-or-sign-in: an address with no user gets a code too, and verifying
36
60
  * it creates the user (verified, inside the same transaction as
@@ -90,6 +114,36 @@ export interface EmailCodeConfig {
90
114
  */
91
115
  send?: (args: EmailCodeSendArgs) => Promise<void> | void;
92
116
  }
117
+ /**
118
+ * Rate limits on the email + password routes (#1136), through the same
119
+ * limiter and keys (`auth.rateLimitKey`) as the email-code limits. Each is
120
+ * `[count, windowSeconds]` per address and per IP, or `false` to turn one
121
+ * off. Over a limit: 429 `{ error: { kind: "rate_limit" } }`.
122
+ */
123
+ export interface PasswordRateLimits {
124
+ /**
125
+ * Password guesses: `/auth/sign-in`, `/auth/sign-in-v2` and
126
+ * `/auth/change-password` (per signed-in address). Default
127
+ * `{ perEmail: [10, 900], perIp: [50, 900] }`.
128
+ */
129
+ signIn?: CodeRateLimits;
130
+ /** `/auth/sign-up`. Default `{ perEmail: false, perIp: [10, 3600] }`. */
131
+ signUp?: CodeRateLimits;
132
+ /**
133
+ * `/auth/forgot-password`, which mails a link. Default
134
+ * `{ perEmail: [5, 900], perIp: [20, 900] }`.
135
+ */
136
+ forgot?: CodeRateLimits;
137
+ /**
138
+ * `/auth/reset-password`, per IP (a reset token is 256 random bits and
139
+ * names no address). Default `{ perIp: [20, 900] }`.
140
+ */
141
+ reset?: CodeRateLimits;
142
+ }
143
+ /** `PasswordRateLimits` with every limit set, from the defaults where left out. */
144
+ export declare function passwordLimitDefaults(config?: PasswordRateLimits): Required<{
145
+ [K in keyof PasswordRateLimits]: Required<CodeRateLimits>;
146
+ }>;
93
147
  /** What `onConnected` is handed. */
94
148
  export interface ConnectedArgs {
95
149
  user: User;
@@ -157,7 +211,13 @@ export type LegacySessionMigrator = (session: SessionWithUser, ctx: {
157
211
  }) => boolean | Promise<boolean>;
158
212
  export interface AuthConfig {
159
213
  basePath?: string;
160
- verifyEmail?: boolean;
214
+ /**
215
+ * Password sign-in, forgot/reset and change password accept only a verified
216
+ * address. Default `true`. With `false`, sign-up stores no verification
217
+ * token and hands `onSignUp` `""`. A function of the request decides it per
218
+ * request (#1135).
219
+ */
220
+ verifyEmail?: AuthSwitch;
161
221
  /**
162
222
  * The email + password routes. Default `true`. `false` answers 404 on
163
223
  * `POST /auth/sign-in`, `sign-in-v2`, `sign-up`, `forgot-password`,
@@ -166,16 +226,29 @@ export interface AuthConfig {
166
226
  * Nothing else changes: sign-out, `/auth/me`, email codes and OAuth keep
167
227
  * working, and so do `verifyPassword` and `hashPassword` for an app that
168
228
  * calls them itself.
229
+ *
230
+ * A function of the request switches them per request, for an app serving
231
+ * several hosts or tenants (#1135): off, the same 404.
232
+ */
233
+ password?: AuthSwitch;
234
+ /**
235
+ * Rate limits on the password routes (#1136): sign-in (and change
236
+ * password), sign-up, forgot and reset password. See `PasswordRateLimits`
237
+ * for the defaults; partitioned by `rateLimitKey` like the email-code limits.
169
238
  */
170
- password?: boolean;
239
+ passwordLimits?: PasswordRateLimits;
171
240
  /**
172
241
  * The magic-link + PIN pair. Default `true`. `false` answers 404 on
173
242
  * `POST /auth/magic-link`, `sign-in-with-pin` and `sign-in-with-pin-v2`
174
243
  * (#879). The `/auth/sign-in/magic-link` page (the `auth/MagicLinkSignIn`
175
244
  * view) stays while `emailCode.enabled` is on, since it takes the link
176
245
  * `emailCode.send` is handed; with both off it is not mounted (#1040).
246
+ *
247
+ * A function of the request switches them per request (#1135): off, the
248
+ * same 404. The `/auth/sign-in/magic-link` page answers 404 on a request
249
+ * where both this and `emailCode.enabled` are off.
177
250
  */
178
- magicLink?: boolean;
251
+ magicLink?: AuthSwitch;
179
252
  /**
180
253
  * Where a signed-in user goes when there is no intended URL to return to —
181
254
  * the fallback of `Auth.intendedUrl()` and of the OAuth callback's
@@ -356,7 +429,8 @@ export interface AuthConfig {
356
429
  /**
357
430
  * Partitions the keys of gemi's auth rate limits (#1125): the email-code and
358
431
  * magic-link request, verify and link limits (`emailCode.requestLimit`,
359
- * `emailCode.verifyLimit`), per address and per IP. Answer a string derived
432
+ * `emailCode.verifyLimit`) and the password limits (`passwordLimits`, #1136),
433
+ * per address and per IP. Answer a string derived
360
434
  * from the request, such as the tenant the host names, and that counter is
361
435
  * kept per partition, so the same address in two tenants does not share a
362
436
  * budget. `args.limit` says which counter is asked about, so an app can
@@ -395,7 +469,8 @@ export interface AuthConfig {
395
469
  onAuthenticated?: (args: AuthenticatedArgs) => Promise<void> | void;
396
470
  }
397
471
  /**
398
- * Throws on a `password` or `magicLink` that is not a boolean: `"false"` would
472
+ * Throws on a `password`, `magicLink`, `verifyEmail` or `emailCode.enabled`
473
+ * that is neither a boolean nor a function of the request: `"false"` would
399
474
  * leave the routes on. Run at boot by `AuthServiceProvider`, and again when
400
475
  * the config is merged.
401
476
  */
@@ -415,8 +490,8 @@ export declare function emailCodeDefaults(config?: EmailCodeConfig): Required<Em
415
490
  */
416
491
  export declare function verifyPasswordHash(password: string, hash: string | null | undefined): Promise<boolean>;
417
492
  /**
418
- * One `oauthProviders` entry: a provider, or a provider behind a feature flag.
419
- * See `AuthConfig.oauthProviders`.
493
+ * One `oauthProviders` entry: a provider, or a provider behind a feature flag
494
+ * or a per-request switch. See `AuthConfig.oauthProviders`.
420
495
  */
421
496
  export type OAuthProviderEntry = OAuthProvider | {
422
497
  provider: OAuthProvider;
@@ -426,11 +501,19 @@ export type OAuthProviderEntry = OAuthProvider | {
426
501
  * leaves it out.
427
502
  */
428
503
  feature?: FeatureKey;
504
+ /**
505
+ * Whether the provider is offered, as a boolean or a function of the
506
+ * request (#1135), such as whether the tenant the host names has
507
+ * configured its own client. Off answers like an off `feature`. Both
508
+ * set, both must be on. Default `true`.
509
+ */
510
+ enabled?: AuthSwitch;
429
511
  };
430
- /** Splits an `oauthProviders` entry into its provider and its feature gate. */
512
+ /** Splits an `oauthProviders` entry into its provider and its gates. */
431
513
  export declare function oauthProviderEntry(entry: OAuthProviderEntry | undefined): {
432
514
  provider: OAuthProvider;
433
515
  feature?: string;
516
+ enabled?: AuthSwitch;
434
517
  } | null;
435
518
  /**
436
519
  * Refuses an `oauthProviders` entry that is neither a provider nor a
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../auth/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../auth/config.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,15 @@
1
+ import type { HttpRequest } from "../../http/HttpRequest";
1
2
  import { type OAuthProviderEntry } from "../config";
2
3
  import type { OAuthProvider } from "./OAuthProvider";
3
4
  /**
4
5
  * The sign-in provider `name` names in `auth.oauthProviders`, or `null` when
5
- * there is none or its `feature` is off for this request (#885).
6
+ * there is none, its `feature` is off for this request (#885), or its
7
+ * `enabled` answers false for it (#1135).
8
+ *
9
+ * An `enabled` function is asked with `req`, else the ambient request. With
10
+ * no request at all it answers off, as a feature read outside one does.
6
11
  */
7
- export declare function enabledOAuthProvider(providers: Record<string, OAuthProviderEntry>, name: string): Promise<OAuthProvider | null>;
12
+ export declare function enabledOAuthProvider(providers: Record<string, OAuthProviderEntry>, name: string, req?: HttpRequest<any, any> | null): Promise<OAuthProvider | null>;
8
13
  /** The names of the providers that are on for this request, in declaration order. */
9
- export declare function enabledOAuthProviderNames(providers: Record<string, OAuthProviderEntry>): Promise<string[]>;
14
+ export declare function enabledOAuthProviderNames(providers: Record<string, OAuthProviderEntry>, req?: HttpRequest<any, any> | null): Promise<string[]>;
10
15
  //# sourceMappingURL=providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../auth/oauth/providers.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC7C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAK/B;AAED,qFAAqF;AACrF,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAC5C,OAAO,CAAC,MAAM,EAAE,CAAC,CAMnB"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../auth/oauth/providers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAoC,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAWrD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC7C,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAuB,GACnD,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAS/B;AAED,qFAAqF;AACrF,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC7C,GAAG,GAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAuB,GACnD,OAAO,CAAC,MAAM,EAAE,CAAC,CAMnB"}
@@ -74,15 +74,24 @@ export declare function resetFallbackCodeLimiter(): void;
74
74
  * the whole window, so none may cost more than a hash's worth of memory.
75
75
  */
76
76
  export declare function limiterKeyPart(value: string): string;
77
+ /**
78
+ * Which of gemi's auth rate limits a counter belongs to. The first three are
79
+ * the email-code and magic-link limits (#1125); the rest are the password
80
+ * routes' (#1136).
81
+ */
82
+ export type AuthRateLimitScope = "request" | "verify" | "link" | "sign-in" | "sign-up" | "forgot" | "reset";
77
83
  /** What `auth.rateLimitKey` is handed (#1125). */
78
84
  export interface AuthRateLimitKeyArgs {
79
85
  req: HttpRequest<any, any>;
80
86
  /**
81
87
  * Which counter: `"request"` (asking for a code or link: `/auth/email-code`,
82
88
  * `/auth/magic-link`), `"verify"` (guessing one: `/auth/email-code/verify`,
83
- * `/auth/sign-in-with-pin(-v2)`) or `"link"` (`/auth/sign-in/magic-link`).
89
+ * `/auth/sign-in-with-pin(-v2)`), `"link"` (`/auth/sign-in/magic-link`), and
90
+ * since #1136 the password routes: `"sign-in"` (`/auth/sign-in(-v2)`,
91
+ * `/auth/change-password`), `"sign-up"`, `"forgot"` (`/auth/forgot-password`)
92
+ * and `"reset"` (`/auth/reset-password`).
84
93
  */
85
- scope: "request" | "verify" | "link";
94
+ scope: AuthRateLimitScope;
86
95
  /** The per-address or the per-IP counter of that scope. */
87
96
  limit: "perEmail" | "perIp";
88
97
  }
@@ -95,7 +104,9 @@ export type AuthRateLimitKey = (args: AuthRateLimitKeyArgs) => string | null | u
95
104
  /**
96
105
  * Spends one hit of each configured limit for `scope`, per IP first and then
97
106
  * per email, and throws the middleware's 429 (`{ error: { kind: "rate_limit" } }`)
98
- * on the first one that is spent. An IP over its limit does not also spend the
107
+ * on the first one that is spent. `onRefused`, when given, runs before that
108
+ * throw with the counter that refused, so a caller can spend what an allowed
109
+ * attempt would have (the password sign-in's decoy hash). An IP over its limit does not also spend the
99
110
  * address's budget, so somebody hammering from one address cannot use up a
100
111
  * victim's.
101
112
  *
@@ -108,7 +119,7 @@ export type AuthRateLimitKey = (args: AuthRateLimitKeyArgs) => string | null | u
108
119
  * an app can give each tenant its own budget. Asked only for a limit that is
109
120
  * on, and only for the per-address counter when there is an address.
110
121
  */
111
- export declare function enforceCodeRateLimits(scope: "request" | "verify" | "link", email: string | null, req: HttpRequest<any, any>, limits: CodeRateLimits, partition?: AuthRateLimitKey): Promise<void>;
122
+ export declare function enforceCodeRateLimits(scope: AuthRateLimitScope, email: string | null, req: HttpRequest<any, any>, limits: CodeRateLimits, partition?: AuthRateLimitKey, onRefused?: (limit: "perEmail" | "perIp") => Promise<void> | void): Promise<void>;
112
123
  /**
113
124
  * Counts one guess at the code in row `rowId` and reports whether it is within
114
125
  * `maxAttempts`. The key names the row, so a newly issued code starts at zero.
@@ -1 +1 @@
1
- {"version":3,"file":"oneTimeCode.d.ts","sourceRoot":"","sources":["../../auth/oneTimeCode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAGnE;;;;;;;;;;;;;;;;;GAiBG;AAEH,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,MAAM,CAAC;AAE/C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/F;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,SAAS,EAAE,OAAO,GACjB,OAAO,CAeT;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQvD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED,qEAAqE;AACrE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;AAE3E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,IAAI,WAAW,CAazC;AAED,6DAA6D;AAC7D,wBAAgB,wBAAwB,SAEvC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,kDAAkD;AAClD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3B;;;;OAIG;IACH,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,2DAA2D;IAC3D,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,oBAAoB,KACvB,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,EACpC,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,EAC1B,MAAM,EAAE,cAAc,EACtB,SAAS,CAAC,EAAE,gBAAgB,iBAwB7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,gBAAgB,SAAK,GACpB,OAAO,CAAC,OAAO,CAAC,CAOlB"}
1
+ {"version":3,"file":"oneTimeCode.d.ts","sourceRoot":"","sources":["../../auth/oneTimeCode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAGnE;;;;;;;;;;;;;;;;;GAiBG;AAEH,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,MAAM,CAAC;AAE/C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/F;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,SAAS,EAAE,OAAO,GACjB,OAAO,CAeT;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQvD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED,qEAAqE;AACrE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;AAE3E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,IAAI,WAAW,CAazC;AAED,6DAA6D;AAC7D,wBAAgB,wBAAwB,SAEvC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAC1B,SAAS,GACT,QAAQ,GACR,MAAM,GACN,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,kDAAkD;AAClD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3B;;;;;;;OAOG;IACH,KAAK,EAAE,kBAAkB,CAAC;IAC1B,2DAA2D;IAC3D,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,oBAAoB,KACvB,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;AASpE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,EAC1B,MAAM,EAAE,cAAc,EACtB,SAAS,CAAC,EAAE,gBAAgB,EAC5B,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,iBA0BlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,gBAAgB,SAAK,GACpB,OAAO,CAAC,OAAO,CAAC,CAOlB"}
@@ -1,6 +1,6 @@
1
1
  import { ApiRouter } from "../http/ApiRouter";
2
2
  import { ViewRouter } from "../http/ViewRouter";
3
- import type { AuthConfig } from "./config";
3
+ import { type AuthConfig } from "./config";
4
4
  import { AuthController } from "./AuthController";
5
5
  /**
6
6
  * The views gemi's auth router renders from the application's `app/views`,
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../auth/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAmB,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAcD,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,UAAe,GAAG,mBAAmB,EAAE,CAiBnF;AAiBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,UAAe,GAAG,UAAU,UAAU,CA8BlF;AAED,qBAAa,aAAc,SAAQ,SAAS;IAC1C,WAAW,WAAqB;IAChC,MAAM;;;;;;;;;;;;;;;MAiBJ;CACH"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../auth/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAmB,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAgBD,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,UAAe,GAAG,mBAAmB,EAAE,CAiBnF;AAiBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,UAAe,GAAG,UAAU,UAAU,CA8BlF;AAED,qBAAa,aAAc,SAAQ,SAAS;IAC1C,WAAW,WAAqB;IAChC,MAAM;;;;;;;;;;;;;;;MAiBJ;CACH"}
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{Dc as B9,Qc as P9,Yb as E9,ac as K3,bc as b9,fc as F9,kc as e,wd as I9,xc as N9}from"./chunk-91vxf94n.js";import{Dd as i3,Fd as B3,Id as i9,Jd as l9,Kd as J$,Md as O$}from"./chunk-5sjteb6f.js";import{Pd as h9,Ud as m9,Wd as u9,be as x,ce as d9,de as c9,fe as p9,ge as L$}from"./chunk-tr8s1z7k.js";import{je as P}from"./chunk-y16jhwrv.js";import{Ag as f3,Be as R9,Cf as Z3,Dg as w3,Eg as $$,Fe as x$,Fg as G3,Gg as Z$,Hg as z$,Ie as U$,If as H3,Ig as v3,Jf as u3,Jg as a,Kf as k,Mg as q$,Nf as V$,Ng as L3,Of as Y$,Og as p3,Pf as K$,Rf as w,Se as F$,Te as l3,Tg as Q$,Ug as H$,Xe as J3,Ye as X3,_g as A$,cg as e3,ng as a3,of as d3,pg as n,tg as r3,ug as r9,vg as e9,xe as l,ye as X$,zg as g3}from"./chunk-px7yzba8.js";import{Ji as J9,Ni as P3,Oi as F3,Pi as z3,di as p,fi as m,ui as o3}from"./chunk-5nqwxjf1.js";import{Vi as s9}from"./chunk-p9avgpzd.js";import{ej as g}from"./chunk-n31hppcx.js";import{kj as c3}from"./chunk-rz6npg3r.js";import{nj as N$,oj as n3,rj as N3,sj as t3,vj as P$}from"./chunk-fzwaybhd.js";import{Jj as t9,Oj as o9}from"./chunk-4b5rpya9.js";import{ck as g9,ek as u}from"./chunk-dcwsya9e.js";import{fk as A}from"./chunk-h5s56wzw.js";import{lk as D$}from"./chunk-73svx8gr.js";import{$k as s3}from"./chunk-t797crcj.js";import{gl as U3,jl as y}from"./chunk-ry9jard2.js";import{sl as m3}from"./chunk-8z1z4zbq.js";import{El as a9}from"./chunk-r1sjx2q9.js";var T$="mcp",k$=/^[\x21\x23-\x5B\x5D-\x7E]+$/;class O extends e{status;constructor($,Z){super($);this.status=Z;this.name="McpToolError"}}class v extends Error{reason;constructor($,Z){super($);this.reason=Z;this.name="McpCallRefusedError"}}var $9=/^[A-Za-z0-9_-]{1,64}$/,M$=/:([A-Za-z_][A-Za-z0-9_]*)([?*+]?)/g,Z9=4000,M=1e5,R$=/^(text\/|application\/([\w.+-]*\+)?(json|xml))/i,L9=new WeakMap;function V6($){return L9.get($)}class i{router;dispatcher;static token="router.mcp";plans=new Map;scopeTools=new Map;files;featureOn;constructor($,Z,z={}){this.router=$;this.dispatcher=Z;this.files=w$(z.files),this.featureOn=z.featureOn??X3;for(let[G,W]of Object.entries($.routes??{}))this.plans.set(G,E$(W)?this.planNative(G,W):this.plan(G,W));this.resolveScopes()}list($,Z){if(D3($),$.kind==="local")return this.descriptors(Z);let z=[];for(let[G,W]of this.plans){if(!W.remote||!this.grants($.principal,G))continue;if(Y9(W.remote,Z))z.push(W.remote)}return z}async available($,Z){let z=[];for(let G of this.list($,Z))if(await this.isOn(G))z.push(G);return z}descriptors($){let Z=[];for(let{descriptor:z}of this.plans.values())if(Y9(z,$))Z.push(z);return Z}get maxFileBytes(){return this.files.maxBytes}scopes(){return[...this.scopeTools].map(([$,{description:Z}])=>({name:$,description:Z}))}scopesFor($){return[...this.scopeTools].filter(([,{tools:Z}])=>Z.has($)).map(([Z])=>Z)}async execute($,Z,z,G,W={}){D3($);let X=this.plans.get(Z);if(X&&!await this.isOn(X.descriptor)){if($.kind==="remote")throw new v(`There is no tool named "${Z}".`,"unknown-tool");throw new O(`There is no tool named "${Z}".`,404)}if($.kind==="remote"){if(!X?.remote||!this.grants($.principal,Z))throw new v(`There is no tool named "${Z}".`,"unknown-tool");if(X.descriptor.requiresApproval&&W.approved!==!0&&!W3(X))throw new v(`"${Z}" needs the user's approval, and this call does not have it.`,"approval-required");G=void 0}if(!X)throw Error(`McpRegistry: there is no tool named "${Z}".`);if(X.kind==="tool")return await this.executeNative(X,$,z,G,W);let Y=X,K=$.kind==="remote"?Y.remote:Y.descriptor,Q=K.inputSchema.safeParse(z);if(Q.ok===!1)throw new O(`Invalid arguments for "${Z}": ${Q.errors.join(", ")}`);let V=Q.value,H={caller:$,req:$.req,tool:K,input:V,ctx:G},U=await this.fillPath(Y,H),{path:I}=this.dispatcher.getRouteHandlerAndParams(new Request(`http://gemi.internal/api${U}`));if(I!==K.url)throw new O(`"${Z}" has nothing at ${U}.`,404);let J={};for(let _ of Y.jsonKeys)if(V[_]!==void 0)J[_]=V[_];let F,B="";if(Y.fileFields.length>0)F=await this.formData(Y,J,H);else if(K.method==="GET")B=l$(J);else if(Y.jsonKeys.length>0)F=J;let T=this.router.credentials?await this.bind(Y,"the credentials",()=>this.router.credentials(H)):void 0,j={...T?{credentials:T}:{},...W.signal?{signal:W.signal}:{},...W.progress?{progress:W.progress}:{},...$.kind==="remote"?{identity:{user:$.principal.user,grant:{via:$.principal.via,id:$.principal.id,scopes:$.principal.scopes,...$.principal.clientId?{clientId:$.principal.clientId}:{}}}}:{}},C;try{let _=B?`${U}?${B}`:U;C=Object.keys(j).length>0?await this.dispatcher.dispatchAs($.req,K.method,_,F,j):await this.dispatcher.dispatchAs($.req,K.method,_,F)}catch(_){throw console.error(`[gemi/mcp] Dispatching "${Z}" failed:`,_),new O(`"${Z}" failed on the server.`,500)}if(!Y.result&&!K.outputSchema)return await U9(Z,C);return await this.project(Y,H,C)}async isOn($){return $.feature===void 0||await this.featureOn($.feature)===!0}plan($,Z){if(!$9.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (${Z?.method} ${Z?.url})`;if(!(Z instanceof Object)||Z.__internal_brand!=="McpRoute")throw Error(`McpRouter: "${$}" is not a route or a tool. Declare it with this.fromApiRoute(...) or this.fromTool(...).`);let{method:G,url:W,meta:X}=Z;if(X.feature!==void 0&&(typeof X.feature!=="string"||X.feature===""))throw Error(`${z}: feature must be a feature key from app/features.`);if(W.startsWith("/__gemi__"))throw Error(`${z} is a framework route, not an app route.`);let Y=this.dispatcher.flatRoutes[W]?.[G];if(!Y)throw Error(`${z} names no route of this app. Expose a route by the path and verb it is mounted at.`);let K=[...W.matchAll(M$)].map(([,N,S])=>({name:N,modifier:S})),Q=X.params??{};for(let N of K)if(!(N.name in Q))throw Error(`${z}: the path param "${N.name}" must be bound or declared "input".`);for(let[N,S]of Object.entries(Q)){if(!K.some((h)=>h.name===N))throw Error(`${z}: "${N}" in params is not a param of the url.`);if(Q9(S))u$(z,`params.${N}`,S);else K9(z,`params.${N}`,S)}let V=[],H;if(X.input){if(H=X.input.toJSONSchema(),H.type!=="object"||!H.properties)throw Error(`${z}: input must be an s.object(...), the fields of the request body.`);V=Object.keys(H.properties)}let U=Object.entries(X.files??{}).map(([N,S])=>({name:N,binder:S}));for(let N of U)K9(z,`files.${N.name}`,N.binder);if(X.result!==void 0&&typeof X.result!=="function")throw Error(`${z}: result must be a function.`);if(X.output!==void 0&&typeof X.output?.safeParse!=="function")throw Error(`${z}: output must be a schema, built with s.`);if(X.title!==void 0&&(typeof X.title!=="string"||X.title===""))throw Error(`${z}: title must be a non-empty string.`);let I=V9(z,G,X.annotations);if(U.length>0&&G==="GET")throw Error(`${z}: a GET has no body to carry a file.`);let J={},F=(N,S)=>{if(N in J)throw Error(`${z}: "${N}" is the input key of two params or files, and the model can only send one.`);J[N]=S},B=new Map,T=new Map;for(let N of K){let S=Q[N.name];if(S==="input"){let h=p.string().describe(`The ":${N.name}" segment of the url.`);F(N.name,N.modifier==="?"||N.modifier==="*"?h.optional():h)}else if(Q9(S)){let h=S.as??N.name;F(h,S.input),T.set(N.name,{key:h,param:S})}else B.set(N.name,S)}let j={};for(let N of U)if(N.binder==="input")F(N.name,p.string().describe("The id of an attachment the user uploaded or a tool produced (gemi_att_\u2026), whose file is sent as this field.")),j[N.name]=this.remoteFileSchema();let C=[...Object.keys(J),...U.map((N)=>N.name)];for(let N of new Set(C))if(V.includes(N))throw Error(`${z}: "${N}" is both an input field and a param or file, and the model can only send one.`);let _=Object.freeze({kind:"route",name:$,description:X.description,method:G,url:W,inputSchema:H9(X.input,H,p.object(J)),...X.output?{outputSchema:X.output}:{},...X.title?{title:X.title}:{},annotations:I,tags:Object.freeze([...X.tags??[]]),requiresApproval:X.requiresApproval===!0,...X.feature!==void 0?{feature:X.feature}:{},...Y.source?{source:Y.source}:{}}),r=!U.every((N)=>N.binder==="input")?null:U.length===0?_:Object.freeze({..._,inputSchema:H9(X.input,H,p.object(p$(J,Object.keys(j))),j)});return{kind:"route",descriptor:_,remote:r,params:K,paramBinders:B,modelParams:T,fileFields:U,jsonKeys:V,...X.result?{result:X.result}:{}}}remoteFileSchema(){let{maxBytes:$,fetch:Z}=this.files,z={name:{type:"string",description:"The file's name, like report.pdf."},mimeType:{type:"string",description:"The file's media type, like application/pdf."},data:{type:"string",contentEncoding:"base64",description:`The file's bytes, base64-encoded (RFC 4648, standard alphabet). At most ${$} bytes decoded.`}};if(Z)z.url={type:"string",format:"uri",description:"An https URL the server downloads the file from, instead of data."};let G={type:"object",description:Z?"A file, sent as base64 in data or fetched from url: exactly one of the two.":"A file, sent as base64 in data.",properties:z,required:["name","mimeType"],additionalProperties:!1},W=Object.keys(z),X=(Y)=>{if(typeof Y!=="object"||Y===null||Array.isArray(Y))return{ok:!1,errors:["a file must be an object"]};let K=[],Q={};for(let V of Object.keys(Y))if(!W.includes(V))K.push(`a file has no field "${V}"`);for(let V of W){let H=Y[V];if(H===void 0||H===null){if(V==="name"||V==="mimeType")K.push(`a file needs "${V}"`);continue}if(typeof H!=="string")K.push(`a file's "${V}" must be a string`);else Q[V]=H}return K.length>0?{ok:!1,errors:K}:{ok:!0,value:Q}};return{toJSONSchema:()=>G,safeParse:X,parse(Y){let K=X(Y);if(K.ok===!1)throw Error(K.errors.join(", "));return K.value}}}planNative($,Z){if(!$9.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (a native tool)`,{tool:G,meta:W={}}=Z;if(!(G instanceof Object)||typeof G.name!=="string")throw Error(`${z} is not an AgentTool. Pass one built with AgentTool.create(...).`);if(G.answeredBy==="client"||typeof G.execute!=="function")throw Error(`${z}: "${G.name}" is answered by the client, and only a tool the server runs can be called through the registry.`);if(typeof G.inputSchema==="function")throw Error(`${z}: "${G.name}" resolves its input schema per run, and the registry lists one schema to every caller. Give it a fixed inputSchema.`);if(typeof G.inputSchema?.safeParse!=="function")throw Error(`${z}: its inputSchema must be a schema, built with s.`);if(typeof W!=="object"||W===null)throw Error(`${z}: the meta must be an object.`);if(W.description!==void 0&&(typeof W.description!=="string"||W.description.trim()===""))throw Error(`${z}: description must be a non-empty string.`);if(W.title!==void 0&&(typeof W.title!=="string"||W.title===""))throw Error(`${z}: title must be a non-empty string.`);if(W.tags!==void 0&&(!Array.isArray(W.tags)||W.tags.some((Q)=>typeof Q!=="string")))throw Error(`${z}: tags must be an array of strings.`);if(W.requiresApproval===!1&&G.requiresApproval)throw Error(`${z}: "${G.name}" requires approval, and requiresApproval: false would run it without asking. Leave it out, or register a tool that does not ask.`);let X=W.remote;if(X!==void 0){if(typeof X!=="object"||X===null||typeof X.context!=="function")throw Error(`${z}: remote must be { context(call) }, building the AgentContext a remote call runs with.`);if(X.progress!==void 0&&typeof X.progress!=="function")throw Error(`${z}: remote.progress must be a function.`)}let Y=W.description??G.description;if(typeof Y!=="string"||Y.trim()==="")throw Error(`${z} needs a description: the tool's own, or the meta's.`);let K=Object.freeze({kind:"tool",name:$,description:Y,inputSchema:G.inputSchema,...G.outputSchema?{outputSchema:G.outputSchema}:{},...W.title?{title:W.title}:{},annotations:V9(z,void 0,W.annotations),tags:Object.freeze([...W.tags??[]]),requiresApproval:G.requiresApproval||W.requiresApproval===!0});return{kind:"tool",descriptor:K,remote:X?K:null,tool:G,meta:W}}async approvalRequired($,Z,z,G={}){let W=this.plans.get(Z);if(!W)return!0;if(!W3(W))return W.descriptor.requiresApproval;let X=W;if($.kind!=="remote"||!X.meta.remote)return!0;let Y=X.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)return!0;let K={caller:$,req:$.req,tool:X.descriptor,input:Y.value},Q;try{Q=await this.bind(X,"the remote context",()=>X.meta.remote.context(K))}catch{return!0}if(typeof Q!=="object"||Q===null)return!0;let V=G.signal??new AbortController().signal;return X9(X,Y.value,W9(G9(X,Q,V)))}nativeApproval($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return W3(Z)??Z.descriptor.requiresApproval}nativeTool($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return Z.tool}startNative($,Z,z,G){let W=this.plans.get(Z);if(W?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${Z}".`);if($===void 0)return W.tool.execute(z,G);if(D3($),$.kind!=="local")throw Error("McpRegistry: startNative is for a local caller. A remote call goes through execute().");let X=W.descriptor.inputSchema.safeParse(z);if(X.ok===!1)throw new O(`Invalid arguments for "${Z}": ${X.errors.join(", ")}`);return this.runNative(W,{caller:$,req:$.req,tool:W.descriptor,input:X.value},G)}runNative($,Z,z){let G={...z};return L9.set(G,{...Z,ctx:G}),$.tool.execute(Z.input,G)}async executeNative($,Z,z,G,W){let{name:X}=$.descriptor,Y=$.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)throw new O(`Invalid arguments for "${X}": ${Y.errors.join(", ")}`);let K={caller:Z,req:Z.req,tool:$.descriptor,input:Y.value},Q=(_,_3)=>{if(!W.progress)return;let r;try{r=$.meta.remote?.progress?$.meta.remote.progress(_,_3):y$(_,_3)}catch(N){console.error(`[gemi/mcp] The progress mapping of "${X}" failed:`,N);return}if(r)W.progress(r)};if(Z.kind==="local"){if(!G)throw Error(`McpRegistry: "${X}" is a native tool, which runs with the tool context of an agent call, and none was passed to execute().`);return await z9(this.runNative($,{...K,ctx:G},G),Q)}let V=$.meta.remote,H=await this.bind($,"the remote context",()=>V.context(K));if(typeof H!=="object"||H===null)throw console.error(`[gemi/mcp] The remote context of "${X}" is not an object:`,H),new O(`"${X}" failed on the server.`,500);let U=$.tool.timeoutMs,I=[...W.signal?[W.signal]:[],...U!==void 0?[AbortSignal.timeout(U)]:[]],J=I.length===0?new AbortController().signal:I.length===1?I[0]:AbortSignal.any(I),F=G9($,H,J);if(!W.approved&&W3($)&&await X9($,K.input,W9(F)))throw new v(`"${X}" needs the user's approval, and this call does not have it.`,"approval-required");let B;try{B=await z9(this.runNative($,{...K,ctx:F},F),Q,J)}catch(_){if(J.aborted&&_===J.reason){if(W.signal?.aborted)throw new O(`"${X}" was cancelled.`,499);throw new O(`"${X}" did not finish within ${U} ms.`,504)}if(_ instanceof O)throw _;if(_ instanceof e||_ instanceof v)throw new O(_.message);throw console.error(`[gemi/mcp] "${X}" failed for a remote caller:`,_),new O(`"${X}" failed on the server.`,500)}let T=(_)=>{return console.error(`[gemi/mcp] "${X}" ${_}`),new O(`"${X}" failed on the server.`,500)};if(N9(B))throw T("answered a job handle, and a remote call has no background jobs.");let j=B;if($.descriptor.outputSchema){let _=$.descriptor.outputSchema.safeParse(j);if(_.ok===!1)throw T(`answered what its output schema refuses: ${_.errors.join(", ")}`);j=_.value}if(j===void 0)return null;if(typeof j==="string")return j.length>M?`${j.slice(0,M)}\u2026 [cut at ${M} of ${j.length} characters]`:j;let C=JSON.stringify(j);if(C!==void 0&&C.length>M)return`${C.slice(0,M)}\u2026 [cut at ${M} of ${C.length} characters]`;return j}async fillPath($,Z){let{input:z,req:G}=Z,W=$.descriptor.url;for(let X of $.params){let Y=$.paramBinders.get(X.name),K=$.modelParams.get(X.name),Q;if(Y||K){if(Q=K?await this.bind($,`the param "${X.name}"`,()=>K.param.bind(z[K.key],G,Z),{refusals:!0}):await this.bind($,`the param "${X.name}"`,()=>Y(G,Z)),Q===void 0||Q===null||Q==="")throw console.error(`[gemi/mcp] The ${K?"resolver":"binder"} for "${X.name}" of "${$.descriptor.name}" returned ${JSON.stringify(Q)}.`),new O(`"${$.descriptor.name}" failed on the server.`,500)}else Q=z[X.name];let V=`:${X.name}${X.modifier}`;if(Q===void 0||Q===null||Q===""){if(X.modifier!=="?"&&X.modifier!=="*")throw new O(`"${X.name}" of "${$.descriptor.name}" must not be empty.`);W=W.replace(`/${V}`,"");continue}W=W.replace(V,i$($.descriptor.name,X,String(Q)))}return W}async formData($,Z,z){let{input:G,ctx:W}=z,X=$.descriptor.name;if(z.caller.kind==="remote"){let K=new FormData;for(let[Q,V]of Object.entries(Z))O3(K,Q,V);for(let Q of $.fileFields)K.append(Q.name,await this.remoteFile(X,Q.name,G[Q.name]));return K}if(!W)throw Error(`McpRegistry: "${X}" sends a file, which is resolved through the tool context's attachments, and none was passed to execute().`);let Y=new FormData;for(let[K,Q]of Object.entries(Z))O3(Y,K,Q);for(let K of $.fileFields){let Q=K.binder==="input"?G[K.name]:await this.bind($,`the file "${K.name}"`,()=>K.binder(W,z));if(typeof Q!=="string"||Q==="")throw new O(`"${X}" needs a file for "${K.name}", and this turn has none. Ask the user to attach one.`);Y.append(K.name,await W.attachments.file(Q))}return Y}async remoteFile($,Z,z){let G=(H)=>new O(`"${Z}" of "${$}" ${H}`,400),W=z,{maxBytes:X,fetch:Y}=this.files;if(!v$(W.name))throw G("needs a name of 1 to 255 characters, without control characters or slashes.");if(!g$.test(W.mimeType))throw G(`has a mimeType that is not a media type: "${W.mimeType.slice(0,100)}".`);let K=typeof W.data==="string",Q=typeof W.url==="string";if(K===Q)throw G(Y?"needs exactly one of data or url.":"needs its bytes, base64, in data.");if(K){let H=W.data.replace(/\s+/g,"");if(Math.floor(H.length*3/4)-m$(H)>X)throw G(`is larger than the ${X} bytes a file may be.`);if(H.length%4!==0||!h$.test(H))throw G("has data that is not base64 (RFC 4648, standard alphabet, padded).");return new File([Buffer.from(H,"base64")],W.name,{type:W.mimeType})}if(!Y)throw G("cannot be fetched from a URL here. Send its bytes, base64, in data.");let V;try{V=new URL(W.url)}catch{throw G("has a url that is not a URL.")}if(V.protocol!=="https:")throw G("can only be fetched from an https URL.");try{let H=await J9(V.href,{...Y,maxSize:Math.min(Y.maxSize??X,X),redirect:"follow"});if(!H.ok)throw G(`could not be fetched: ${V.host} answered ${H.status}.`);let U=await H.arrayBuffer();return new File([U],W.name,{type:W.mimeType})}catch(H){if(H instanceof O)throw H;throw G(`could not be fetched from ${V.host}: ${H instanceof Error?H.message:"failed"}.`)}}grants($,Z){for(let z of $.scopes??[])if(this.scopeTools.get(z)?.tools.has(Z))return!0;return!1}resolveScopes(){let $=this.router.scopes;if($===void 0){this.scopeTools.set(T$,{description:"Use this app's tools as you",tools:new Set(this.plans.keys())});return}if(typeof $!=="object"||$===null)throw Error("McpRouter: scopes must be an object of scope names.");let Z=new Set([...this.plans.values()].flatMap(({descriptor:z})=>z.tags));for(let[z,G]of Object.entries($)){let W=`McpRouter: scope "${z}"`;if(!k$.test(z))throw Error(`${W} is not a valid OAuth scope: printable ASCII, no spaces or quotes.`);if(typeof G?.description!=="string"||G.description==="")throw Error(`${W} needs a description: it is what a consent screen shows.`);let X=new Set;for(let Y of G.tags??[]){if(!Z.has(Y))throw Error(`${W} names the tag "${Y}", which no tool has.`);for(let[K,{descriptor:Q}]of this.plans)if(Q.tags.includes(Y))X.add(K)}for(let Y of G.names??[]){if(!this.plans.has(Y))throw Error(`${W} names "${Y}", which is no tool.`);X.add(Y)}if(X.size===0)throw Error(`${W} reaches no tool. Give it tags or names.`);this.scopeTools.set(z,{description:G.description,tools:X})}}async project($,Z,z){let{name:G,outputSchema:W}=$.descriptor;if(z.status<200||z.status>=300)return await U9(G,z);let X=(U,I)=>{if(I===void 0)console.error(`[gemi/mcp] "${G}" ${U}`);else console.error(`[gemi/mcp] "${G}" ${U}`,I);return new O(`"${G}" failed on the server.`,500)},Y=z.headers.get("Content-Type"),K=await z.text(),Q=null;if(K!=="")try{Q=JSON.parse(K)}catch{throw X(`answered ${Y??"a body with no content-type"} that is not JSON, and its result or output needs JSON.`)}let V=Q;if($.result)try{V=await $.result(Q,Z)}catch(U){throw X("failed in its result projection:",U)}if(W){let U=W.safeParse(V);if(U.ok===!1)throw X(`answered what its output schema refuses: ${U.errors.join(", ")}`);V=U.value}if(V===void 0)return null;let H=JSON.stringify(V);if(H!==void 0&&H.length>M)return`${H.slice(0,M)}\u2026 [cut at ${M} of ${H.length} characters]`;return V}async bind($,Z,z,G={}){try{return await z()}catch(W){if(G.refusals&&W instanceof e)throw W;throw console.error(`[gemi/mcp] Binding ${Z} of "${$.descriptor.name}" failed:`,W),new O(`"${$.descriptor.name}" failed on the server.`,500)}}}function E$($){return $ instanceof Object&&$.__internal_brand==="McpTool"}function b$($){return typeof $==="object"&&$!==null&&typeof $.next==="function"&&Symbol.asyncIterator in $}async function z9($,Z,z){let G;if(z)G=new Promise((X,Y)=>{if(z.aborted)Y(z.reason);else z.addEventListener("abort",()=>Y(z.reason),{once:!0})}),G.catch(()=>{});let W=(X)=>G?Promise.race([X,G]):X;if(!b$($))return await W(Promise.resolve($));try{let X=0,Y=await W($.next());while(!Y.done)Z(Y.value,++X),Y=await W($.next());return Y.value}catch(X){throw $.return(void 0).catch(()=>{}),X}}function y$($,Z){if(typeof $==="string")return{progress:Z,message:$};if(typeof $==="object"&&$!==null){let{progress:z,total:G,message:W}=$;if(typeof z==="number"&&Number.isFinite(z))return{progress:z,...typeof G==="number"?{total:G}:{},...typeof W==="string"?{message:W}:{}};if(typeof W==="string")return{progress:Z,message:W}}return{progress:Z}}function G9($,Z,z){let G=$.descriptor.name,W=`mcp_${crypto.randomUUID()}`,X=`mcp_call_${crypto.randomUUID()}`,Y=(Q)=>async()=>{throw new e(`"${G}" was called by a remote MCP client, which has no ${Q}.`,{retryable:!1})},K={put:Y("attachment store"),get:Y("attachment store"),read:Y("attachment store"),file:Y("attachment store")};return{context:Z,body:{},runId:W,toolCallId:X,signal:z,step:1,depth:0,resumed:!1,attachments:K,turn:Object.freeze({attachments:Object.freeze([])}),runAgent:Y("agent run to nest a sub-agent in"),generateImage:Y("attachment store to put an image in"),editImage:Y("attachment store to put an image in"),generate:(Q)=>I9({...Q,signal:Q.signal?AbortSignal.any([z,Q.signal]):z},{origin:{mcp:G,runId:W,toolCallId:X}}),jobs:B9({jobs:void 0,threadId:void 0,runId:W,toolCallId:X,toolName:G,depth:0,async:$.tool.async,attachments:null}),memory:P9(),meter:F9().meter}}function W3($){if($.kind!=="tool"||$.meta.requiresApproval===!0)return;return $.tool.approvalPredicate}function W9($){return{context:$.context,body:$.body,runId:$.runId,threadId:$.threadId,toolCallId:$.toolCallId,step:$.step,depth:$.depth,signal:$.signal}}async function X9($,Z,z){try{return await $.tool.approvalPredicate(Z,z)!==!1}catch(G){return console.error(`[gemi/mcp] The requiresApproval of "${$.descriptor.name}" threw, so the call asks the user:`,G),!0}}function D3($){if($?.kind==="local"&&$.req)return;if($?.kind==="remote"&&$.req&&$.principal?.user&&typeof $.principal.id==="string"&&Array.isArray($.principal.scopes))return;throw Error('McpRegistry: a caller is { kind: "local", req } or { kind: "remote", req, principal }, with the principal a caller resolver verified.')}function Y9($,Z){if(Z?.names&&!Z.names.includes($.name))return!1;if(Z?.tags&&!$.tags.some((z)=>Z.tags.includes(z)))return!1;return!0}var f$=10485760;function w$($){let Z=$?.maxBytes??f$;if(!Number.isSafeInteger(Z)||Z<=0)throw Error("McpRegistry: files.maxBytes must be a positive whole number of bytes.");let z=$?.fetchUrls===!0?{}:typeof $?.fetchUrls==="object"&&$.fetchUrls!==null?$.fetchUrls:null;return{maxBytes:Z,fetch:z}}function v$($){if($.length===0||$.length>255)return!1;for(let Z of $){let z=Z.codePointAt(0);if(z<32||z===127||Z==="/"||Z==="\\")return!1}return!0}var g$=/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}(\s*;.{0,200})?$/,h$=/^[A-Za-z0-9+/]*={0,2}$/;function m$($){return $.endsWith("==")?2:$.endsWith("=")?1:0}function K9($,Z,z){if(z!=="input"&&typeof z!=="function")throw Error(`${$}: ${Z} must be a function or "input".`)}function Q9($){return $ instanceof Object&&$.__internal_brand==="McpModelParam"}function u$($,Z,z){if(z.as!==void 0&&(typeof z.as!=="string"||z.as===""))throw Error(`${$}: ${Z}.as must be a non-empty string.`);let G=z.input;if(typeof G?.safeParse!=="function"||typeof G.toJSONSchema!=="function")throw Error(`${$}: ${Z}.input must be a schema, built with s.`);if(typeof z.bind!=="function")throw Error(`${$}: ${Z}.bind must be a function.`)}var d$=new Set(["readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);function c$($){switch($){case"GET":return{readOnlyHint:!0};case"DELETE":return{destructiveHint:!0};case"PUT":return{idempotentHint:!0};default:return{}}}function V9($,Z,z){if(z!==void 0&&(typeof z!=="object"||z===null))throw Error(`${$}: annotations must be an object of hints.`);let G=Z?c$(Z):{};for(let[W,X]of Object.entries(z??{})){if(!d$.has(W))throw Error(`${$}: "${W}" is not a tool annotation. Use readOnlyHint, destructiveHint, idempotentHint or openWorldHint.`);if(X===void 0)continue;if(typeof X!=="boolean")throw Error(`${$}: annotations.${W} must be true or false.`);G[W]=X}if(G.readOnlyHint===!0&&(G.destructiveHint||G.idempotentHint))throw Error(`${$} is read-only${z?.readOnlyHint?"":` (a ${Z})`} and also ${G.destructiveHint?"destructive":"idempotent"}, which only a tool that is not read-only can be. Set readOnlyHint: false if it changes something.`);return Object.freeze(G)}function H9($,Z,z,G={}){let W=z.toJSONSchema(),X=Object.fromEntries(Object.entries(G).map(([Q,V])=>[Q,V.toJSONSchema()])),Y={...Z??{},type:"object",properties:{...Z?.properties??{},...W.properties,...X},required:[...Z?.required??[],...W.required??[],...Object.keys(G)],additionalProperties:!1},K=(Q)=>{if(typeof Q!=="object"||Q===null||Array.isArray(Q))return{ok:!1,errors:["expected an object"]};let V=[],H={};if($){let I=$.safeParse(Q);if(I.ok===!1)V.push(...I.errors);else H={...I.value}}let U=z.safeParse(Q);if(U.ok===!1)V.push(...U.errors);else H={...H,...U.value};for(let[I,J]of Object.entries(G)){let F=Q[I];if(F===void 0){V.push(`"${I}" is required`);continue}let B=J.safeParse(F);if(B.ok===!1)V.push(...B.errors.map((T)=>`${I}: ${T}`));else H[I]=B.value}return V.length>0?{ok:!1,errors:V}:{ok:!0,value:H}};return{toJSONSchema:()=>Y,safeParse:K,parse(Q){let V=K(Q);if(V.ok===!1)throw Error(V.errors.join(", "));return V.value}}}function p$($,Z){return Object.fromEntries(Object.entries($).filter(([z])=>!Z.includes(z)))}function i$($,Z,z){let G=Z.modifier==="*"||Z.modifier==="+"?z.split("/"):[z];if(G.some((W)=>W==="."||W===".."))throw new O(`"${z}" is not a valid value for "${Z.name}" of "${$}".`);return G.map(encodeURIComponent).join("/")}function O3($,Z,z){if(z===void 0||z===null)return;if(Array.isArray(z)){for(let G of z)O3($,Z,G);return}$.append(Z,typeof z==="object"?JSON.stringify(z):String(z))}function l$($){let Z=new URLSearchParams,z=(G,W)=>{if(W===void 0||W===null)return;if(Array.isArray(W)){for(let X of W)z(G,X);return}Z.append(G,typeof W==="object"?JSON.stringify(W):String(W))};for(let[G,W]of Object.entries($))z(G,W);return Z.toString()}async function U9($,Z){if(Z.status>=200&&Z.status<300){let G=Z.headers.get("Content-Type");if(G&&!R$.test(G)){let X=(await Z.arrayBuffer()).byteLength;return`"${$}" answered with ${X} bytes of ${G}, which is not shown.`}let W=await Z.text();if(W==="")return null;if(W.length>M)return`${W.slice(0,M)}\u2026 [cut at ${M} of ${W.length} characters]`;try{return JSON.parse(W)}catch{return W}}let z=await Z.text();if(Z.status>=400&&Z.status<500){let G=z.length>Z9?`${z.slice(0,Z9)}\u2026`:z;throw new O(`"${$}" was refused with ${Z.status}${G?`: ${G}`:"."}`,Z.status)}if(Z.status<500)console.error(`[gemi/mcp] "${$}" answered ${Z.status}${Z.headers.get("Location")?` to ${Z.headers.get("Location")}`:""}, which a tool call cannot follow.`);throw new O(`"${$}" failed on the server.`,Z.status)}import{createHash as n$,randomBytes as s$,timingSafeEqual as t$}from"crypto";function j3($){let Z=$.headers.get("authorization");if(!Z)return null;let z=/^Bearer[ ]+([\x21-\x7e]+)$/i.exec(Z.trim());return z?z[1]:null}class o${options;name="api-key";constructor($){this.options=$;if(typeof $?.prefix!=="string"||!/^[A-Za-z0-9_-]{3,32}$/.test($.prefix))throw Error('McpApiKeyResolver: prefix is required: 3 to 32 letters, digits, _ or -, like "myapp_mcp_".');if(typeof $.verify!=="function")throw Error("McpApiKeyResolver: verify must be a function that looks a key up.")}static generate($){return`${$}${s$(32).toString("base64url")}`}static hash($){return n$("sha256").update($).digest("hex")}static hashesMatch($,Z){let z=Buffer.from($),G=Buffer.from(Z);return z.length===G.length&&t$(z,G)}async resolve($){let Z=j3($);if(!Z?.startsWith(this.options.prefix))return null;let z=await this.options.verify(Z,$);if(!z)return{ok:!1,error:"invalid_token",description:"The API key is not valid."};if(!z.user||typeof z.id!=="string"||z.id===""||!Array.isArray(z.scopes))throw Error("McpApiKeyResolver: verify must answer { user, id, scopes } for a key it knows, or null.");return{ok:!0,principal:{user:z.user,via:this.name,id:z.id,scopes:[...z.scopes]}}}}import{createHash as y9,randomBytes as j9}from"crypto";async function A3($,Z){let z=a$();if(!z)return null;let G=await z.consume($,Z);return G.allowed?null:Math.max(1,Math.ceil(G.retryAfter/1000))}function a$(){try{let $=y();return $.bound(l)?$.make(l):null}catch{return null}}var x3=["2026-07-28"],Y3=["2025-11-25","2025-06-18","2025-03-26"],C3=[...x3,...Y3],S3="io.modelcontextprotocol/protocolVersion",q3="io.modelcontextprotocol/clientCapabilities";var T3="io.modelcontextprotocol/serverInfo",D={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};class L extends Error{code;data;status;constructor($,Z,z,G=200){super(Z);this.code=$;this.data=z;this.status=G;this.name="JsonRpcError"}}function R($,Z){return{jsonrpc:"2.0",id:$,error:{code:Z.code,message:Z.message,...Z.data!==void 0?{data:Z.data}:{}}}}function _9($){if(Array.isArray($))throw new L(D.InvalidRequest,"Batched requests are not supported.",void 0,400);if(typeof $!=="object"||$===null||$.jsonrpc!=="2.0")throw new L(D.InvalidRequest,"Not a JSON-RPC 2.0 message.",void 0,400);let Z=$,z=Z.id,G=typeof z==="string"||typeof z==="number"&&Number.isFinite(z);if(typeof Z.method==="string"){if(Z.params!==void 0&&(typeof Z.params!=="object"||Z.params===null||Array.isArray(Z.params)))throw new L(D.InvalidRequest,"params must be an object.",void 0,400);if(z===void 0)return{kind:"notification",message:Z};if(!G)throw new L(D.InvalidRequest,"id must be a string or a number.",void 0,400);return{kind:"request",message:Z}}if(G&&(("result"in Z)||("error"in Z)))return{kind:"response",message:Z};throw new L(D.InvalidRequest,"Not a JSON-RPC request, notification or response.",void 0,400)}function k3($,Z){let z=$.outputSchema?.toJSONSchema(),G={...$.annotations,...$.title&&!Z?{title:$.title}:{}};return{name:$.name,...$.title?{title:$.title}:{},description:$.description,inputSchema:$.inputSchema.toJSONSchema(),...z&&(Z||z.type==="object")?{outputSchema:z}:{},...Object.keys(G).length>0?{annotations:G}:{}}}function q($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function D9($){let Z=/^=\?base64\?([A-Za-z0-9+/]*={0,2})\?=$/.exec($);if(!Z)return $;try{let z=Buffer.from(Z[1],"base64");return new TextDecoder("utf-8",{fatal:!0}).decode(z)}catch{return null}}import{createHmac as r$,timingSafeEqual as e$}from"crypto";function M3($,Z,z){let G=Buffer.from(JSON.stringify(z)).toString("base64url");return`${Z}.${G}.${O9($,Z,G).toString("base64url")}`}function R3($,Z,z,G=Date.now()){if(typeof z!=="string"||z.length>8192)return null;let W=z.split(".");if(W.length!==3||W[0]!==Z)return null;let[,X,Y]=W,K=Buffer.from(Y,"base64url"),Q=O9($,Z,X);if(K.length!==Q.length||!e$(K,Q))return null;let V;try{V=JSON.parse(Buffer.from(X,"base64url").toString("utf8"))}catch{return null}if(typeof V!=="object"||V===null)return null;if(typeof V.exp!=="number"||V.exp<=G)return null;return V}function O9($,Z,z){return r$("sha256",K3($)).update(`${Z}.${z}`).digest()}var E3="gemi.mcp.request-state.v1",A9="gemi.mcp.session.v1",$2=86400000,x9=600000,C9="gemi_approval",b3=2000,Z2={limit:600,window:60},z2={limit:30,window:60};class $3{registry;static token="router.mcp.http";endpoint;resolvers;context;allowedOrigins;rateLimit;maxBodyBytes;serverInfo;instructions;nonces;approvalTimeoutMs;onCall;feature;featureOn;pending=new Map;inflight=new Map;constructor($,Z,z={}){this.registry=$;if(typeof Z.url!=="string")throw Error(`route.mcp.remote.url is required: the endpoint's canonical URL, like "https://example.com/mcp".`);this.endpoint=X2(Z.url);let G=Z.resolvers??[];if(!Array.isArray(G)||G.length===0)throw Error("route.mcp.remote is enabled without a caller resolver. Configure route.mcp.remote.resolvers \u2014 an McpOAuthServer, an McpApiKeyResolver, or your own \u2014 or leave the endpoint off. Without one every request would be refused, or answered as nobody.");for(let W of G)if(typeof W?.resolve!=="function"||typeof W.name!=="string"||W.name==="")throw Error("route.mcp.remote.resolvers: each resolver needs a name and a resolve().");if(this.resolvers=G,K3(E3),this.context={resource:this.resource,registry:$},this.allowedOrigins=new Set((Z.allowedOrigins??[]).map((W)=>{if(new URL(W).origin!==W)throw Error(`route.mcp.remote.allowedOrigins: "${W}" is not an origin (scheme://host[:port]).`);return W})),this.allowedOrigins.add(this.endpoint.origin),this.rateLimit=Z.rateLimit===!1?!1:Z.rateLimit??Z2,this.maxBodyBytes=Z.maxBodyBytes??Math.ceil($.maxFileBytes*1.4)+1048576,this.serverInfo={name:Z.server?.name??"gemi",version:Z.server?.version??"1.0.0"},this.instructions=Z.server?.instructions,this.nonces=Z.nonces??new E9,this.approvalTimeoutMs=Z.approvalTimeoutMs??x9,Z.onCall!==void 0&&typeof Z.onCall!=="function")throw Error("route.mcp.remote.onCall must be a function.");if(this.onCall=Z.onCall,Z.feature!==void 0){if(typeof Z.feature!=="string"||Z.feature==="")throw Error("route.mcp.remote.feature must be a feature key from app/features.");this.feature=Z.feature}this.featureOn=z.featureOn??X3;for(let W of G)W.boot?.(this.context)}get resource(){return this.endpoint.href.replace(/\/$/,"")}async handle($){let Z=new URL($.url);if(Z.host!==this.endpoint.host)return null;if(this.feature!==void 0){if(!this.ownsPath(Z.pathname))return null;if(await this.featureOn(this.feature)!==!0)return null}for(let W of this.resolvers){let X=await W.handle?.($,this.context);if(X)return X}if(Z.pathname!==this.endpoint.pathname)return null;let z=$.headers.get("origin");if(z!==null&&!this.allowedOrigins.has(z))return f(R(null,new L(D.InvalidRequest,"Origin not allowed.")),403);let G=z?W2(z):{};if($.method==="OPTIONS")return new Response(null,{status:204,headers:{...G,"Access-Control-Allow-Methods":"POST","Access-Control-Allow-Headers":"Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name, Last-Event-ID","Access-Control-Max-Age":"600"}});if($.method!=="POST")return S9(new Response(null,{status:405,headers:{Allow:"POST, OPTIONS"}}),G);return S9(await this.post($),G)}ownsPath($){let Z=this.endpoint.pathname.replace(/\/$/,"");return $===this.endpoint.pathname||$===Z||$.startsWith(`${Z}/`)||$.startsWith("/.well-known/")}async post($){let Z=null;for(let Y of this.resolvers){let K=await Y.resolve($,this.context);if(K===null)continue;if(K.ok===!1)return await this.failedAttempt($)??this.unauthorized(K.description);Z={...K.principal,via:Y.name};break}if(!Z)return(j3($)!==null?await this.failedAttempt($):null)??this.unauthorized();let z=await this.spend(Z);if(z)return z;let G=$.headers.get("content-type")??"";if(!/^application\/json\s*(;|$)/i.test(G))return new Response("Content-Type must be application/json.",{status:415});let W;try{W=JSON.parse(await G2($,this.maxBodyBytes))}catch(Y){if(Y instanceof V3)return f(R(null,new L(D.InvalidRequest,`The request is larger than ${this.maxBodyBytes} bytes.`)),413);return f(R(null,new L(D.ParseError,"Parse error.")),400)}let X=new m($,{},"api",this.endpoint.pathname);return await g.run(X,async()=>{try{return await this.dispatch($,X,Z,W)}catch(Y){if(Y instanceof L){let K=q(W)&&(typeof W.id==="string"||typeof W.id==="number")?W.id:null;return f(R(K,Y),Y.status)}return console.error("[gemi/mcp] The MCP endpoint failed:",Y),f(R(null,new L(D.InternalError,"Internal error.")),500)}},{user:Z.user})}async dispatch($,Z,z,G){let W=_9(G),X={kind:"remote",req:Z,principal:z};if(W.kind==="response"){let F=this.session($,z),B=this.pending.get(String(W.message.id));if(B&&B.session===F.id)this.pending.delete(String(W.message.id)),B.resolve(W.message);return new Response(null,{status:202})}let{message:Y}=W,K=Y.params??{},Q=q(K._meta)?K._meta:{};if(typeof Q[S3]==="string"){if(this.checkModernHeaders($,Y,Q[S3]),W.kind==="notification")return new Response(null,{status:202});return await this.respond(Y,async(F,B)=>this.modern({principal:z,caller:X,message:Y,params:K,era:{modern:!0},stream:F,signal:B}),T9(K),$.signal)}if(Y.method==="initialize"){if(W.kind!=="request")throw new L(D.InvalidRequest,"initialize is a request.",void 0,400);return this.initialize(W.message,K,z)}let V=this.session($,z),H=$.headers.get("mcp-protocol-version");if(H!==null&&H!==V.state.v)throw new L(D.InvalidRequest,`MCP-Protocol-Version ${H} is not the session's ${V.state.v}.`,void 0,400);if(W.kind==="notification"){if(Y.method==="notifications/cancelled"){let F=K.requestId;this.inflight.get(`${V.id}:${String(F)}`)?.abort()}return new Response(null,{status:202})}let U=`${V.id}:${String(Y.id)}`,I=new AbortController;this.inflight.set(U,I);let J=AbortSignal.any([I.signal,$.signal]);try{return await this.respond(Y,async(F,B)=>this.legacy({principal:z,caller:X,message:Y,params:K,era:{modern:!1,session:V.state,sessionId:V.id},stream:F,signal:B}),T9(K)||K2(this.registry,Y,V.state),J,()=>this.inflight.delete(U))}catch(F){throw this.inflight.delete(U),F}}async modern($){switch($.message.method){case"server/discover":return this.complete({supportedVersions:C3,capabilities:{tools:{}},...this.instructions?{instructions:this.instructions}:{},ttlMs:60000,cacheScope:"private"});case"tools/list":return this.complete({tools:(await this.registry.available($.caller)).map((Z)=>k3(Z,!0)),ttlMs:60000,cacheScope:"private"});case"tools/call":return await this.callTool($);default:throw new L(D.MethodNotFound,`Method not found: ${$.message.method}`,void 0,404)}}async legacy($){switch($.message.method){case"ping":return{};case"tools/list":return{tools:(await this.registry.available($.caller)).map((Z)=>k3(Z,!1))};case"tools/call":return await this.callTool($);default:throw new L(D.MethodNotFound,`Method not found: ${$.message.method}`)}}complete($){return{resultType:"complete",...$,_meta:{[T3]:this.serverInfo}}}initialize($,Z,z){let G=Z.protocolVersion,W=Y3.includes(G)?G:Y3[0],X=q(Z.capabilities)?Z.capabilities:{},Y={v:W,e:q9(X.elicitation),p:Q3(z),exp:Date.now()+$2},K=M3(A9,"gms1",Y);return f({jsonrpc:"2.0",id:$.id,result:{protocolVersion:W,capabilities:{tools:{listChanged:!1}},serverInfo:this.serverInfo,...this.instructions?{instructions:this.instructions}:{}}},200,{"Mcp-Session-Id":K})}session($,Z){let z=$.headers.get("mcp-session-id");if(!z)throw new L(D.InvalidRequest,"Missing Mcp-Session-Id. Send initialize first, or a request carrying io.modelcontextprotocol/protocolVersion in _meta.",void 0,400);let G=R3(A9,"gms1",z);if(!G||G.p!==Q3(Z))throw new L(D.InvalidRequest,"Session not found.",void 0,404);return{id:z,state:G}}checkModernHeaders($,Z,z){if(!x3.includes(z))throw new L(D.UnsupportedProtocolVersion,"Unsupported protocol version",{supported:C3,requested:z},400);let G=(Y)=>new L(D.HeaderMismatch,`Header mismatch: ${Y}`,void 0,400);if($.headers.get("mcp-protocol-version")!==z)throw G("MCP-Protocol-Version does not match the protocol version in _meta.");if($.headers.get("mcp-method")!==Z.method)throw G("Mcp-Method does not match the method.");let W=Z.params??{},X=Z.method==="tools/call"||Z.method==="prompts/get"?W.name:Z.method==="resources/read"?W.uri:void 0;if(X!==void 0){let Y=$.headers.get("mcp-name");if(Y===null||D9(Y)!==X)throw G("Mcp-Name does not match the request's name.")}}async callTool($){let Z=$.params.name;if(typeof Z!=="string")throw new L(D.InvalidParams,"tools/call needs a tool name.");let z=$.params.arguments??{};if(!this.onCall)return await this.runTool($,Z,z,{approved:!1});let G=performance.now(),W={approved:!1};try{let X=await this.runTool($,Z,z,W);if(!W.pending)await this.report($,Z,z,W,G);return X}catch(X){if(!W.outcome){if(W.outcome="error",W.message=X instanceof L?X.message:"Internal error.",!(X instanceof L))W.error=X}throw await this.report($,Z,z,W,G),X}}async report($,Z,z,G,W){let{principal:X}=$;try{await this.onCall({user:X.user,via:X.via,credentialId:X.id,clientId:X.clientId??null,scopes:X.scopes,tool:Z,arguments:z,outcome:G.outcome??"ok",...G.reason!==void 0?{reason:G.reason}:{},...G.message!==void 0?{message:G.message}:{},...G.status!==void 0?{status:G.status}:{},...G.error!==void 0?{error:G.error}:{},approved:G.approved,durationMs:Math.round((performance.now()-W)*1000)/1000,req:$.caller.req})}catch(Y){console.error(`[gemi/mcp] route.mcp.remote.onCall failed for "${Z}":`,Y)}}async runTool($,Z,z,G){let{caller:W,principal:X}=$,Y=(J,F)=>{G.outcome="denied",G.reason=J,G.message=F},K=(J,F,B)=>{if(G.outcome="error",G.message=J,F!==void 0)G.status=F;if(B!==void 0)G.error=B},Q=(await this.registry.available(W,{names:[Z]}))[0];if(!Q)throw Y("unknown-tool",`Unknown tool: ${Z}`),new L(D.InvalidParams,`Unknown tool: ${Z}`);if(Q.requiresApproval){let J=Q.inputSchema.safeParse(z);if(J.ok===!1){let B=`Invalid arguments for "${Z}": ${J.errors.join(", ")}`;return K(B),this.toolResult($,{content:[{type:"text",text:B}],isError:!0})}if($.era.modern&&q($.params.inputResponses)&&$.params.requestState!==void 0||await this.registry.approvalRequired(W,Z,z,{signal:$.signal})){let B=await this.approval($,Q,z,Y,G);if(B.kind==="answer")return B.result;G.approved=!0}}let V=Q2($),H;try{H=await this.registry.execute(W,Z,z,void 0,{approved:G.approved,signal:$.signal,...V?{progress:V}:{}})}catch(J){if(J instanceof O){if(J.status===401||J.status===403)Y("forbidden",J.message),G.status=J.status;else K(J.message,J.status);return this.toolResult($,{content:[{type:"text",text:J.message}],isError:!0})}if(J instanceof v){let B=J.reason==="unknown-tool"?`Unknown tool: ${Z}`:J.message;throw Y(J.reason,B),new L(D.InvalidParams,B)}console.error(`[gemi/mcp] "${Z}" failed for ${X.via}:${X.id}:`,J);let F=`"${Z}" failed on the server.`;return K(F,void 0,J),this.toolResult($,{content:[{type:"text",text:F}],isError:!0})}let U=typeof H==="string"?H:JSON.stringify(H??null),I=Q.outputSchema&&($.era.modern||q(H))?{structuredContent:H}:{};return G.outcome="ok",this.toolResult($,{content:[{type:"text",text:U}],...I,isError:!1})}toolResult($,Z){return $.era.modern?this.complete(Z):Z}async approval($,Z,z,G,W){let X=V2(Z,z),Y=(I,J="approval-declined")=>{return G(J,I),{kind:"answer",result:this.toolResult($,{content:[{type:"text",text:I}],isError:!0})}},K=(I,J)=>{return G(I,J.message),J};if($.era.modern){let I=q($.params._meta)?$.params._meta:{},J=q(I[q3])?I[q3]:{},F=q($.params.inputResponses)?$.params.inputResponses:null,B=$.params.requestState,T=Y2(z);if(F&&B!==void 0){let C=R3(E3,"grs1",B);if(!C||C.p!==Q3($.principal)||C.t!==Z.name||C.a!==T)throw K("approval-invalid",new L(D.InvalidParams,"requestState is not valid for this call."));if(!await this.spendNonce(C.n,C.exp))throw K("approval-replayed",new L(D.InvalidParams,"requestState has already been used."));return k9(F[C9])?{kind:"approved"}:Y(`The user did not approve "${Z.name}", and it did not run.`)}if(!q9(J.elicitation))throw K("approval-unavailable",new L(D.MissingRequiredClientCapability,`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation).`,{requiredCapabilities:{elicitation:{form:{}}}},400));let j={p:Q3($.principal),t:Z.name,a:T,n:j9(16).toString("base64url"),exp:Date.now()+x9};return W.pending=!0,{kind:"answer",result:{resultType:"input_required",inputRequests:{[C9]:{method:"elicitation/create",params:{mode:"form",...X}}},requestState:M3(E3,"grs1",j),_meta:{[T3]:this.serverInfo}}}}let Q=$.era;if(!Q.session.e||!$.stream)return Y(`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation). It did not run.`,"approval-unavailable");let V=`gemi-approval-${j9(12).toString("base64url")}`,H=Q.sessionId,U=await new Promise((I)=>{let J=setTimeout(()=>{this.pending.delete(V),I(null)},this.approvalTimeoutMs),F=(B)=>{clearTimeout(J),I(B)};this.pending.set(V,{session:H,resolve:F}),$.signal.addEventListener("abort",()=>{this.pending.delete(V),F(null)}),$.stream.send({jsonrpc:"2.0",id:V,method:"elicitation/create",params:Q.session.v==="2025-11-25"?{mode:"form",...X}:X})});return U&&!U.error&&k9(U.result)?{kind:"approved"}:Y(`The user did not approve "${Z.name}", and it did not run.`)}async spendNonce($,Z){try{return await this.nonces.consume($,Z)}catch(z){return console.error("[gemi/mcp] Spending an approval failed:",z),!1}}async respond($,Z,z,G,W){if(!z)try{let Q=await Z(null,G);return f({jsonrpc:"2.0",id:$.id,result:Q},200)}finally{W?.()}let X=new AbortController,Y=AbortSignal.any([X.signal,G]),K=new f9(()=>X.abort());return(async()=>{try{let Q=await Z(K,Y);K.send({jsonrpc:"2.0",id:$.id,result:Q})}catch(Q){if(Q instanceof L)K.send(R($.id,Q));else console.error("[gemi/mcp] The MCP endpoint failed:",Q),K.send(R($.id,new L(D.InternalError,"Internal error.")))}finally{W?.(),K.close()}})(),new Response(K.readable,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-store","X-Accel-Buffering":"no"}})}unauthorized($){let Z=this.resolvers.map((G)=>G.challenge?.(this.context)).find(Boolean)??'Bearer realm="mcp"',z=$?`${Z}, error="invalid_token", error_description="${$.replace(/["\\]/g,"")}"`:Z;return f(R(null,new L(D.InvalidRequest,"Unauthorized.")),401,{"WWW-Authenticate":z})}async failedAttempt($){let Z=R9(new m($,{},"api",this.endpoint.pathname)),z=await A3(`mcp-auth-failed:${Z}`,z2);return z===null?null:M9(z)}async spend($){if(!this.rateLimit)return null;let Z=await A3(`mcp-endpoint:${$.via}:${$.id}`,this.rateLimit);return Z===null?null:M9(Z)}}class f9{readable;controller;closed=!1;encoder=new TextEncoder;constructor($){this.readable=new ReadableStream({start:(Z)=>{this.controller=Z},cancel:()=>{this.closed=!0,$()}})}send($){if(this.closed)return;this.controller.enqueue(this.encoder.encode(`event: message
2
+ import{Dc as B9,Qc as P9,Yb as E9,ac as K3,bc as b9,fc as F9,kc as e,wd as I9,xc as N9}from"./chunk-91vxf94n.js";import{Dd as i3,Fd as B3,Id as i9,Jd as l9,Kd as J$,Md as O$}from"./chunk-5sjteb6f.js";import{Pd as h9,Ud as m9,Wd as u9,be as x,ce as d9,de as c9,fe as p9,ge as L$}from"./chunk-tr8s1z7k.js";import{je as P}from"./chunk-y16jhwrv.js";import{Ag as f3,Be as R9,Cf as Z3,Dg as w3,Eg as $$,Fe as x$,Fg as G3,Gg as Z$,Hg as z$,Ie as U$,If as H3,Ig as v3,Jf as u3,Jg as a,Kf as k,Mg as q$,Nf as V$,Ng as L3,Of as Y$,Og as p3,Pf as K$,Rf as w,Se as F$,Te as l3,Tg as Q$,Ug as H$,Xe as J3,Ye as X3,_g as A$,cg as e3,ng as a3,of as d3,pg as n,tg as r3,ug as r9,vg as e9,xe as l,ye as X$,zg as g3}from"./chunk-f54p1qc9.js";import{Ji as J9,Ni as P3,Oi as F3,Pi as z3,di as p,fi as m,ui as o3}from"./chunk-5nqwxjf1.js";import{Vi as s9}from"./chunk-p9avgpzd.js";import{ej as g}from"./chunk-n31hppcx.js";import{kj as c3}from"./chunk-rz6npg3r.js";import{nj as N$,oj as n3,rj as N3,sj as t3,vj as P$}from"./chunk-fzwaybhd.js";import{Jj as t9,Oj as o9}from"./chunk-4b5rpya9.js";import{ck as g9,ek as u}from"./chunk-dcwsya9e.js";import{fk as A}from"./chunk-h5s56wzw.js";import{lk as D$}from"./chunk-73svx8gr.js";import{$k as s3}from"./chunk-t797crcj.js";import{gl as U3,jl as y}from"./chunk-ry9jard2.js";import{sl as m3}from"./chunk-8z1z4zbq.js";import{El as a9}from"./chunk-r1sjx2q9.js";var T$="mcp",k$=/^[\x21\x23-\x5B\x5D-\x7E]+$/;class O extends e{status;constructor($,Z){super($);this.status=Z;this.name="McpToolError"}}class v extends Error{reason;constructor($,Z){super($);this.reason=Z;this.name="McpCallRefusedError"}}var $9=/^[A-Za-z0-9_-]{1,64}$/,M$=/:([A-Za-z_][A-Za-z0-9_]*)([?*+]?)/g,Z9=4000,M=1e5,R$=/^(text\/|application\/([\w.+-]*\+)?(json|xml))/i,L9=new WeakMap;function V6($){return L9.get($)}class i{router;dispatcher;static token="router.mcp";plans=new Map;scopeTools=new Map;files;featureOn;constructor($,Z,z={}){this.router=$;this.dispatcher=Z;this.files=w$(z.files),this.featureOn=z.featureOn??X3;for(let[G,W]of Object.entries($.routes??{}))this.plans.set(G,E$(W)?this.planNative(G,W):this.plan(G,W));this.resolveScopes()}list($,Z){if(D3($),$.kind==="local")return this.descriptors(Z);let z=[];for(let[G,W]of this.plans){if(!W.remote||!this.grants($.principal,G))continue;if(Y9(W.remote,Z))z.push(W.remote)}return z}async available($,Z){let z=[];for(let G of this.list($,Z))if(await this.isOn(G))z.push(G);return z}descriptors($){let Z=[];for(let{descriptor:z}of this.plans.values())if(Y9(z,$))Z.push(z);return Z}get maxFileBytes(){return this.files.maxBytes}scopes(){return[...this.scopeTools].map(([$,{description:Z}])=>({name:$,description:Z}))}scopesFor($){return[...this.scopeTools].filter(([,{tools:Z}])=>Z.has($)).map(([Z])=>Z)}async execute($,Z,z,G,W={}){D3($);let X=this.plans.get(Z);if(X&&!await this.isOn(X.descriptor)){if($.kind==="remote")throw new v(`There is no tool named "${Z}".`,"unknown-tool");throw new O(`There is no tool named "${Z}".`,404)}if($.kind==="remote"){if(!X?.remote||!this.grants($.principal,Z))throw new v(`There is no tool named "${Z}".`,"unknown-tool");if(X.descriptor.requiresApproval&&W.approved!==!0&&!W3(X))throw new v(`"${Z}" needs the user's approval, and this call does not have it.`,"approval-required");G=void 0}if(!X)throw Error(`McpRegistry: there is no tool named "${Z}".`);if(X.kind==="tool")return await this.executeNative(X,$,z,G,W);let Y=X,K=$.kind==="remote"?Y.remote:Y.descriptor,Q=K.inputSchema.safeParse(z);if(Q.ok===!1)throw new O(`Invalid arguments for "${Z}": ${Q.errors.join(", ")}`);let V=Q.value,H={caller:$,req:$.req,tool:K,input:V,ctx:G},U=await this.fillPath(Y,H),{path:I}=this.dispatcher.getRouteHandlerAndParams(new Request(`http://gemi.internal/api${U}`));if(I!==K.url)throw new O(`"${Z}" has nothing at ${U}.`,404);let J={};for(let _ of Y.jsonKeys)if(V[_]!==void 0)J[_]=V[_];let F,B="";if(Y.fileFields.length>0)F=await this.formData(Y,J,H);else if(K.method==="GET")B=l$(J);else if(Y.jsonKeys.length>0)F=J;let T=this.router.credentials?await this.bind(Y,"the credentials",()=>this.router.credentials(H)):void 0,j={...T?{credentials:T}:{},...W.signal?{signal:W.signal}:{},...W.progress?{progress:W.progress}:{},...$.kind==="remote"?{identity:{user:$.principal.user,grant:{via:$.principal.via,id:$.principal.id,scopes:$.principal.scopes,...$.principal.clientId?{clientId:$.principal.clientId}:{}}}}:{}},C;try{let _=B?`${U}?${B}`:U;C=Object.keys(j).length>0?await this.dispatcher.dispatchAs($.req,K.method,_,F,j):await this.dispatcher.dispatchAs($.req,K.method,_,F)}catch(_){throw console.error(`[gemi/mcp] Dispatching "${Z}" failed:`,_),new O(`"${Z}" failed on the server.`,500)}if(!Y.result&&!K.outputSchema)return await U9(Z,C);return await this.project(Y,H,C)}async isOn($){return $.feature===void 0||await this.featureOn($.feature)===!0}plan($,Z){if(!$9.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (${Z?.method} ${Z?.url})`;if(!(Z instanceof Object)||Z.__internal_brand!=="McpRoute")throw Error(`McpRouter: "${$}" is not a route or a tool. Declare it with this.fromApiRoute(...) or this.fromTool(...).`);let{method:G,url:W,meta:X}=Z;if(X.feature!==void 0&&(typeof X.feature!=="string"||X.feature===""))throw Error(`${z}: feature must be a feature key from app/features.`);if(W.startsWith("/__gemi__"))throw Error(`${z} is a framework route, not an app route.`);let Y=this.dispatcher.flatRoutes[W]?.[G];if(!Y)throw Error(`${z} names no route of this app. Expose a route by the path and verb it is mounted at.`);let K=[...W.matchAll(M$)].map(([,N,S])=>({name:N,modifier:S})),Q=X.params??{};for(let N of K)if(!(N.name in Q))throw Error(`${z}: the path param "${N.name}" must be bound or declared "input".`);for(let[N,S]of Object.entries(Q)){if(!K.some((h)=>h.name===N))throw Error(`${z}: "${N}" in params is not a param of the url.`);if(Q9(S))u$(z,`params.${N}`,S);else K9(z,`params.${N}`,S)}let V=[],H;if(X.input){if(H=X.input.toJSONSchema(),H.type!=="object"||!H.properties)throw Error(`${z}: input must be an s.object(...), the fields of the request body.`);V=Object.keys(H.properties)}let U=Object.entries(X.files??{}).map(([N,S])=>({name:N,binder:S}));for(let N of U)K9(z,`files.${N.name}`,N.binder);if(X.result!==void 0&&typeof X.result!=="function")throw Error(`${z}: result must be a function.`);if(X.output!==void 0&&typeof X.output?.safeParse!=="function")throw Error(`${z}: output must be a schema, built with s.`);if(X.title!==void 0&&(typeof X.title!=="string"||X.title===""))throw Error(`${z}: title must be a non-empty string.`);let I=V9(z,G,X.annotations);if(U.length>0&&G==="GET")throw Error(`${z}: a GET has no body to carry a file.`);let J={},F=(N,S)=>{if(N in J)throw Error(`${z}: "${N}" is the input key of two params or files, and the model can only send one.`);J[N]=S},B=new Map,T=new Map;for(let N of K){let S=Q[N.name];if(S==="input"){let h=p.string().describe(`The ":${N.name}" segment of the url.`);F(N.name,N.modifier==="?"||N.modifier==="*"?h.optional():h)}else if(Q9(S)){let h=S.as??N.name;F(h,S.input),T.set(N.name,{key:h,param:S})}else B.set(N.name,S)}let j={};for(let N of U)if(N.binder==="input")F(N.name,p.string().describe("The id of an attachment the user uploaded or a tool produced (gemi_att_\u2026), whose file is sent as this field.")),j[N.name]=this.remoteFileSchema();let C=[...Object.keys(J),...U.map((N)=>N.name)];for(let N of new Set(C))if(V.includes(N))throw Error(`${z}: "${N}" is both an input field and a param or file, and the model can only send one.`);let _=Object.freeze({kind:"route",name:$,description:X.description,method:G,url:W,inputSchema:H9(X.input,H,p.object(J)),...X.output?{outputSchema:X.output}:{},...X.title?{title:X.title}:{},annotations:I,tags:Object.freeze([...X.tags??[]]),requiresApproval:X.requiresApproval===!0,...X.feature!==void 0?{feature:X.feature}:{},...Y.source?{source:Y.source}:{}}),r=!U.every((N)=>N.binder==="input")?null:U.length===0?_:Object.freeze({..._,inputSchema:H9(X.input,H,p.object(p$(J,Object.keys(j))),j)});return{kind:"route",descriptor:_,remote:r,params:K,paramBinders:B,modelParams:T,fileFields:U,jsonKeys:V,...X.result?{result:X.result}:{}}}remoteFileSchema(){let{maxBytes:$,fetch:Z}=this.files,z={name:{type:"string",description:"The file's name, like report.pdf."},mimeType:{type:"string",description:"The file's media type, like application/pdf."},data:{type:"string",contentEncoding:"base64",description:`The file's bytes, base64-encoded (RFC 4648, standard alphabet). At most ${$} bytes decoded.`}};if(Z)z.url={type:"string",format:"uri",description:"An https URL the server downloads the file from, instead of data."};let G={type:"object",description:Z?"A file, sent as base64 in data or fetched from url: exactly one of the two.":"A file, sent as base64 in data.",properties:z,required:["name","mimeType"],additionalProperties:!1},W=Object.keys(z),X=(Y)=>{if(typeof Y!=="object"||Y===null||Array.isArray(Y))return{ok:!1,errors:["a file must be an object"]};let K=[],Q={};for(let V of Object.keys(Y))if(!W.includes(V))K.push(`a file has no field "${V}"`);for(let V of W){let H=Y[V];if(H===void 0||H===null){if(V==="name"||V==="mimeType")K.push(`a file needs "${V}"`);continue}if(typeof H!=="string")K.push(`a file's "${V}" must be a string`);else Q[V]=H}return K.length>0?{ok:!1,errors:K}:{ok:!0,value:Q}};return{toJSONSchema:()=>G,safeParse:X,parse(Y){let K=X(Y);if(K.ok===!1)throw Error(K.errors.join(", "));return K.value}}}planNative($,Z){if(!$9.test($))throw Error(`McpRouter: "${$}" is not a valid tool name. A routes key is the tool's name as a model and an MCP client see it, used verbatim \u2014 letters, digits, "_" and "-", at most 64.`);let z=`McpRouter: "${$}" (a native tool)`,{tool:G,meta:W={}}=Z;if(!(G instanceof Object)||typeof G.name!=="string")throw Error(`${z} is not an AgentTool. Pass one built with AgentTool.create(...).`);if(G.answeredBy==="client"||typeof G.execute!=="function")throw Error(`${z}: "${G.name}" is answered by the client, and only a tool the server runs can be called through the registry.`);if(typeof G.inputSchema==="function")throw Error(`${z}: "${G.name}" resolves its input schema per run, and the registry lists one schema to every caller. Give it a fixed inputSchema.`);if(typeof G.inputSchema?.safeParse!=="function")throw Error(`${z}: its inputSchema must be a schema, built with s.`);if(typeof W!=="object"||W===null)throw Error(`${z}: the meta must be an object.`);if(W.description!==void 0&&(typeof W.description!=="string"||W.description.trim()===""))throw Error(`${z}: description must be a non-empty string.`);if(W.title!==void 0&&(typeof W.title!=="string"||W.title===""))throw Error(`${z}: title must be a non-empty string.`);if(W.tags!==void 0&&(!Array.isArray(W.tags)||W.tags.some((Q)=>typeof Q!=="string")))throw Error(`${z}: tags must be an array of strings.`);if(W.requiresApproval===!1&&G.requiresApproval)throw Error(`${z}: "${G.name}" requires approval, and requiresApproval: false would run it without asking. Leave it out, or register a tool that does not ask.`);let X=W.remote;if(X!==void 0){if(typeof X!=="object"||X===null||typeof X.context!=="function")throw Error(`${z}: remote must be { context(call) }, building the AgentContext a remote call runs with.`);if(X.progress!==void 0&&typeof X.progress!=="function")throw Error(`${z}: remote.progress must be a function.`)}let Y=W.description??G.description;if(typeof Y!=="string"||Y.trim()==="")throw Error(`${z} needs a description: the tool's own, or the meta's.`);let K=Object.freeze({kind:"tool",name:$,description:Y,inputSchema:G.inputSchema,...G.outputSchema?{outputSchema:G.outputSchema}:{},...W.title?{title:W.title}:{},annotations:V9(z,void 0,W.annotations),tags:Object.freeze([...W.tags??[]]),requiresApproval:G.requiresApproval||W.requiresApproval===!0});return{kind:"tool",descriptor:K,remote:X?K:null,tool:G,meta:W}}async approvalRequired($,Z,z,G={}){let W=this.plans.get(Z);if(!W)return!0;if(!W3(W))return W.descriptor.requiresApproval;let X=W;if($.kind!=="remote"||!X.meta.remote)return!0;let Y=X.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)return!0;let K={caller:$,req:$.req,tool:X.descriptor,input:Y.value},Q;try{Q=await this.bind(X,"the remote context",()=>X.meta.remote.context(K))}catch{return!0}if(typeof Q!=="object"||Q===null)return!0;let V=G.signal??new AbortController().signal;return X9(X,Y.value,W9(G9(X,Q,V)))}nativeApproval($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return W3(Z)??Z.descriptor.requiresApproval}nativeTool($){let Z=this.plans.get($);if(Z?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${$}".`);return Z.tool}startNative($,Z,z,G){let W=this.plans.get(Z);if(W?.kind!=="tool")throw Error(`McpRegistry: there is no native tool named "${Z}".`);if($===void 0)return W.tool.execute(z,G);if(D3($),$.kind!=="local")throw Error("McpRegistry: startNative is for a local caller. A remote call goes through execute().");let X=W.descriptor.inputSchema.safeParse(z);if(X.ok===!1)throw new O(`Invalid arguments for "${Z}": ${X.errors.join(", ")}`);return this.runNative(W,{caller:$,req:$.req,tool:W.descriptor,input:X.value},G)}runNative($,Z,z){let G={...z};return L9.set(G,{...Z,ctx:G}),$.tool.execute(Z.input,G)}async executeNative($,Z,z,G,W){let{name:X}=$.descriptor,Y=$.descriptor.inputSchema.safeParse(z);if(Y.ok===!1)throw new O(`Invalid arguments for "${X}": ${Y.errors.join(", ")}`);let K={caller:Z,req:Z.req,tool:$.descriptor,input:Y.value},Q=(_,_3)=>{if(!W.progress)return;let r;try{r=$.meta.remote?.progress?$.meta.remote.progress(_,_3):y$(_,_3)}catch(N){console.error(`[gemi/mcp] The progress mapping of "${X}" failed:`,N);return}if(r)W.progress(r)};if(Z.kind==="local"){if(!G)throw Error(`McpRegistry: "${X}" is a native tool, which runs with the tool context of an agent call, and none was passed to execute().`);return await z9(this.runNative($,{...K,ctx:G},G),Q)}let V=$.meta.remote,H=await this.bind($,"the remote context",()=>V.context(K));if(typeof H!=="object"||H===null)throw console.error(`[gemi/mcp] The remote context of "${X}" is not an object:`,H),new O(`"${X}" failed on the server.`,500);let U=$.tool.timeoutMs,I=[...W.signal?[W.signal]:[],...U!==void 0?[AbortSignal.timeout(U)]:[]],J=I.length===0?new AbortController().signal:I.length===1?I[0]:AbortSignal.any(I),F=G9($,H,J);if(!W.approved&&W3($)&&await X9($,K.input,W9(F)))throw new v(`"${X}" needs the user's approval, and this call does not have it.`,"approval-required");let B;try{B=await z9(this.runNative($,{...K,ctx:F},F),Q,J)}catch(_){if(J.aborted&&_===J.reason){if(W.signal?.aborted)throw new O(`"${X}" was cancelled.`,499);throw new O(`"${X}" did not finish within ${U} ms.`,504)}if(_ instanceof O)throw _;if(_ instanceof e||_ instanceof v)throw new O(_.message);throw console.error(`[gemi/mcp] "${X}" failed for a remote caller:`,_),new O(`"${X}" failed on the server.`,500)}let T=(_)=>{return console.error(`[gemi/mcp] "${X}" ${_}`),new O(`"${X}" failed on the server.`,500)};if(N9(B))throw T("answered a job handle, and a remote call has no background jobs.");let j=B;if($.descriptor.outputSchema){let _=$.descriptor.outputSchema.safeParse(j);if(_.ok===!1)throw T(`answered what its output schema refuses: ${_.errors.join(", ")}`);j=_.value}if(j===void 0)return null;if(typeof j==="string")return j.length>M?`${j.slice(0,M)}\u2026 [cut at ${M} of ${j.length} characters]`:j;let C=JSON.stringify(j);if(C!==void 0&&C.length>M)return`${C.slice(0,M)}\u2026 [cut at ${M} of ${C.length} characters]`;return j}async fillPath($,Z){let{input:z,req:G}=Z,W=$.descriptor.url;for(let X of $.params){let Y=$.paramBinders.get(X.name),K=$.modelParams.get(X.name),Q;if(Y||K){if(Q=K?await this.bind($,`the param "${X.name}"`,()=>K.param.bind(z[K.key],G,Z),{refusals:!0}):await this.bind($,`the param "${X.name}"`,()=>Y(G,Z)),Q===void 0||Q===null||Q==="")throw console.error(`[gemi/mcp] The ${K?"resolver":"binder"} for "${X.name}" of "${$.descriptor.name}" returned ${JSON.stringify(Q)}.`),new O(`"${$.descriptor.name}" failed on the server.`,500)}else Q=z[X.name];let V=`:${X.name}${X.modifier}`;if(Q===void 0||Q===null||Q===""){if(X.modifier!=="?"&&X.modifier!=="*")throw new O(`"${X.name}" of "${$.descriptor.name}" must not be empty.`);W=W.replace(`/${V}`,"");continue}W=W.replace(V,i$($.descriptor.name,X,String(Q)))}return W}async formData($,Z,z){let{input:G,ctx:W}=z,X=$.descriptor.name;if(z.caller.kind==="remote"){let K=new FormData;for(let[Q,V]of Object.entries(Z))O3(K,Q,V);for(let Q of $.fileFields)K.append(Q.name,await this.remoteFile(X,Q.name,G[Q.name]));return K}if(!W)throw Error(`McpRegistry: "${X}" sends a file, which is resolved through the tool context's attachments, and none was passed to execute().`);let Y=new FormData;for(let[K,Q]of Object.entries(Z))O3(Y,K,Q);for(let K of $.fileFields){let Q=K.binder==="input"?G[K.name]:await this.bind($,`the file "${K.name}"`,()=>K.binder(W,z));if(typeof Q!=="string"||Q==="")throw new O(`"${X}" needs a file for "${K.name}", and this turn has none. Ask the user to attach one.`);Y.append(K.name,await W.attachments.file(Q))}return Y}async remoteFile($,Z,z){let G=(H)=>new O(`"${Z}" of "${$}" ${H}`,400),W=z,{maxBytes:X,fetch:Y}=this.files;if(!v$(W.name))throw G("needs a name of 1 to 255 characters, without control characters or slashes.");if(!g$.test(W.mimeType))throw G(`has a mimeType that is not a media type: "${W.mimeType.slice(0,100)}".`);let K=typeof W.data==="string",Q=typeof W.url==="string";if(K===Q)throw G(Y?"needs exactly one of data or url.":"needs its bytes, base64, in data.");if(K){let H=W.data.replace(/\s+/g,"");if(Math.floor(H.length*3/4)-m$(H)>X)throw G(`is larger than the ${X} bytes a file may be.`);if(H.length%4!==0||!h$.test(H))throw G("has data that is not base64 (RFC 4648, standard alphabet, padded).");return new File([Buffer.from(H,"base64")],W.name,{type:W.mimeType})}if(!Y)throw G("cannot be fetched from a URL here. Send its bytes, base64, in data.");let V;try{V=new URL(W.url)}catch{throw G("has a url that is not a URL.")}if(V.protocol!=="https:")throw G("can only be fetched from an https URL.");try{let H=await J9(V.href,{...Y,maxSize:Math.min(Y.maxSize??X,X),redirect:"follow"});if(!H.ok)throw G(`could not be fetched: ${V.host} answered ${H.status}.`);let U=await H.arrayBuffer();return new File([U],W.name,{type:W.mimeType})}catch(H){if(H instanceof O)throw H;throw G(`could not be fetched from ${V.host}: ${H instanceof Error?H.message:"failed"}.`)}}grants($,Z){for(let z of $.scopes??[])if(this.scopeTools.get(z)?.tools.has(Z))return!0;return!1}resolveScopes(){let $=this.router.scopes;if($===void 0){this.scopeTools.set(T$,{description:"Use this app's tools as you",tools:new Set(this.plans.keys())});return}if(typeof $!=="object"||$===null)throw Error("McpRouter: scopes must be an object of scope names.");let Z=new Set([...this.plans.values()].flatMap(({descriptor:z})=>z.tags));for(let[z,G]of Object.entries($)){let W=`McpRouter: scope "${z}"`;if(!k$.test(z))throw Error(`${W} is not a valid OAuth scope: printable ASCII, no spaces or quotes.`);if(typeof G?.description!=="string"||G.description==="")throw Error(`${W} needs a description: it is what a consent screen shows.`);let X=new Set;for(let Y of G.tags??[]){if(!Z.has(Y))throw Error(`${W} names the tag "${Y}", which no tool has.`);for(let[K,{descriptor:Q}]of this.plans)if(Q.tags.includes(Y))X.add(K)}for(let Y of G.names??[]){if(!this.plans.has(Y))throw Error(`${W} names "${Y}", which is no tool.`);X.add(Y)}if(X.size===0)throw Error(`${W} reaches no tool. Give it tags or names.`);this.scopeTools.set(z,{description:G.description,tools:X})}}async project($,Z,z){let{name:G,outputSchema:W}=$.descriptor;if(z.status<200||z.status>=300)return await U9(G,z);let X=(U,I)=>{if(I===void 0)console.error(`[gemi/mcp] "${G}" ${U}`);else console.error(`[gemi/mcp] "${G}" ${U}`,I);return new O(`"${G}" failed on the server.`,500)},Y=z.headers.get("Content-Type"),K=await z.text(),Q=null;if(K!=="")try{Q=JSON.parse(K)}catch{throw X(`answered ${Y??"a body with no content-type"} that is not JSON, and its result or output needs JSON.`)}let V=Q;if($.result)try{V=await $.result(Q,Z)}catch(U){throw X("failed in its result projection:",U)}if(W){let U=W.safeParse(V);if(U.ok===!1)throw X(`answered what its output schema refuses: ${U.errors.join(", ")}`);V=U.value}if(V===void 0)return null;let H=JSON.stringify(V);if(H!==void 0&&H.length>M)return`${H.slice(0,M)}\u2026 [cut at ${M} of ${H.length} characters]`;return V}async bind($,Z,z,G={}){try{return await z()}catch(W){if(G.refusals&&W instanceof e)throw W;throw console.error(`[gemi/mcp] Binding ${Z} of "${$.descriptor.name}" failed:`,W),new O(`"${$.descriptor.name}" failed on the server.`,500)}}}function E$($){return $ instanceof Object&&$.__internal_brand==="McpTool"}function b$($){return typeof $==="object"&&$!==null&&typeof $.next==="function"&&Symbol.asyncIterator in $}async function z9($,Z,z){let G;if(z)G=new Promise((X,Y)=>{if(z.aborted)Y(z.reason);else z.addEventListener("abort",()=>Y(z.reason),{once:!0})}),G.catch(()=>{});let W=(X)=>G?Promise.race([X,G]):X;if(!b$($))return await W(Promise.resolve($));try{let X=0,Y=await W($.next());while(!Y.done)Z(Y.value,++X),Y=await W($.next());return Y.value}catch(X){throw $.return(void 0).catch(()=>{}),X}}function y$($,Z){if(typeof $==="string")return{progress:Z,message:$};if(typeof $==="object"&&$!==null){let{progress:z,total:G,message:W}=$;if(typeof z==="number"&&Number.isFinite(z))return{progress:z,...typeof G==="number"?{total:G}:{},...typeof W==="string"?{message:W}:{}};if(typeof W==="string")return{progress:Z,message:W}}return{progress:Z}}function G9($,Z,z){let G=$.descriptor.name,W=`mcp_${crypto.randomUUID()}`,X=`mcp_call_${crypto.randomUUID()}`,Y=(Q)=>async()=>{throw new e(`"${G}" was called by a remote MCP client, which has no ${Q}.`,{retryable:!1})},K={put:Y("attachment store"),get:Y("attachment store"),read:Y("attachment store"),file:Y("attachment store")};return{context:Z,body:{},runId:W,toolCallId:X,signal:z,step:1,depth:0,resumed:!1,attachments:K,turn:Object.freeze({attachments:Object.freeze([])}),runAgent:Y("agent run to nest a sub-agent in"),generateImage:Y("attachment store to put an image in"),editImage:Y("attachment store to put an image in"),generate:(Q)=>I9({...Q,signal:Q.signal?AbortSignal.any([z,Q.signal]):z},{origin:{mcp:G,runId:W,toolCallId:X}}),jobs:B9({jobs:void 0,threadId:void 0,runId:W,toolCallId:X,toolName:G,depth:0,async:$.tool.async,attachments:null}),memory:P9(),meter:F9().meter}}function W3($){if($.kind!=="tool"||$.meta.requiresApproval===!0)return;return $.tool.approvalPredicate}function W9($){return{context:$.context,body:$.body,runId:$.runId,threadId:$.threadId,toolCallId:$.toolCallId,step:$.step,depth:$.depth,signal:$.signal}}async function X9($,Z,z){try{return await $.tool.approvalPredicate(Z,z)!==!1}catch(G){return console.error(`[gemi/mcp] The requiresApproval of "${$.descriptor.name}" threw, so the call asks the user:`,G),!0}}function D3($){if($?.kind==="local"&&$.req)return;if($?.kind==="remote"&&$.req&&$.principal?.user&&typeof $.principal.id==="string"&&Array.isArray($.principal.scopes))return;throw Error('McpRegistry: a caller is { kind: "local", req } or { kind: "remote", req, principal }, with the principal a caller resolver verified.')}function Y9($,Z){if(Z?.names&&!Z.names.includes($.name))return!1;if(Z?.tags&&!$.tags.some((z)=>Z.tags.includes(z)))return!1;return!0}var f$=10485760;function w$($){let Z=$?.maxBytes??f$;if(!Number.isSafeInteger(Z)||Z<=0)throw Error("McpRegistry: files.maxBytes must be a positive whole number of bytes.");let z=$?.fetchUrls===!0?{}:typeof $?.fetchUrls==="object"&&$.fetchUrls!==null?$.fetchUrls:null;return{maxBytes:Z,fetch:z}}function v$($){if($.length===0||$.length>255)return!1;for(let Z of $){let z=Z.codePointAt(0);if(z<32||z===127||Z==="/"||Z==="\\")return!1}return!0}var g$=/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}(\s*;.{0,200})?$/,h$=/^[A-Za-z0-9+/]*={0,2}$/;function m$($){return $.endsWith("==")?2:$.endsWith("=")?1:0}function K9($,Z,z){if(z!=="input"&&typeof z!=="function")throw Error(`${$}: ${Z} must be a function or "input".`)}function Q9($){return $ instanceof Object&&$.__internal_brand==="McpModelParam"}function u$($,Z,z){if(z.as!==void 0&&(typeof z.as!=="string"||z.as===""))throw Error(`${$}: ${Z}.as must be a non-empty string.`);let G=z.input;if(typeof G?.safeParse!=="function"||typeof G.toJSONSchema!=="function")throw Error(`${$}: ${Z}.input must be a schema, built with s.`);if(typeof z.bind!=="function")throw Error(`${$}: ${Z}.bind must be a function.`)}var d$=new Set(["readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);function c$($){switch($){case"GET":return{readOnlyHint:!0};case"DELETE":return{destructiveHint:!0};case"PUT":return{idempotentHint:!0};default:return{}}}function V9($,Z,z){if(z!==void 0&&(typeof z!=="object"||z===null))throw Error(`${$}: annotations must be an object of hints.`);let G=Z?c$(Z):{};for(let[W,X]of Object.entries(z??{})){if(!d$.has(W))throw Error(`${$}: "${W}" is not a tool annotation. Use readOnlyHint, destructiveHint, idempotentHint or openWorldHint.`);if(X===void 0)continue;if(typeof X!=="boolean")throw Error(`${$}: annotations.${W} must be true or false.`);G[W]=X}if(G.readOnlyHint===!0&&(G.destructiveHint||G.idempotentHint))throw Error(`${$} is read-only${z?.readOnlyHint?"":` (a ${Z})`} and also ${G.destructiveHint?"destructive":"idempotent"}, which only a tool that is not read-only can be. Set readOnlyHint: false if it changes something.`);return Object.freeze(G)}function H9($,Z,z,G={}){let W=z.toJSONSchema(),X=Object.fromEntries(Object.entries(G).map(([Q,V])=>[Q,V.toJSONSchema()])),Y={...Z??{},type:"object",properties:{...Z?.properties??{},...W.properties,...X},required:[...Z?.required??[],...W.required??[],...Object.keys(G)],additionalProperties:!1},K=(Q)=>{if(typeof Q!=="object"||Q===null||Array.isArray(Q))return{ok:!1,errors:["expected an object"]};let V=[],H={};if($){let I=$.safeParse(Q);if(I.ok===!1)V.push(...I.errors);else H={...I.value}}let U=z.safeParse(Q);if(U.ok===!1)V.push(...U.errors);else H={...H,...U.value};for(let[I,J]of Object.entries(G)){let F=Q[I];if(F===void 0){V.push(`"${I}" is required`);continue}let B=J.safeParse(F);if(B.ok===!1)V.push(...B.errors.map((T)=>`${I}: ${T}`));else H[I]=B.value}return V.length>0?{ok:!1,errors:V}:{ok:!0,value:H}};return{toJSONSchema:()=>Y,safeParse:K,parse(Q){let V=K(Q);if(V.ok===!1)throw Error(V.errors.join(", "));return V.value}}}function p$($,Z){return Object.fromEntries(Object.entries($).filter(([z])=>!Z.includes(z)))}function i$($,Z,z){let G=Z.modifier==="*"||Z.modifier==="+"?z.split("/"):[z];if(G.some((W)=>W==="."||W===".."))throw new O(`"${z}" is not a valid value for "${Z.name}" of "${$}".`);return G.map(encodeURIComponent).join("/")}function O3($,Z,z){if(z===void 0||z===null)return;if(Array.isArray(z)){for(let G of z)O3($,Z,G);return}$.append(Z,typeof z==="object"?JSON.stringify(z):String(z))}function l$($){let Z=new URLSearchParams,z=(G,W)=>{if(W===void 0||W===null)return;if(Array.isArray(W)){for(let X of W)z(G,X);return}Z.append(G,typeof W==="object"?JSON.stringify(W):String(W))};for(let[G,W]of Object.entries($))z(G,W);return Z.toString()}async function U9($,Z){if(Z.status>=200&&Z.status<300){let G=Z.headers.get("Content-Type");if(G&&!R$.test(G)){let X=(await Z.arrayBuffer()).byteLength;return`"${$}" answered with ${X} bytes of ${G}, which is not shown.`}let W=await Z.text();if(W==="")return null;if(W.length>M)return`${W.slice(0,M)}\u2026 [cut at ${M} of ${W.length} characters]`;try{return JSON.parse(W)}catch{return W}}let z=await Z.text();if(Z.status>=400&&Z.status<500){let G=z.length>Z9?`${z.slice(0,Z9)}\u2026`:z;throw new O(`"${$}" was refused with ${Z.status}${G?`: ${G}`:"."}`,Z.status)}if(Z.status<500)console.error(`[gemi/mcp] "${$}" answered ${Z.status}${Z.headers.get("Location")?` to ${Z.headers.get("Location")}`:""}, which a tool call cannot follow.`);throw new O(`"${$}" failed on the server.`,Z.status)}import{createHash as n$,randomBytes as s$,timingSafeEqual as t$}from"crypto";function j3($){let Z=$.headers.get("authorization");if(!Z)return null;let z=/^Bearer[ ]+([\x21-\x7e]+)$/i.exec(Z.trim());return z?z[1]:null}class o${options;name="api-key";constructor($){this.options=$;if(typeof $?.prefix!=="string"||!/^[A-Za-z0-9_-]{3,32}$/.test($.prefix))throw Error('McpApiKeyResolver: prefix is required: 3 to 32 letters, digits, _ or -, like "myapp_mcp_".');if(typeof $.verify!=="function")throw Error("McpApiKeyResolver: verify must be a function that looks a key up.")}static generate($){return`${$}${s$(32).toString("base64url")}`}static hash($){return n$("sha256").update($).digest("hex")}static hashesMatch($,Z){let z=Buffer.from($),G=Buffer.from(Z);return z.length===G.length&&t$(z,G)}async resolve($){let Z=j3($);if(!Z?.startsWith(this.options.prefix))return null;let z=await this.options.verify(Z,$);if(!z)return{ok:!1,error:"invalid_token",description:"The API key is not valid."};if(!z.user||typeof z.id!=="string"||z.id===""||!Array.isArray(z.scopes))throw Error("McpApiKeyResolver: verify must answer { user, id, scopes } for a key it knows, or null.");return{ok:!0,principal:{user:z.user,via:this.name,id:z.id,scopes:[...z.scopes]}}}}import{createHash as y9,randomBytes as j9}from"crypto";async function A3($,Z){let z=a$();if(!z)return null;let G=await z.consume($,Z);return G.allowed?null:Math.max(1,Math.ceil(G.retryAfter/1000))}function a$(){try{let $=y();return $.bound(l)?$.make(l):null}catch{return null}}var x3=["2026-07-28"],Y3=["2025-11-25","2025-06-18","2025-03-26"],C3=[...x3,...Y3],S3="io.modelcontextprotocol/protocolVersion",q3="io.modelcontextprotocol/clientCapabilities";var T3="io.modelcontextprotocol/serverInfo",D={ParseError:-32700,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602,InternalError:-32603,HeaderMismatch:-32020,MissingRequiredClientCapability:-32021,UnsupportedProtocolVersion:-32022};class L extends Error{code;data;status;constructor($,Z,z,G=200){super(Z);this.code=$;this.data=z;this.status=G;this.name="JsonRpcError"}}function R($,Z){return{jsonrpc:"2.0",id:$,error:{code:Z.code,message:Z.message,...Z.data!==void 0?{data:Z.data}:{}}}}function _9($){if(Array.isArray($))throw new L(D.InvalidRequest,"Batched requests are not supported.",void 0,400);if(typeof $!=="object"||$===null||$.jsonrpc!=="2.0")throw new L(D.InvalidRequest,"Not a JSON-RPC 2.0 message.",void 0,400);let Z=$,z=Z.id,G=typeof z==="string"||typeof z==="number"&&Number.isFinite(z);if(typeof Z.method==="string"){if(Z.params!==void 0&&(typeof Z.params!=="object"||Z.params===null||Array.isArray(Z.params)))throw new L(D.InvalidRequest,"params must be an object.",void 0,400);if(z===void 0)return{kind:"notification",message:Z};if(!G)throw new L(D.InvalidRequest,"id must be a string or a number.",void 0,400);return{kind:"request",message:Z}}if(G&&(("result"in Z)||("error"in Z)))return{kind:"response",message:Z};throw new L(D.InvalidRequest,"Not a JSON-RPC request, notification or response.",void 0,400)}function k3($,Z){let z=$.outputSchema?.toJSONSchema(),G={...$.annotations,...$.title&&!Z?{title:$.title}:{}};return{name:$.name,...$.title?{title:$.title}:{},description:$.description,inputSchema:$.inputSchema.toJSONSchema(),...z&&(Z||z.type==="object")?{outputSchema:z}:{},...Object.keys(G).length>0?{annotations:G}:{}}}function q($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function D9($){let Z=/^=\?base64\?([A-Za-z0-9+/]*={0,2})\?=$/.exec($);if(!Z)return $;try{let z=Buffer.from(Z[1],"base64");return new TextDecoder("utf-8",{fatal:!0}).decode(z)}catch{return null}}import{createHmac as r$,timingSafeEqual as e$}from"crypto";function M3($,Z,z){let G=Buffer.from(JSON.stringify(z)).toString("base64url");return`${Z}.${G}.${O9($,Z,G).toString("base64url")}`}function R3($,Z,z,G=Date.now()){if(typeof z!=="string"||z.length>8192)return null;let W=z.split(".");if(W.length!==3||W[0]!==Z)return null;let[,X,Y]=W,K=Buffer.from(Y,"base64url"),Q=O9($,Z,X);if(K.length!==Q.length||!e$(K,Q))return null;let V;try{V=JSON.parse(Buffer.from(X,"base64url").toString("utf8"))}catch{return null}if(typeof V!=="object"||V===null)return null;if(typeof V.exp!=="number"||V.exp<=G)return null;return V}function O9($,Z,z){return r$("sha256",K3($)).update(`${Z}.${z}`).digest()}var E3="gemi.mcp.request-state.v1",A9="gemi.mcp.session.v1",$2=86400000,x9=600000,C9="gemi_approval",b3=2000,Z2={limit:600,window:60},z2={limit:30,window:60};class $3{registry;static token="router.mcp.http";endpoint;resolvers;context;allowedOrigins;rateLimit;maxBodyBytes;serverInfo;instructions;nonces;approvalTimeoutMs;onCall;feature;featureOn;pending=new Map;inflight=new Map;constructor($,Z,z={}){this.registry=$;if(typeof Z.url!=="string")throw Error(`route.mcp.remote.url is required: the endpoint's canonical URL, like "https://example.com/mcp".`);this.endpoint=X2(Z.url);let G=Z.resolvers??[];if(!Array.isArray(G)||G.length===0)throw Error("route.mcp.remote is enabled without a caller resolver. Configure route.mcp.remote.resolvers \u2014 an McpOAuthServer, an McpApiKeyResolver, or your own \u2014 or leave the endpoint off. Without one every request would be refused, or answered as nobody.");for(let W of G)if(typeof W?.resolve!=="function"||typeof W.name!=="string"||W.name==="")throw Error("route.mcp.remote.resolvers: each resolver needs a name and a resolve().");if(this.resolvers=G,K3(E3),this.context={resource:this.resource,registry:$},this.allowedOrigins=new Set((Z.allowedOrigins??[]).map((W)=>{if(new URL(W).origin!==W)throw Error(`route.mcp.remote.allowedOrigins: "${W}" is not an origin (scheme://host[:port]).`);return W})),this.allowedOrigins.add(this.endpoint.origin),this.rateLimit=Z.rateLimit===!1?!1:Z.rateLimit??Z2,this.maxBodyBytes=Z.maxBodyBytes??Math.ceil($.maxFileBytes*1.4)+1048576,this.serverInfo={name:Z.server?.name??"gemi",version:Z.server?.version??"1.0.0"},this.instructions=Z.server?.instructions,this.nonces=Z.nonces??new E9,this.approvalTimeoutMs=Z.approvalTimeoutMs??x9,Z.onCall!==void 0&&typeof Z.onCall!=="function")throw Error("route.mcp.remote.onCall must be a function.");if(this.onCall=Z.onCall,Z.feature!==void 0){if(typeof Z.feature!=="string"||Z.feature==="")throw Error("route.mcp.remote.feature must be a feature key from app/features.");this.feature=Z.feature}this.featureOn=z.featureOn??X3;for(let W of G)W.boot?.(this.context)}get resource(){return this.endpoint.href.replace(/\/$/,"")}async handle($){let Z=new URL($.url);if(Z.host!==this.endpoint.host)return null;if(this.feature!==void 0){if(!this.ownsPath(Z.pathname))return null;if(await this.featureOn(this.feature)!==!0)return null}for(let W of this.resolvers){let X=await W.handle?.($,this.context);if(X)return X}if(Z.pathname!==this.endpoint.pathname)return null;let z=$.headers.get("origin");if(z!==null&&!this.allowedOrigins.has(z))return f(R(null,new L(D.InvalidRequest,"Origin not allowed.")),403);let G=z?W2(z):{};if($.method==="OPTIONS")return new Response(null,{status:204,headers:{...G,"Access-Control-Allow-Methods":"POST","Access-Control-Allow-Headers":"Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id, Mcp-Method, Mcp-Name, Last-Event-ID","Access-Control-Max-Age":"600"}});if($.method!=="POST")return S9(new Response(null,{status:405,headers:{Allow:"POST, OPTIONS"}}),G);return S9(await this.post($),G)}ownsPath($){let Z=this.endpoint.pathname.replace(/\/$/,"");return $===this.endpoint.pathname||$===Z||$.startsWith(`${Z}/`)||$.startsWith("/.well-known/")}async post($){let Z=null;for(let Y of this.resolvers){let K=await Y.resolve($,this.context);if(K===null)continue;if(K.ok===!1)return await this.failedAttempt($)??this.unauthorized(K.description);Z={...K.principal,via:Y.name};break}if(!Z)return(j3($)!==null?await this.failedAttempt($):null)??this.unauthorized();let z=await this.spend(Z);if(z)return z;let G=$.headers.get("content-type")??"";if(!/^application\/json\s*(;|$)/i.test(G))return new Response("Content-Type must be application/json.",{status:415});let W;try{W=JSON.parse(await G2($,this.maxBodyBytes))}catch(Y){if(Y instanceof V3)return f(R(null,new L(D.InvalidRequest,`The request is larger than ${this.maxBodyBytes} bytes.`)),413);return f(R(null,new L(D.ParseError,"Parse error.")),400)}let X=new m($,{},"api",this.endpoint.pathname);return await g.run(X,async()=>{try{return await this.dispatch($,X,Z,W)}catch(Y){if(Y instanceof L){let K=q(W)&&(typeof W.id==="string"||typeof W.id==="number")?W.id:null;return f(R(K,Y),Y.status)}return console.error("[gemi/mcp] The MCP endpoint failed:",Y),f(R(null,new L(D.InternalError,"Internal error.")),500)}},{user:Z.user})}async dispatch($,Z,z,G){let W=_9(G),X={kind:"remote",req:Z,principal:z};if(W.kind==="response"){let F=this.session($,z),B=this.pending.get(String(W.message.id));if(B&&B.session===F.id)this.pending.delete(String(W.message.id)),B.resolve(W.message);return new Response(null,{status:202})}let{message:Y}=W,K=Y.params??{},Q=q(K._meta)?K._meta:{};if(typeof Q[S3]==="string"){if(this.checkModernHeaders($,Y,Q[S3]),W.kind==="notification")return new Response(null,{status:202});return await this.respond(Y,async(F,B)=>this.modern({principal:z,caller:X,message:Y,params:K,era:{modern:!0},stream:F,signal:B}),T9(K),$.signal)}if(Y.method==="initialize"){if(W.kind!=="request")throw new L(D.InvalidRequest,"initialize is a request.",void 0,400);return this.initialize(W.message,K,z)}let V=this.session($,z),H=$.headers.get("mcp-protocol-version");if(H!==null&&H!==V.state.v)throw new L(D.InvalidRequest,`MCP-Protocol-Version ${H} is not the session's ${V.state.v}.`,void 0,400);if(W.kind==="notification"){if(Y.method==="notifications/cancelled"){let F=K.requestId;this.inflight.get(`${V.id}:${String(F)}`)?.abort()}return new Response(null,{status:202})}let U=`${V.id}:${String(Y.id)}`,I=new AbortController;this.inflight.set(U,I);let J=AbortSignal.any([I.signal,$.signal]);try{return await this.respond(Y,async(F,B)=>this.legacy({principal:z,caller:X,message:Y,params:K,era:{modern:!1,session:V.state,sessionId:V.id},stream:F,signal:B}),T9(K)||K2(this.registry,Y,V.state),J,()=>this.inflight.delete(U))}catch(F){throw this.inflight.delete(U),F}}async modern($){switch($.message.method){case"server/discover":return this.complete({supportedVersions:C3,capabilities:{tools:{}},...this.instructions?{instructions:this.instructions}:{},ttlMs:60000,cacheScope:"private"});case"tools/list":return this.complete({tools:(await this.registry.available($.caller)).map((Z)=>k3(Z,!0)),ttlMs:60000,cacheScope:"private"});case"tools/call":return await this.callTool($);default:throw new L(D.MethodNotFound,`Method not found: ${$.message.method}`,void 0,404)}}async legacy($){switch($.message.method){case"ping":return{};case"tools/list":return{tools:(await this.registry.available($.caller)).map((Z)=>k3(Z,!1))};case"tools/call":return await this.callTool($);default:throw new L(D.MethodNotFound,`Method not found: ${$.message.method}`)}}complete($){return{resultType:"complete",...$,_meta:{[T3]:this.serverInfo}}}initialize($,Z,z){let G=Z.protocolVersion,W=Y3.includes(G)?G:Y3[0],X=q(Z.capabilities)?Z.capabilities:{},Y={v:W,e:q9(X.elicitation),p:Q3(z),exp:Date.now()+$2},K=M3(A9,"gms1",Y);return f({jsonrpc:"2.0",id:$.id,result:{protocolVersion:W,capabilities:{tools:{listChanged:!1}},serverInfo:this.serverInfo,...this.instructions?{instructions:this.instructions}:{}}},200,{"Mcp-Session-Id":K})}session($,Z){let z=$.headers.get("mcp-session-id");if(!z)throw new L(D.InvalidRequest,"Missing Mcp-Session-Id. Send initialize first, or a request carrying io.modelcontextprotocol/protocolVersion in _meta.",void 0,400);let G=R3(A9,"gms1",z);if(!G||G.p!==Q3(Z))throw new L(D.InvalidRequest,"Session not found.",void 0,404);return{id:z,state:G}}checkModernHeaders($,Z,z){if(!x3.includes(z))throw new L(D.UnsupportedProtocolVersion,"Unsupported protocol version",{supported:C3,requested:z},400);let G=(Y)=>new L(D.HeaderMismatch,`Header mismatch: ${Y}`,void 0,400);if($.headers.get("mcp-protocol-version")!==z)throw G("MCP-Protocol-Version does not match the protocol version in _meta.");if($.headers.get("mcp-method")!==Z.method)throw G("Mcp-Method does not match the method.");let W=Z.params??{},X=Z.method==="tools/call"||Z.method==="prompts/get"?W.name:Z.method==="resources/read"?W.uri:void 0;if(X!==void 0){let Y=$.headers.get("mcp-name");if(Y===null||D9(Y)!==X)throw G("Mcp-Name does not match the request's name.")}}async callTool($){let Z=$.params.name;if(typeof Z!=="string")throw new L(D.InvalidParams,"tools/call needs a tool name.");let z=$.params.arguments??{};if(!this.onCall)return await this.runTool($,Z,z,{approved:!1});let G=performance.now(),W={approved:!1};try{let X=await this.runTool($,Z,z,W);if(!W.pending)await this.report($,Z,z,W,G);return X}catch(X){if(!W.outcome){if(W.outcome="error",W.message=X instanceof L?X.message:"Internal error.",!(X instanceof L))W.error=X}throw await this.report($,Z,z,W,G),X}}async report($,Z,z,G,W){let{principal:X}=$;try{await this.onCall({user:X.user,via:X.via,credentialId:X.id,clientId:X.clientId??null,scopes:X.scopes,tool:Z,arguments:z,outcome:G.outcome??"ok",...G.reason!==void 0?{reason:G.reason}:{},...G.message!==void 0?{message:G.message}:{},...G.status!==void 0?{status:G.status}:{},...G.error!==void 0?{error:G.error}:{},approved:G.approved,durationMs:Math.round((performance.now()-W)*1000)/1000,req:$.caller.req})}catch(Y){console.error(`[gemi/mcp] route.mcp.remote.onCall failed for "${Z}":`,Y)}}async runTool($,Z,z,G){let{caller:W,principal:X}=$,Y=(J,F)=>{G.outcome="denied",G.reason=J,G.message=F},K=(J,F,B)=>{if(G.outcome="error",G.message=J,F!==void 0)G.status=F;if(B!==void 0)G.error=B},Q=(await this.registry.available(W,{names:[Z]}))[0];if(!Q)throw Y("unknown-tool",`Unknown tool: ${Z}`),new L(D.InvalidParams,`Unknown tool: ${Z}`);if(Q.requiresApproval){let J=Q.inputSchema.safeParse(z);if(J.ok===!1){let B=`Invalid arguments for "${Z}": ${J.errors.join(", ")}`;return K(B),this.toolResult($,{content:[{type:"text",text:B}],isError:!0})}if($.era.modern&&q($.params.inputResponses)&&$.params.requestState!==void 0||await this.registry.approvalRequired(W,Z,z,{signal:$.signal})){let B=await this.approval($,Q,z,Y,G);if(B.kind==="answer")return B.result;G.approved=!0}}let V=Q2($),H;try{H=await this.registry.execute(W,Z,z,void 0,{approved:G.approved,signal:$.signal,...V?{progress:V}:{}})}catch(J){if(J instanceof O){if(J.status===401||J.status===403)Y("forbidden",J.message),G.status=J.status;else K(J.message,J.status);return this.toolResult($,{content:[{type:"text",text:J.message}],isError:!0})}if(J instanceof v){let B=J.reason==="unknown-tool"?`Unknown tool: ${Z}`:J.message;throw Y(J.reason,B),new L(D.InvalidParams,B)}console.error(`[gemi/mcp] "${Z}" failed for ${X.via}:${X.id}:`,J);let F=`"${Z}" failed on the server.`;return K(F,void 0,J),this.toolResult($,{content:[{type:"text",text:F}],isError:!0})}let U=typeof H==="string"?H:JSON.stringify(H??null),I=Q.outputSchema&&($.era.modern||q(H))?{structuredContent:H}:{};return G.outcome="ok",this.toolResult($,{content:[{type:"text",text:U}],...I,isError:!1})}toolResult($,Z){return $.era.modern?this.complete(Z):Z}async approval($,Z,z,G,W){let X=V2(Z,z),Y=(I,J="approval-declined")=>{return G(J,I),{kind:"answer",result:this.toolResult($,{content:[{type:"text",text:I}],isError:!0})}},K=(I,J)=>{return G(I,J.message),J};if($.era.modern){let I=q($.params._meta)?$.params._meta:{},J=q(I[q3])?I[q3]:{},F=q($.params.inputResponses)?$.params.inputResponses:null,B=$.params.requestState,T=Y2(z);if(F&&B!==void 0){let C=R3(E3,"grs1",B);if(!C||C.p!==Q3($.principal)||C.t!==Z.name||C.a!==T)throw K("approval-invalid",new L(D.InvalidParams,"requestState is not valid for this call."));if(!await this.spendNonce(C.n,C.exp))throw K("approval-replayed",new L(D.InvalidParams,"requestState has already been used."));return k9(F[C9])?{kind:"approved"}:Y(`The user did not approve "${Z.name}", and it did not run.`)}if(!q9(J.elicitation))throw K("approval-unavailable",new L(D.MissingRequiredClientCapability,`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation).`,{requiredCapabilities:{elicitation:{form:{}}}},400));let j={p:Q3($.principal),t:Z.name,a:T,n:j9(16).toString("base64url"),exp:Date.now()+x9};return W.pending=!0,{kind:"answer",result:{resultType:"input_required",inputRequests:{[C9]:{method:"elicitation/create",params:{mode:"form",...X}}},requestState:M3(E3,"grs1",j),_meta:{[T3]:this.serverInfo}}}}let Q=$.era;if(!Q.session.e||!$.stream)return Y(`"${Z.name}" needs the user's approval, and this client cannot ask for it (elicitation). It did not run.`,"approval-unavailable");let V=`gemi-approval-${j9(12).toString("base64url")}`,H=Q.sessionId,U=await new Promise((I)=>{let J=setTimeout(()=>{this.pending.delete(V),I(null)},this.approvalTimeoutMs),F=(B)=>{clearTimeout(J),I(B)};this.pending.set(V,{session:H,resolve:F}),$.signal.addEventListener("abort",()=>{this.pending.delete(V),F(null)}),$.stream.send({jsonrpc:"2.0",id:V,method:"elicitation/create",params:Q.session.v==="2025-11-25"?{mode:"form",...X}:X})});return U&&!U.error&&k9(U.result)?{kind:"approved"}:Y(`The user did not approve "${Z.name}", and it did not run.`)}async spendNonce($,Z){try{return await this.nonces.consume($,Z)}catch(z){return console.error("[gemi/mcp] Spending an approval failed:",z),!1}}async respond($,Z,z,G,W){if(!z)try{let Q=await Z(null,G);return f({jsonrpc:"2.0",id:$.id,result:Q},200)}finally{W?.()}let X=new AbortController,Y=AbortSignal.any([X.signal,G]),K=new f9(()=>X.abort());return(async()=>{try{let Q=await Z(K,Y);K.send({jsonrpc:"2.0",id:$.id,result:Q})}catch(Q){if(Q instanceof L)K.send(R($.id,Q));else console.error("[gemi/mcp] The MCP endpoint failed:",Q),K.send(R($.id,new L(D.InternalError,"Internal error.")))}finally{W?.(),K.close()}})(),new Response(K.readable,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-store","X-Accel-Buffering":"no"}})}unauthorized($){let Z=this.resolvers.map((G)=>G.challenge?.(this.context)).find(Boolean)??'Bearer realm="mcp"',z=$?`${Z}, error="invalid_token", error_description="${$.replace(/["\\]/g,"")}"`:Z;return f(R(null,new L(D.InvalidRequest,"Unauthorized.")),401,{"WWW-Authenticate":z})}async failedAttempt($){let Z=R9(new m($,{},"api",this.endpoint.pathname)),z=await A3(`mcp-auth-failed:${Z}`,z2);return z===null?null:M9(z)}async spend($){if(!this.rateLimit)return null;let Z=await A3(`mcp-endpoint:${$.via}:${$.id}`,this.rateLimit);return Z===null?null:M9(Z)}}class f9{readable;controller;closed=!1;encoder=new TextEncoder;constructor($){this.readable=new ReadableStream({start:(Z)=>{this.controller=Z},cancel:()=>{this.closed=!0,$()}})}send($){if(this.closed)return;this.controller.enqueue(this.encoder.encode(`event: message
3
3
  data: ${JSON.stringify($)}
4
4
 
5
5
  `))}close(){if(this.closed)return;this.closed=!0,this.controller.close()}}class V3 extends Error{}async function G2($,Z){let z=Number($.headers.get("content-length"));if(Number.isFinite(z)&&z>Z)throw new V3;if(!$.body)return"";let G=$.body.getReader(),W=[],X=0;for(;;){let{done:Y,value:K}=await G.read();if(Y)break;if(X+=K.byteLength,X>Z)throw await G.cancel(),new V3;W.push(K)}return Buffer.concat(W).toString("utf8")}function f($,Z,z={}){return new Response(JSON.stringify($),{status:Z,headers:{"Content-Type":"application/json","Cache-Control":"no-store",...z}})}function S9($,Z){for(let[z,G]of Object.entries(Z))$.headers.set(z,G);return $}function W2($){return{"Access-Control-Allow-Origin":$,"Access-Control-Expose-Headers":"Mcp-Session-Id, WWW-Authenticate",Vary:"Origin"}}function X2($){let Z;try{Z=new URL($)}catch{throw Error(`route.mcp.remote.url: "${$}" is not a URL.`)}let z=Z.hostname==="localhost"||Z.hostname==="127.0.0.1"||Z.hostname==="[::1]";if(Z.protocol!=="https:"&&!(Z.protocol==="http:"&&z))throw Error("route.mcp.remote.url must be https (http only on localhost): tokens travel to it.");if(Z.search||Z.hash||Z.username||Z.password)throw Error("route.mcp.remote.url must have no query, fragment or credentials.");if(Z.pathname==="/"||Z.pathname.endsWith("/"))throw Error('route.mcp.remote.url needs a path of its own, like "/mcp", without a trailing slash.');return Z}function Q3($){return y9("sha256").update(`${$.via}\x00${$.id}\x00${$.user?.id}`).digest("base64url").slice(0,32)}function Y2($){return y9("sha256").update(b9($??{})).digest("base64url")}function q9($){if(!q($))return!1;if(Object.keys($).length===0)return!0;return"form"in $}function T9($){let Z=q($._meta)?$._meta:{};return typeof Z.progressToken==="string"||typeof Z.progressToken==="number"}function K2($,Z,z){if(Z.method!=="tools/call"||!z.e)return!1;let G=Z.params?.name;return typeof G==="string"&&$.descriptors({names:[G]})[0]?.requiresApproval===!0}function Q2($){let z=(q($.params._meta)?$.params._meta:{}).progressToken;if(!$.stream||typeof z!=="string"&&typeof z!=="number")return;let G=-1/0;return(W)=>{if(typeof W?.progress!=="number"||!Number.isFinite(W.progress)||W.progress<=G)return;G=W.progress,$.stream.send({jsonrpc:"2.0",method:"notifications/progress",params:{progressToken:z,progress:W.progress,...typeof W.total==="number"?{total:W.total}:{},...typeof W.message==="string"?{message:W.message.slice(0,1000)}:{}}})}}function V2($,Z){let z=JSON.stringify(Z??{},null,1),G=z.length>b3?`${z.slice(0,b3)}\u2026 (${z.length-b3} more characters not shown)`:z;return{message:`Allow "${$.title??$.name}" to run? ${$.description}