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

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 (113) hide show
  1. package/README.md +608 -2
  2. package/dist/cloudflare/index.d.ts +22 -0
  3. package/dist/cloudflare/index.d.ts.map +1 -0
  4. package/dist/cloudflare/index.js +21 -0
  5. package/dist/cloudflare/sentinel.d.ts +69 -0
  6. package/dist/cloudflare/sentinel.d.ts.map +1 -0
  7. package/dist/cloudflare/sentinel.js +50 -0
  8. package/dist/cloudflare/worker.d.ts +511 -0
  9. package/dist/cloudflare/worker.d.ts.map +1 -0
  10. package/dist/cloudflare/worker.js +738 -0
  11. package/dist/dev/index.d.ts +8 -0
  12. package/dist/dev/index.d.ts.map +1 -0
  13. package/dist/dev/index.js +7 -0
  14. package/dist/dev/keypair.d.ts +24 -0
  15. package/dist/dev/keypair.d.ts.map +1 -0
  16. package/dist/dev/keypair.js +60 -0
  17. package/dist/internal/aiProviders.d.ts +67 -0
  18. package/dist/internal/aiProviders.d.ts.map +1 -0
  19. package/dist/internal/aiProviders.js +220 -0
  20. package/dist/internal/appSettings.d.ts +237 -0
  21. package/dist/internal/appSettings.d.ts.map +1 -0
  22. package/dist/internal/appSettings.js +374 -0
  23. package/dist/internal/capabilities.d.ts +1344 -0
  24. package/dist/internal/capabilities.d.ts.map +1 -0
  25. package/dist/internal/capabilities.js +1521 -0
  26. package/dist/internal/devProviders.d.ts +49 -0
  27. package/dist/internal/devProviders.d.ts.map +1 -0
  28. package/dist/internal/devProviders.js +62 -0
  29. package/dist/internal/email.d.ts +280 -0
  30. package/dist/internal/email.d.ts.map +1 -0
  31. package/dist/internal/email.js +613 -0
  32. package/dist/internal/events.d.ts +182 -0
  33. package/dist/internal/events.d.ts.map +1 -0
  34. package/dist/internal/events.js +324 -0
  35. package/dist/internal/gatewaySettings.d.ts +82 -0
  36. package/dist/internal/gatewaySettings.d.ts.map +1 -0
  37. package/dist/internal/gatewaySettings.js +209 -0
  38. package/dist/internal/identity.d.ts +18 -3
  39. package/dist/internal/identity.d.ts.map +1 -1
  40. package/dist/internal/identity.js +53 -14
  41. package/dist/internal/index.d.ts +17 -1
  42. package/dist/internal/index.d.ts.map +1 -1
  43. package/dist/internal/index.js +17 -1
  44. package/dist/internal/members.d.ts +35 -0
  45. package/dist/internal/members.d.ts.map +1 -0
  46. package/dist/internal/members.js +7 -0
  47. package/dist/internal/oauthClient.d.ts +63 -0
  48. package/dist/internal/oauthClient.d.ts.map +1 -0
  49. package/dist/internal/oauthClient.js +194 -0
  50. package/dist/internal/oauthScopes.d.ts +117 -0
  51. package/dist/internal/oauthScopes.d.ts.map +1 -0
  52. package/dist/internal/oauthScopes.js +416 -0
  53. package/dist/internal/organizationName.d.ts +18 -0
  54. package/dist/internal/organizationName.d.ts.map +1 -0
  55. package/dist/internal/organizationName.js +24 -0
  56. package/dist/internal/protocol.d.ts +86 -2
  57. package/dist/internal/protocol.d.ts.map +1 -1
  58. package/dist/internal/protocol.js +112 -1
  59. package/dist/internal/providerApps.d.ts +75 -0
  60. package/dist/internal/providerApps.d.ts.map +1 -0
  61. package/dist/internal/providerApps.js +59 -0
  62. package/dist/internal/providerRegistry.d.ts +147 -0
  63. package/dist/internal/providerRegistry.d.ts.map +1 -0
  64. package/dist/internal/providerRegistry.js +262 -0
  65. package/dist/internal/providerSpec.d.ts +55 -0
  66. package/dist/internal/providerSpec.d.ts.map +1 -0
  67. package/dist/internal/providerSpec.js +746 -0
  68. package/dist/internal/remoteMcp.d.ts +188 -0
  69. package/dist/internal/remoteMcp.d.ts.map +1 -0
  70. package/dist/internal/remoteMcp.js +543 -0
  71. package/dist/internal/tools.d.ts +115 -0
  72. package/dist/internal/tools.d.ts.map +1 -0
  73. package/dist/internal/tools.js +80 -0
  74. package/dist/server/attribution.d.ts +39 -0
  75. package/dist/server/attribution.d.ts.map +1 -0
  76. package/dist/server/attribution.js +67 -0
  77. package/dist/server/authorizeUrl.d.ts +43 -0
  78. package/dist/server/authorizeUrl.d.ts.map +1 -0
  79. package/dist/server/authorizeUrl.js +110 -0
  80. package/dist/server/emit.d.ts +63 -0
  81. package/dist/server/emit.d.ts.map +1 -0
  82. package/dist/server/emit.js +101 -0
  83. package/dist/server/everyApp.d.ts +38 -12
  84. package/dist/server/everyApp.d.ts.map +1 -1
  85. package/dist/server/everyApp.js +92 -28
  86. package/dist/server/gatewayFetch.d.ts +24 -8
  87. package/dist/server/gatewayFetch.d.ts.map +1 -1
  88. package/dist/server/gatewayFetch.js +81 -36
  89. package/dist/server/index.d.ts +10 -1
  90. package/dist/server/index.d.ts.map +1 -1
  91. package/dist/server/index.js +8 -1
  92. package/dist/server/integrationFetch.d.ts +131 -0
  93. package/dist/server/integrationFetch.d.ts.map +1 -0
  94. package/dist/server/integrationFetch.js +526 -0
  95. package/dist/server/listMembers.d.ts +32 -0
  96. package/dist/server/listMembers.d.ts.map +1 -0
  97. package/dist/server/listMembers.js +74 -0
  98. package/dist/server/nodeServer.d.ts +48 -0
  99. package/dist/server/nodeServer.d.ts.map +1 -0
  100. package/dist/server/nodeServer.js +45 -0
  101. package/dist/server/sendEmail.d.ts +39 -0
  102. package/dist/server/sendEmail.d.ts.map +1 -0
  103. package/dist/server/sendEmail.js +114 -0
  104. package/dist/server/tools.d.ts +184 -0
  105. package/dist/server/tools.d.ts.map +1 -0
  106. package/dist/server/tools.js +347 -0
  107. package/dist/server/toolsEndpoint.d.ts +32 -0
  108. package/dist/server/toolsEndpoint.d.ts.map +1 -0
  109. package/dist/server/toolsEndpoint.js +231 -0
  110. package/package.json +30 -17
  111. package/dist/server/mcp.d.ts +0 -66
  112. package/dist/server/mcp.d.ts.map +0 -1
  113. package/dist/server/mcp.js +0 -147
