@every-app/sdk 0.2.0 → 0.3.0-rc.10

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 (189) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +609 -3
  3. package/dist/cloudflare/catalogSettings.generated.d.ts +81 -0
  4. package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
  5. package/dist/cloudflare/catalogSettings.generated.js +174 -0
  6. package/dist/cloudflare/index.d.ts +23 -0
  7. package/dist/cloudflare/index.d.ts.map +1 -0
  8. package/dist/cloudflare/index.js +24 -0
  9. package/dist/cloudflare/sentinel.d.ts +127 -0
  10. package/dist/cloudflare/sentinel.d.ts.map +1 -0
  11. package/dist/cloudflare/sentinel.js +85 -0
  12. package/dist/cloudflare/worker.d.ts +805 -0
  13. package/dist/cloudflare/worker.d.ts.map +1 -0
  14. package/dist/cloudflare/worker.js +997 -0
  15. package/dist/dev/index.d.ts +8 -0
  16. package/dist/dev/index.d.ts.map +1 -0
  17. package/dist/dev/index.js +7 -0
  18. package/dist/dev/keypair.d.ts +26 -0
  19. package/dist/dev/keypair.d.ts.map +1 -0
  20. package/dist/dev/keypair.js +62 -0
  21. package/dist/index.d.ts +6 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +5 -0
  24. package/dist/internal/aiDefault.d.ts +204 -0
  25. package/dist/internal/aiDefault.d.ts.map +1 -0
  26. package/dist/internal/aiDefault.js +334 -0
  27. package/dist/internal/aiProviders.d.ts +72 -0
  28. package/dist/internal/aiProviders.d.ts.map +1 -0
  29. package/dist/internal/aiProviders.js +233 -0
  30. package/dist/internal/appSettings.d.ts +315 -0
  31. package/dist/internal/appSettings.d.ts.map +1 -0
  32. package/dist/internal/appSettings.js +549 -0
  33. package/dist/internal/audit.d.ts +108 -0
  34. package/dist/internal/audit.d.ts.map +1 -0
  35. package/dist/internal/audit.js +235 -0
  36. package/dist/internal/capabilities.d.ts +3174 -0
  37. package/dist/internal/capabilities.d.ts.map +1 -0
  38. package/dist/internal/capabilities.js +1110 -0
  39. package/dist/internal/catalog/commerce.d.ts +394 -0
  40. package/dist/internal/catalog/commerce.d.ts.map +1 -0
  41. package/dist/internal/catalog/commerce.js +477 -0
  42. package/dist/internal/catalog/comms.d.ts +375 -0
  43. package/dist/internal/catalog/comms.d.ts.map +1 -0
  44. package/dist/internal/catalog/comms.js +520 -0
  45. package/dist/internal/catalog/index.d.ts +1973 -0
  46. package/dist/internal/catalog/index.d.ts.map +1 -0
  47. package/dist/internal/catalog/index.js +19 -0
  48. package/dist/internal/catalog/inference.d.ts +393 -0
  49. package/dist/internal/catalog/inference.d.ts.map +1 -0
  50. package/dist/internal/catalog/inference.js +460 -0
  51. package/dist/internal/catalog/infra.d.ts +423 -0
  52. package/dist/internal/catalog/infra.d.ts.map +1 -0
  53. package/dist/internal/catalog/infra.js +543 -0
  54. package/dist/internal/catalog/search.d.ts +400 -0
  55. package/dist/internal/catalog/search.d.ts.map +1 -0
  56. package/dist/internal/catalog/search.js +463 -0
  57. package/dist/internal/devProviders.d.ts +49 -0
  58. package/dist/internal/devProviders.d.ts.map +1 -0
  59. package/dist/internal/devProviders.js +80 -0
  60. package/dist/internal/email.d.ts +280 -0
  61. package/dist/internal/email.d.ts.map +1 -0
  62. package/dist/internal/email.js +613 -0
  63. package/dist/internal/events.d.ts +193 -0
  64. package/dist/internal/events.d.ts.map +1 -0
  65. package/dist/internal/events.js +367 -0
  66. package/dist/internal/gatewaySettings.d.ts +83 -0
  67. package/dist/internal/gatewaySettings.d.ts.map +1 -0
  68. package/dist/internal/gatewaySettings.js +215 -0
  69. package/dist/internal/identity.d.ts +57 -5
  70. package/dist/internal/identity.d.ts.map +1 -1
  71. package/dist/internal/identity.js +99 -22
  72. package/dist/internal/index.d.ts +22 -1
  73. package/dist/internal/index.d.ts.map +1 -1
  74. package/dist/internal/index.js +22 -1
  75. package/dist/internal/members.d.ts +36 -0
  76. package/dist/internal/members.d.ts.map +1 -0
  77. package/dist/internal/members.js +7 -0
  78. package/dist/internal/oauthClient.d.ts +61 -0
  79. package/dist/internal/oauthClient.d.ts.map +1 -0
  80. package/dist/internal/oauthClient.js +133 -0
  81. package/dist/internal/oauthPresets.d.ts +33 -0
  82. package/dist/internal/oauthPresets.d.ts.map +1 -0
  83. package/dist/internal/oauthPresets.js +1064 -0
  84. package/dist/internal/oauthScopes.d.ts +172 -0
  85. package/dist/internal/oauthScopes.d.ts.map +1 -0
  86. package/dist/internal/oauthScopes.js +510 -0
  87. package/dist/internal/oauthSpec.d.ts +102 -0
  88. package/dist/internal/oauthSpec.d.ts.map +1 -0
  89. package/dist/internal/oauthSpec.js +789 -0
  90. package/dist/internal/organizationName.d.ts +18 -0
  91. package/dist/internal/organizationName.d.ts.map +1 -0
  92. package/dist/internal/organizationName.js +24 -0
  93. package/dist/internal/protocol.d.ts +150 -3
  94. package/dist/internal/protocol.d.ts.map +1 -1
  95. package/dist/internal/protocol.js +163 -2
  96. package/dist/internal/providerApps.d.ts +75 -0
  97. package/dist/internal/providerApps.d.ts.map +1 -0
  98. package/dist/internal/providerApps.js +59 -0
  99. package/dist/internal/providerRegistry.d.ts +218 -0
  100. package/dist/internal/providerRegistry.d.ts.map +1 -0
  101. package/dist/internal/providerRegistry.js +432 -0
  102. package/dist/internal/providerSpec.d.ts +66 -0
  103. package/dist/internal/providerSpec.d.ts.map +1 -0
  104. package/dist/internal/providerSpec.js +1154 -0
  105. package/dist/internal/remoteMcp.d.ts +188 -0
  106. package/dist/internal/remoteMcp.d.ts.map +1 -0
  107. package/dist/internal/remoteMcp.js +543 -0
  108. package/dist/internal/signInProviders.d.ts +104 -0
  109. package/dist/internal/signInProviders.d.ts.map +1 -0
  110. package/dist/internal/signInProviders.js +245 -0
  111. package/dist/internal/tools.d.ts +115 -0
  112. package/dist/internal/tools.d.ts.map +1 -0
  113. package/dist/internal/tools.js +80 -0
  114. package/dist/manifest.d.ts +238 -0
  115. package/dist/manifest.d.ts.map +1 -0
  116. package/dist/manifest.js +30 -0
  117. package/dist/server/ai.d.ts +111 -0
  118. package/dist/server/ai.d.ts.map +1 -0
  119. package/dist/server/ai.js +145 -0
  120. package/dist/server/aiBinding.d.ts +68 -0
  121. package/dist/server/aiBinding.d.ts.map +1 -0
  122. package/dist/server/aiBinding.js +294 -0
  123. package/dist/server/attribution.d.ts +43 -0
  124. package/dist/server/attribution.d.ts.map +1 -0
  125. package/dist/server/attribution.js +75 -0
  126. package/dist/server/authorizeUrl.d.ts +43 -0
  127. package/dist/server/authorizeUrl.d.ts.map +1 -0
  128. package/dist/server/authorizeUrl.js +106 -0
  129. package/dist/server/connectUrl.d.ts +21 -0
  130. package/dist/server/connectUrl.d.ts.map +1 -0
  131. package/dist/server/connectUrl.js +37 -0
  132. package/dist/server/context.d.ts +68 -0
  133. package/dist/server/context.d.ts.map +1 -0
  134. package/dist/server/context.js +117 -0
  135. package/dist/server/emailBinding.d.ts +72 -0
  136. package/dist/server/emailBinding.d.ts.map +1 -0
  137. package/dist/server/emailBinding.js +124 -0
  138. package/dist/server/emit.d.ts +63 -0
  139. package/dist/server/emit.d.ts.map +1 -0
  140. package/dist/server/emit.js +101 -0
  141. package/dist/server/env.d.ts +44 -0
  142. package/dist/server/env.d.ts.map +1 -0
  143. package/dist/server/env.js +1 -0
  144. package/dist/server/everyApp.d.ts +65 -19
  145. package/dist/server/everyApp.d.ts.map +1 -1
  146. package/dist/server/everyApp.js +195 -30
  147. package/dist/server/fromMcpTools.d.ts +89 -0
  148. package/dist/server/fromMcpTools.d.ts.map +1 -0
  149. package/dist/server/fromMcpTools.js +192 -0
  150. package/dist/server/gatewayFetch.d.ts +54 -14
  151. package/dist/server/gatewayFetch.d.ts.map +1 -1
  152. package/dist/server/gatewayFetch.js +201 -37
  153. package/dist/server/gatewayUrl.d.ts +13 -0
  154. package/dist/server/gatewayUrl.d.ts.map +1 -0
  155. package/dist/server/gatewayUrl.js +34 -0
  156. package/dist/server/index.d.ts +23 -3
  157. package/dist/server/index.d.ts.map +1 -1
  158. package/dist/server/index.js +19 -2
  159. package/dist/server/integrationFetch.d.ts +162 -0
  160. package/dist/server/integrationFetch.d.ts.map +1 -0
  161. package/dist/server/integrationFetch.js +688 -0
  162. package/dist/server/listMembers.d.ts +32 -0
  163. package/dist/server/listMembers.d.ts.map +1 -0
  164. package/dist/server/listMembers.js +71 -0
  165. package/dist/server/nodeServer.d.ts +48 -0
  166. package/dist/server/nodeServer.d.ts.map +1 -0
  167. package/dist/server/nodeServer.js +45 -0
  168. package/dist/server/refusal.d.ts +55 -0
  169. package/dist/server/refusal.d.ts.map +1 -0
  170. package/dist/server/refusal.js +193 -0
  171. package/dist/server/sendEmail.d.ts +39 -0
  172. package/dist/server/sendEmail.d.ts.map +1 -0
  173. package/dist/server/sendEmail.js +114 -0
  174. package/dist/server/tools.d.ts +184 -0
  175. package/dist/server/tools.d.ts.map +1 -0
  176. package/dist/server/tools.js +347 -0
  177. package/dist/server/toolsEndpoint.d.ts +32 -0
  178. package/dist/server/toolsEndpoint.d.ts.map +1 -0
  179. package/dist/server/toolsEndpoint.js +237 -0
  180. package/dist/tanstack-start/index.d.ts +9 -0
  181. package/dist/tanstack-start/index.d.ts.map +1 -0
  182. package/dist/tanstack-start/index.js +29 -0
  183. package/dist/testing/index.d.ts +93 -0
  184. package/dist/testing/index.d.ts.map +1 -0
  185. package/dist/testing/index.js +156 -0
  186. package/package.json +42 -8
  187. package/dist/server/mcp.d.ts +0 -66
  188. package/dist/server/mcp.d.ts.map +0 -1
  189. package/dist/server/mcp.js +0 -147
