@every-app/sdk 0.3.0-rc.1 → 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.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/cloudflare/catalogSettings.generated.d.ts +81 -0
- package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
- package/dist/cloudflare/catalogSettings.generated.js +174 -0
- package/dist/cloudflare/index.d.ts +3 -2
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +4 -1
- package/dist/cloudflare/sentinel.d.ts +60 -2
- package/dist/cloudflare/sentinel.d.ts.map +1 -1
- package/dist/cloudflare/sentinel.js +37 -2
- package/dist/cloudflare/worker.d.ts +357 -63
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +363 -104
- package/dist/dev/index.d.ts +1 -1
- package/dist/dev/index.d.ts.map +1 -1
- package/dist/dev/index.js +1 -1
- package/dist/dev/keypair.d.ts +2 -0
- package/dist/dev/keypair.d.ts.map +1 -1
- package/dist/dev/keypair.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/internal/aiDefault.d.ts +204 -0
- package/dist/internal/aiDefault.d.ts.map +1 -0
- package/dist/internal/aiDefault.js +334 -0
- package/dist/internal/aiProviders.d.ts +7 -2
- package/dist/internal/aiProviders.d.ts.map +1 -1
- package/dist/internal/aiProviders.js +17 -4
- package/dist/internal/appSettings.d.ts +82 -4
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +204 -29
- package/dist/internal/audit.d.ts +108 -0
- package/dist/internal/audit.d.ts.map +1 -0
- package/dist/internal/audit.js +235 -0
- package/dist/internal/capabilities.d.ts +2268 -438
- package/dist/internal/capabilities.d.ts.map +1 -1
- package/dist/internal/capabilities.js +128 -539
- package/dist/internal/catalog/commerce.d.ts +394 -0
- package/dist/internal/catalog/commerce.d.ts.map +1 -0
- package/dist/internal/catalog/commerce.js +477 -0
- package/dist/internal/catalog/comms.d.ts +375 -0
- package/dist/internal/catalog/comms.d.ts.map +1 -0
- package/dist/internal/catalog/comms.js +520 -0
- package/dist/internal/catalog/index.d.ts +1973 -0
- package/dist/internal/catalog/index.d.ts.map +1 -0
- package/dist/internal/catalog/index.js +19 -0
- package/dist/internal/catalog/inference.d.ts +393 -0
- package/dist/internal/catalog/inference.d.ts.map +1 -0
- package/dist/internal/catalog/inference.js +460 -0
- package/dist/internal/catalog/infra.d.ts +423 -0
- package/dist/internal/catalog/infra.d.ts.map +1 -0
- package/dist/internal/catalog/infra.js +543 -0
- package/dist/internal/catalog/search.d.ts +400 -0
- package/dist/internal/catalog/search.d.ts.map +1 -0
- package/dist/internal/catalog/search.js +463 -0
- package/dist/internal/devProviders.d.ts +2 -2
- package/dist/internal/devProviders.d.ts.map +1 -1
- package/dist/internal/devProviders.js +19 -1
- package/dist/internal/events.d.ts +13 -2
- package/dist/internal/events.d.ts.map +1 -1
- package/dist/internal/events.js +47 -4
- package/dist/internal/gatewaySettings.d.ts +3 -2
- package/dist/internal/gatewaySettings.d.ts.map +1 -1
- package/dist/internal/gatewaySettings.js +12 -6
- package/dist/internal/identity.d.ts +41 -4
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +48 -10
- package/dist/internal/index.d.ts +6 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +6 -1
- package/dist/internal/members.d.ts +3 -2
- package/dist/internal/members.d.ts.map +1 -1
- package/dist/internal/oauthClient.d.ts +10 -12
- package/dist/internal/oauthClient.d.ts.map +1 -1
- package/dist/internal/oauthClient.js +20 -81
- package/dist/internal/oauthPresets.d.ts +33 -0
- package/dist/internal/oauthPresets.d.ts.map +1 -0
- package/dist/internal/oauthPresets.js +1064 -0
- package/dist/internal/oauthScopes.d.ts +56 -1
- package/dist/internal/oauthScopes.d.ts.map +1 -1
- package/dist/internal/oauthScopes.js +98 -4
- package/dist/internal/oauthSpec.d.ts +102 -0
- package/dist/internal/oauthSpec.d.ts.map +1 -0
- package/dist/internal/oauthSpec.js +789 -0
- package/dist/internal/protocol.d.ts +64 -1
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +51 -1
- package/dist/internal/providerRegistry.d.ts +77 -6
- package/dist/internal/providerRegistry.d.ts.map +1 -1
- package/dist/internal/providerRegistry.js +178 -8
- package/dist/internal/providerSpec.d.ts +18 -7
- package/dist/internal/providerSpec.d.ts.map +1 -1
- package/dist/internal/providerSpec.js +442 -34
- package/dist/internal/signInProviders.d.ts +104 -0
- package/dist/internal/signInProviders.d.ts.map +1 -0
- package/dist/internal/signInProviders.js +245 -0
- package/dist/manifest.d.ts +238 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +30 -0
- package/dist/server/ai.d.ts +111 -0
- package/dist/server/ai.d.ts.map +1 -0
- package/dist/server/ai.js +145 -0
- package/dist/server/aiBinding.d.ts +68 -0
- package/dist/server/aiBinding.d.ts.map +1 -0
- package/dist/server/aiBinding.js +294 -0
- package/dist/server/attribution.d.ts +9 -5
- package/dist/server/attribution.d.ts.map +1 -1
- package/dist/server/attribution.js +12 -4
- package/dist/server/authorizeUrl.d.ts +1 -1
- package/dist/server/authorizeUrl.d.ts.map +1 -1
- package/dist/server/authorizeUrl.js +2 -6
- package/dist/server/connectUrl.d.ts +21 -0
- package/dist/server/connectUrl.d.ts.map +1 -0
- package/dist/server/connectUrl.js +37 -0
- package/dist/server/context.d.ts +68 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +117 -0
- package/dist/server/emailBinding.d.ts +72 -0
- package/dist/server/emailBinding.d.ts.map +1 -0
- package/dist/server/emailBinding.js +124 -0
- package/dist/server/emit.d.ts +1 -1
- package/dist/server/emit.d.ts.map +1 -1
- package/dist/server/emit.js +7 -7
- package/dist/server/env.d.ts +44 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +1 -0
- package/dist/server/everyApp.d.ts +27 -7
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +106 -5
- package/dist/server/fromMcpTools.d.ts +89 -0
- package/dist/server/fromMcpTools.d.ts.map +1 -0
- package/dist/server/fromMcpTools.js +192 -0
- package/dist/server/gatewayFetch.d.ts +42 -18
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +138 -19
- package/dist/server/gatewayUrl.d.ts +13 -0
- package/dist/server/gatewayUrl.d.ts.map +1 -0
- package/dist/server/gatewayUrl.js +34 -0
- package/dist/server/index.d.ts +15 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +12 -2
- package/dist/server/integrationFetch.d.ts +70 -39
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +244 -82
- package/dist/server/listMembers.d.ts +1 -1
- package/dist/server/listMembers.d.ts.map +1 -1
- package/dist/server/listMembers.js +8 -11
- package/dist/server/refusal.d.ts +55 -0
- package/dist/server/refusal.d.ts.map +1 -0
- package/dist/server/refusal.js +193 -0
- package/dist/server/sendEmail.d.ts +1 -1
- package/dist/server/sendEmail.d.ts.map +1 -1
- package/dist/server/sendEmail.js +7 -7
- package/dist/server/toolsEndpoint.d.ts.map +1 -1
- package/dist/server/toolsEndpoint.js +11 -5
- package/dist/tanstack-start/index.d.ts +9 -0
- package/dist/tanstack-start/index.d.ts.map +1 -0
- package/dist/tanstack-start/index.js +29 -0
- package/dist/testing/index.d.ts +93 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +156 -0
- package/package.json +35 -14
|
@@ -1,33 +1,14 @@
|
|
|
1
|
-
import { CATALOG, ConfigurationError, GATEWAY_ERROR_HEADER, INTEGRATION_PROXY_PREFIX, OAUTH_TOKEN_BODY_LIMIT, allowedScopes, apiKeyHosts, authorizationFor, capabilitySettings, carriesToken, declaredScopeSets, describeTokenEndpoints, devProviderFile, grantedScopes, injectClientCredentials, integrationProxyPath, oauthClientCredentials,
|
|
2
|
-
import { applyAttribution,
|
|
3
|
-
import { BINDING_ORIGIN, streamingRequest, } from "./gatewayFetch.js";
|
|
4
|
-
|
|
5
|
-
* A `fetch` for one of the gateway's capabilities. Call the provider's real
|
|
6
|
-
* URLs (`https://api.dataforseo.com/v3/…`); this sends them over the
|
|
7
|
-
* AppGateway binding, which checks the app's manifest lists the capability,
|
|
8
|
-
* injects the key the gateway holds and forwards the call. The app never
|
|
9
|
-
* sees the key. A refusal the gateway makes itself comes back as a response
|
|
10
|
-
* {@link gatewayRefusal} recognizes; anything else is the provider's answer.
|
|
11
|
-
*
|
|
12
|
-
* For an OAuth client (`linkedin`, `mastodon`, ...) it reaches the
|
|
13
|
-
* provider's token endpoints only, and the gateway puts its client on the
|
|
14
|
-
* request: send the code (or refresh token) without `client_id` or
|
|
15
|
-
* `client_secret`. Build the authorize URL with {@link authorizeUrl} from
|
|
16
|
-
* {@link integrationStatus}, and call the provider's API with the user's
|
|
17
|
-
* token directly.
|
|
18
|
-
*
|
|
19
|
-
* In local dev only, with no binding, the developer's own key or client
|
|
20
|
-
* from `.dev.vars` reaches the provider directly, under the gateway's names:
|
|
21
|
-
* a catalog provider's from the catalog, a provider registered on the
|
|
22
|
-
* gateway from its spec in `.everyapp/providers/<id>.json` (`everyapp
|
|
23
|
-
* provider show <id> --save` writes it), put on the call as the gateway's
|
|
24
|
-
* spec says.
|
|
25
|
-
*/
|
|
26
|
-
export function integrationFetch({ env, provider, for: target, }) {
|
|
1
|
+
import { ACCOUNT_HEADER, CATALOG, ConfigurationError, GATEWAY_ERROR_HEADER, INTEGRATION_PROXY_PREFIX, OAUTH_TOKEN_BODY_LIMIT, allowedScopes, apiKeyHosts, authorizationFor, capabilitySettings, carriesToken, declaredScopeSets, describeTokenEndpoints, devProviderFile, grantedScopes, heldTokenCallAllowed, injectClientCredentials, integrationProxyPath, oauthClientCredentials, oauthReadMethods, oauthWriteMethods, providerSettingPrefix, requestedScopes, requestedTokenScopes, resolveDevProvider, rewriteTokenRequestScope, scopeExcess, tokenEndpointFor, tokenGrantType, EMAIL_SENDERS_ENV, chooseEmailProvider, parseEmailList, parseEmailSender, } from "../internal/index.js";
|
|
2
|
+
import { applyAttribution, attributionFor, } from "./attribution.js";
|
|
3
|
+
import { BINDING_ORIGIN, gatewayBinding, streamingRequest, } from "./gatewayFetch.js";
|
|
4
|
+
export function integrationFetch({ env, provider, for: explicitTarget, account, optional = false, }) {
|
|
27
5
|
const catalogEntry = fetchableCapability(provider);
|
|
28
|
-
|
|
6
|
+
const what = `integrationFetch("${provider}")`;
|
|
7
|
+
// Checked now, so a call nobody's fails where the fetch is made; and
|
|
8
|
+
// again per call, where an identity may since have neared its expiry.
|
|
9
|
+
attributionFor(env, explicitTarget, what);
|
|
29
10
|
const values = env;
|
|
30
|
-
const binding =
|
|
11
|
+
const binding = gatewayBinding(env);
|
|
31
12
|
if (binding && typeof binding.fetch !== "function") {
|
|
32
13
|
throw new ConfigurationError("EVERY_APP_GATEWAY is configured but is not a valid service binding.");
|
|
33
14
|
}
|
|
@@ -36,10 +17,28 @@ export function integrationFetch({ env, provider, for: target, }) {
|
|
|
36
17
|
const integration = catalogEntry ??
|
|
37
18
|
(binding ? undefined : devRegisteredProvider(provider, values));
|
|
38
19
|
const local = binding || !integration ? null : localCredentials(integration, values);
|
|
39
|
-
|
|
40
|
-
|
|
20
|
+
// In dev an OAuth provider with a held token in `.dev.vars` serves API
|
|
21
|
+
// calls without the client (the token stands in for a connection).
|
|
22
|
+
const devToken = !binding && integration?.mode === "oauth_client" && integration.flow
|
|
23
|
+
? stringValue(values[devAccessTokenName(provider)])
|
|
24
|
+
: undefined;
|
|
25
|
+
// An OAuth provider with a Gateway-owned flow answers an API call
|
|
26
|
+
// without the client (`integration_not_connected`, below); a token
|
|
27
|
+
// endpoint call without the client throws when it is made.
|
|
28
|
+
const decidesLater = integration?.mode === "oauth_client" && integration.flow !== undefined;
|
|
29
|
+
if (!binding && !local && !devToken && integration && !decidesLater) {
|
|
30
|
+
if (optional)
|
|
31
|
+
return null;
|
|
32
|
+
const names = [
|
|
33
|
+
...capabilitySettings(integration),
|
|
34
|
+
...(integration.mode === "oauth_client" && integration.flow
|
|
35
|
+
? [devAccessTokenName(provider)]
|
|
36
|
+
: []),
|
|
37
|
+
];
|
|
38
|
+
throw new ConfigurationError(`${integration.label} is unavailable: deploy with the EVERY_APP_GATEWAY binding, or set ${names.join(", ")} in .dev.vars for local development.`);
|
|
41
39
|
}
|
|
42
40
|
return async (input, init) => {
|
|
41
|
+
const target = attributionFor(env, explicitTarget, what);
|
|
43
42
|
const outbound = new Request(input, init);
|
|
44
43
|
const upstream = new URL(outbound.url);
|
|
45
44
|
const headers = new Headers(outbound.headers);
|
|
@@ -55,6 +54,30 @@ export function integrationFetch({ env, provider, for: target, }) {
|
|
|
55
54
|
return binding.fetch(streamingRequest(`${BINDING_ORIGIN}${integrationProxyPath(provider, upstream)}`, outbound, headers));
|
|
56
55
|
}
|
|
57
56
|
if (integration.mode === "oauth_client") {
|
|
57
|
+
// A call to the provider's API with the token the gateway holds
|
|
58
|
+
// (docs/design/2026-10-oauth-providers.md section 7), for an entry
|
|
59
|
+
// that supports the Gateway-owned flow; a token endpoint stays the
|
|
60
|
+
// app-driven call it always was.
|
|
61
|
+
const toApi = integration.flow !== undefined &&
|
|
62
|
+
upstream.protocol === "https:" &&
|
|
63
|
+
integration.api.includes(upstream.host) &&
|
|
64
|
+
!tokenEndpointFor(integration, upstream);
|
|
65
|
+
if (toApi) {
|
|
66
|
+
if (binding) {
|
|
67
|
+
if (account)
|
|
68
|
+
headers.set(ACCOUNT_HEADER, account);
|
|
69
|
+
applyAttribution(headers, target);
|
|
70
|
+
return binding.fetch(streamingRequest(`${BINDING_ORIGIN}${integrationProxyPath(provider, upstream)}`, outbound, headers));
|
|
71
|
+
}
|
|
72
|
+
return devHeldTokenCall({
|
|
73
|
+
provider,
|
|
74
|
+
capability: integration,
|
|
75
|
+
outbound,
|
|
76
|
+
upstream,
|
|
77
|
+
headers,
|
|
78
|
+
values,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
58
81
|
return oauthClientCall({
|
|
59
82
|
provider: provider,
|
|
60
83
|
capability: integration,
|
|
@@ -92,6 +115,93 @@ export function integrationFetch({ env, provider, for: target, }) {
|
|
|
92
115
|
return fetch(streamingRequest(upstream.toString(), outbound, headers));
|
|
93
116
|
};
|
|
94
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* The `.dev.vars` name of a held token for `provider` in local dev
|
|
120
|
+
* (`GOOGLE_WORKSPACE_ACCESS_TOKEN`, `GITHUB_ACCESS_TOKEN`): a token the
|
|
121
|
+
* developer obtained themselves, standing in for the connection the
|
|
122
|
+
* gateway would hold. Dev-only: the gateway never reads it.
|
|
123
|
+
*/
|
|
124
|
+
export function devAccessTokenName(provider) {
|
|
125
|
+
return `${providerSettingPrefix(provider)}ACCESS_TOKEN`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* An app's call to an OAuth provider's API in local dev, with no
|
|
129
|
+
* gateway: the gateway's held-token checks in its order (the app's
|
|
130
|
+
* declared sets, the method, the route), then the developer's own token
|
|
131
|
+
* from `.dev.vars` as the bearer, straight to the provider.
|
|
132
|
+
*/
|
|
133
|
+
async function devHeldTokenCall({ provider, capability, outbound, upstream, headers, values, }) {
|
|
134
|
+
const token = stringValue(values[devAccessTokenName(provider)]);
|
|
135
|
+
if (!token) {
|
|
136
|
+
return devRefusal(409, "integration_not_connected", `${capability.label} isn't connected here. In local dev, set ${devAccessTokenName(provider)} in .dev.vars to a token you obtained yourself; deployed, the person connects at /connect/${provider}.`, { connectPath: `/connect/${provider}`, reconnect: false });
|
|
137
|
+
}
|
|
138
|
+
const policy = capability.scopePolicy;
|
|
139
|
+
const grant = policy
|
|
140
|
+
? devScopeSets(policy, provider, capability.label, values, "any")
|
|
141
|
+
: null;
|
|
142
|
+
if (grant && "problem" in grant) {
|
|
143
|
+
return devRefusal(403, grant.code, grant.problem);
|
|
144
|
+
}
|
|
145
|
+
const method = outbound.method.toUpperCase();
|
|
146
|
+
const reads = oauthReadMethods(capability).includes(method);
|
|
147
|
+
const writes = !reads &&
|
|
148
|
+
capability.access.includes("write") &&
|
|
149
|
+
oauthWriteMethods(capability).includes(method) &&
|
|
150
|
+
devDeclaredAccess(provider, values) === "write";
|
|
151
|
+
if (policy && grant) {
|
|
152
|
+
const allowed = heldTokenCallAllowed({
|
|
153
|
+
policy,
|
|
154
|
+
declaredSets: grant.sets,
|
|
155
|
+
// The developer's token stands for a connection granted every set.
|
|
156
|
+
connectionSets: grant.sets,
|
|
157
|
+
hosts: capability.api,
|
|
158
|
+
method,
|
|
159
|
+
upstream,
|
|
160
|
+
readMethods: oauthReadMethods(capability),
|
|
161
|
+
writes,
|
|
162
|
+
});
|
|
163
|
+
if (!allowed.ok) {
|
|
164
|
+
const status = {
|
|
165
|
+
integration_not_connected: 409,
|
|
166
|
+
integration_method_not_allowed: 405,
|
|
167
|
+
integration_scope_not_allowed: 403,
|
|
168
|
+
}[allowed.code];
|
|
169
|
+
return devRefusal(status, allowed.code, allowed.code === "integration_not_connected"
|
|
170
|
+
? `${capability.label} is connected without ${allowed.missingSets.join(", ")}.`
|
|
171
|
+
: allowed.message);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else if (!reads && !writes) {
|
|
175
|
+
return devRefusal(405, "integration_method_not_allowed", `${capability.label} calls may use ${oauthReadMethods(capability).join(" or ")} with access: "read"; ${method} needs access: "write" in the app's capabilities entry, on a provider that offers it.`);
|
|
176
|
+
}
|
|
177
|
+
applyAttribution(headers, undefined);
|
|
178
|
+
headers.set("authorization", `Bearer ${token}`);
|
|
179
|
+
for (const name of ["access_token", "token"]) {
|
|
180
|
+
upstream.searchParams.delete(name);
|
|
181
|
+
}
|
|
182
|
+
headers.delete("x-http-method-override");
|
|
183
|
+
return fetch(new Request(upstream.toString(), {
|
|
184
|
+
method,
|
|
185
|
+
headers,
|
|
186
|
+
body: method === "GET" || method === "HEAD" ? null : outbound.body,
|
|
187
|
+
signal: outbound.signal,
|
|
188
|
+
// As the gateway: the token never follows a redirect.
|
|
189
|
+
redirect: "manual",
|
|
190
|
+
...(method === "GET" || method === "HEAD" ? {} : { duplex: "half" }),
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
/** The `access` the manifest entry for `provider` declares in dev (EVERYAPP_DEV_CAPABILITIES), or null. */
|
|
194
|
+
function devDeclaredAccess(provider, values) {
|
|
195
|
+
const raw = values["EVERYAPP_DEV_CAPABILITIES"];
|
|
196
|
+
try {
|
|
197
|
+
const capabilities = typeof raw === "string" ? jsonRecord(JSON.parse(raw)) : undefined;
|
|
198
|
+
const entry = jsonRecord(capabilities?.[provider]);
|
|
199
|
+
return typeof entry?.["access"] === "string" ? entry["access"] : null;
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
95
205
|
/**
|
|
96
206
|
* The developer's own key or client from `.dev.vars` (with EVERYAPP_DEV
|
|
97
207
|
* set), under the gateway's names; null until every setting it needs is.
|
|
@@ -110,12 +220,7 @@ function localCredentials(integration, values) {
|
|
|
110
220
|
* with the developer's client put on it by the gateway's own rule.
|
|
111
221
|
*/
|
|
112
222
|
async function oauthClientCall({ provider, capability, outbound, upstream, headers, values, binding, target, client, }) {
|
|
113
|
-
|
|
114
|
-
// instance) and refuses any other, so any origin stands in for it here.
|
|
115
|
-
const settings = binding && capability.hostSetting
|
|
116
|
-
? { [capability.hostSetting]: upstream.origin }
|
|
117
|
-
: values;
|
|
118
|
-
const endpoint = tokenEndpointFor(capability, upstream, settings);
|
|
223
|
+
const endpoint = tokenEndpointFor(capability, upstream);
|
|
119
224
|
const method = outbound.method.toUpperCase();
|
|
120
225
|
if (!endpoint || !endpoint.methods.includes(method)) {
|
|
121
226
|
throw new TypeError(`integrationFetch("${provider}") only reaches ${capability.label}'s token endpoints (${describeTokenEndpoints(capability)}), not ${method} ${upstream.origin}${upstream.pathname}. Call its API with the user's token directly.`);
|
|
@@ -125,6 +230,9 @@ async function oauthClientCall({ provider, capability, outbound, upstream, heade
|
|
|
125
230
|
return binding.fetch(streamingRequest(`${BINDING_ORIGIN}${integrationProxyPath(provider, upstream)}`, outbound, headers));
|
|
126
231
|
}
|
|
127
232
|
applyAttribution(headers, undefined);
|
|
233
|
+
if (!client) {
|
|
234
|
+
throw new ConfigurationError(`${capability.label}'s token endpoints need the client in .dev.vars for local development: set ${capabilitySettings(capability).join(", ")}.`);
|
|
235
|
+
}
|
|
128
236
|
// The gateway's scope checks, in its order, answering its refusals: an
|
|
129
237
|
// app sees in `everyapp dev` what the gateway will say.
|
|
130
238
|
const policy = capability.scopePolicy;
|
|
@@ -173,13 +281,15 @@ async function oauthClientCall({ provider, capability, outbound, upstream, heade
|
|
|
173
281
|
* `x-everyapp-error`) from the local-dev twin, so {@link gatewayRefusal}
|
|
174
282
|
* reads it the same way.
|
|
175
283
|
*/
|
|
176
|
-
function devRefusal(status, code, message) {
|
|
284
|
+
function devRefusal(status, code, message, extra = {}) {
|
|
177
285
|
const labels = {
|
|
178
286
|
400: "Bad Request",
|
|
179
287
|
403: "Forbidden",
|
|
288
|
+
405: "Method Not Allowed",
|
|
289
|
+
409: "Conflict",
|
|
180
290
|
502: "Bad Gateway",
|
|
181
291
|
};
|
|
182
|
-
return Response.json({ error: labels[status] ?? "Error", code, message }, { status, headers: { [GATEWAY_ERROR_HEADER]: code } });
|
|
292
|
+
return Response.json({ error: labels[status] ?? "Error", code, message, ...extra }, { status, headers: { [GATEWAY_ERROR_HEADER]: code } });
|
|
183
293
|
}
|
|
184
294
|
/**
|
|
185
295
|
* The scope sets the manifest declares for `id`, read from
|
|
@@ -191,7 +301,9 @@ function devRefusal(status, code, message) {
|
|
|
191
301
|
* doesn't offer). Fails closed like the gateway: a hand-rolled dev harness
|
|
192
302
|
* that passes no capabilities gets nothing.
|
|
193
303
|
*/
|
|
194
|
-
function devScopeSets(policy, id, label, values
|
|
304
|
+
function devScopeSets(policy, id, label, values,
|
|
305
|
+
/** The grant the entry needs: `write` for a token-endpoint call (the app-driven flow), `any` for a held-token call. */
|
|
306
|
+
grant = "write") {
|
|
195
307
|
const offered = Object.keys(policy.sets).join(", ");
|
|
196
308
|
const raw = values["EVERYAPP_DEV_CAPABILITIES"];
|
|
197
309
|
let capabilities;
|
|
@@ -211,11 +323,16 @@ function devScopeSets(policy, id, label, values) {
|
|
|
211
323
|
const entry = Object.hasOwn(capabilities, id)
|
|
212
324
|
? jsonRecord(capabilities[id])
|
|
213
325
|
: undefined;
|
|
214
|
-
// The gateway's check 2: listing the client for writing is the grant
|
|
215
|
-
|
|
326
|
+
// The gateway's check 2: listing the client for writing is the grant
|
|
327
|
+
// of the app-driven flow; a held-token call takes any listing.
|
|
328
|
+
const access = entry?.["access"];
|
|
329
|
+
if (!entry ||
|
|
330
|
+
(grant === "write"
|
|
331
|
+
? access !== "write"
|
|
332
|
+
: access !== "read" && access !== "write")) {
|
|
216
333
|
return {
|
|
217
334
|
code: "capability_not_requested",
|
|
218
|
-
problem: `This app doesn't list ${label} in its capabilities. Add capabilities: { ${JSON.stringify(id)}: { access: "write" } } to everyapp.config.ts and start everyapp dev again.`,
|
|
335
|
+
problem: `This app doesn't list ${label} in its capabilities. Add capabilities: { ${JSON.stringify(id)}: { access: "${grant === "write" ? "write" : "read"}" } } to everyapp.config.ts and start everyapp dev again.`,
|
|
219
336
|
};
|
|
220
337
|
}
|
|
221
338
|
const sets = declaredScopeSets(policy, entry);
|
|
@@ -315,6 +432,8 @@ async function checkTokenResponse(policy, capability, sets, response) {
|
|
|
315
432
|
google: "Ask for only the scopes integrationStatus() returns, without include_granted_scopes, and connect again; if the app needs more, add the scope set to everyapp.config.ts and deploy.",
|
|
316
433
|
microsoft: "On a shared Microsoft client a token carries everything the person consented to this client: have them remove this app's consent at https://myapplications.microsoft.com and connect again, or add the scope set to everyapp.config.ts and deploy.",
|
|
317
434
|
slack: "Slack scopes add up per workspace installation: reinstall the app in the workspace with only the status's scopes, or add the scope set to everyapp.config.ts and deploy.",
|
|
435
|
+
space: "Ask for only the scopes integrationStatus() returns and connect again, or add the scope set to everyapp.config.ts and deploy.",
|
|
436
|
+
comma: "Ask for only the scopes integrationStatus() returns and connect again, or add the scope set to everyapp.config.ts and deploy.",
|
|
318
437
|
}[policy.dialect];
|
|
319
438
|
return devRefusal(403, "integration_scope_exceeded", `${capability.label} granted scopes this app doesn't declare: ${excess.join(", ")}. It declares ${sets.join(", ")} (${requestedScopes(policy, sets).scopes.join(", ")}). Nothing was passed on. ${remedy}`);
|
|
320
439
|
}
|
|
@@ -333,6 +452,9 @@ function devRegisteredProvider(provider, values) {
|
|
|
333
452
|
const resolved = resolveDevProvider(values, provider);
|
|
334
453
|
if (!resolved.found)
|
|
335
454
|
throw new ConfigurationError(resolved.problem);
|
|
455
|
+
if (resolved.capability.mode === "ai") {
|
|
456
|
+
throw new ConfigurationError(`${provider} is an AI provider: list it under providers and call it with createGatewayFetch(), not integrationFetch().`);
|
|
457
|
+
}
|
|
336
458
|
return resolved.capability;
|
|
337
459
|
}
|
|
338
460
|
/**
|
|
@@ -361,9 +483,48 @@ function stringValue(value) {
|
|
|
361
483
|
* set up") up front instead of failing mid-task. An OAuth client's status
|
|
362
484
|
* carries its public `clientId` for the authorize URL.
|
|
363
485
|
*/
|
|
364
|
-
export async function integrationStatus({ env, provider, }) {
|
|
486
|
+
export async function integrationStatus({ env, provider, for: explicitTarget, }) {
|
|
487
|
+
const status = await readIntegrationStatus({
|
|
488
|
+
env,
|
|
489
|
+
provider,
|
|
490
|
+
...(explicitTarget === undefined ? {} : { for: explicitTarget }),
|
|
491
|
+
});
|
|
492
|
+
return withSetup(status, String(provider), env);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* `status` with its setup fields: the Gateway's as it sent them, or in
|
|
496
|
+
* local development (no binding) the `.dev.vars` names a status that
|
|
497
|
+
* isn't configured lacks.
|
|
498
|
+
*/
|
|
499
|
+
function withSetup(status, provider, values) {
|
|
500
|
+
const binding = gatewayBinding(values);
|
|
501
|
+
if (binding || !status.requested || status.configured) {
|
|
502
|
+
return {
|
|
503
|
+
...status,
|
|
504
|
+
settings: Array.isArray(status.settings) ? status.settings : [],
|
|
505
|
+
setup: typeof status.setup === "string" ? status.setup : null,
|
|
506
|
+
command: typeof status.command === "string" ? status.command : null,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
const integration = CATALOG.get(provider) ?? devRegisteredProvider(provider, values);
|
|
510
|
+
const settings = provider === "email"
|
|
511
|
+
? ["EMAIL_FROM"]
|
|
512
|
+
: integration
|
|
513
|
+
? [...capabilitySettings(integration)]
|
|
514
|
+
: [];
|
|
515
|
+
return {
|
|
516
|
+
...status,
|
|
517
|
+
settings,
|
|
518
|
+
setup: settings.length
|
|
519
|
+
? `${integration?.label ?? provider} isn't set up for local development: set ${settings.join(" and ")} in .dev.vars.`
|
|
520
|
+
: `${integration?.label ?? provider} isn't set up for local development.`,
|
|
521
|
+
command: null,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
async function readIntegrationStatus({ env, provider, for: explicitTarget, }) {
|
|
525
|
+
const target = attributionFor(env, explicitTarget, `integrationStatus("${String(provider)}")`);
|
|
365
526
|
const values = env;
|
|
366
|
-
const binding =
|
|
527
|
+
const binding = gatewayBinding(env);
|
|
367
528
|
// A provider registered on the gateway is the gateway's to answer for;
|
|
368
529
|
// without one, the catalog, or in local dev the row's spec from
|
|
369
530
|
// `.everyapp/providers/<id>.json`.
|
|
@@ -389,7 +550,18 @@ export async function integrationStatus({ env, provider, }) {
|
|
|
389
550
|
ready: false,
|
|
390
551
|
});
|
|
391
552
|
if (binding && typeof binding.fetch === "function") {
|
|
392
|
-
const
|
|
553
|
+
const statusUrl = `${BINDING_ORIGIN}${INTEGRATION_PROXY_PREFIX}/${provider}`;
|
|
554
|
+
let response;
|
|
555
|
+
if (target === undefined) {
|
|
556
|
+
response = await binding.fetch(statusUrl);
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
// Whose status: the person's identity (their OAuth connection) or the
|
|
560
|
+
// organization's, as a call would carry it.
|
|
561
|
+
const headers = new Headers();
|
|
562
|
+
applyAttribution(headers, target);
|
|
563
|
+
response = await binding.fetch(statusUrl, { headers });
|
|
564
|
+
}
|
|
393
565
|
if (!response.ok)
|
|
394
566
|
return unavailable();
|
|
395
567
|
return (await response.json());
|
|
@@ -429,11 +601,32 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
429
601
|
const client = values["EVERYAPP_DEV"]
|
|
430
602
|
? oauthClientCredentials(capability, values)
|
|
431
603
|
: null;
|
|
432
|
-
const origin = oauthClientOrigin(capability, values);
|
|
433
604
|
const policy = capability.scopePolicy;
|
|
605
|
+
// An entry with a Gateway-owned flow is listed for reading or writing;
|
|
606
|
+
// the app-driven flow alone needs the write grant.
|
|
434
607
|
const grant = policy
|
|
435
|
-
? devScopeSets(policy, id, capability.label, values)
|
|
608
|
+
? devScopeSets(policy, id, capability.label, values, capability.flow ? "any" : "write")
|
|
436
609
|
: null;
|
|
610
|
+
// The Gateway-owned flow's fields, in dev: a token in `.dev.vars`
|
|
611
|
+
// stands for a connection granted every declared set.
|
|
612
|
+
const flow = capability.flow ? "both" : "app";
|
|
613
|
+
const devToken = capability.flow
|
|
614
|
+
? stringValue(values[devAccessTokenName(id)])
|
|
615
|
+
: undefined;
|
|
616
|
+
const gateway = (sets) => capability.flow
|
|
617
|
+
? {
|
|
618
|
+
flow,
|
|
619
|
+
connectPath: `/connect/${id}`,
|
|
620
|
+
connection: devToken
|
|
621
|
+
? {
|
|
622
|
+
account: "user",
|
|
623
|
+
label: devAccessTokenName(id),
|
|
624
|
+
scopeSets: sets,
|
|
625
|
+
ready: true,
|
|
626
|
+
}
|
|
627
|
+
: null,
|
|
628
|
+
}
|
|
629
|
+
: { flow };
|
|
437
630
|
if (grant && "problem" in grant) {
|
|
438
631
|
if (grant.code === "capability_not_requested") {
|
|
439
632
|
return { requested: false, configured: false, ready: false };
|
|
@@ -443,16 +636,16 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
443
636
|
configured: Boolean(client),
|
|
444
637
|
ready: false,
|
|
445
638
|
scopeSets: [],
|
|
639
|
+
...gateway([]),
|
|
446
640
|
};
|
|
447
641
|
}
|
|
448
642
|
const asked = policy && grant ? requestedScopes(policy, grant.sets) : null;
|
|
449
643
|
return {
|
|
450
644
|
requested: true,
|
|
451
645
|
configured: Boolean(client),
|
|
452
|
-
ready: Boolean(client),
|
|
646
|
+
ready: Boolean(client) || Boolean(devToken),
|
|
453
647
|
...(client ? { clientId: client.clientId } : {}),
|
|
454
|
-
...(client
|
|
455
|
-
...(client && grant && asked
|
|
648
|
+
...((client || devToken) && grant && asked
|
|
456
649
|
? {
|
|
457
650
|
scopeSets: grant.sets,
|
|
458
651
|
scopes: asked.scopes,
|
|
@@ -461,6 +654,7 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
461
654
|
: {}),
|
|
462
655
|
}
|
|
463
656
|
: {}),
|
|
657
|
+
...gateway(grant?.sets ?? []),
|
|
464
658
|
};
|
|
465
659
|
}
|
|
466
660
|
/**
|
|
@@ -492,35 +686,3 @@ function devEmailStatus(values) {
|
|
|
492
686
|
provider: configured && choice.ok ? choice.provider : null,
|
|
493
687
|
};
|
|
494
688
|
}
|
|
495
|
-
/**
|
|
496
|
-
* A refusal the AppGateway binding made, thrown: what `sendEmail()` throws
|
|
497
|
-
* when the gateway won't send (`email_sender_not_allowed`,
|
|
498
|
-
* `email_budget_exhausted`, ...). The thrown twin of {@link gatewayRefusal}.
|
|
499
|
-
*/
|
|
500
|
-
export class GatewayRefusalError extends Error {
|
|
501
|
-
status;
|
|
502
|
-
code;
|
|
503
|
-
constructor({ status, code, message }) {
|
|
504
|
-
super(message);
|
|
505
|
-
this.name = "GatewayRefusalError";
|
|
506
|
-
this.status = status;
|
|
507
|
-
this.code = code;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* The gateway's own refusal in `response`, or null when the response is the
|
|
512
|
-
* provider's answer (which may be an error of its own). Reads the body only
|
|
513
|
-
* for a refusal, so call it before reading the body yourself.
|
|
514
|
-
*/
|
|
515
|
-
export async function gatewayRefusal(response) {
|
|
516
|
-
const code = response.headers.get(GATEWAY_ERROR_HEADER);
|
|
517
|
-
if (!code)
|
|
518
|
-
return null;
|
|
519
|
-
const body = await response.json().catch(() => null);
|
|
520
|
-
const message = body &&
|
|
521
|
-
typeof body === "object" &&
|
|
522
|
-
typeof body.message === "string"
|
|
523
|
-
? body.message
|
|
524
|
-
: `The Every App gateway refused the call (${code}).`;
|
|
525
|
-
return { status: response.status, code, message };
|
|
526
|
-
}
|
|
@@ -28,5 +28,5 @@ export interface ListMembersOptions {
|
|
|
28
28
|
* for a request answers its signed-in user alone, and background work
|
|
29
29
|
* answers no one.
|
|
30
30
|
*/
|
|
31
|
-
export declare function listMembers({ env, for:
|
|
31
|
+
export declare function listMembers({ env, for: explicitTarget, }: ListMembersOptions): Promise<ListMembersResult>;
|
|
32
32
|
//# sourceMappingURL=listMembers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listMembers.d.ts","sourceRoot":"","sources":["../../src/server/listMembers.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"listMembers.d.ts","sourceRoot":"","sources":["../../src/server/listMembers.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAS1B,MAAM,WAAW,kBAAkB;IACjC,8FAA8F;IAC9F,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,WAAW,CAAC,EAChC,GAAG,EACH,GAAG,EAAE,cAAc,GACpB,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkBjD"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ConfigurationError, serviceRoutePath, } from "../internal/index.js";
|
|
2
|
-
import { applyAttribution,
|
|
2
|
+
import { applyAttribution, attributionFor, isRequest, } from "./attribution.js";
|
|
3
3
|
import { getEveryAppUser } from "./everyApp.js";
|
|
4
|
-
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
5
|
-
import { GatewayRefusalError, gatewayRefusal } from "./
|
|
4
|
+
import { BINDING_ORIGIN, gatewayBinding, } from "./gatewayFetch.js";
|
|
5
|
+
import { GatewayRefusalError, gatewayRefusal } from "./refusal.js";
|
|
6
6
|
/**
|
|
7
7
|
* The organization's members who can open the app now, through the
|
|
8
8
|
* gateway's `members` capability: people deactivated, removed from the
|
|
@@ -19,10 +19,10 @@ import { GatewayRefusalError, gatewayRefusal } from "./integrationFetch.js";
|
|
|
19
19
|
* for a request answers its signed-in user alone, and background work
|
|
20
20
|
* answers no one.
|
|
21
21
|
*/
|
|
22
|
-
export async function listMembers({ env, for:
|
|
23
|
-
|
|
22
|
+
export async function listMembers({ env, for: explicitTarget, }) {
|
|
23
|
+
const target = attributionFor(env, explicitTarget, "listMembers");
|
|
24
24
|
const values = env;
|
|
25
|
-
const binding =
|
|
25
|
+
const binding = gatewayBinding(env);
|
|
26
26
|
if (binding) {
|
|
27
27
|
if (typeof binding.fetch !== "function") {
|
|
28
28
|
throw new ConfigurationError("EVERY_APP_GATEWAY is configured but is not a valid service binding.");
|
|
@@ -48,7 +48,7 @@ async function listThroughGateway(binding, target) {
|
|
|
48
48
|
throw new GatewayRefusalError({
|
|
49
49
|
status: response.status,
|
|
50
50
|
code: "members_list_failed",
|
|
51
|
-
message: `The
|
|
51
|
+
message: `The EveryApp gateway answered ${response.status} to the members list.`,
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
return (await response.json());
|
|
@@ -64,11 +64,8 @@ async function listInDev(env, target) {
|
|
|
64
64
|
id: user.id,
|
|
65
65
|
email: user.email,
|
|
66
66
|
name: "",
|
|
67
|
-
role:
|
|
67
|
+
role: user.orgRole,
|
|
68
68
|
},
|
|
69
69
|
],
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
-
function memberRole(role) {
|
|
73
|
-
return role === "owner" || role === "admin" ? role : "member";
|
|
74
|
-
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** What would make it work, as the Gateway words it. */
|
|
2
|
+
export interface SetupInfo {
|
|
3
|
+
/** The Gateway settings it needs (`["DATAFORSEO_API_KEY"]`); `[]` when ready or not a setting. */
|
|
4
|
+
settings: readonly string[];
|
|
5
|
+
/** One sentence for a person, naming what to set and how; null when ready. */
|
|
6
|
+
setup: string | null;
|
|
7
|
+
/** The command an admin runs (`pnpm everyapp configure crm`), or null. */
|
|
8
|
+
command: string | null;
|
|
9
|
+
}
|
|
10
|
+
/** A refusal the AppGateway binding made itself, not the provider. */
|
|
11
|
+
export interface GatewayRefusal extends SetupInfo {
|
|
12
|
+
status: number;
|
|
13
|
+
/** e.g. `capability_not_requested`, `integration_not_configured`. */
|
|
14
|
+
code: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/** The refusal codes that mean no model is set up for the call. */
|
|
18
|
+
export declare const AI_NOT_CONFIGURED_CODES: readonly string[];
|
|
19
|
+
/**
|
|
20
|
+
* A refusal the AppGateway binding made, thrown: what `sendEmail()` throws
|
|
21
|
+
* when the gateway won't send (`email_sender_not_allowed`,
|
|
22
|
+
* `email_budget_exhausted`, ...). The thrown twin of {@link gatewayRefusal}.
|
|
23
|
+
*/
|
|
24
|
+
export declare class GatewayRefusalError extends Error implements GatewayRefusal {
|
|
25
|
+
readonly status: number;
|
|
26
|
+
readonly code: string;
|
|
27
|
+
readonly settings: readonly string[];
|
|
28
|
+
readonly setup: string | null;
|
|
29
|
+
readonly command: string | null;
|
|
30
|
+
constructor({ status, code, message, settings, setup, command, }: Pick<GatewayRefusal, "status" | "code" | "message"> & Partial<SetupInfo>);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The gateway's own refusal in `response`, or null when the response is the
|
|
34
|
+
* provider's answer (which may be an error of its own). Reads the body only
|
|
35
|
+
* for a refusal, so call it before reading the body yourself.
|
|
36
|
+
*/
|
|
37
|
+
export declare function gatewayRefusal(response: Response): Promise<GatewayRefusal | null>;
|
|
38
|
+
/**
|
|
39
|
+
* The Gateway's refusal behind a thrown error, or null when it isn't one:
|
|
40
|
+
* a {@link GatewayRefusalError} (`sendEmail()`, `listMembers()`, `emit()`),
|
|
41
|
+
* an OpenAI SDK `APIError` or an ai-sdk `APICallError` for a call the
|
|
42
|
+
* Gateway refused (also inside ai-sdk's `RetryError` or an error's
|
|
43
|
+
* `cause`), or the SDK's local-development `ConfigurationError` for a
|
|
44
|
+
* missing key, which answers as the deployed refusal would
|
|
45
|
+
* (`ai_provider_not_configured`, status 503, the `.dev.vars` names).
|
|
46
|
+
*/
|
|
47
|
+
export declare function refusalFromError(error: unknown): GatewayRefusal | null;
|
|
48
|
+
/**
|
|
49
|
+
* Whether `error` (or a refusal already read) means no model is set up:
|
|
50
|
+
* `ai_provider_not_configured` or `ai_default_not_configured`, from the
|
|
51
|
+
* Gateway or, in local development, from the SDK with no key in
|
|
52
|
+
* `.dev.vars`. Show `refusalFromError(error).setup` to the person.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isAiNotConfigured(error: unknown): boolean;
|
|
55
|
+
//# sourceMappingURL=refusal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refusal.d.ts","sourceRoot":"","sources":["../../src/server/refusal.ts"],"names":[],"mappings":"AAgBA,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACxB,kGAAkG;IAClG,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,sEAAsE;AACtE,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mEAAmE;AACnE,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAGpD,CAAC;AAEF;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,KAAM,YAAW,cAAc;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;gBAEpB,EACV,MAAM,EACN,IAAI,EACJ,OAAO,EACP,QAAa,EACb,KAAY,EACZ,OAAc,GACf,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;CAS5E;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAKhC;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAWtE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGzD"}
|