@@ -0,0 +1,194 @@
1
+ /**
2
+ * The `oauth_client` capability's wire rules (docs/capabilities.md "OAuth
3
+ * clients"), shared by the gateway, which puts the operator's client on an
4
+ * app's token request, and the SDK's local-dev fallback, which puts the
5
+ * developer's own on it the same way.
6
+ */
7
+ import { base64Utf8, oauthClientOrigin, } from "./capabilities.js";
8
+ /** The largest token request body the gateway reads: real ones are a few hundred bytes. */
9
+ export const OAUTH_TOKEN_BODY_LIMIT = 64 * 1024;
10
+ /**
11
+ * The client `settings` hold for `capability`, or null until every setting
12
+ * it needs is set: the id, the secret (unless it is a public client), and a
13
+ * `hostSetting` that is an https origin when it is set at all.
14
+ */
15
+ export function oauthClientCredentials(capability, settings) {
16
+ const clientId = settingValue(settings[capability.secrets.clientId]);
17
+ const secretName = capability.secrets.clientSecret;
18
+ const clientSecret = secretName
19
+ ? settingValue(settings[secretName])
20
+ : undefined;
21
+ if (!clientId || (secretName && !clientSecret))
22
+ return null;
23
+ if (capability.hostSetting && !oauthClientOrigin(capability, settings)) {
24
+ return null;
25
+ }
26
+ return { clientId, ...(clientSecret ? { clientSecret } : {}) };
27
+ }
28
+ function settingValue(value) {
29
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
30
+ }
31
+ const FORM = "application/x-www-form-urlencoded";
32
+ const JSON_TYPE = "application/json";
33
+ /**
34
+ * `request` with `client` put where `rule` says (the form body, HTTP Basic,
35
+ * the query string or the JSON body), and every client credential the app
36
+ * sent removed wherever it was: the `Authorization` header, and
37
+ * `client_id`/`client_secret` (or the rule's names for them, in any case) in
38
+ * the query string and the body. Bodies are re-serialised from their parsed
39
+ * values, so a crafted body can't carry a second secret past the parser.
40
+ * Token requests are form-encoded or JSON; anything else is refused.
41
+ */
42
+ export function injectClientCredentials(request, rule, client) {
43
+ const idName = rule.params?.clientId ?? "client_id";
44
+ const secretName = rule.params?.clientSecret ?? "client_secret";
45
+ const credentialNames = new Set(["client_id", "client_secret", idName, secretName].map((name) => name.toLowerCase()));
46
+ const isCredential = (name) => credentialNames.has(name.toLowerCase());
47
+ const fields = [
48
+ [idName, client.clientId],
49
+ ...(client.clientSecret
50
+ ? [[secretName, client.clientSecret]]
51
+ : []),
52
+ ];
53
+ // The query keeps the app's other fields as they were sent.
54
+ const url = new URL(request.url);
55
+ const query = url.search
56
+ .slice(1)
57
+ .split("&")
58
+ .filter((pair) => {
59
+ const [name] = new URLSearchParams(pair).keys();
60
+ return pair !== "" && !(name !== undefined && isCredential(name));
61
+ });
62
+ if (rule.inject === "query") {
63
+ query.push(new URLSearchParams(fields).toString());
64
+ }
65
+ url.search = query.join("&");
66
+ const headers = new Headers(request.headers);
67
+ headers.delete("authorization");
68
+ headers.delete("content-length");
69
+ if (rule.inject === "basic") {
70
+ headers.set("authorization", `Basic ${base64Utf8(`${client.clientId}:${client.clientSecret ?? ""}`)}`);
71
+ }
72
+ const type = mediaType(headers.get("content-type"));
73
+ let body = request.body;
74
+ if (body === null || body === "") {
75
+ // Nothing the app sent; the form and JSON rules make the body.
76
+ if (rule.inject === "form") {
77
+ headers.set("content-type", FORM);
78
+ body = new URLSearchParams(fields).toString();
79
+ }
80
+ else if (rule.inject === "json") {
81
+ headers.set("content-type", JSON_TYPE);
82
+ body = JSON.stringify(Object.fromEntries(fields));
83
+ }
84
+ }
85
+ else if (type === FORM) {
86
+ if (rule.inject === "json") {
87
+ return { ok: false, problem: "This token endpoint takes a JSON body." };
88
+ }
89
+ const params = new URLSearchParams(body);
90
+ for (const name of new Set([...params.keys()].filter(isCredential))) {
91
+ params.delete(name);
92
+ }
93
+ if (rule.inject === "form") {
94
+ for (const [name, value] of fields)
95
+ params.set(name, value);
96
+ }
97
+ body = params.toString();
98
+ }
99
+ else if (type === JSON_TYPE) {
100
+ if (rule.inject === "form") {
101
+ return {
102
+ ok: false,
103
+ problem: `This token endpoint takes a form-encoded body (${FORM}).`,
104
+ };
105
+ }
106
+ const parsed = jsonObject(body);
107
+ if (!parsed) {
108
+ return { ok: false, problem: "The body is not a JSON object." };
109
+ }
110
+ for (const name of Object.keys(parsed)) {
111
+ if (isCredential(name))
112
+ delete parsed[name];
113
+ }
114
+ if (rule.inject === "json") {
115
+ for (const [name, value] of fields)
116
+ parsed[name] = value;
117
+ }
118
+ body = JSON.stringify(parsed);
119
+ }
120
+ else {
121
+ return {
122
+ ok: false,
123
+ problem: `A token request's body is form-encoded (${FORM}) or JSON (${JSON_TYPE}).`,
124
+ };
125
+ }
126
+ return { ok: true, url, headers, body };
127
+ }
128
+ /** The grant types logs may name; anything else is logged as `other`. */
129
+ const GRANT_TYPES = new Set([
130
+ "authorization_code",
131
+ "refresh_token",
132
+ "client_credentials",
133
+ "fb_exchange_token",
134
+ "ig_exchange_token",
135
+ "th_exchange_token",
136
+ "urn:ietf:params:oauth:grant-type:token-exchange",
137
+ ]);
138
+ /**
139
+ * The grants the gateway completes: each ends in a user's own tokens. The
140
+ * client-credentials grant, and anything else a network serves on the same
141
+ * endpoint, would mint a token for the gateway's own application instead,
142
+ * which on Meta, Discord, Twitch or Kick manages the application's
143
+ * settings, its webhooks and every tenant's tokens.
144
+ */
145
+ export const USER_BOUND_GRANT_TYPES = new Set([
146
+ "authorization_code",
147
+ "refresh_token",
148
+ "fb_exchange_token",
149
+ "ig_exchange_token",
150
+ "th_exchange_token",
151
+ "urn:ietf:params:oauth:grant-type:token-exchange",
152
+ ]);
153
+ /**
154
+ * A token request's `grant_type` as the app sent it, from its body or query
155
+ * string, or null when it names none (Meta's code exchange). Never the
156
+ * request's other fields.
157
+ */
158
+ export function requestedGrantType(request) {
159
+ let value = null;
160
+ const type = mediaType(request.headers.get("content-type"));
161
+ if (request.body && type === FORM) {
162
+ value = new URLSearchParams(request.body).get("grant_type");
163
+ }
164
+ else if (request.body && type === JSON_TYPE) {
165
+ value = jsonObject(request.body)?.["grant_type"] ?? null;
166
+ }
167
+ value ??= request.url.searchParams.get("grant_type");
168
+ return typeof value === "string" && value ? value : null;
169
+ }
170
+ /**
171
+ * A token request's `grant_type` for logs: one of the known grant types,
172
+ * `other`, or null when it names none.
173
+ */
174
+ export function tokenGrantType(request) {
175
+ const value = requestedGrantType(request);
176
+ if (value === null)
177
+ return null;
178
+ return GRANT_TYPES.has(value) ? value : "other";
179
+ }
180
+ /** A Content-Type's media type, lowercased and without parameters. */
181
+ function mediaType(contentType) {
182
+ return (contentType ?? "").split(";")[0].trim().toLowerCase();
183
+ }
184
+ function jsonObject(text) {
185
+ try {
186
+ const value = JSON.parse(text);
187
+ return value && typeof value === "object" && !Array.isArray(value)
188
+ ? value
189
+ : null;
190
+ }
191
+ catch {
192
+ return null;
193
+ }
194
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Scope sets for an `oauth_client` capability with a `scopePolicy`
3
+ * (docs/capabilities.md "OAuth clients"): what an app's manifest entry
4
+ * declares, what that lets the app ask the provider for, how each provider
5
+ * spells what it granted, and which API routes a set unlocks. Pure
6
+ * functions over the registry, shared by the gateway's token-endpoint
7
+ * check, the SDK's local-dev twin of it and, later, the proxy and the
8
+ * outbound Worker. Nothing here reads a secret or a token value.
9
+ */
10
+ import type { OAuthScopePolicy } from "./capabilities.js";
11
+ import type { TokenRequest } from "./oauthClient.js";
12
+ /** Scopes by the token they belong to: the bot or only token, and Slack's user token. */
13
+ export interface ScopeList {
14
+ scopes: string[];
15
+ userScopes: string[];
16
+ }
17
+ /** What a token response says it granted; a field is present when that kind of token is. */
18
+ export interface GrantedScopes {
19
+ scopes?: string[];
20
+ userScopes?: string[];
21
+ }
22
+ /**
23
+ * The scope set names a manifest entry declares, or null when the entry
24
+ * voids its grant: `scopes` missing, not an array, empty, a non-string
25
+ * element, a name listed twice, or any name the policy doesn't offer. An
26
+ * unknown name voids the whole grant rather than narrowing it silently, so
27
+ * a newer CLI's set name reaching an older gateway is refused outright and
28
+ * a message can say so.
29
+ */
30
+ export declare function declaredScopeSets(policy: OAuthScopePolicy, entry: {
31
+ scopes?: unknown;
32
+ } | undefined): string[] | null;
33
+ /**
34
+ * What an app with `sets` asks the provider for: the sets' scopes in
35
+ * registry order, deduplicated, then `alwaysRequested`. The status hands
36
+ * these out and the authorize URL (Microsoft: the token leg too) carries
37
+ * them verbatim.
38
+ */
39
+ export declare function requestedScopes(policy: OAuthScopePolicy, sets: readonly string[]): ScopeList;
40
+ /**
41
+ * What a token an app with `sets` is handed may carry: the requested
42
+ * scopes and the tolerated ones, in the dialect's canonical spelling so a
43
+ * granted list canonicalised the same way compares exactly.
44
+ */
45
+ export declare function allowedScopes(policy: OAuthScopePolicy, sets: readonly string[]): ScopeList;
46
+ /**
47
+ * Whether a token response body carries a token: an access, refresh or ID
48
+ * token, or Slack's user token under `authed_user`. A 2xx without one
49
+ * (Slack's `ok: false`) is an error the app must see, not a grant.
50
+ */
51
+ export declare function carriesToken(json: unknown): boolean;
52
+ /**
53
+ * The scopes a token response says it granted, canonicalised per dialect,
54
+ * or null when the answer names none for a token it carries, which fails
55
+ * closed: every documented success response of the three providers names
56
+ * them (map-providers: Google and Microsoft `scope`, Slack `scope` and
57
+ * `authed_user.scope`), so a missing field is an answer the gateway can't
58
+ * hold to anything.
59
+ */
60
+ export declare function grantedScopes(policy: OAuthScopePolicy, json: unknown): GrantedScopes | null;
61
+ /**
62
+ * What `granted` carries beyond `allowed`, per token kind, for a refusal's
63
+ * message and log line: the user token's extras as `user:<scope>`. Both
64
+ * lists are in the dialect's canonical spelling already.
65
+ */
66
+ export declare function scopeExcess(granted: GrantedScopes, allowed: ScopeList): string[];
67
+ /**
68
+ * The scopes a token request itself asks for (`scope`, and Slack's
69
+ * `user_scope`, in any case) in its form or JSON body, canonicalised per
70
+ * dialect for comparison with `allowedScopes()`, or null when the body
71
+ * names none. The query string is never read: the gateway refuses a
72
+ * request that puts these there, so only one place decides.
73
+ */
74
+ export declare function requestedTokenScopes(policy: OAuthScopePolicy, request: TokenRequest): GrantedScopes | null;
75
+ /**
76
+ * `request` with its `scope`, in any case, as the policy's `requestScope`
77
+ * says: replaced by the requested list of the app's `sets`, dropped, or
78
+ * kept as sent. A separate step after `injectClientCredentials()`, whose
79
+ * re-serialised form or JSON body this edits the same way; any other body
80
+ * is left alone.
81
+ */
82
+ export declare function rewriteTokenRequestScope(policy: OAuthScopePolicy, sets: readonly string[], request: TokenRequest): TokenRequest;
83
+ /**
84
+ * The declared set that unlocks `method upstream`, or null. Not wired to
85
+ * any live path yet: it becomes the proxy's boundary once the gateway
86
+ * holds tokens, and the outbound Worker's for dispatched apps before that.
87
+ *
88
+ * In order: https only; the host must be on one of the declared sets'
89
+ * routes; the raw pathname is refused when it holds `\`, `//` or `%00`;
90
+ * each raw segment, and each percent-decoding of it while a `%` remains
91
+ * (a provider's layers may each decode once), is refused when it won't
92
+ * decode, holds a control or format character or a backslash, is one of
93
+ * the policy's denied segments in any case, or splits on `/` into a dot
94
+ * segment: `.` or `..`, with or without a `;` parameter (`..;x`), which
95
+ * Google's front end resolves like the bare one. The denied comparison is
96
+ * of the whole segment, because an encoded slash is part of one id to the
97
+ * provider, never a separator: a Search Console site URL whose own path
98
+ * holds `batch` stays matchable, and `2%2FmeasurementProtocolSecrets` is
99
+ * a data stream id that doesn't exist, not the secrets. Then the raw
100
+ * pathname, case preserved, is matched: GET and HEAD need a `paths` entry
101
+ * (exact, or a prefix when it ends in `/`), POST needs a `posts` pattern,
102
+ * and no other method goes through. Matching the raw path is what lets
103
+ * Search Console's `sites/https%3A%2F%2Fexample.com%2F/searchAnalytics/query`
104
+ * match `[^/]+` while `..`, batch tunnels and secrets stay refused however
105
+ * encoded. `X-HTTP-Method-Override`, `access_token` and `token` parameters
106
+ * are the proxy's to strip before it asks; nothing here reads them. The
107
+ * proxy fetches with `redirect: "manual"`: Google answers a dot segment it
108
+ * resolves with a 302 to the resolved path, and following one would carry
109
+ * the token to a path this never matched.
110
+ */
111
+ export declare function scopeRouteAllows(policy: OAuthScopePolicy, sets: readonly string[], method: string, upstream: URL): string | null;
112
+ /**
113
+ * `text` as a JSON object, or null for anything else (an array, a scalar,
114
+ * not JSON). Shared with the gateway's read of a provider's token answer.
115
+ */
116
+ export declare function jsonObject(text: string): Record<string, unknown> | null;
117
+ //# sourceMappingURL=oauthScopes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthScopes.d.ts","sourceRoot":"","sources":["../../src/internal/oauthScopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAEV,gBAAgB,EAEjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,yFAAyF;AACzF,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GACtC,MAAM,EAAE,GAAG,IAAI,CAejB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,SAAS,CASX;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,SAAS,CASX;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CASnD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,OAAO,GACZ,aAAa,GAAG,IAAI,CA6BtB;AA+BD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,SAAS,GACjB,MAAM,EAAE,CASV;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,YAAY,GACpB,aAAa,GAAG,IAAI,CAStB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,YAAY,GACpB,YAAY,CA+Bd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,GAAG,GACZ,MAAM,GAAG,IAAI,CAsBf;AAwJD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMvE"}