@@ -1,20 +1,41 @@
1
1
  /**
2
2
  * `everyApp()` — the app-side identity boundary.
3
3
  *
4
- * import manifest from "../everyapp.config.js";
5
- * export default everyApp(handler, manifest);
4
+ * export default everyApp(handler, { tools });
6
5
  *
7
6
  * The wrapper verifies the gateway-injected identity before app code runs,
8
7
  * stores the result on the original Request, and then delegates to the
9
- * worker-style handler.
8
+ * worker-style handler. The expected audience is the Worker's own name in
9
+ * `env.EVERYAPP_AUDIENCE`, which `everyAppWorker()` sets at deploy (the
10
+ * gateway stamps every token it mints for the app with it); only in
11
+ * development, where `everyapp dev` mints for the app id, does the app id in
12
+ * `env.EVERYAPP_APP_ID` stand in. The Worker never imports
13
+ * `everyapp.config.ts` (the Cloudflare Vite plugin hides every file
14
+ * `cloudflare.config.ts` imports from the Worker in dev).
15
+ * It also answers the gateway's internal tools contract
16
+ * (`/__everyapp/tools/*`) for the app's `defineTools()` catalog.
17
+ *
18
+ * Around the handler and around each tool call it opens the request
19
+ * context (context.ts): `currentUser()` reads the user anywhere below, and
20
+ * every call back to the Gateway is attributed to the request without a
21
+ * `for`. A deployed Worker is pinned to its organization
22
+ * (`EVERY_APP_ORG_ID`), and an identity for any other is refused on both
23
+ * paths. The response leaves without `Set-Cookie`: the perimeter strips
24
+ * every `Cookie` before a request reaches the app, so a cookie the app's
25
+ * framework sets could never come back, and one named like the Gateway's
26
+ * session cookie would lock the person out of the app host.
10
27
  */
