@every-app/sdk 0.3.0-rc.5 → 0.3.0-rc.6
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/dist/cloudflare/catalogSettings.generated.d.ts +1 -16
- package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -1
- package/dist/cloudflare/catalogSettings.generated.js +0 -49
- package/dist/cloudflare/worker.d.ts +14 -0
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +19 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/aiDefault.d.ts +70 -7
- package/dist/internal/aiDefault.d.ts.map +1 -1
- package/dist/internal/aiDefault.js +145 -15
- package/dist/internal/aiProviders.d.ts +3 -1
- package/dist/internal/aiProviders.d.ts.map +1 -1
- package/dist/internal/aiProviders.js +12 -3
- package/dist/internal/appSettings.d.ts +65 -5
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +141 -23
- package/dist/internal/capabilities.d.ts +52 -433
- package/dist/internal/capabilities.d.ts.map +1 -1
- package/dist/internal/capabilities.js +25 -558
- package/dist/internal/catalog/index.d.ts +6 -6
- package/dist/internal/catalog/inference.d.ts +6 -6
- package/dist/internal/catalog/inference.d.ts.map +1 -1
- package/dist/internal/catalog/inference.js +9 -6
- package/dist/internal/events.d.ts.map +1 -1
- package/dist/internal/events.js +1 -0
- package/dist/internal/gatewaySettings.d.ts +0 -6
- package/dist/internal/gatewaySettings.d.ts.map +1 -1
- package/dist/internal/gatewaySettings.js +1 -14
- package/dist/internal/identity.d.ts +12 -1
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +11 -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 +7 -3
- package/dist/internal/oauthPresets.d.ts.map +1 -1
- package/dist/internal/oauthPresets.js +533 -3
- package/dist/internal/oauthSpec.d.ts +44 -1
- package/dist/internal/oauthSpec.d.ts.map +1 -1
- package/dist/internal/oauthSpec.js +147 -34
- package/dist/internal/protocol.d.ts +14 -0
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +7 -0
- package/dist/internal/providerRegistry.d.ts +61 -1
- package/dist/internal/providerRegistry.d.ts.map +1 -1
- package/dist/internal/providerRegistry.js +127 -6
- package/dist/internal/providerSpec.d.ts +14 -7
- package/dist/internal/providerSpec.d.ts.map +1 -1
- package/dist/internal/providerSpec.js +306 -7
- package/dist/manifest.d.ts +25 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/server/ai.d.ts +45 -0
- package/dist/server/ai.d.ts.map +1 -1
- package/dist/server/ai.js +77 -1
- package/dist/server/aiBinding.d.ts.map +1 -1
- package/dist/server/aiBinding.js +3 -3
- 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/emailBinding.js +1 -1
- package/dist/server/emit.js +1 -1
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +20 -7
- package/dist/server/index.d.ts +3 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -2
- package/dist/server/integrationFetch.d.ts +4 -31
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +44 -42
- package/dist/server/listMembers.js +1 -1
- 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.js +1 -1
- package/package.json +1 -1
|
@@ -40,7 +40,7 @@ function scopedClientIds() {
|
|
|
40
40
|
* `codeChallenge`, PKCE as S256. The app keeps its `state` and verifier
|
|
41
41
|
* for the callback.
|
|
42
42
|
*
|
|
43
|
-
* A client without scope sets
|
|
43
|
+
* A client without scope sets is refused: the
|
|
44
44
|
* registry's checklist for one isn't what the gateway holds a token to,
|
|
45
45
|
* so an app builds that URL itself from the status's `clientId`.
|
|
46
46
|
*
|
|
@@ -66,11 +66,7 @@ export function authorizeUrl({ provider, status, redirectUri, state, codeChallen
|
|
|
66
66
|
? `authorizeUrl(${JSON.stringify(provider)}): include_granted_scopes would widen the token to every scope the person granted this client, which the gateway refuses (integration_scope_exceeded); leave it out of params.`
|
|
67
67
|
: `authorizeUrl(${JSON.stringify(provider)}) sets ${name} itself; leave it out of params.`);
|
|
68
68
|
}
|
|
69
|
-
const
|
|
70
|
-
if (!/^https:/.test(capability.authorize.url) && !base) {
|
|
71
|
-
throw new TypeError(`authorizeUrl(${JSON.stringify(provider)}) needs the instance ${capability.label} is on: the status carries it as origin once ${capability.hostSetting} is set.`);
|
|
72
|
-
}
|
|
73
|
-
const url = new URL(capability.authorize.url, base);
|
|
69
|
+
const url = new URL(capability.authorize.url);
|
|
74
70
|
// The status speaks for the gateway: its scopes are the token's ceiling.
|
|
75
71
|
const scopes = status.scopes;
|
|
76
72
|
const slack = url.host === "slack.com";
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* account (EMAIL_REST_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, EMAIL_FROM).
|
|
17
17
|
*/
|
|
18
18
|
import { ConfigurationError, } from "../internal/index.js";
|
|
19
|
-
import { GatewayRefusalError } from "./
|
|
19
|
+
import { GatewayRefusalError } from "./refusal.js";
|
|
20
20
|
import { sendEmail } from "./sendEmail.js";
|
|
21
21
|
/**
|
|
22
22
|
* A `send_email` binding (`SendEmail`) over the Gateway: pass it where code
|
package/dist/server/emit.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { APP_EVENT_DATA_MAX_BYTES, APP_ID_ENV, ConfigurationError, EVENTS_EMIT_PATH, appEventNameProblem, appEventType, checkEventData, } from "../internal/index.js";
|
|
12
12
|
import { applyAttribution, attributionFor, } from "./attribution.js";
|
|
13
13
|
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
14
|
-
import { GatewayRefusalError, gatewayRefusal } from "./
|
|
14
|
+
import { GatewayRefusalError, gatewayRefusal } from "./refusal.js";
|
|
15
15
|
/**
|
|
16
16
|
* Put an event on the gateway's event bus, for the organization's webhook
|
|
17
17
|
* and email subscribers. The gateway names it `app.<app id>.<event>`, so an
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gatewayFetch.d.ts","sourceRoot":"","sources":["../../src/server/gatewayFetch.ts"],"names":[],"mappings":"AAaA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,cAAc,sCAAsC,CAAC;AAGlE,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxE;AAeD,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAE,GACtD,OAAO,KAAK,GAAG,IAAI,CAAC;AACvB,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GACjC,OAAO,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"gatewayFetch.d.ts","sourceRoot":"","sources":["../../src/server/gatewayFetch.ts"],"names":[],"mappings":"AAaA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,cAAc,sCAAsC,CAAC;AAGlE,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxE;AAeD,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAE,GACtD,OAAO,KAAK,GAAG,IAAI,CAAC;AACvB,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GACjC,OAAO,KAAK,CAAC;AA2HhB,sFAAsF;AACtF,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,GACf,OAAO,CAUT"}
|
|
@@ -15,7 +15,7 @@ export function createGatewayFetch({ env: workerEnv, for: explicitTarget, option
|
|
|
15
15
|
if (!binding && Object.keys(devProviders).length === 0) {
|
|
16
16
|
if (optional)
|
|
17
17
|
return null;
|
|
18
|
-
throw new ConfigurationError(`AI gateway unavailable: deploy with the EVERY_APP_GATEWAY binding, or set the provider's key (${listOf(Object.values(DEV_AI_PROVIDERS).map((spec) => settingsNames(spec, "with")), "or")}) in .dev.vars for direct local development
|
|
18
|
+
throw new ConfigurationError(`AI gateway unavailable: deploy with the EVERY_APP_GATEWAY binding, or set the provider's key (${listOf(Object.values(DEV_AI_PROVIDERS).map((spec) => settingsNames(spec, "with")), "or")}) in .dev.vars for direct local development.`, { code: "ai_provider_not_configured" });
|
|
19
19
|
}
|
|
20
20
|
return async (input, init) => {
|
|
21
21
|
const target = attributionFor(env, explicitTarget, "createGatewayFetch");
|
|
@@ -32,7 +32,10 @@ export function createGatewayFetch({ env: workerEnv, for: explicitTarget, option
|
|
|
32
32
|
const { provider, spec, path, search } = direct;
|
|
33
33
|
const dev = devProviders[provider];
|
|
34
34
|
if (!dev) {
|
|
35
|
-
throw new ConfigurationError(`Set ${settingsNames(spec)} in .dev.vars to call ${provider} in local development
|
|
35
|
+
throw new ConfigurationError(`Set ${settingsNames(spec)} in .dev.vars to call ${provider} in local development.`, {
|
|
36
|
+
code: "ai_provider_not_configured",
|
|
37
|
+
settings: aiProviderSettings(spec),
|
|
38
|
+
});
|
|
36
39
|
}
|
|
37
40
|
const url = joinProviderUrl(`${spec.origin}${dev.basePath}`, path, search);
|
|
38
41
|
if (!url)
|
|
@@ -129,15 +132,20 @@ function directProviderPath(input, env) {
|
|
|
129
132
|
let fillModel = null;
|
|
130
133
|
if (provider === AI_DEFAULT_PROVIDER) {
|
|
131
134
|
// The default in dev, by the gateway's rule on the developer's own
|
|
132
|
-
// `.dev.vars`: the first provider of the order with every setting set
|
|
135
|
+
// `.dev.vars`: the first provider of the order with every setting set,
|
|
136
|
+
// with its seed models (dev has no operator settings; a request that
|
|
137
|
+
// names a model sends it as it is).
|
|
133
138
|
const values = env;
|
|
134
139
|
const resolution = resolveAiDefault({
|
|
135
|
-
|
|
140
|
+
provider: null,
|
|
136
141
|
isSet: (name) => typeof values[name] === "string" &&
|
|
137
142
|
values[name].trim().length > 0,
|
|
138
143
|
});
|
|
139
144
|
if (!resolution.configured) {
|
|
140
|
-
throw new ConfigurationError(`Set ${resolution.settings.join(" and ")} (or another model provider's key) in .dev.vars to call the default model in local development
|
|
145
|
+
throw new ConfigurationError(`Set ${resolution.settings.join(" and ")} (or another model provider's key) in .dev.vars to call the default model in local development.`, {
|
|
146
|
+
code: "ai_default_not_configured",
|
|
147
|
+
settings: resolution.settings,
|
|
148
|
+
});
|
|
141
149
|
}
|
|
142
150
|
const route = path === AI_DEFAULT_ROUTES.chat
|
|
143
151
|
? resolution.chat
|
|
@@ -149,9 +157,14 @@ function directProviderPath(input, env) {
|
|
|
149
157
|
}
|
|
150
158
|
provider = resolution.provider;
|
|
151
159
|
path = route.path;
|
|
152
|
-
fillModel =
|
|
160
|
+
fillModel =
|
|
161
|
+
route === resolution.chat
|
|
162
|
+
? resolution.model
|
|
163
|
+
: (resolution.embeddingsModel ?? null);
|
|
153
164
|
}
|
|
154
|
-
const spec = provider
|
|
165
|
+
const spec = provider
|
|
166
|
+
? devAiProvider(provider, env)
|
|
167
|
+
: undefined;
|
|
155
168
|
if (!provider || !spec) {
|
|
156
169
|
throw new ConfigurationError(`Direct local provider fallback only supports ${listOf([AI_DEFAULT_PROVIDER, ...Object.keys(DEV_AI_PROVIDERS)].map((name) => `${AI_PROXY_PREFIX}${name}`), "and")} paths.`);
|
|
157
170
|
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -13,8 +13,9 @@ export { GATEWAY_ERROR_HEADER } from "../internal/protocol.js";
|
|
|
13
13
|
export { authorizeUrl, type AuthorizeUrlOptions } from "./authorizeUrl.js";
|
|
14
14
|
export { connectPath, connectUrl, type ConnectUrlOptions, } from "./connectUrl.js";
|
|
15
15
|
export { createGatewayFetch, type CreateGatewayFetchOptions, } from "./gatewayFetch.js";
|
|
16
|
-
export { ai, aiBaseUrl, providerBaseUrl, AI_DEFAULT_BASE_URL, type AiClient, } from "./ai.js";
|
|
17
|
-
export { GatewayRefusalError, gatewayRefusal,
|
|
16
|
+
export { ai, aiBaseUrl, aiStatus, providerBaseUrl, AI_DEFAULT_BASE_URL, type AiClient, type AiStatus, } from "./ai.js";
|
|
17
|
+
export { AI_NOT_CONFIGURED_CODES, GatewayRefusalError, gatewayRefusal, isAiNotConfigured, refusalFromError, type GatewayRefusal, type SetupInfo, } from "./refusal.js";
|
|
18
|
+
export { devAccessTokenName, integrationFetch, integrationStatus, type EmailIntegrationStatus, type IntegrationFetchOptions, type IntegrationStatus, type IntegrationStatusOf, type OAuthClientIntegrationStatus, } from "./integrationFetch.js";
|
|
18
19
|
export { nodeServerHandler, type NodeServer, type NodeServerHandlerOptions, } from "./nodeServer.js";
|
|
19
20
|
export { sendEmail, type SendEmailOptions } from "./sendEmail.js";
|
|
20
21
|
export { gatewayAiBinding, type GatewayAiBindingOptions } from "./aiBinding.js";
|
|
@@ -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,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,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,2FAA2F;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,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,GAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,EAAE,EACF,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,KAAK,QAAQ,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.js
CHANGED
|
@@ -12,8 +12,9 @@ export { GATEWAY_ERROR_HEADER } from "../internal/protocol.js";
|
|
|
12
12
|
export { authorizeUrl } from "./authorizeUrl.js";
|
|
13
13
|
export { connectPath, connectUrl, } from "./connectUrl.js";
|
|
14
14
|
export { createGatewayFetch, } from "./gatewayFetch.js";
|
|
15
|
-
export { ai, aiBaseUrl, providerBaseUrl, AI_DEFAULT_BASE_URL, } from "./ai.js";
|
|
16
|
-
export { GatewayRefusalError, gatewayRefusal,
|
|
15
|
+
export { ai, aiBaseUrl, aiStatus, providerBaseUrl, AI_DEFAULT_BASE_URL, } from "./ai.js";
|
|
16
|
+
export { AI_NOT_CONFIGURED_CODES, GatewayRefusalError, gatewayRefusal, isAiNotConfigured, refusalFromError, } from "./refusal.js";
|
|
17
|
+
export { devAccessTokenName, integrationFetch, integrationStatus, } from "./integrationFetch.js";
|
|
17
18
|
export { nodeServerHandler, } from "./nodeServer.js";
|
|
18
19
|
export { sendEmail } from "./sendEmail.js";
|
|
19
20
|
export { gatewayAiBinding } from "./aiBinding.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
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
|
+
import type { SetupInfo } from "./refusal.js";
|
|
3
4
|
export interface IntegrationFetchOptions {
|
|
4
5
|
/**
|
|
5
6
|
* The Worker env: the EVERY_APP_GATEWAY binding when deployed, or in local
|
|
@@ -50,7 +51,7 @@ export interface IntegrationFetchOptions {
|
|
|
50
51
|
* sees the key. A refusal the gateway makes itself comes back as a response
|
|
51
52
|
* {@link gatewayRefusal} recognizes; anything else is the provider's answer.
|
|
52
53
|
*
|
|
53
|
-
* For an OAuth client (`
|
|
54
|
+
* For an OAuth client (`google-workspace`, `slack`, ...) it reaches the
|
|
54
55
|
* provider's token endpoints only, and the gateway puts its client on the
|
|
55
56
|
* request: send the code (or refresh token) without `client_id` or
|
|
56
57
|
* `client_secret`. Build the authorize URL with {@link authorizeUrl} from
|
|
@@ -75,7 +76,7 @@ export declare function integrationFetch(options: IntegrationFetchOptions): type
|
|
|
75
76
|
* gateway would hold. Dev-only: the gateway never reads it.
|
|
76
77
|
*/
|
|
77
78
|
export declare function devAccessTokenName(provider: string): string;
|
|
78
|
-
export interface IntegrationStatus {
|
|
79
|
+
export interface IntegrationStatus extends SetupInfo {
|
|
79
80
|
/** The app's manifest lists the capability. */
|
|
80
81
|
requested: boolean;
|
|
81
82
|
/** The gateway holds a key for it (in local dev: `.dev.vars` sets one). */
|
|
@@ -96,13 +97,8 @@ export type EmailIntegrationStatus = IntegrationStatus & Pick<EmailCapabilitySta
|
|
|
96
97
|
* the app lists the capability and the gateway holds the client.
|
|
97
98
|
*/
|
|
98
99
|
export interface OAuthClientIntegrationStatus extends IntegrationStatus {
|
|
99
|
-
/** The client's public id, for the authorize URL
|
|
100
|
+
/** The client's public id, for the authorize URL. */
|
|
100
101
|
clientId?: string;
|
|
101
|
-
/**
|
|
102
|
-
* The provider's origin when the operator chose it (Mastodon's instance,
|
|
103
|
-
* `MASTODON_URL`): the authorize page, token endpoint and API are on it.
|
|
104
|
-
*/
|
|
105
|
-
origin?: string;
|
|
106
102
|
/**
|
|
107
103
|
* For a client with scope sets (`google-workspace`, `microsoft-365`): the
|
|
108
104
|
* set names the app's manifest entry declares, `[]` when the entry voids
|
|
@@ -163,27 +159,4 @@ export declare function integrationStatus<P extends CapabilityId | (string & {})
|
|
|
163
159
|
*/
|
|
164
160
|
for?: GatewayCallFor;
|
|
165
161
|
}): Promise<IntegrationStatusOf<P>>;
|
|
166
|
-
/** A refusal the AppGateway binding made itself, not the provider. */
|
|
167
|
-
export interface GatewayRefusal {
|
|
168
|
-
status: number;
|
|
169
|
-
/** e.g. `capability_not_requested`, `integration_not_configured`. */
|
|
170
|
-
code: string;
|
|
171
|
-
message: string;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* A refusal the AppGateway binding made, thrown: what `sendEmail()` throws
|
|
175
|
-
* when the gateway won't send (`email_sender_not_allowed`,
|
|
176
|
-
* `email_budget_exhausted`, ...). The thrown twin of {@link gatewayRefusal}.
|
|
177
|
-
*/
|
|
178
|
-
export declare class GatewayRefusalError extends Error implements GatewayRefusal {
|
|
179
|
-
readonly status: number;
|
|
180
|
-
readonly code: string;
|
|
181
|
-
constructor({ status, code, message }: GatewayRefusal);
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* The gateway's own refusal in `response`, or null when the response is the
|
|
185
|
-
* provider's answer (which may be an error of its own). Reads the body only
|
|
186
|
-
* for a refusal, so call it before reading the body yourself.
|
|
187
|
-
*/
|
|
188
|
-
export declare function gatewayRefusal(response: Response): Promise<GatewayRefusal | null>;
|
|
189
162
|
//# sourceMappingURL=integrationFetch.d.ts.map
|
|
@@ -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,4 +1,4 @@
|
|
|
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,
|
|
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
2
|
import { applyAttribution, attributionFor, } from "./attribution.js";
|
|
3
3
|
import { BINDING_ORIGIN, streamingRequest, } from "./gatewayFetch.js";
|
|
4
4
|
export function integrationFetch({ env, provider, for: explicitTarget, account, optional = false, }) {
|
|
@@ -61,7 +61,7 @@ export function integrationFetch({ env, provider, for: explicitTarget, account,
|
|
|
61
61
|
const toApi = integration.flow !== undefined &&
|
|
62
62
|
upstream.protocol === "https:" &&
|
|
63
63
|
integration.api.includes(upstream.host) &&
|
|
64
|
-
!tokenEndpointFor(integration, upstream
|
|
64
|
+
!tokenEndpointFor(integration, upstream);
|
|
65
65
|
if (toApi) {
|
|
66
66
|
if (binding) {
|
|
67
67
|
if (account)
|
|
@@ -220,12 +220,7 @@ function localCredentials(integration, values) {
|
|
|
220
220
|
* with the developer's client put on it by the gateway's own rule.
|
|
221
221
|
*/
|
|
222
222
|
async function oauthClientCall({ provider, capability, outbound, upstream, headers, values, binding, target, client, }) {
|
|
223
|
-
|
|
224
|
-
// instance) and refuses any other, so any origin stands in for it here.
|
|
225
|
-
const settings = binding && capability.hostSetting
|
|
226
|
-
? { [capability.hostSetting]: upstream.origin }
|
|
227
|
-
: values;
|
|
228
|
-
const endpoint = tokenEndpointFor(capability, upstream, settings);
|
|
223
|
+
const endpoint = tokenEndpointFor(capability, upstream);
|
|
229
224
|
const method = outbound.method.toUpperCase();
|
|
230
225
|
if (!endpoint || !endpoint.methods.includes(method)) {
|
|
231
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.`);
|
|
@@ -457,6 +452,9 @@ function devRegisteredProvider(provider, values) {
|
|
|
457
452
|
const resolved = resolveDevProvider(values, provider);
|
|
458
453
|
if (!resolved.found)
|
|
459
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
|
+
}
|
|
460
458
|
return resolved.capability;
|
|
461
459
|
}
|
|
462
460
|
/**
|
|
@@ -486,6 +484,44 @@ function stringValue(value) {
|
|
|
486
484
|
* carries its public `clientId` for the authorize URL.
|
|
487
485
|
*/
|
|
488
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 = values["EVERY_APP_GATEWAY"];
|
|
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, }) {
|
|
489
525
|
const target = attributionFor(env, explicitTarget, `integrationStatus("${String(provider)}")`);
|
|
490
526
|
const values = env;
|
|
491
527
|
const binding = values["EVERY_APP_GATEWAY"];
|
|
@@ -565,7 +601,6 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
565
601
|
const client = values["EVERYAPP_DEV"]
|
|
566
602
|
? oauthClientCredentials(capability, values)
|
|
567
603
|
: null;
|
|
568
|
-
const origin = oauthClientOrigin(capability, values);
|
|
569
604
|
const policy = capability.scopePolicy;
|
|
570
605
|
// An entry with a Gateway-owned flow is listed for reading or writing;
|
|
571
606
|
// the app-driven flow alone needs the write grant.
|
|
@@ -610,7 +645,6 @@ function devOAuthClientStatus(id, capability, values) {
|
|
|
610
645
|
configured: Boolean(client),
|
|
611
646
|
ready: Boolean(client) || Boolean(devToken),
|
|
612
647
|
...(client ? { clientId: client.clientId } : {}),
|
|
613
|
-
...(client && origin ? { origin } : {}),
|
|
614
648
|
...((client || devToken) && grant && asked
|
|
615
649
|
? {
|
|
616
650
|
scopeSets: grant.sets,
|
|
@@ -652,35 +686,3 @@ function devEmailStatus(values) {
|
|
|
652
686
|
provider: configured && choice.ok ? choice.provider : null,
|
|
653
687
|
};
|
|
654
688
|
}
|
|
655
|
-
/**
|
|
656
|
-
* A refusal the AppGateway binding made, thrown: what `sendEmail()` throws
|
|
657
|
-
* when the gateway won't send (`email_sender_not_allowed`,
|
|
658
|
-
* `email_budget_exhausted`, ...). The thrown twin of {@link gatewayRefusal}.
|
|
659
|
-
*/
|
|
660
|
-
export class GatewayRefusalError extends Error {
|
|
661
|
-
status;
|
|
662
|
-
code;
|
|
663
|
-
constructor({ status, code, message }) {
|
|
664
|
-
super(message);
|
|
665
|
-
this.name = "GatewayRefusalError";
|
|
666
|
-
this.status = status;
|
|
667
|
-
this.code = code;
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* The gateway's own refusal in `response`, or null when the response is the
|
|
672
|
-
* provider's answer (which may be an error of its own). Reads the body only
|
|
673
|
-
* for a refusal, so call it before reading the body yourself.
|
|
674
|
-
*/
|
|
675
|
-
export async function gatewayRefusal(response) {
|
|
676
|
-
const code = response.headers.get(GATEWAY_ERROR_HEADER);
|
|
677
|
-
if (!code)
|
|
678
|
-
return null;
|
|
679
|
-
const body = await response.json().catch(() => null);
|
|
680
|
-
const message = body &&
|
|
681
|
-
typeof body === "object" &&
|
|
682
|
-
typeof body.message === "string"
|
|
683
|
-
? body.message
|
|
684
|
-
: `The EveryApp gateway refused the call (${code}).`;
|
|
685
|
-
return { status: response.status, code, message };
|
|
686
|
-
}
|
|
@@ -2,7 +2,7 @@ import { ConfigurationError, serviceRoutePath, } from "../internal/index.js";
|
|
|
2
2
|
import { applyAttribution, attributionFor, isRequest, } from "./attribution.js";
|
|
3
3
|
import { getEveryAppUser } from "./everyApp.js";
|
|
4
4
|
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
5
|
-
import { GatewayRefusalError, gatewayRefusal } from "./
|
|
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
|
|
@@ -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"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Gateway's own refusals, read the same way wherever they surface: a
|
|
3
|
+
* `Response` from a gateway fetch ({@link gatewayRefusal}), the error an
|
|
4
|
+
* SDK helper throws ({@link GatewayRefusalError}), or the error an AI
|
|
5
|
+
* client throws for a refused call (an OpenAI SDK's `APIError`, ai-sdk's
|
|
6
|
+
* `APICallError`) ({@link refusalFromError}).
|
|
7
|
+
*
|
|
8
|
+
* A refusal that means "not set up" (`integration_not_configured`,
|
|
9
|
+
* `ai_provider_not_configured`, `ai_default_not_configured`) carries what
|
|
10
|
+
* to do in the Gateway's words: `settings` (the setting names it needs),
|
|
11
|
+
* `setup` (one sentence for a person) and `command` (what an admin runs,
|
|
12
|
+
* `pnpm everyapp configure <app>`, or null). Show them as they are; never
|
|
13
|
+
* match the message text or hardcode a setting name or a command.
|
|
14
|
+
*/
|
|
15
|
+
import { ConfigurationError, GATEWAY_ERROR_HEADER } from "../internal/index.js";
|
|
16
|
+
/** The refusal codes that mean no model is set up for the call. */
|
|
17
|
+
export const AI_NOT_CONFIGURED_CODES = [
|
|
18
|
+
"ai_provider_not_configured",
|
|
19
|
+
"ai_default_not_configured",
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* A refusal the AppGateway binding made, thrown: what `sendEmail()` throws
|
|
23
|
+
* when the gateway won't send (`email_sender_not_allowed`,
|
|
24
|
+
* `email_budget_exhausted`, ...). The thrown twin of {@link gatewayRefusal}.
|
|
25
|
+
*/
|
|
26
|
+
export class GatewayRefusalError extends Error {
|
|
27
|
+
status;
|
|
28
|
+
code;
|
|
29
|
+
settings;
|
|
30
|
+
setup;
|
|
31
|
+
command;
|
|
32
|
+
constructor({ status, code, message, settings = [], setup = null, command = null, }) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = "GatewayRefusalError";
|
|
35
|
+
this.status = status;
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.settings = settings;
|
|
38
|
+
this.setup = setup;
|
|
39
|
+
this.command = command;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The gateway's own refusal in `response`, or null when the response is the
|
|
44
|
+
* provider's answer (which may be an error of its own). Reads the body only
|
|
45
|
+
* for a refusal, so call it before reading the body yourself.
|
|
46
|
+
*/
|
|
47
|
+
export async function gatewayRefusal(response) {
|
|
48
|
+
const code = response.headers.get(GATEWAY_ERROR_HEADER);
|
|
49
|
+
if (!code)
|
|
50
|
+
return null;
|
|
51
|
+
const body = await response.json().catch(() => null);
|
|
52
|
+
return refusalOf(response.status, code, body);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The Gateway's refusal behind a thrown error, or null when it isn't one:
|
|
56
|
+
* a {@link GatewayRefusalError} (`sendEmail()`, `listMembers()`, `emit()`),
|
|
57
|
+
* an OpenAI SDK `APIError` or an ai-sdk `APICallError` for a call the
|
|
58
|
+
* Gateway refused (also inside ai-sdk's `RetryError` or an error's
|
|
59
|
+
* `cause`), or the SDK's local-development `ConfigurationError` for a
|
|
60
|
+
* missing key, which answers as the deployed refusal would
|
|
61
|
+
* (`ai_provider_not_configured`, status 503, the `.dev.vars` names).
|
|
62
|
+
*/
|
|
63
|
+
export function refusalFromError(error) {
|
|
64
|
+
const seen = new Set();
|
|
65
|
+
let current = error;
|
|
66
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
67
|
+
seen.add(current);
|
|
68
|
+
const found = refusalHere(current);
|
|
69
|
+
if (found)
|
|
70
|
+
return found;
|
|
71
|
+
const record = current;
|
|
72
|
+
current = record["lastError"] ?? record["cause"];
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Whether `error` (or a refusal already read) means no model is set up:
|
|
78
|
+
* `ai_provider_not_configured` or `ai_default_not_configured`, from the
|
|
79
|
+
* Gateway or, in local development, from the SDK with no key in
|
|
80
|
+
* `.dev.vars`. Show `refusalFromError(error).setup` to the person.
|
|
81
|
+
*/
|
|
82
|
+
export function isAiNotConfigured(error) {
|
|
83
|
+
const refusal = isRefusal(error) ? error : refusalFromError(error);
|
|
84
|
+
return refusal !== null && AI_NOT_CONFIGURED_CODES.includes(refusal.code);
|
|
85
|
+
}
|
|
86
|
+
function isRefusal(value) {
|
|
87
|
+
return (!!value &&
|
|
88
|
+
typeof value === "object" &&
|
|
89
|
+
!(value instanceof Error) &&
|
|
90
|
+
typeof value.code === "string" &&
|
|
91
|
+
typeof value.status === "number");
|
|
92
|
+
}
|
|
93
|
+
function refusalHere(error) {
|
|
94
|
+
// A Response is read with gatewayRefusal(), which can read its body.
|
|
95
|
+
if (error instanceof Response)
|
|
96
|
+
return null;
|
|
97
|
+
if (error instanceof GatewayRefusalError) {
|
|
98
|
+
return {
|
|
99
|
+
status: error.status,
|
|
100
|
+
code: error.code,
|
|
101
|
+
message: error.message,
|
|
102
|
+
settings: error.settings,
|
|
103
|
+
setup: error.setup,
|
|
104
|
+
command: error.command,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (error instanceof ConfigurationError) {
|
|
108
|
+
if (!error.code)
|
|
109
|
+
return null;
|
|
110
|
+
return {
|
|
111
|
+
status: 503,
|
|
112
|
+
code: error.code,
|
|
113
|
+
message: error.message,
|
|
114
|
+
settings: error.settings,
|
|
115
|
+
setup: error.message,
|
|
116
|
+
command: null,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const record = error;
|
|
120
|
+
// ai-sdk's APICallError: lowercase header names, the body as text.
|
|
121
|
+
const responseHeaders = record["responseHeaders"];
|
|
122
|
+
if (responseHeaders && typeof responseHeaders === "object") {
|
|
123
|
+
const code = headerOf(responseHeaders, GATEWAY_ERROR_HEADER);
|
|
124
|
+
if (!code)
|
|
125
|
+
return null;
|
|
126
|
+
return refusalOf(numberOf(record["statusCode"]), code, parseJson(record["responseBody"]), messageOf(error));
|
|
127
|
+
}
|
|
128
|
+
// An OpenAI SDK APIError: `headers` (Headers or a record), `status`,
|
|
129
|
+
// and `error`, the body's `error` object (which carries the same fields).
|
|
130
|
+
const headers = record["headers"];
|
|
131
|
+
if (headers && typeof headers === "object" && "status" in record) {
|
|
132
|
+
const code = headerOf(headers, GATEWAY_ERROR_HEADER);
|
|
133
|
+
if (!code)
|
|
134
|
+
return null;
|
|
135
|
+
return refusalOf(numberOf(record["status"]), code, record["error"], messageOf(error));
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
/** A refusal from its status, code and body (the Gateway's `{ code, message, … }`, or OpenAI's `{ error: {…} }`). */
|
|
140
|
+
function refusalOf(status, code, body, fallback) {
|
|
141
|
+
const top = recordOf(body);
|
|
142
|
+
const inner = recordOf(top?.["error"]);
|
|
143
|
+
const field = (name) => top?.[name] ?? inner?.[name];
|
|
144
|
+
const message = stringOf(top?.["message"]) ??
|
|
145
|
+
stringOf(inner?.["message"]) ??
|
|
146
|
+
fallback ??
|
|
147
|
+
`The EveryApp gateway refused the call (${code}).`;
|
|
148
|
+
const settings = field("settings");
|
|
149
|
+
return {
|
|
150
|
+
status,
|
|
151
|
+
code,
|
|
152
|
+
message,
|
|
153
|
+
settings: Array.isArray(settings)
|
|
154
|
+
? settings.filter((name) => typeof name === "string")
|
|
155
|
+
: [],
|
|
156
|
+
setup: stringOf(field("setup")) ?? null,
|
|
157
|
+
command: stringOf(field("command")) ?? null,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function headerOf(headers, name) {
|
|
161
|
+
if (typeof headers.get === "function") {
|
|
162
|
+
return headers.get(name);
|
|
163
|
+
}
|
|
164
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
165
|
+
if (key.toLowerCase() === name && typeof value === "string")
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
function recordOf(value) {
|
|
171
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
172
|
+
? value
|
|
173
|
+
: null;
|
|
174
|
+
}
|
|
175
|
+
function stringOf(value) {
|
|
176
|
+
return typeof value === "string" && value ? value : undefined;
|
|
177
|
+
}
|
|
178
|
+
function numberOf(value) {
|
|
179
|
+
return typeof value === "number" ? value : 0;
|
|
180
|
+
}
|
|
181
|
+
function parseJson(value) {
|
|
182
|
+
if (typeof value !== "string")
|
|
183
|
+
return null;
|
|
184
|
+
try {
|
|
185
|
+
return JSON.parse(value);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function messageOf(error) {
|
|
192
|
+
return error instanceof Error && error.message ? error.message : undefined;
|
|
193
|
+
}
|
package/dist/server/sendEmail.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConfigurationError, EMAIL_SENDERS_ENV, emailDomain, emailProviderRefusal, emailRestBody, emailRestUrl, emailSenderRefusal, parseEmailList, parseEmailSender, parseSendEmailMessage, readEmailRestResponse, senderAllowed, serviceRoutePath, } from "../internal/index.js";
|
|
2
2
|
import { applyAttribution, attributionFor, } from "./attribution.js";
|
|
3
3
|
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
4
|
-
import { GatewayRefusalError, gatewayRefusal } from "./
|
|
4
|
+
import { GatewayRefusalError, gatewayRefusal } from "./refusal.js";
|
|
5
5
|
/**
|
|
6
6
|
* Send an email through the gateway's `email` capability: its sender
|
|
7
7
|
* (EMAIL_FROM) unless `message.from` names an address the installation's
|