@every-app/sdk 0.3.0-rc.2 → 0.3.0-rc.4
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/README.md +1 -1
- package/dist/cloudflare/index.d.ts +2 -2
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +1 -1
- package/dist/cloudflare/sentinel.d.ts +57 -2
- package/dist/cloudflare/sentinel.d.ts.map +1 -1
- package/dist/cloudflare/sentinel.js +27 -2
- package/dist/cloudflare/worker.d.ts +297 -5
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +279 -12
- 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/internal/aiDefault.d.ts +141 -0
- package/dist/internal/aiDefault.d.ts.map +1 -0
- package/dist/internal/aiDefault.js +204 -0
- package/dist/internal/aiProviders.d.ts +4 -1
- package/dist/internal/aiProviders.d.ts.map +1 -1
- package/dist/internal/aiProviders.js +5 -1
- package/dist/internal/appSettings.d.ts +20 -2
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +53 -7
- 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 +276 -7
- package/dist/internal/capabilities.d.ts.map +1 -1
- package/dist/internal/capabilities.js +111 -0
- package/dist/internal/catalog/index.d.ts +39 -2
- package/dist/internal/catalog/index.d.ts.map +1 -1
- package/dist/internal/catalog/inference.d.ts +39 -2
- package/dist/internal/catalog/inference.d.ts.map +1 -1
- package/dist/internal/catalog/inference.js +36 -4
- 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 +42 -4
- package/dist/internal/identity.d.ts +29 -3
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +37 -9
- package/dist/internal/index.d.ts +5 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +5 -1
- package/dist/internal/members.d.ts +3 -2
- package/dist/internal/members.d.ts.map +1 -1
- package/dist/internal/oauthPresets.d.ts +29 -0
- package/dist/internal/oauthPresets.d.ts.map +1 -0
- package/dist/internal/oauthPresets.js +534 -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 +59 -0
- package/dist/internal/oauthSpec.d.ts.map +1 -0
- package/dist/internal/oauthSpec.js +676 -0
- package/dist/internal/protocol.d.ts +36 -1
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +30 -1
- package/dist/internal/providerRegistry.d.ts +17 -6
- package/dist/internal/providerRegistry.d.ts.map +1 -1
- package/dist/internal/providerRegistry.js +47 -2
- package/dist/internal/providerSpec.d.ts +11 -7
- package/dist/internal/providerSpec.d.ts.map +1 -1
- package/dist/internal/providerSpec.js +134 -37
- package/dist/internal/signInProviders.d.ts.map +1 -1
- package/dist/internal/signInProviders.js +11 -4
- package/dist/server/ai.d.ts +45 -0
- package/dist/server/ai.d.ts.map +1 -0
- package/dist/server/ai.js +40 -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/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/emit.d.ts +1 -1
- package/dist/server/emit.d.ts.map +1 -1
- package/dist/server/emit.js +4 -4
- 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 +8 -6
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +78 -11
- package/dist/server/index.d.ts +7 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +6 -2
- package/dist/server/integrationFetch.d.ts +55 -8
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +198 -18
- package/dist/server/listMembers.d.ts +1 -1
- package/dist/server/listMembers.d.ts.map +1 -1
- package/dist/server/listMembers.js +5 -8
- package/dist/server/sendEmail.d.ts +1 -1
- package/dist/server/sendEmail.d.ts.map +1 -1
- package/dist/server/sendEmail.js +4 -4
- package/dist/server/toolsEndpoint.d.ts.map +1 -1
- package/dist/server/toolsEndpoint.js +11 -5
- package/package.json +13 -14
- package/LICENSE +0 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,OAAO,EACP,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,OAAO,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,WAAW,EACX,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EACL,WAAW,EACX,UAAU,EACV,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,EAAE,EAAE,mBAAmB,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,GAClC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,wBAAwB,GAC9B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,uBAAuB,EACvB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,SAAS,EACT,WAAW,EACX,UAAU,EACV,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,OAAO,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
*
|
|
4
4
|
* There is intentionally no client-side export.
|
|
5
5
|
*/
|
|
6
|
-
export { ConfigurationError, IdentityError, everyApp, getEveryAppUser, hasScope, requireEveryAppUser, } from "./everyApp.js";
|
|
6
|
+
export { ConfigurationError, IdentityError, everyApp, getEveryAppUser, hasScope, isAdmin, requireCurrentUser, requireEveryAppUser, } from "./everyApp.js";
|
|
7
|
+
export { OrganizationMismatchError, RequestContextError, currentUser, withOrganization, } from "./context.js";
|
|
7
8
|
export { AttributionError } from "./attribution.js";
|
|
8
9
|
export { authorizeUrl } from "./authorizeUrl.js";
|
|
10
|
+
export { connectPath, connectUrl, } from "./connectUrl.js";
|
|
9
11
|
export { createGatewayFetch, } from "./gatewayFetch.js";
|
|
10
|
-
export {
|
|
12
|
+
export { ai, AI_DEFAULT_BASE_URL } from "./ai.js";
|
|
13
|
+
export { GatewayRefusalError, gatewayRefusal, devAccessTokenName, integrationFetch, integrationStatus, } from "./integrationFetch.js";
|
|
11
14
|
export { nodeServerHandler, } from "./nodeServer.js";
|
|
12
15
|
export { sendEmail } from "./sendEmail.js";
|
|
13
16
|
export { listMembers } from "./listMembers.js";
|
|
14
17
|
export { emit } from "./emit.js";
|
|
15
18
|
export { ToolError, defineTools, toolResult, } from "./tools.js";
|
|
19
|
+
export { fromMcpTools, } from "./fromMcpTools.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ApiKeyCapabilityId, type CapabilityId, type EmailCapabilityStatus, type OAuthClientCapabilityId } from "../internal/index.js";
|
|
1
|
+
import { type ApiKeyCapabilityId, type CapabilityId, type ConnectionAccount, type EmailCapabilityStatus, type OAuthClientCapabilityId } from "../internal/index.js";
|
|
2
2
|
import { type GatewayCallFor } from "./attribution.js";
|
|
3
3
|
export interface IntegrationFetchOptions {
|
|
4
4
|
/**
|
|
@@ -17,13 +17,22 @@ export interface IntegrationFetchOptions {
|
|
|
17
17
|
*/
|
|
18
18
|
provider: ApiKeyCapabilityId | OAuthClientCapabilityId | (string & {});
|
|
19
19
|
/**
|
|
20
|
-
* Whom the call is for
|
|
21
|
-
*
|
|
22
|
-
* (
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* Whom the call is for. Left out, the request `everyApp()` is serving
|
|
21
|
+
* (its user, while the identity is good) or the organization
|
|
22
|
+
* `withOrganization()` named; outside both, `RequestContextError`.
|
|
23
|
+
* Explicitly: the inbound request, or `{ background: true,
|
|
24
|
+
* organizationId }` for work no person started (crons, Workflows,
|
|
25
|
+
* queues). A shared app's Worker must end up with one or the other
|
|
26
|
+
* ({@link AttributionError}).
|
|
25
27
|
*/
|
|
26
28
|
for?: GatewayCallFor;
|
|
29
|
+
/**
|
|
30
|
+
* For an OAuth provider the gateway holds connections for: whose
|
|
31
|
+
* connection the call uses, the person's (`user`, the default when a
|
|
32
|
+
* person is behind the call) or the organization's (`organization`,
|
|
33
|
+
* the default for background work). Sent as `x-everyapp-account`.
|
|
34
|
+
*/
|
|
35
|
+
account?: ConnectionAccount;
|
|
27
36
|
}
|
|
28
37
|
/**
|
|
29
38
|
* A `fetch` for one of the gateway's capabilities. Call the provider's real
|
|
@@ -47,7 +56,14 @@ export interface IntegrationFetchOptions {
|
|
|
47
56
|
* provider show <id> --save` writes it), put on the call as the gateway's
|
|
48
57
|
* spec says.
|
|
49
58
|
*/
|
|
50
|
-
export declare function integrationFetch({ env, provider, for:
|
|
59
|
+
export declare function integrationFetch({ env, provider, for: explicitTarget, account, }: IntegrationFetchOptions): typeof fetch;
|
|
60
|
+
/**
|
|
61
|
+
* The `.dev.vars` name of a held token for `provider` in local dev
|
|
62
|
+
* (`GOOGLE_WORKSPACE_ACCESS_TOKEN`, `GITHUB_ACCESS_TOKEN`): a token the
|
|
63
|
+
* developer obtained themselves, standing in for the connection the
|
|
64
|
+
* gateway would hold. Dev-only: the gateway never reads it.
|
|
65
|
+
*/
|
|
66
|
+
export declare function devAccessTokenName(provider: string): string;
|
|
51
67
|
export interface IntegrationStatus {
|
|
52
68
|
/** The app's manifest lists the capability. */
|
|
53
69
|
requested: boolean;
|
|
@@ -92,6 +108,29 @@ export interface OAuthClientIntegrationStatus extends IntegrationStatus {
|
|
|
92
108
|
scopes?: readonly string[];
|
|
93
109
|
/** Slack's `user_scope` strings, when the sets name any. */
|
|
94
110
|
userScopes?: readonly string[];
|
|
111
|
+
/**
|
|
112
|
+
* Which flows the client supports: `app` (the app runs authorize and
|
|
113
|
+
* callback itself and keeps the tokens, the social networks), `gateway`
|
|
114
|
+
* (the Gateway holds the connection; API calls go through
|
|
115
|
+
* `integrationFetch` with the token injected) or `both` (Google,
|
|
116
|
+
* Microsoft, Slack, Discord and every registered OAuth provider).
|
|
117
|
+
*/
|
|
118
|
+
flow?: "app" | "gateway" | "both";
|
|
119
|
+
/** Where a person connects on the Gateway: `/connect/<id>`; see `connectUrl()`. */
|
|
120
|
+
connectPath?: string;
|
|
121
|
+
/**
|
|
122
|
+
* The connection the caller's account would use (the person's, or the
|
|
123
|
+
* organization's for background work), or null when there is none yet;
|
|
124
|
+
* `reconnect` when it exists but lacks a set the app declares or has
|
|
125
|
+
* expired, so the person has to connect again.
|
|
126
|
+
*/
|
|
127
|
+
connection?: {
|
|
128
|
+
account: ConnectionAccount;
|
|
129
|
+
label: string | null;
|
|
130
|
+
scopeSets: readonly string[];
|
|
131
|
+
ready: boolean;
|
|
132
|
+
reconnect?: boolean;
|
|
133
|
+
} | null;
|
|
95
134
|
}
|
|
96
135
|
/** The status of a capability: email's carries its senders, an OAuth client's its id. */
|
|
97
136
|
export type IntegrationStatusOf<P extends string> = P extends "email" ? EmailIntegrationStatus : P extends OAuthClientCapabilityId ? OAuthClientIntegrationStatus : IntegrationStatus;
|
|
@@ -101,9 +140,17 @@ export type IntegrationStatusOf<P extends string> = P extends "email" ? EmailInt
|
|
|
101
140
|
* set up") up front instead of failing mid-task. An OAuth client's status
|
|
102
141
|
* carries its public `clientId` for the authorize URL.
|
|
103
142
|
*/
|
|
104
|
-
export declare function integrationStatus<P extends CapabilityId | (string & {})>({ env, provider, }: {
|
|
143
|
+
export declare function integrationStatus<P extends CapabilityId | (string & {})>({ env, provider, for: explicitTarget, }: {
|
|
105
144
|
env: object;
|
|
106
145
|
provider: P;
|
|
146
|
+
/**
|
|
147
|
+
* Whom the status is for: the request being served (its person), so an
|
|
148
|
+
* OAuth provider's `connection` is that person's; background work
|
|
149
|
+
* (`withOrganization()`) its organization, whose own connection is then
|
|
150
|
+
* reported. Explicitly the inbound request or `{ background: true,
|
|
151
|
+
* organizationId }`, as on every call.
|
|
152
|
+
*/
|
|
153
|
+
for?: GatewayCallFor;
|
|
107
154
|
}): Promise<IntegrationStatusOf<P>>;
|
|
108
155
|
/** A refusal the AppGateway binding made itself, not the provider. */
|
|
109
156
|
export interface GatewayRefusal {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integrationFetch.d.ts","sourceRoot":"","sources":["../../src/server/integrationFetch.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"integrationFetch.d.ts","sourceRoot":"","sources":["../../src/server/integrationFetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
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, oauthClientOrigin, requestedScopes, requestedTokenScopes, resolveDevProvider, rewriteTokenRequestScope, scopeExcess, tokenEndpointFor, tokenGrantType, EMAIL_SENDERS_ENV, chooseEmailProvider, parseEmailList, parseEmailSender, } from "../internal/index.js";
|
|
2
|
-
import { applyAttribution,
|
|
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, oauthClientOrigin, 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
3
|
import { BINDING_ORIGIN, streamingRequest, } from "./gatewayFetch.js";
|
|
4
4
|
/**
|
|
5
5
|
* A `fetch` for one of the gateway's capabilities. Call the provider's real
|
|
@@ -23,9 +23,12 @@ import { BINDING_ORIGIN, streamingRequest, } from "./gatewayFetch.js";
|
|
|
23
23
|
* provider show <id> --save` writes it), put on the call as the gateway's
|
|
24
24
|
* spec says.
|
|
25
25
|
*/
|
|
26
|
-
export function integrationFetch({ env, provider, for:
|
|
26
|
+
export function integrationFetch({ env, provider, for: explicitTarget, account, }) {
|
|
27
27
|
const catalogEntry = fetchableCapability(provider);
|
|
28
|
-
|
|
28
|
+
const what = `integrationFetch("${provider}")`;
|
|
29
|
+
// Checked now, so a call nobody's fails where the fetch is made; and
|
|
30
|
+
// again per call, where an identity may since have neared its expiry.
|
|
31
|
+
attributionFor(env, explicitTarget, what);
|
|
29
32
|
const values = env;
|
|
30
33
|
const binding = values["EVERY_APP_GATEWAY"];
|
|
31
34
|
if (binding && typeof binding.fetch !== "function") {
|
|
@@ -36,10 +39,26 @@ export function integrationFetch({ env, provider, for: target, }) {
|
|
|
36
39
|
const integration = catalogEntry ??
|
|
37
40
|
(binding ? undefined : devRegisteredProvider(provider, values));
|
|
38
41
|
const local = binding || !integration ? null : localCredentials(integration, values);
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
// In dev an OAuth provider with a held token in `.dev.vars` serves API
|
|
43
|
+
// calls without the client (the token stands in for a connection).
|
|
44
|
+
const devToken = !binding && integration?.mode === "oauth_client" && integration.flow
|
|
45
|
+
? stringValue(values[devAccessTokenName(provider)])
|
|
46
|
+
: undefined;
|
|
47
|
+
// An OAuth provider with a Gateway-owned flow answers an API call
|
|
48
|
+
// without the client (`integration_not_connected`, below); a token
|
|
49
|
+
// endpoint call without the client throws when it is made.
|
|
50
|
+
const decidesLater = integration?.mode === "oauth_client" && integration.flow !== undefined;
|
|
51
|
+
if (!binding && !local && !devToken && integration && !decidesLater) {
|
|
52
|
+
const names = [
|
|
53
|
+
...capabilitySettings(integration),
|
|
54
|
+
...(integration.mode === "oauth_client" && integration.flow
|
|
55
|
+
? [devAccessTokenName(provider)]
|
|
56
|
+
: []),
|
|
57
|
+
];
|
|
58
|
+
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
59
|
}
|
|
42
60
|
return async (input, init) => {
|
|
61
|
+
const target = attributionFor(env, explicitTarget, what);
|
|
43
62
|
const outbound = new Request(input, init);
|
|
44
63
|
const upstream = new URL(outbound.url);
|
|
45
64
|
const headers = new Headers(outbound.headers);
|
|
@@ -55,6 +74,30 @@ export function integrationFetch({ env, provider, for: target, }) {
|
|
|
55
74
|
return binding.fetch(streamingRequest(`${BINDING_ORIGIN}${integrationProxyPath(provider, upstream)}`, outbound, headers));
|
|
56
75
|
}
|
|
57
76
|
if (integration.mode === "oauth_client") {
|
|
77
|
+
// A call to the provider's API with the token the gateway holds
|
|
78
|
+
// (docs/design/2026-10-oauth-providers.md section 7), for an entry
|
|
79
|
+
// that supports the Gateway-owned flow; a token endpoint stays the
|
|
80
|
+
// app-driven call it always was.
|
|
81
|
+
const toApi = integration.flow !== undefined &&
|
|
82
|
+
upstream.protocol === "https:" &&
|
|
83
|
+
integration.api.includes(upstream.host) &&
|
|
84
|
+
!tokenEndpointFor(integration, upstream, binding && integration.hostSetting ? undefined : values);
|
|
85
|
+
if (toApi) {
|
|
86
|
+
if (binding) {
|
|
87
|
+
if (account)
|
|
88
|
+
headers.set(ACCOUNT_HEADER, account);
|
|
89
|
+
applyAttribution(headers, target);
|
|
90
|
+
return binding.fetch(streamingRequest(`${BINDING_ORIGIN}${integrationProxyPath(provider, upstream)}`, outbound, headers));
|
|
91
|
+
}
|
|
92
|
+
return devHeldTokenCall({
|
|
93
|
+
provider,
|
|
94
|
+
capability: integration,
|
|
95
|
+
outbound,
|
|
96
|
+
upstream,
|
|
97
|
+
headers,
|
|
98
|
+
values,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
58
101
|
return oauthClientCall({
|
|
59
102
|
provider: provider,
|
|
60
103
|
capability: integration,
|
|
@@ -92,6 +135,93 @@ export function integrationFetch({ env, provider, for: target, }) {
|
|
|
92
135
|
return fetch(streamingRequest(upstream.toString(), outbound, headers));
|
|
93
136
|
};
|
|
94
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* The `.dev.vars` name of a held token for `provider` in local dev
|
|
140
|
+
* (`GOOGLE_WORKSPACE_ACCESS_TOKEN`, `GITHUB_ACCESS_TOKEN`): a token the
|
|
141
|
+
* developer obtained themselves, standing in for the connection the
|
|
142
|
+
* gateway would hold. Dev-only: the gateway never reads it.
|
|
143
|
+
*/
|
|
144
|
+
export function devAccessTokenName(provider) {
|
|
145
|
+
return `${providerSettingPrefix(provider)}ACCESS_TOKEN`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* An app's call to an OAuth provider's API in local dev, with no
|
|
149
|
+
* gateway: the gateway's held-token checks in its order (the app's
|
|
150
|
+
* declared sets, the method, the route), then the developer's own token
|
|
151
|
+
* from `.dev.vars` as the bearer, straight to the provider.
|
|
152
|
+
*/
|
|
153
|
+
async function devHeldTokenCall({ provider, capability, outbound, upstream, headers, values, }) {
|
|
154
|
+
const token = stringValue(values[devAccessTokenName(provider)]);
|
|
155
|
+
if (!token) {
|
|
156
|
+
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 });
|
|
157
|
+
}
|
|
158
|
+
const policy = capability.scopePolicy;
|
|
159
|
+
const grant = policy
|
|
160
|
+
? devScopeSets(policy, provider, capability.label, values, "any")
|
|
161
|
+
: null;
|
|
162
|
+
if (grant && "problem" in grant) {
|
|
163
|
+
return devRefusal(403, grant.code, grant.problem);
|
|
164
|
+
}
|
|
165
|
+
const method = outbound.method.toUpperCase();
|
|
166
|
+
const reads = oauthReadMethods(capability).includes(method);
|
|
167
|
+
const writes = !reads &&
|
|
168
|
+
capability.access.includes("write") &&
|
|
169
|
+
oauthWriteMethods(capability).includes(method) &&
|
|
170
|
+
devDeclaredAccess(provider, values) === "write";
|
|
171
|
+
if (policy && grant) {
|
|
172
|
+
const allowed = heldTokenCallAllowed({
|
|
173
|
+
policy,
|
|
174
|
+
declaredSets: grant.sets,
|
|
175
|
+
// The developer's token stands for a connection granted every set.
|
|
176
|
+
connectionSets: grant.sets,
|
|
177
|
+
hosts: capability.api,
|
|
178
|
+
method,
|
|
179
|
+
upstream,
|
|
180
|
+
readMethods: oauthReadMethods(capability),
|
|
181
|
+
writes,
|
|
182
|
+
});
|
|
183
|
+
if (!allowed.ok) {
|
|
184
|
+
const status = {
|
|
185
|
+
integration_not_connected: 409,
|
|
186
|
+
integration_method_not_allowed: 405,
|
|
187
|
+
integration_scope_not_allowed: 403,
|
|
188
|
+
}[allowed.code];
|
|
189
|
+
return devRefusal(status, allowed.code, allowed.code === "integration_not_connected"
|
|
190
|
+
? `${capability.label} is connected without ${allowed.missingSets.join(", ")}.`
|
|
191
|
+
: allowed.message);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else if (!reads && !writes) {
|
|
195
|
+
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.`);
|
|
196
|
+
}
|
|
197
|
+
applyAttribution(headers, undefined);
|
|
198
|
+
headers.set("authorization", `Bearer ${token}`);
|
|
199
|
+
for (const name of ["access_token", "token"]) {
|
|
200
|
+
upstream.searchParams.delete(name);
|
|
201
|
+
}
|
|
202
|
+
headers.delete("x-http-method-override");
|
|
203
|
+
return fetch(new Request(upstream.toString(), {
|
|
204
|
+
method,
|
|
205
|
+
headers,
|
|
206
|
+
body: method === "GET" || method === "HEAD" ? null : outbound.body,
|
|
207
|
+
signal: outbound.signal,
|
|
208
|
+
// As the gateway: the token never follows a redirect.
|
|
209
|
+
redirect: "manual",
|
|
210
|
+
...(method === "GET" || method === "HEAD" ? {} : { duplex: "half" }),
|
|
211
|
+
}));
|
|
212
|
+
}
|
|
213
|
+
/** The `access` the manifest entry for `provider` declares in dev (EVERYAPP_DEV_CAPABILITIES), or null. */
|
|
214
|
+
function devDeclaredAccess(provider, values) {
|
|
215
|
+
const raw = values["EVERYAPP_DEV_CAPABILITIES"];
|
|
216
|
+
try {
|
|
217
|
+
const capabilities = typeof raw === "string" ? jsonRecord(JSON.parse(raw)) : undefined;
|
|
218
|
+
const entry = jsonRecord(capabilities?.[provider]);
|
|
219
|
+
return typeof entry?.["access"] === "string" ? entry["access"] : null;
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
95
225
|
/**
|
|
96
226
|
* The developer's own key or client from `.dev.vars` (with EVERYAPP_DEV
|
|
97
227
|
* set), under the gateway's names; null until every setting it needs is.
|
|
@@ -125,6 +255,9 @@ async function oauthClientCall({ provider, capability, outbound, upstream, heade
|
|
|
125
255
|
return binding.fetch(streamingRequest(`${BINDING_ORIGIN}${integrationProxyPath(provider, upstream)}`, outbound, headers));
|
|
126
256
|
}
|
|
127
257
|
applyAttribution(headers, undefined);
|
|
258
|
+
if (!client) {
|
|
259
|
+
throw new ConfigurationError(`${capability.label}'s token endpoints need the client in .dev.vars for local development: set ${capabilitySettings(capability).join(", ")}.`);
|
|
260
|
+
}
|
|
128
261
|
// The gateway's scope checks, in its order, answering its refusals: an
|
|
129
262
|
// app sees in `everyapp dev` what the gateway will say.
|
|
130
263
|
const policy = capability.scopePolicy;
|
|
@@ -173,13 +306,15 @@ async function oauthClientCall({ provider, capability, outbound, upstream, heade
|
|
|
173
306
|
* `x-everyapp-error`) from the local-dev twin, so {@link gatewayRefusal}
|
|
174
307
|
* reads it the same way.
|
|
175
308
|
*/
|
|
176
|
-
function devRefusal(status, code, message) {
|
|
309
|
+
function devRefusal(status, code, message, extra = {}) {
|
|
177
310
|
const labels = {
|
|
178
311
|
400: "Bad Request",
|
|
179
312
|
403: "Forbidden",
|
|
313
|
+
405: "Method Not Allowed",
|
|
314
|
+
409: "Conflict",
|
|
180
315
|
502: "Bad Gateway",
|
|
181
316
|
};
|
|
182
|
-
return Response.json({ error: labels[status] ?? "Error", code, message }, { status, headers: { [GATEWAY_ERROR_HEADER]: code } });
|
|
317
|
+
return Response.json({ error: labels[status] ?? "Error", code, message, ...extra }, { status, headers: { [GATEWAY_ERROR_HEADER]: code } });
|
|
183
318
|
}
|
|
184
319
|
/**
|
|
185
320
|
* The scope sets the manifest declares for `id`, read from
|
|
@@ -191,7 +326,9 @@ function devRefusal(status, code, message) {
|
|
|
191
326
|
* doesn't offer). Fails closed like the gateway: a hand-rolled dev harness
|
|
192
327
|
* that passes no capabilities gets nothing.
|
|
193
328
|
*/
|
|
194
|
-
function devScopeSets(policy, id, label, values
|
|
329
|
+
function devScopeSets(policy, id, label, values,
|
|
330
|
+
/** The grant the entry needs: `write` for a token-endpoint call (the app-driven flow), `any` for a held-token call. */
|
|
331
|
+
grant = "write") {
|
|
195
332
|
const offered = Object.keys(policy.sets).join(", ");
|
|
196
333
|
const raw = values["EVERYAPP_DEV_CAPABILITIES"];
|
|
197
334
|
let capabilities;
|
|
@@ -211,11 +348,16 @@ function devScopeSets(policy, id, label, values) {
|
|
|
211
348
|
const entry = Object.hasOwn(capabilities, id)
|
|
212
349
|
? jsonRecord(capabilities[id])
|
|
213
350
|
: undefined;
|
|
214
|
-
// The gateway's check 2: listing the client for writing is the grant
|
|
215
|
-
|
|
351
|
+
// The gateway's check 2: listing the client for writing is the grant
|
|
352
|
+
// of the app-driven flow; a held-token call takes any listing.
|
|
353
|
+
const access = entry?.["access"];
|
|
354
|
+
if (!entry ||
|
|
355
|
+
(grant === "write"
|
|
356
|
+
? access !== "write"
|
|
357
|
+
: access !== "read" && access !== "write")) {
|
|
216
358
|
return {
|
|
217
359
|
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.`,
|
|
360
|
+
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
361
|
};
|
|
220
362
|
}
|
|
221
363
|
const sets = declaredScopeSets(policy, entry);
|
|
@@ -315,6 +457,8 @@ async function checkTokenResponse(policy, capability, sets, response) {
|
|
|
315
457
|
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
458
|
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
459
|
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.",
|
|
460
|
+
space: "Ask for only the scopes integrationStatus() returns and connect again, or add the scope set to everyapp.config.ts and deploy.",
|
|
461
|
+
comma: "Ask for only the scopes integrationStatus() returns and connect again, or add the scope set to everyapp.config.ts and deploy.",
|
|
318
462
|
}[policy.dialect];
|
|
319
463
|
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
464
|
}
|
|
@@ -361,7 +505,8 @@ function stringValue(value) {
|
|
|
361
505
|
* set up") up front instead of failing mid-task. An OAuth client's status
|
|
362
506
|
* carries its public `clientId` for the authorize URL.
|
|
363
507
|
*/
|
|
364
|
-
export async function integrationStatus({ env, provider, }) {
|
|
508
|
+
export async function integrationStatus({ env, provider, for: explicitTarget, }) {
|
|
509
|
+
const target = attributionFor(env, explicitTarget, `integrationStatus("${String(provider)}")`);
|
|
365
510
|
const values = env;
|
|
366
511
|
const binding = values["EVERY_APP_GATEWAY"];
|
|
367
512
|
// A provider registered on the gateway is the gateway's to answer for;
|
|
@@ -389,7 +534,18 @@ export async function integrationStatus({ env, provider, }) {
|
|
|
389
534
|
ready: false,
|
|
390
535
|
});
|
|
391
536
|
if (binding && typeof binding.fetch === "function") {
|
|
392
|
-
const
|
|
537
|
+
const statusUrl = `${BINDING_ORIGIN}${INTEGRATION_PROXY_PREFIX}/${provider}`;
|
|
538
|
+
let response;
|
|
539
|
+
if (target === undefined) {
|
|
540
|
+
response = await binding.fetch(statusUrl);
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
// Whose status: the person's identity (their OAuth connection) or the
|
|
544
|
+
// organization's, as a call would carry it.
|
|
545
|
+
const headers = new Headers();
|
|
546
|
+
applyAttribution(headers, target);
|
|
547
|
+
response = await binding.fetch(statusUrl, { headers });
|
|
548
|
+
}
|
|
393
549
|
if (!response.ok)
|
|
394
550
|
return unavailable();
|
|
395
551
|
return (await response.json());
|
|
@@ -431,9 +587,31 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
431
587
|
: null;
|
|
432
588
|
const origin = oauthClientOrigin(capability, values);
|
|
433
589
|
const policy = capability.scopePolicy;
|
|
590
|
+
// An entry with a Gateway-owned flow is listed for reading or writing;
|
|
591
|
+
// the app-driven flow alone needs the write grant.
|
|
434
592
|
const grant = policy
|
|
435
|
-
? devScopeSets(policy, id, capability.label, values)
|
|
593
|
+
? devScopeSets(policy, id, capability.label, values, capability.flow ? "any" : "write")
|
|
436
594
|
: null;
|
|
595
|
+
// The Gateway-owned flow's fields, in dev: a token in `.dev.vars`
|
|
596
|
+
// stands for a connection granted every declared set.
|
|
597
|
+
const flow = capability.flow ? "both" : "app";
|
|
598
|
+
const devToken = capability.flow
|
|
599
|
+
? stringValue(values[devAccessTokenName(id)])
|
|
600
|
+
: undefined;
|
|
601
|
+
const gateway = (sets) => capability.flow
|
|
602
|
+
? {
|
|
603
|
+
flow,
|
|
604
|
+
connectPath: `/connect/${id}`,
|
|
605
|
+
connection: devToken
|
|
606
|
+
? {
|
|
607
|
+
account: "user",
|
|
608
|
+
label: devAccessTokenName(id),
|
|
609
|
+
scopeSets: sets,
|
|
610
|
+
ready: true,
|
|
611
|
+
}
|
|
612
|
+
: null,
|
|
613
|
+
}
|
|
614
|
+
: { flow };
|
|
437
615
|
if (grant && "problem" in grant) {
|
|
438
616
|
if (grant.code === "capability_not_requested") {
|
|
439
617
|
return { requested: false, configured: false, ready: false };
|
|
@@ -443,16 +621,17 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
443
621
|
configured: Boolean(client),
|
|
444
622
|
ready: false,
|
|
445
623
|
scopeSets: [],
|
|
624
|
+
...gateway([]),
|
|
446
625
|
};
|
|
447
626
|
}
|
|
448
627
|
const asked = policy && grant ? requestedScopes(policy, grant.sets) : null;
|
|
449
628
|
return {
|
|
450
629
|
requested: true,
|
|
451
630
|
configured: Boolean(client),
|
|
452
|
-
ready: Boolean(client),
|
|
631
|
+
ready: Boolean(client) || Boolean(devToken),
|
|
453
632
|
...(client ? { clientId: client.clientId } : {}),
|
|
454
633
|
...(client && origin ? { origin } : {}),
|
|
455
|
-
...(client && grant && asked
|
|
634
|
+
...((client || devToken) && grant && asked
|
|
456
635
|
? {
|
|
457
636
|
scopeSets: grant.sets,
|
|
458
637
|
scopes: asked.scopes,
|
|
@@ -461,6 +640,7 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
461
640
|
: {}),
|
|
462
641
|
}
|
|
463
642
|
: {}),
|
|
643
|
+
...gateway(grant?.sets ?? []),
|
|
464
644
|
};
|
|
465
645
|
}
|
|
466
646
|
/**
|
|
@@ -521,6 +701,6 @@ export async function gatewayRefusal(response) {
|
|
|
521
701
|
typeof body === "object" &&
|
|
522
702
|
typeof body.message === "string"
|
|
523
703
|
? body.message
|
|
524
|
-
: `The
|
|
704
|
+
: `The EveryApp gateway refused the call (${code}).`;
|
|
525
705
|
return { status: response.status, code, message };
|
|
526
706
|
}
|
|
@@ -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;AAK1B,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,CAoBjD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
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
4
|
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
5
5
|
import { GatewayRefusalError, gatewayRefusal } from "./integrationFetch.js";
|
|
@@ -19,8 +19,8 @@ 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
25
|
const binding = values["EVERY_APP_GATEWAY"];
|
|
26
26
|
if (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
|
-
}
|
|
@@ -35,5 +35,5 @@ export interface SendEmailOptions {
|
|
|
35
35
|
* `.dev.vars` it goes out for real through Email Sending's REST API, from
|
|
36
36
|
* the developer's own account.
|
|
37
37
|
*/
|
|
38
|
-
export declare function sendEmail({ env, for:
|
|
38
|
+
export declare function sendEmail({ env, for: explicitTarget, message, }: SendEmailOptions): Promise<SendEmailResult>;
|
|
39
39
|
//# sourceMappingURL=sendEmail.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sendEmail.d.ts","sourceRoot":"","sources":["../../src/server/sendEmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAeL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAI1B,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,SAAS,CAAC,EAC9B,GAAG,EACH,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"sendEmail.d.ts","sourceRoot":"","sources":["../../src/server/sendEmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAeL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAI1B,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,SAAS,CAAC,EAC9B,GAAG,EACH,GAAG,EAAE,cAAc,EACnB,OAAO,GACR,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAoB7C"}
|
package/dist/server/sendEmail.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConfigurationError, EMAIL_SENDERS_ENV, emailDomain, emailProviderRefusal, emailRestBody, emailRestUrl, emailSenderRefusal, parseEmailList, parseEmailSender, parseSendEmailMessage, readEmailRestResponse, senderAllowed, serviceRoutePath, } from "../internal/index.js";
|
|
2
|
-
import { applyAttribution,
|
|
2
|
+
import { applyAttribution, attributionFor, } from "./attribution.js";
|
|
3
3
|
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
4
4
|
import { GatewayRefusalError, gatewayRefusal } from "./integrationFetch.js";
|
|
5
5
|
/**
|
|
@@ -19,8 +19,8 @@ import { GatewayRefusalError, gatewayRefusal } from "./integrationFetch.js";
|
|
|
19
19
|
* `.dev.vars` it goes out for real through Email Sending's REST API, from
|
|
20
20
|
* the developer's own account.
|
|
21
21
|
*/
|
|
22
|
-
export async function sendEmail({ env, for:
|
|
23
|
-
|
|
22
|
+
export async function sendEmail({ env, for: explicitTarget, message, }) {
|
|
23
|
+
const target = attributionFor(env, explicitTarget, "sendEmail");
|
|
24
24
|
const values = env;
|
|
25
25
|
const binding = values["EVERY_APP_GATEWAY"];
|
|
26
26
|
if (binding) {
|
|
@@ -49,7 +49,7 @@ async function sendThroughGateway(binding, target, message) {
|
|
|
49
49
|
throw new GatewayRefusalError({
|
|
50
50
|
status: response.status,
|
|
51
51
|
code: "email_send_failed",
|
|
52
|
-
message: `The
|
|
52
|
+
message: `The EveryApp gateway answered ${response.status} to the send.`,
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
return (await response.json());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolsEndpoint.d.ts","sourceRoot":"","sources":["../../src/server/toolsEndpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAcL,KAAK,sBAAsB,EAO5B,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"toolsEndpoint.d.ts","sourceRoot":"","sources":["../../src/server/toolsEndpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAcL,KAAK,sBAAsB,EAO5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAOL,KAAK,OAAO,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,QAAQ,EAAE,sBAAsB,CAAC;CAClC;AAoFD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,oBAAoB,EACzB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAyB1B"}
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
* The perimeter also refuses these paths from outside and strips inbound
|
|
15
15
|
* `x-everyapp-*` headers, so only the gateway's ToolBus ever reaches them.
|
|
16
16
|
*/
|
|
17
|
-
import { ConfigurationError, IDENTITY_HEADER, IdentityError, SYSTEM_HEADER, TOOLS_CALL_PATH, TOOLS_LIST_PATH, TOOLS_PROTOCOL_VERSION, catalogHash, requiredScopeForRisk, resolveVerifyOptions,
|
|
17
|
+
import { ConfigurationError, IDENTITY_HEADER, IdentityError, SYSTEM_HEADER, TOOLS_CALL_PATH, TOOLS_LIST_PATH, TOOLS_PROTOCOL_VERSION, assertOrganizationPin, catalogHash, requiredScopeForRisk, resolveVerifyOptions, verifyIdentity, verifySystemJwt, } from "../internal/index.js";
|
|
18
|
+
import { serveRequest } from "./context.js";
|
|
18
19
|
import { SDK_VERSION, ToolError, toToolResult, toolSetInternals, validateWithSchema, } from "./tools.js";
|
|
19
20
|
function toolsJson(status, body, headers = {}) {
|
|
20
21
|
return Response.json(body, {
|
|
@@ -148,9 +149,12 @@ function parseCallRequest(body) {
|
|
|
148
149
|
return { v: TOOLS_PROTOCOL_VERSION, name, arguments: args, callId };
|
|
149
150
|
}
|
|
150
151
|
async function callTool(request, env, ctx, verify, options) {
|
|
151
|
-
let user;
|
|
152
|
+
let user, expiresAt;
|
|
152
153
|
try {
|
|
153
|
-
user = await
|
|
154
|
+
({ user, expiresAt } = await verifyIdentity(request.headers.get(IDENTITY_HEADER) ?? "", verify));
|
|
155
|
+
// The same pin as the handler path: a call for another organization's
|
|
156
|
+
// install never runs a tool here.
|
|
157
|
+
assertOrganizationPin(user, options.identity.organizationId);
|
|
154
158
|
}
|
|
155
159
|
catch (error) {
|
|
156
160
|
if (error instanceof IdentityError) {
|
|
@@ -194,13 +198,15 @@ async function callTool(request, env, ctx, verify, options) {
|
|
|
194
198
|
});
|
|
195
199
|
let result;
|
|
196
200
|
try {
|
|
197
|
-
|
|
201
|
+
// The call runs in the request context like a page would: currentUser()
|
|
202
|
+
// is the caller, and its Gateway calls are attributed to them.
|
|
203
|
+
const value = await serveRequest({ request, user, expiresAt }, () => tool.handler(input.value, {
|
|
198
204
|
user,
|
|
199
205
|
env: env,
|
|
200
206
|
ctx,
|
|
201
207
|
request,
|
|
202
208
|
callId: call.callId,
|
|
203
|
-
});
|
|
209
|
+
}));
|
|
204
210
|
result = await toToolResult(tool, value);
|
|
205
211
|
}
|
|
206
212
|
catch (error) {
|