11
- import { ConfigurationError, IdentityError, type EveryAppUser, type IdentityResult } from "../internal/index.js";
12
- export { ConfigurationError, IdentityError };
13
- export type { EveryAppUser, IdentityResult };
14
- export interface ExecutionContextLike {
15
- waitUntil(promise: Promise<unknown>): void;
16
- passThroughOnException?(): void;
17
- }
28
+ import { ConfigurationError, IdentityError, isAdmin, type EveryAppUser, type IdentityResult, type OrgRole } from "../internal/index.js";
29
+ import type { ToolSet } from "./tools.js";
30
+ export { ConfigurationError, IdentityError, isAdmin };
31
+ export type { EveryAppUser, IdentityResult, OrgRole };
32
+ /**
33
+ * The runtime's `ExecutionContext`, which `everyApp()` passes to the handler
34
+ * as the Worker received it, so it goes on to Hono's `app.fetch(request,
35
+ * env, ctx)` or React Router's request handler as is. Tests that call
36
+ * `fetch` themselves pass a stub cast to it.
37
+ */
38
+ export type ExecutionContextLike = ExecutionContext;
18
39
  export interface EveryAppManifestLike {
19
40
  id: string;
20
41
  [key: string]: unknown;
@@ -31,25 +52,50 @@ export interface EveryAppOptions {
31
52
  * Never enable this in production.
32
53
  */
33
54
  allowDevIdentities?: boolean;
55
+ /**
56
+ * Agent tools from `defineTools()`. The gateway snapshots them at deploy
57
+ * and serves them to MCP clients; see `defineTools`.
58
+ */
59
+ tools?: ToolSet;
34
60
  /** Override for tests. */
35
61
  now?: number;
36
62
  }
37
- /** The handler accepted by everyApp, with the verified user as a 4th argument. */
38
- export type EveryAppHandler<TEnv = Record<string, unknown>> = (request: Request, env: TEnv, ctx: ExecutionContextLike, user: EveryAppUser | null) => Response | Promise<Response>;
39
- interface EveryAppExport<TEnv> {
40
- fetch(request: Request, env: TEnv, ctx: ExecutionContextLike): Promise<Response>;
63
+ /**
64
+ * The handler accepted by everyApp, with the verified user as a 4th argument.
65
+ * `TCtx` narrows the context, e.g. to `ExecutionContext<Props>`.
66
+ */
67
+ export type EveryAppHandler<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext> = (request: Request, env: TEnv, ctx: TCtx, user: EveryAppUser | null) => Response | Promise<Response>;
68
+ interface EveryAppExport<TEnv, TCtx extends ExecutionContextLike> {
69
+ fetch(request: Request, env: TEnv, ctx: TCtx): Promise<Response>;
41
70
  }
42
71
  /**
43
72
  * Return the verified Every App user for this request, or null for a declared
44
- * public request. Uses the request cache first, then verifies the identity
45
- * headers from the app id and public keys configured in env.
73
+ * public request. `request` is the inbound `Request` or just its `Headers`
74
+ * (a framework that hands out headers alone needs no made-up Request).
75
+ * Answers from the request context or the per-request cache first, then
76
+ * verifies the identity headers from the audience and public keys in env.
77
+ * Inside a handler `everyApp()` serves, `currentUser()` is the shorter way.
46
78
  */
47
- export declare function getEveryAppUser(request: Request, env: object): Promise<EveryAppUser | null>;
79
+ export declare function getEveryAppUser(request: Request | Headers, env: object): Promise<EveryAppUser | null>;
48
80
  /**
49
81
  * Return the verified user, or throw the same 401 JSON Response shape as
50
82
  * everyApp() when the request is public or unauthenticated.
51
83
  */
52
- export declare function requireEveryAppUser(request: Request, env: object): Promise<EveryAppUser>;
84
+ export declare function requireEveryAppUser(request: Request | Headers, env: object): Promise<EveryAppUser>;
85
+ /**
86
+ * The user of the request being served (`currentUser()`), or throw the
87
+ * same 401 JSON Response as `requireEveryAppUser()` on a public route.
88
+ * Outside a request (`withOrganization()` work, a handler not under
89
+ * `everyApp()`) it throws `RequestContextError`, as `currentUser()` does.
90
+ */
91
+ export declare function requireCurrentUser(): EveryAppUser;
53
92
  export declare function hasScope(user: EveryAppUser, scope: string): boolean;
54
- export declare function everyApp<TEnv = Record<string, unknown>>(handler: EveryAppHandler<TEnv>, manifest: EveryAppManifestLike, options?: EveryAppOptions): EveryAppExport<TEnv>;
93
+ /** Wrap a Worker fetch handler with Every App identity verification. */
94
+ export declare function everyApp<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext>(handler: EveryAppHandler<TEnv, TCtx>, options?: EveryAppOptions): EveryAppExport<TEnv, TCtx>;
95
+ /**
96
+ * @deprecated Drop the manifest: the app id now comes from
97
+ * `env.EVERYAPP_APP_ID` and the audience from `env.EVERYAPP_AUDIENCE`.
98
+ * When passed, it must match the app id.
99
+ */
100
+ export declare function everyApp<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext>(handler: EveryAppHandler<TEnv, TCtx>, manifest: EveryAppManifestLike | undefined, options?: EveryAppOptions): EveryAppExport<TEnv, TCtx>;
55
101
  //# sourceMappingURL=everyApp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"everyApp.d.ts","sourceRoot":"","sources":["../../src/server/everyApp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAEL,kBAAkB,EAElB,aAAa,EAIb,KAAK,YAAY,EACjB,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3C,sBAAsB,CAAC,IAAI,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,kFAAkF;AAClF,MAAM,MAAM,eAAe,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAC5D,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,oBAAoB,EACzB,IAAI,EAAE,YAAY,GAAG,IAAI,KACtB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,UAAU,cAAc,CAAC,IAAI;IAC3B,KAAK,CACH,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAiFD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW9B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,CAAC,CAevB;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,wBAAgB,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrD,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,EAC9B,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,eAAoB,GAC5B,cAAc,CAAC,IAAI,CAAC,CAqBtB"}
1
+ {"version":3,"file":"everyApp.d.ts","sourceRoot":"","sources":["../../src/server/everyApp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAGL,kBAAkB,EAElB,aAAa,EAMb,OAAO,EACP,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,OAAO,EAEb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,CACzB,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,SAAS,oBAAoB,GAAG,gBAAgB,IAClD,CACF,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,YAAY,GAAG,IAAI,KACtB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,UAAU,cAAc,CAAC,IAAI,EAAE,IAAI,SAAS,oBAAoB;IAC9D,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClE;AAuKD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,GAAG,OAAO,EAC1B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW9B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,GAAG,OAAO,EAC1B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,CAAC,CAevB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAMjD;AA0BD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnE;AAUD,wEAAwE;AACxE,wBAAgB,QAAQ,CACtB,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,SAAS,oBAAoB,GAAG,gBAAgB,EAEpD,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,EACpC,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC9B;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,SAAS,oBAAoB,GAAG,gBAAgB,EAEpD,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,EACpC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,EAC1C,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC"}
@@ -1,15 +1,34 @@
1
1
  /**
2
2
  * `everyApp()` — the app-side identity boundary.
3
3
  *
4
- * import manifest from "../everyapp.config.js";
5
- * export default everyApp(handler, manifest);
4
+ * export default everyApp(handler, { tools });
6
5
  *
7
6
  * The wrapper verifies the gateway-injected identity before app code runs,
8
7
  * stores the result on the original Request, and then delegates to the
9
- * worker-style handler.
8
+ * worker-style handler. The expected audience is the Worker's own name in
9
+ * `env.EVERYAPP_AUDIENCE`, which `everyAppWorker()` sets at deploy (the
10
+ * gateway stamps every token it mints for the app with it); only in
11
+ * development, where `everyapp dev` mints for the app id, does the app id in
12
+ * `env.EVERYAPP_APP_ID` stand in. The Worker never imports
13
+ * `everyapp.config.ts` (the Cloudflare Vite plugin hides every file
14
+ * `cloudflare.config.ts` imports from the Worker in dev).
15
+ * It also answers the gateway's internal tools contract
16
+ * (`/__everyapp/tools/*`) for the app's `defineTools()` catalog.
17
+ *
18
+ * Around the handler and around each tool call it opens the request
19
+ * context (context.ts): `currentUser()` reads the user anywhere below, and
20
+ * every call back to the Gateway is attributed to the request without a
21
+ * `for`. A deployed Worker is pinned to its organization
22
+ * (`EVERY_APP_ORG_ID`), and an identity for any other is refused on both
23
+ * paths. The response leaves without `Set-Cookie`: the perimeter strips
24
+ * every `Cookie` before a request reaches the app, so a cookie the app's
25
+ * framework sets could never come back, and one named like the Gateway's
26
+ * session cookie would lock the person out of the app host.
10
27
  */
11
- import { APP_ID_ENV, ConfigurationError, DEV_ENV, IdentityError, ISSUER_ENV, PUBLIC_KEYS_ENV, getIdentityFromRequest, } from "../internal/index.js";
12
- export { ConfigurationError, IdentityError };
28
+ import { APP_ID_ENV, AUDIENCE_ENV, ConfigurationError, DEV_ENV, IdentityError, IDENTITY_HEADER, ISSUER_ENV, ORG_ID_ENV, PUBLIC_KEYS_ENV, getIdentityFromRequest, isAdmin, } from "../internal/index.js";
29
+ import { currentUser, serveRequest } from "./context.js";
30
+ import { handleToolsRequest } from "./toolsEndpoint.js";
31
+ export { ConfigurationError, IdentityError, isAdmin };
13
32
  const requestIdentities = new WeakMap();
14
33
  function envValue(env, key) {
15
34
  if (!env || typeof env !== "object")
@@ -19,7 +38,7 @@ function envValue(env, key) {
19
38
  }
20
39
  function configFrom(manifest, options = {}) {
21
40
  return {
22
- audience: manifest.id,
41
+ manifestAppId: manifest?.id,
23
42
  issuer: options.issuer,
24
43
  keysEnvVar: options.keysEnvVar ?? PUBLIC_KEYS_ENV,
25
44
  publicKeys: options.publicKeys,
@@ -27,51 +46,125 @@ function configFrom(manifest, options = {}) {
27
46
  now: options.now,
28
47
  };
29
48
  }
49
+ /**
50
+ * The app id: EVERYAPP_APP_ID, or a manifest passed to everyApp() for
51
+ * Workers without it; the two must agree when both are present.
52
+ */
53
+ function appIdFor(env, config) {
54
+ const fromEnv = envValue(env, APP_ID_ENV);
55
+ if (fromEnv && config.manifestAppId && fromEnv !== config.manifestAppId) {
56
+ throw new ConfigurationError(`${APP_ID_ENV} ("${fromEnv}") does not match the manifest id ("${config.manifestAppId}").`);
57
+ }
58
+ return fromEnv ?? config.manifestAppId;
59
+ }
60
+ function devIdentitiesAllowed(env, config) {
61
+ const devEnv = envValue(env, DEV_ENV);
62
+ return (config.allowDevIdentities ??
63
+ (devEnv !== undefined &&
64
+ (devEnv === "1" || devEnv.toLowerCase() === "true")));
65
+ }
66
+ /**
67
+ * The audience identity tokens must carry: this Worker's name, from
68
+ * EVERYAPP_AUDIENCE. The gateway mints for the Worker, not the app id, so a
69
+ * token for one organization's copy of an app never opens another's. Only
70
+ * under the dev opt-in, where `everyapp dev` mints for the app id, does the
71
+ * app id stand in when EVERYAPP_AUDIENCE is unset.
72
+ */
73
+ function audienceFor(env, config) {
74
+ const appId = appIdFor(env, config);
75
+ const audience = envValue(env, AUDIENCE_ENV);
76
+ if (audience)
77
+ return audience;
78
+ if (appId && devIdentitiesAllowed(env, config))
79
+ return appId;
80
+ throw new ConfigurationError(`${AUDIENCE_ENV} is not set — the app's cloudflare.config.ts must declare it (everyAppWorker() does at deploy).`);
81
+ }
82
+ /**
83
+ * The organization a deployed Worker serves ({@link ORG_ID_ENV}), which an
84
+ * identity must name. Under the dev opt-in there is none to enforce: the
85
+ * stub gateway's one organization is the only one, and `everyapp dev
86
+ * --mode mirror` signs real organizations in.
87
+ */
88
+ function pinnedOrganization(env, config) {
89
+ if (devIdentitiesAllowed(env, config))
90
+ return undefined;
91
+ return envValue(env, ORG_ID_ENV);
92
+ }
30
93
  function unauthorized(message) {
31
94
  return Response.json({ error: "unauthenticated", message }, { status: 401 });
32
95
  }
33
96
  function misconfigured(message) {
34
97
  return Response.json({ error: "misconfigured", message }, { status: 500 });
35
98
  }
36
- async function resolveIdentity(request, env, config) {
37
- const devEnv = env && typeof env === "object"
38
- ? env[DEV_ENV]
39
- : undefined;
40
- return getIdentityFromRequest(request, {
41
- audience: config.audience,
99
+ function identityOptions(env, config, audience) {
100
+ return {
101
+ audience,
102
+ organizationId: pinnedOrganization(env, config),
42
103
  issuer: config.issuer ?? envValue(env, ISSUER_ENV),
43
104
  publicKeys: config.publicKeys,
44
105
  env: env,
45
106
  keysEnvVar: config.keysEnvVar,
46
- allowDevIdentities: config.allowDevIdentities ??
47
- (typeof devEnv === "string" &&
48
- (devEnv === "1" || devEnv.toLowerCase() === "true")),
107
+ allowDevIdentities: devIdentitiesAllowed(env, config),
49
108
  now: config.now,
50
- });
109
+ };
110
+ }
111
+ async function resolveIdentity(request, env, config) {
112
+ return getIdentityFromRequest(request, identityOptions(env, config, audienceFor(env, config)));
51
113
  }
52
114
  function rememberIdentity(request, identity) {
53
115
  requestIdentities.set(request, identity);
54
116
  }
55
- function helperConfigFromEnv(env) {
56
- const audience = envValue(env, APP_ID_ENV);
57
- if (!audience) {
58
- throw new ConfigurationError(`${APP_ID_ENV} is not set — the CLI must inject the app id for identity verification.`);
117
+ /**
118
+ * The user the request context already verified, when `request` carries
119
+ * the same identity token: a framework that rebuilds the request (TanStack
120
+ * Start's `getRequest()`, a Hono context) still gets the one verification.
121
+ */
122
+ function contextUserFor(request) {
123
+ const headers = "headers" in request ? request.headers : request;
124
+ const token = headers.get(IDENTITY_HEADER);
125
+ if (!token)
126
+ return null;
127
+ const scoped = servedRequestToken();
128
+ return scoped && scoped.token === token ? scoped.user : null;
129
+ }
130
+ /**
131
+ * The served request's token and user, or null outside a request. Reads
132
+ * the context without throwing (currentUser() throws outside one).
133
+ */
134
+ function servedRequestToken() {
135
+ let user;
136
+ try {
137
+ user = currentUser();
59
138
  }
60
- return {
61
- audience,
62
- keysEnvVar: PUBLIC_KEYS_ENV,
63
- };
139
+ catch {
140
+ return null;
141
+ }
142
+ if (!user)
143
+ return null;
144
+ const served = servedRequests.get(user);
145
+ return served ? { token: served, user } : null;
64
146
  }
147
+ // The identity token of each request everyApp() serves, by its user, so a
148
+ // second read of the same token answers from the context.
149
+ const servedRequests = new WeakMap();
65
150
  /**
66
151
  * Return the verified Every App user for this request, or null for a declared
67
- * public request. Uses the request cache first, then verifies the identity
68
- * headers from the app id and public keys configured in env.
152
+ * public request. `request` is the inbound `Request` or just its `Headers`
153
+ * (a framework that hands out headers alone needs no made-up Request).
154
+ * Answers from the request context or the per-request cache first, then
155
+ * verifies the identity headers from the audience and public keys in env.
156
+ * Inside a handler `everyApp()` serves, `currentUser()` is the shorter way.
69
157
  */
70
158
  export async function getEveryAppUser(request, env) {
71
159
  const cached = requestIdentities.get(request);
72
160
  if (cached)
73
161
  return cached.user;
74
- const identity = await resolveIdentity(request, env, helperConfigFromEnv(env));
162
+ const fromContext = contextUserFor(request);
163
+ if (fromContext)
164
+ return fromContext;
165
+ const identity = await resolveIdentity(request, env, {
166
+ keysEnvVar: PUBLIC_KEYS_ENV,
167
+ });
75
168
  rememberIdentity(request, identity);
76
169
  return identity.user;
77
170
  }
@@ -94,16 +187,83 @@ export async function requireEveryAppUser(request, env) {
94
187
  throw error;
95
188
  }
96
189
  }
190
+ /**
191
+ * The user of the request being served (`currentUser()`), or throw the
192
+ * same 401 JSON Response as `requireEveryAppUser()` on a public route.
193
+ * Outside a request (`withOrganization()` work, a handler not under
194
+ * `everyApp()`) it throws `RequestContextError`, as `currentUser()` does.
195
+ */
196
+ export function requireCurrentUser() {
197
+ const user = currentUser();
198
+ if (!user) {
199
+ throw unauthorized("this request does not have an authenticated user");
200
+ }
201
+ return user;
202
+ }
203
+ /**
204
+ * `response` without `Set-Cookie`: the perimeter strips every `Cookie`
205
+ * before a request reaches the app, so no cookie the app sets ever comes
206
+ * back, and one named like the Gateway's session cookie locks the person
207
+ * out of the app host (the perimeter refuses a session cookie sent twice).
208
+ * A WebSocket handshake (101) passes as it is: it can't be rebuilt from
209
+ * its body, and the perimeter drops its cookies' `Domain`.
210
+ */
211
+ function withoutCookies(response) {
212
+ if (response.status === 101 || !response.headers.has("set-cookie")) {
213
+ return response;
214
+ }
215
+ console.warn("[everyapp] Dropped a Set-Cookie header: the Gateway never sends an app's cookies back to it.");
216
+ const headers = new Headers(response.headers);
217
+ headers.delete("set-cookie");
218
+ return new Response(response.body, {
219
+ status: response.status,
220
+ statusText: response.statusText,
221
+ headers,
222
+ });
223
+ }
97
224
  export function hasScope(user, scope) {
98
225
  return user.scopes.includes("*") || user.scopes.includes(scope);
99
226
  }
100
- export function everyApp(handler, manifest, options = {}) {
227
+ function isManifest(value) {
228
+ return (typeof value === "object" &&
229
+ value !== null &&
230
+ typeof value.id === "string");
231
+ }
232
+ export function everyApp(handler, manifestOrOptions, legacyOptions = {}) {
233
+ const manifest = isManifest(manifestOrOptions)
234
+ ? manifestOrOptions
235
+ : undefined;
236
+ const options = manifest || manifestOrOptions === undefined
237
+ ? legacyOptions
238
+ : manifestOrOptions;
101
239
  const config = configFrom(manifest, options);
102
240
  return {
103
241
  async fetch(request, env, ctx) {
242
+ let audience;
243
+ let appId;
244
+ try {
245
+ audience = audienceFor(env, config);
246
+ appId = appIdFor(env, config) ?? audience;
247
+ }
248
+ catch (err) {
249
+ if (err instanceof ConfigurationError) {
250
+ console.error(err);
251
+ return misconfigured(err.message);
252
+ }
253
+ throw err;
254
+ }
255
+ // The reserved tools contract carries its own gateway-minted tokens and
256
+ // never reaches the app's handler.
257
+ const toolsResponse = await handleToolsRequest(request, env, ctx, {
258
+ toolSet: options.tools,
259
+ appId,
260
+ identity: identityOptions(env, config, audience),
261
+ });
262
+ if (toolsResponse)
263
+ return toolsResponse;
104
264
  let identity;
105
265
  try {
106
- identity = await resolveIdentity(request, env, config);
266
+ identity = await getIdentityFromRequest(request, identityOptions(env, config, audience));
107
267
  rememberIdentity(request, identity);
108
268
  }
109
269
  catch (err) {
@@ -115,7 +275,12 @@ export function everyApp(handler, manifest, options = {}) {
115
275
  return unauthorized(err.message);
116
276
  throw err;
117
277
  }
118
- return handler(request, env, ctx, identity.user);
278
+ const { user, expiresAt } = identity;
279
+ if (user) {
280
+ servedRequests.set(user, request.headers.get(IDENTITY_HEADER) ?? "");
281
+ }
282
+ const response = await serveRequest({ request, user, expiresAt }, () => handler(request, env, ctx, user));
283
+ return withoutCookies(response);
119
284
  },
120
285
  };
121
286
  }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `fromMcpTools()` — an app's existing MCP tools as `defineTools()` entries.
3
+ *
4
+ * const tools: McpToolLike[] = [];
5
+ * registerMyTools((name, config, handler) =>
6
+ * tools.push({ name, ...config, handler }),
7
+ * );
8
+ * export default everyApp(handler, {
9
+ * tools: defineTools(fromMcpTools(tools), { instructions }),
10
+ * });
11
+ *
12
+ * Takes the shape `McpServer.registerTool(name, config, handler)` is called
13
+ * with (or what a low-level server's `tools/list` returns, plus a handler),
14
+ * structurally: the SDK takes no dependency on `@modelcontextprotocol/sdk`,
15
+ * and a live `McpServer` keeps its registry private, so the app hands over
16
+ * the list it registers from.
17
+ */
18
+ import { type ToolRisk } from "../internal/index.js";
19
+ import { type StandardSchemaWithJSON, type ToolContext, type ToolDefinition, type ToolSchema } from "./tools.js";
20
+ /** MCP tool annotations (all hints); only these are read. */
21
+ export interface McpToolAnnotationsLike {
22
+ title?: string;
23
+ readOnlyHint?: boolean;
24
+ destructiveHint?: boolean;
25
+ idempotentHint?: boolean;
26
+ openWorldHint?: boolean;
27
+ }
28
+ /** An MCP `CallToolResult`, structurally. */
29
+ export interface McpToolResultLike {
30
+ content?: ReadonlyArray<{
31
+ readonly type: string;
32
+ }>;
33
+ structuredContent?: unknown;
34
+ isError?: boolean;
35
+ }
36
+ /**
37
+ * A tool schema as MCP servers write one: a {@link ToolSchema} (a full zod
38
+ * object, `{ jsonSchema, validate }`), a raw shape of Standard Schemas
39
+ * (`{ query: z.string() }`, what `McpServer.registerTool` takes), or a plain
40
+ * JSON Schema object (a low-level server's `tools/list`), which is described
41
+ * but not validated: the handler checks its own arguments, as it did before.
42
+ */
43
+ export type McpToolSchemaLike = ToolSchema | Readonly<Record<string, StandardSchemaWithJSON>> | Readonly<Record<string, unknown>>;
44
+ /** One MCP tool: `registerTool`'s name, config and handler, flattened. */
45
+ export interface McpToolLike<TExtra = ToolContext> {
46
+ name: string;
47
+ title?: string;
48
+ description?: string;
49
+ /** Omitted: the tool takes no arguments. */
50
+ inputSchema?: McpToolSchemaLike;
51
+ outputSchema?: McpToolSchemaLike;
52
+ annotations?: McpToolAnnotationsLike;
53
+ /**
54
+ * Called with the validated arguments and the value of
55
+ * {@link FromMcpToolsOptions.context} (the call's {@link ToolContext} by
56
+ * default). Return a `CallToolResult`; throw {@link ToolError} for a message
57
+ * the model may read.
58
+ */
59
+ handler: (args: never, extra: TExtra) => McpToolResultLike | Promise<McpToolResultLike>;
60
+ }
61
+ export interface FromMcpToolsOptions<TExtra = ToolContext> {
62
+ /**
63
+ * What each handler gets as its second argument, built per call from the
64
+ * verified caller (`user`, `env`, `request`, `callId`). Default: the
65
+ * {@link ToolContext} itself.
66
+ */
67
+ context?: (context: ToolContext) => TExtra | Promise<TExtra>;
68
+ /**
69
+ * A tool's risk, overriding the default for the tools it returns a risk
70
+ * for. Default: `readOnlyHint: true` is `read`, `destructiveHint: true`
71
+ * is `destructive`, anything else `write`.
72
+ */
73
+ risk?: (tool: McpToolLike<TExtra>) => ToolRisk | undefined;
74
+ }
75
+ /**
76
+ * Adapt MCP tools into `defineTools()` entries, keyed by tool name, to spread
77
+ * beside the app's own: `defineTools({ ...fromMcpTools(list), my_tool })`.
78
+ *
79
+ * - `title`, `description` (the name when absent), `idempotentHint` and
80
+ * `openWorldHint` carry over; risk as {@link FromMcpToolsOptions.risk}.
81
+ * - A result's text blocks, joined by a blank line, are what the model
82
+ * reads; `structuredContent` is sent as structured content (checked
83
+ * against `outputSchema` when there is one). Other blocks are dropped.
84
+ * - `isError: true` becomes a {@link ToolError} with the result's text.
85
+ *
86
+ * Names must already be lowercase snake_case; `defineTools()` checks them.
87
+ */
88
+ export declare function fromMcpTools<TExtra = ToolContext>(tools: Iterable<McpToolLike<TExtra>>, options?: FromMcpToolsOptions<TExtra>): Record<string, ToolDefinition>;
89
+ //# sourceMappingURL=fromMcpTools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fromMcpTools.d.ts","sourceRoot":"","sources":["../../src/server/fromMcpTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAIpB,6DAA6D;AAC7D,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,GAChD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,WAAW,WAAW,CAAC,MAAM,GAAG,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC;;;;;OAKG;IACH,OAAO,EAAE,CACP,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,MAAM,KACV,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,mBAAmB,CAAC,MAAM,GAAG,WAAW;IACvD;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,QAAQ,GAAG,SAAS,CAAC;CAC5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,MAAM,GAAG,WAAW,EAC/C,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EACpC,OAAO,GAAE,mBAAmB,CAAC,MAAM,CAAM,GACxC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA+ChC"}