@every-app/sdk 0.2.0 → 0.3.0-rc.2
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 +608 -2
- package/dist/cloudflare/index.d.ts +22 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +21 -0
- package/dist/cloudflare/sentinel.d.ts +69 -0
- package/dist/cloudflare/sentinel.d.ts.map +1 -0
- package/dist/cloudflare/sentinel.js +50 -0
- package/dist/cloudflare/worker.d.ts +592 -0
- package/dist/cloudflare/worker.d.ts.map +1 -0
- package/dist/cloudflare/worker.js +817 -0
- package/dist/dev/index.d.ts +8 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +7 -0
- package/dist/dev/keypair.d.ts +24 -0
- package/dist/dev/keypair.d.ts.map +1 -0
- package/dist/dev/keypair.js +60 -0
- package/dist/internal/aiProviders.d.ts +67 -0
- package/dist/internal/aiProviders.d.ts.map +1 -0
- package/dist/internal/aiProviders.js +220 -0
- package/dist/internal/appSettings.d.ts +237 -0
- package/dist/internal/appSettings.d.ts.map +1 -0
- package/dist/internal/appSettings.js +374 -0
- package/dist/internal/capabilities.d.ts +3249 -0
- package/dist/internal/capabilities.d.ts.map +1 -0
- package/dist/internal/capabilities.js +1532 -0
- 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 +338 -0
- package/dist/internal/catalog/comms.d.ts.map +1 -0
- package/dist/internal/catalog/comms.js +477 -0
- package/dist/internal/catalog/index.d.ts +1899 -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 +356 -0
- package/dist/internal/catalog/inference.d.ts.map +1 -0
- package/dist/internal/catalog/inference.js +425 -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 +49 -0
- package/dist/internal/devProviders.d.ts.map +1 -0
- package/dist/internal/devProviders.js +62 -0
- package/dist/internal/email.d.ts +280 -0
- package/dist/internal/email.d.ts.map +1 -0
- package/dist/internal/email.js +613 -0
- package/dist/internal/events.d.ts +182 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +326 -0
- package/dist/internal/gatewaySettings.d.ts +83 -0
- package/dist/internal/gatewaySettings.d.ts.map +1 -0
- package/dist/internal/gatewaySettings.js +217 -0
- package/dist/internal/identity.d.ts +18 -3
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +53 -14
- package/dist/internal/index.d.ts +18 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +18 -1
- package/dist/internal/members.d.ts +35 -0
- package/dist/internal/members.d.ts.map +1 -0
- package/dist/internal/members.js +7 -0
- package/dist/internal/oauthClient.d.ts +63 -0
- package/dist/internal/oauthClient.d.ts.map +1 -0
- package/dist/internal/oauthClient.js +194 -0
- package/dist/internal/oauthScopes.d.ts +117 -0
- package/dist/internal/oauthScopes.d.ts.map +1 -0
- package/dist/internal/oauthScopes.js +416 -0
- package/dist/internal/organizationName.d.ts +18 -0
- package/dist/internal/organizationName.d.ts.map +1 -0
- package/dist/internal/organizationName.js +24 -0
- package/dist/internal/protocol.d.ts +86 -2
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +112 -1
- package/dist/internal/providerApps.d.ts +75 -0
- package/dist/internal/providerApps.d.ts.map +1 -0
- package/dist/internal/providerApps.js +59 -0
- package/dist/internal/providerRegistry.d.ts +147 -0
- package/dist/internal/providerRegistry.d.ts.map +1 -0
- package/dist/internal/providerRegistry.js +266 -0
- package/dist/internal/providerSpec.d.ts +55 -0
- package/dist/internal/providerSpec.d.ts.map +1 -0
- package/dist/internal/providerSpec.js +758 -0
- package/dist/internal/remoteMcp.d.ts +188 -0
- package/dist/internal/remoteMcp.d.ts.map +1 -0
- package/dist/internal/remoteMcp.js +543 -0
- package/dist/internal/signInProviders.d.ts +104 -0
- package/dist/internal/signInProviders.d.ts.map +1 -0
- package/dist/internal/signInProviders.js +238 -0
- package/dist/internal/tools.d.ts +115 -0
- package/dist/internal/tools.d.ts.map +1 -0
- package/dist/internal/tools.js +80 -0
- package/dist/server/attribution.d.ts +39 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +67 -0
- package/dist/server/authorizeUrl.d.ts +43 -0
- package/dist/server/authorizeUrl.d.ts.map +1 -0
- package/dist/server/authorizeUrl.js +110 -0
- package/dist/server/emit.d.ts +63 -0
- package/dist/server/emit.d.ts.map +1 -0
- package/dist/server/emit.js +101 -0
- package/dist/server/everyApp.d.ts +38 -12
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +92 -28
- package/dist/server/gatewayFetch.d.ts +24 -8
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +81 -36
- package/dist/server/index.d.ts +10 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +8 -1
- package/dist/server/integrationFetch.d.ts +131 -0
- package/dist/server/integrationFetch.d.ts.map +1 -0
- package/dist/server/integrationFetch.js +526 -0
- package/dist/server/listMembers.d.ts +32 -0
- package/dist/server/listMembers.d.ts.map +1 -0
- package/dist/server/listMembers.js +74 -0
- package/dist/server/nodeServer.d.ts +48 -0
- package/dist/server/nodeServer.d.ts.map +1 -0
- package/dist/server/nodeServer.js +45 -0
- package/dist/server/sendEmail.d.ts +39 -0
- package/dist/server/sendEmail.d.ts.map +1 -0
- package/dist/server/sendEmail.js +114 -0
- package/dist/server/tools.d.ts +184 -0
- package/dist/server/tools.d.ts.map +1 -0
- package/dist/server/tools.js +347 -0
- package/dist/server/toolsEndpoint.d.ts +32 -0
- package/dist/server/toolsEndpoint.d.ts.map +1 -0
- package/dist/server/toolsEndpoint.js +231 -0
- package/package.json +19 -6
- package/dist/server/mcp.d.ts +0 -66
- package/dist/server/mcp.d.ts.map +0 -1
- package/dist/server/mcp.js +0 -147
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { CAPABILITIES, ConfigurationError, } from "../internal/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parameters the helper owns: the status decides the scopes, the caller's
|
|
4
|
+
* other arguments decide the rest (PKCE from `codeChallenge`, always as
|
|
5
|
+
* S256), each provider's own are fixed (Google's `access_type=offline` is
|
|
6
|
+
* what gets a refresh token, Microsoft's `response_mode=query` is what
|
|
7
|
+
* the callback reads), and Google's `include_granted_scopes` would widen
|
|
8
|
+
* the token to every scope the person ever granted this client, which the
|
|
9
|
+
* gateway refuses (`integration_scope_exceeded`).
|
|
10
|
+
*/
|
|
11
|
+
const RESERVED_PARAMS = [
|
|
12
|
+
"scope",
|
|
13
|
+
"user_scope",
|
|
14
|
+
"client_id",
|
|
15
|
+
"redirect_uri",
|
|
16
|
+
"state",
|
|
17
|
+
"response_type",
|
|
18
|
+
"code_challenge",
|
|
19
|
+
"code_challenge_method",
|
|
20
|
+
"access_type",
|
|
21
|
+
"response_mode",
|
|
22
|
+
"include_granted_scopes",
|
|
23
|
+
];
|
|
24
|
+
/** The OAuth clients with scope sets: the ones this helper builds for. */
|
|
25
|
+
function scopedClientIds() {
|
|
26
|
+
return Object.entries(CAPABILITIES)
|
|
27
|
+
.filter(([, found]) => found.mode === "oauth_client" && found.scopePolicy)
|
|
28
|
+
.map(([id]) => id);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The provider's authorize URL to send a person to, for a client with
|
|
32
|
+
* scope sets (`google-workspace`, `microsoft-365`, `slack`), built from the
|
|
33
|
+
* capability's status: the registry's authorize endpoint (or the instance
|
|
34
|
+
* the status names), `client_id`, `response_type=code`, `redirect_uri`,
|
|
35
|
+
* `state`, and the scopes the status allows this app, which are exactly
|
|
36
|
+
* what the gateway will let the token carry. Each provider's own needs
|
|
37
|
+
* are added: Google's `access_type=offline` (a refresh token), Microsoft's
|
|
38
|
+
* `response_mode=query`, Slack's comma-joined `scope` and its `user_scope`
|
|
39
|
+
* (the status's `userScopes`, when the app's sets include a user set). With
|
|
40
|
+
* `codeChallenge`, PKCE as S256. The app keeps its `state` and verifier
|
|
41
|
+
* for the callback.
|
|
42
|
+
*
|
|
43
|
+
* A client without scope sets (LinkedIn, Mastodon, ...) is refused: the
|
|
44
|
+
* registry's checklist for one isn't what the gateway holds a token to,
|
|
45
|
+
* so an app builds that URL itself from the status's `clientId`.
|
|
46
|
+
*
|
|
47
|
+
* Throws a `TypeError` naming the fix when the client has no scope sets,
|
|
48
|
+
* when the status isn't ready or has no `clientId`, when the status lacks
|
|
49
|
+
* `scopes`, or when `params` names a parameter the helper sets.
|
|
50
|
+
*/
|
|
51
|
+
export function authorizeUrl({ provider, status, redirectUri, state, codeChallenge, params, }) {
|
|
52
|
+
const capability = oauthClientCapability(provider);
|
|
53
|
+
if (!capability.scopePolicy) {
|
|
54
|
+
throw new TypeError(`authorizeUrl() builds URLs for clients with scope sets (${scopedClientIds().join(", ")}); build ${capability.label}'s authorize URL yourself from the status's clientId.`);
|
|
55
|
+
}
|
|
56
|
+
if (!status.ready || !status.clientId) {
|
|
57
|
+
throw new TypeError(`authorizeUrl(${JSON.stringify(provider)}) needs a ready status with a clientId, and integrationStatus() answered ready: ${String(status.ready)}. Show ${capability.label} as not available instead: its operator sets the client up on the gateway, and an app lists the scope sets it uses in everyapp.config.ts.`);
|
|
58
|
+
}
|
|
59
|
+
if (!status.scopes) {
|
|
60
|
+
throw new TypeError(`authorizeUrl(${JSON.stringify(provider)}) takes ${capability.label}'s scopes from integrationStatus().scopes, which this status lacks: pass the status as the gateway (or everyapp dev) answered it.`);
|
|
61
|
+
}
|
|
62
|
+
for (const name of Object.keys(params ?? {})) {
|
|
63
|
+
if (!RESERVED_PARAMS.includes(name))
|
|
64
|
+
continue;
|
|
65
|
+
throw new TypeError(name === "include_granted_scopes"
|
|
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
|
+
: `authorizeUrl(${JSON.stringify(provider)}) sets ${name} itself; leave it out of params.`);
|
|
68
|
+
}
|
|
69
|
+
const base = status.origin ?? capability.defaultOrigin;
|
|
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);
|
|
74
|
+
// The status speaks for the gateway: its scopes are the token's ceiling.
|
|
75
|
+
const scopes = status.scopes;
|
|
76
|
+
const slack = url.host === "slack.com";
|
|
77
|
+
url.searchParams.set("client_id", status.clientId);
|
|
78
|
+
url.searchParams.set("response_type", "code");
|
|
79
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
80
|
+
url.searchParams.set("state", state);
|
|
81
|
+
url.searchParams.set("scope", scopes.join(slack ? "," : " "));
|
|
82
|
+
if (status.userScopes && status.userScopes.length > 0) {
|
|
83
|
+
url.searchParams.set("user_scope", status.userScopes.join(","));
|
|
84
|
+
}
|
|
85
|
+
if (codeChallenge) {
|
|
86
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
87
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
88
|
+
}
|
|
89
|
+
if (url.host === "accounts.google.com") {
|
|
90
|
+
// Without it Google issues no refresh token.
|
|
91
|
+
url.searchParams.set("access_type", "offline");
|
|
92
|
+
}
|
|
93
|
+
else if (url.host === "login.microsoftonline.com") {
|
|
94
|
+
url.searchParams.set("response_mode", "query");
|
|
95
|
+
}
|
|
96
|
+
for (const [name, value] of Object.entries(params ?? {})) {
|
|
97
|
+
url.searchParams.set(name, value);
|
|
98
|
+
}
|
|
99
|
+
return url;
|
|
100
|
+
}
|
|
101
|
+
/** The OAuth client `provider` names, from plain JavaScript or a stale type too. */
|
|
102
|
+
function oauthClientCapability(provider) {
|
|
103
|
+
const found = Object.hasOwn(CAPABILITIES, provider)
|
|
104
|
+
? CAPABILITIES[provider]
|
|
105
|
+
: undefined;
|
|
106
|
+
if (found?.mode !== "oauth_client") {
|
|
107
|
+
throw new ConfigurationError(`${JSON.stringify(String(provider))} isn't an OAuth client the gateway holds.`);
|
|
108
|
+
}
|
|
109
|
+
return found;
|
|
110
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `emit()`: an app's own event onto the gateway's event bus
|
|
3
|
+
* (docs/design/2026-10-events-out.md, section 7). It is shaped like
|
|
4
|
+
* `sendEmail()` on purpose: the same `{ env, for }` attribution, the same
|
|
5
|
+
* route over the EVERY_APP_GATEWAY binding, the same refusals thrown as
|
|
6
|
+
* `GatewayRefusalError`, and the same local-dev twin that checks what the
|
|
7
|
+
* gateway would check and prints instead of sending. The name and data
|
|
8
|
+
* rules live in `internal/events.ts`, which the gateway reads too, so the
|
|
9
|
+
* two can't drift.
|
|
10
|
+
*/
|
|
11
|
+
import { type EmitEventResult } from "../internal/index.js";
|
|
12
|
+
import { type GatewayCallFor } from "./attribution.js";
|
|
13
|
+
export interface EmitOptions {
|
|
14
|
+
/** The Worker env: the EVERY_APP_GATEWAY binding when deployed; EVERYAPP_DEV in local dev. */
|
|
15
|
+
env: object;
|
|
16
|
+
/**
|
|
17
|
+
* Whom the event is about: the inbound request (its user becomes the
|
|
18
|
+
* event's actor), or `{ background: true, organizationId }` for work no
|
|
19
|
+
* person started (a cron, a queue, a provider's webhook). An
|
|
20
|
+
* organization's own app may omit it for background work; a shared app's
|
|
21
|
+
* Worker must pass one or the other ({@link AttributionError}).
|
|
22
|
+
*/
|
|
23
|
+
for?: GatewayCallFor;
|
|
24
|
+
/**
|
|
25
|
+
* The app's own name for what happened: lowercase letters, digits and
|
|
26
|
+
* underscores in dotted segments (`invoice.paid`, `todo.completed`), at
|
|
27
|
+
* most 64 characters. The gateway delivers it as `app.<app id>.<event>`.
|
|
28
|
+
*/
|
|
29
|
+
event: string;
|
|
30
|
+
/**
|
|
31
|
+
* What a subscriber needs to act on it: a JSON object, at most 8 KiB
|
|
32
|
+
* serialized, nested at most 8 levels. Ids, names, amounts and states;
|
|
33
|
+
* never a credential. A key named like one at any depth (`token`,
|
|
34
|
+
* `secret`, `password`, `apiKey`, `session`, `cookie`, ...) is refused.
|
|
35
|
+
*/
|
|
36
|
+
data: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Put an event on the gateway's event bus, for the organization's webhook
|
|
40
|
+
* and email subscribers. The gateway names it `app.<app id>.<event>`, so an
|
|
41
|
+
* app can never emit one of the gateway's own types (`member.joined`);
|
|
42
|
+
* owners and admins choose `app.<app id>.*` (or one name) in Manage
|
|
43
|
+
* workspace, Events, or with `everyapp events add`. Nothing is declared in
|
|
44
|
+
* the manifest. Delivery happens after the call returns: a subscriber that
|
|
45
|
+
* is down doesn't slow or fail the app.
|
|
46
|
+
*
|
|
47
|
+
* `data` goes, as written, to every URL a subscriber chose (Slack, Zapier,
|
|
48
|
+
* an agent): put in it what a person or a workflow reads, never a
|
|
49
|
+
* credential, a session or a person's private content they didn't expect
|
|
50
|
+
* to leave the app. The gateway refuses a key named like a credential.
|
|
51
|
+
*
|
|
52
|
+
* Throws {@link GatewayRefusalError} when the gateway won't take it
|
|
53
|
+
* (`event_name_invalid`, `event_data_invalid`, `event_data_refused`,
|
|
54
|
+
* `event_data_too_large`, `event_rate_limited` past 600 an hour, ...), with
|
|
55
|
+
* the code and a message to show. An emit that must never fail the work
|
|
56
|
+
* around it goes under `ctx.waitUntil()` or a `.catch()`.
|
|
57
|
+
*
|
|
58
|
+
* In local dev (`everyapp dev`, no binding) the event is checked the way
|
|
59
|
+
* the gateway checks it, printed, and answered `{ id: "dev-…", type }`;
|
|
60
|
+
* nothing is delivered.
|
|
61
|
+
*/
|
|
62
|
+
export declare function emit({ env, for: target, event, data, }: EmitOptions): Promise<EmitEventResult>;
|
|
63
|
+
//# sourceMappingURL=emit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/server/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EASL,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAI1B,MAAM,WAAW,WAAW;IAC1B,8FAA8F;IAC9F,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,IAAI,CAAC,EACzB,GAAG,EACH,GAAG,EAAE,MAAM,EACX,KAAK,EACL,IAAI,GACL,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAoBxC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `emit()`: an app's own event onto the gateway's event bus
|
|
3
|
+
* (docs/design/2026-10-events-out.md, section 7). It is shaped like
|
|
4
|
+
* `sendEmail()` on purpose: the same `{ env, for }` attribution, the same
|
|
5
|
+
* route over the EVERY_APP_GATEWAY binding, the same refusals thrown as
|
|
6
|
+
* `GatewayRefusalError`, and the same local-dev twin that checks what the
|
|
7
|
+
* gateway would check and prints instead of sending. The name and data
|
|
8
|
+
* rules live in `internal/events.ts`, which the gateway reads too, so the
|
|
9
|
+
* two can't drift.
|
|
10
|
+
*/
|
|
11
|
+
import { APP_EVENT_DATA_MAX_BYTES, APP_ID_ENV, ConfigurationError, EVENTS_EMIT_PATH, appEventNameProblem, appEventType, checkEventData, } from "../internal/index.js";
|
|
12
|
+
import { applyAttribution, checkAttribution, } from "./attribution.js";
|
|
13
|
+
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
14
|
+
import { GatewayRefusalError, gatewayRefusal } from "./integrationFetch.js";
|
|
15
|
+
/**
|
|
16
|
+
* Put an event on the gateway's event bus, for the organization's webhook
|
|
17
|
+
* and email subscribers. The gateway names it `app.<app id>.<event>`, so an
|
|
18
|
+
* app can never emit one of the gateway's own types (`member.joined`);
|
|
19
|
+
* owners and admins choose `app.<app id>.*` (or one name) in Manage
|
|
20
|
+
* workspace, Events, or with `everyapp events add`. Nothing is declared in
|
|
21
|
+
* the manifest. Delivery happens after the call returns: a subscriber that
|
|
22
|
+
* is down doesn't slow or fail the app.
|
|
23
|
+
*
|
|
24
|
+
* `data` goes, as written, to every URL a subscriber chose (Slack, Zapier,
|
|
25
|
+
* an agent): put in it what a person or a workflow reads, never a
|
|
26
|
+
* credential, a session or a person's private content they didn't expect
|
|
27
|
+
* to leave the app. The gateway refuses a key named like a credential.
|
|
28
|
+
*
|
|
29
|
+
* Throws {@link GatewayRefusalError} when the gateway won't take it
|
|
30
|
+
* (`event_name_invalid`, `event_data_invalid`, `event_data_refused`,
|
|
31
|
+
* `event_data_too_large`, `event_rate_limited` past 600 an hour, ...), with
|
|
32
|
+
* the code and a message to show. An emit that must never fail the work
|
|
33
|
+
* around it goes under `ctx.waitUntil()` or a `.catch()`.
|
|
34
|
+
*
|
|
35
|
+
* In local dev (`everyapp dev`, no binding) the event is checked the way
|
|
36
|
+
* the gateway checks it, printed, and answered `{ id: "dev-…", type }`;
|
|
37
|
+
* nothing is delivered.
|
|
38
|
+
*/
|
|
39
|
+
export async function emit({ env, for: target, event, data, }) {
|
|
40
|
+
checkAttribution(env, target, "emit");
|
|
41
|
+
const values = env;
|
|
42
|
+
const binding = values["EVERY_APP_GATEWAY"];
|
|
43
|
+
if (binding) {
|
|
44
|
+
if (typeof binding.fetch !== "function") {
|
|
45
|
+
throw new ConfigurationError("EVERY_APP_GATEWAY is configured but is not a valid service binding.");
|
|
46
|
+
}
|
|
47
|
+
return emitThroughGateway(binding, target, { event, data });
|
|
48
|
+
}
|
|
49
|
+
if (!values["EVERYAPP_DEV"]) {
|
|
50
|
+
throw new ConfigurationError("Events are unavailable: deploy with the EVERY_APP_GATEWAY binding (everyapp deploy), or run under everyapp dev.");
|
|
51
|
+
}
|
|
52
|
+
return emitInDev(values, { event, data });
|
|
53
|
+
}
|
|
54
|
+
async function emitThroughGateway(binding, target, body) {
|
|
55
|
+
const headers = new Headers({ "content-type": "application/json" });
|
|
56
|
+
applyAttribution(headers, target);
|
|
57
|
+
const response = await binding.fetch(new Request(`${BINDING_ORIGIN}${EVENTS_EMIT_PATH}`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers,
|
|
60
|
+
body: JSON.stringify(body),
|
|
61
|
+
}));
|
|
62
|
+
const refusal = await gatewayRefusal(response);
|
|
63
|
+
if (refusal)
|
|
64
|
+
throw new GatewayRefusalError(refusal);
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
throw new GatewayRefusalError({
|
|
67
|
+
status: response.status,
|
|
68
|
+
code: "event_emit_failed",
|
|
69
|
+
message: `The Every App gateway answered ${response.status} to the event.`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return (await response.json());
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* What the gateway would do, with no gateway: the same name and data
|
|
76
|
+
* rules, then one line on the console. The data isn't printed: it may hold
|
|
77
|
+
* a person's content, and the line is for "it fired", not for its payload.
|
|
78
|
+
*/
|
|
79
|
+
function emitInDev(values, { event, data }) {
|
|
80
|
+
const nameProblem = appEventNameProblem(event);
|
|
81
|
+
if (nameProblem) {
|
|
82
|
+
throw new GatewayRefusalError({
|
|
83
|
+
status: 400,
|
|
84
|
+
code: "event_name_invalid",
|
|
85
|
+
message: nameProblem,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const checked = checkEventData(data, APP_EVENT_DATA_MAX_BYTES);
|
|
89
|
+
if (!checked.ok) {
|
|
90
|
+
throw new GatewayRefusalError({
|
|
91
|
+
status: checked.code === "event_data_too_large" ? 413 : 400,
|
|
92
|
+
code: checked.code,
|
|
93
|
+
message: checked.message,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const appId = values[APP_ID_ENV];
|
|
97
|
+
// The gateway prefixes the manifest id; a dev env without it still shows the shape.
|
|
98
|
+
const type = appEventType(typeof appId === "string" && appId.trim() ? appId.trim() : "app", event);
|
|
99
|
+
console.info(`[everyapp dev] event ${type} (not delivered: no Gateway)`);
|
|
100
|
+
return { id: `dev-${crypto.randomUUID()}`, type };
|
|
101
|
+
}
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `everyApp()` — the app-side identity boundary.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* export default everyApp(handler, manifest);
|
|
4
|
+
* export default everyApp(handler, { tools });
|
|
6
5
|
*
|
|
7
6
|
* The wrapper verifies the gateway-injected identity before app code runs,
|
|
8
7
|
* stores the result on the original Request, and then delegates to the
|
|
9
|
-
* worker-style handler.
|
|
8
|
+
* worker-style handler. The expected audience is the Worker's own name in
|
|
9
|
+
* `env.EVERYAPP_AUDIENCE`, which `everyAppWorker()` sets at deploy (the
|
|
10
|
+
* gateway stamps every token it mints for the app with it); only in
|
|
11
|
+
* development, where `everyapp dev` mints for the app id, does the app id in
|
|
12
|
+
* `env.EVERYAPP_APP_ID` stand in. The Worker never imports
|
|
13
|
+
* `everyapp.config.ts` (the Cloudflare Vite plugin hides every file
|
|
14
|
+
* `cloudflare.config.ts` imports from the Worker in dev).
|
|
15
|
+
* It also answers the gateway's internal tools contract
|
|
16
|
+
* (`/__everyapp/tools/*`) for the app's `defineTools()` catalog.
|
|
10
17
|
*/
|
|
11
18
|
import { ConfigurationError, IdentityError, type EveryAppUser, type IdentityResult } from "../internal/index.js";
|
|
19
|
+
import type { ToolSet } from "./tools.js";
|
|
12
20
|
export { ConfigurationError, IdentityError };
|
|
13
21
|
export type { EveryAppUser, IdentityResult };
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
/**
|
|
23
|
+
* The runtime's `ExecutionContext`, which `everyApp()` passes to the handler
|
|
24
|
+
* as the Worker received it, so it goes on to Hono's `app.fetch(request,
|
|
25
|
+
* env, ctx)` or React Router's request handler as is. Tests that call
|
|
26
|
+
* `fetch` themselves pass a stub cast to it.
|
|
27
|
+
*/
|
|
28
|
+
export type ExecutionContextLike = ExecutionContext;
|
|
18
29
|
export interface EveryAppManifestLike {
|
|
19
30
|
id: string;
|
|
20
31
|
[key: string]: unknown;
|
|
@@ -31,13 +42,21 @@ export interface EveryAppOptions {
|
|
|
31
42
|
* Never enable this in production.
|
|
32
43
|
*/
|
|
33
44
|
allowDevIdentities?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Agent tools from `defineTools()`. The gateway snapshots them at deploy
|
|
47
|
+
* and serves them to MCP clients; see `defineTools`.
|
|
48
|
+
*/
|
|
49
|
+
tools?: ToolSet;
|
|
34
50
|
/** Override for tests. */
|
|
35
51
|
now?: number;
|
|
36
52
|
}
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
/**
|
|
54
|
+
* The handler accepted by everyApp, with the verified user as a 4th argument.
|
|
55
|
+
* `TCtx` narrows the context, e.g. to `ExecutionContext<Props>`.
|
|
56
|
+
*/
|
|
57
|
+
export type EveryAppHandler<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext> = (request: Request, env: TEnv, ctx: TCtx, user: EveryAppUser | null) => Response | Promise<Response>;
|
|
58
|
+
interface EveryAppExport<TEnv, TCtx extends ExecutionContextLike> {
|
|
59
|
+
fetch(request: Request, env: TEnv, ctx: TCtx): Promise<Response>;
|
|
41
60
|
}
|
|
42
61
|
/**
|
|
43
62
|
* Return the verified Every App user for this request, or null for a declared
|
|
@@ -51,5 +70,12 @@ export declare function getEveryAppUser(request: Request, env: object): Promise<
|
|
|
51
70
|
*/
|
|
52
71
|
export declare function requireEveryAppUser(request: Request, env: object): Promise<EveryAppUser>;
|
|
53
72
|
export declare function hasScope(user: EveryAppUser, scope: string): boolean;
|
|
54
|
-
|
|
73
|
+
/** Wrap a Worker fetch handler with Every App identity verification. */
|
|
74
|
+
export declare function everyApp<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext>(handler: EveryAppHandler<TEnv, TCtx>, options?: EveryAppOptions): EveryAppExport<TEnv, TCtx>;
|
|
75
|
+
/**
|
|
76
|
+
* @deprecated Drop the manifest: the app id now comes from
|
|
77
|
+
* `env.EVERYAPP_APP_ID` and the audience from `env.EVERYAPP_AUDIENCE`.
|
|
78
|
+
* When passed, it must match the app id.
|
|
79
|
+
*/
|
|
80
|
+
export declare function everyApp<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext>(handler: EveryAppHandler<TEnv, TCtx>, manifest: EveryAppManifestLike | undefined, options?: EveryAppOptions): EveryAppExport<TEnv, TCtx>;
|
|
55
81
|
//# sourceMappingURL=everyApp.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"everyApp.d.ts","sourceRoot":"","sources":["../../src/server/everyApp.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"everyApp.d.ts","sourceRoot":"","sources":["../../src/server/everyApp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,kBAAkB,EAElB,aAAa,EAIb,KAAK,YAAY,EACjB,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,CACzB,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,SAAS,oBAAoB,GAAG,gBAAgB,IAClD,CACF,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,YAAY,GAAG,IAAI,KACtB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,UAAU,cAAc,CAAC,IAAI,EAAE,IAAI,SAAS,oBAAoB;IAC9D,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClE;AAoHD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,CAAC,CAevB;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnE;AAUD,wEAAwE;AACxE,wBAAgB,QAAQ,CACtB,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,SAAS,oBAAoB,GAAG,gBAAgB,EAEpD,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,EACpC,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC9B;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,SAAS,oBAAoB,GAAG,gBAAgB,EAEpD,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,EACpC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,EAC1C,OAAO,CAAC,EAAE,eAAe,GACxB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC"}
|
package/dist/server/everyApp.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `everyApp()` — the app-side identity boundary.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* export default everyApp(handler, manifest);
|
|
4
|
+
* export default everyApp(handler, { tools });
|
|
6
5
|
*
|
|
7
6
|
* The wrapper verifies the gateway-injected identity before app code runs,
|
|
8
7
|
* stores the result on the original Request, and then delegates to the
|
|
9
|
-
* worker-style handler.
|
|
8
|
+
* worker-style handler. The expected audience is the Worker's own name in
|
|
9
|
+
* `env.EVERYAPP_AUDIENCE`, which `everyAppWorker()` sets at deploy (the
|
|
10
|
+
* gateway stamps every token it mints for the app with it); only in
|
|
11
|
+
* development, where `everyapp dev` mints for the app id, does the app id in
|
|
12
|
+
* `env.EVERYAPP_APP_ID` stand in. The Worker never imports
|
|
13
|
+
* `everyapp.config.ts` (the Cloudflare Vite plugin hides every file
|
|
14
|
+
* `cloudflare.config.ts` imports from the Worker in dev).
|
|
15
|
+
* It also answers the gateway's internal tools contract
|
|
16
|
+
* (`/__everyapp/tools/*`) for the app's `defineTools()` catalog.
|
|
10
17
|
*/
|
|
11
|
-
import { APP_ID_ENV, ConfigurationError, DEV_ENV, IdentityError, ISSUER_ENV, PUBLIC_KEYS_ENV, getIdentityFromRequest, } from "../internal/index.js";
|
|
18
|
+
import { APP_ID_ENV, AUDIENCE_ENV, ConfigurationError, DEV_ENV, IdentityError, ISSUER_ENV, PUBLIC_KEYS_ENV, getIdentityFromRequest, } from "../internal/index.js";
|
|
19
|
+
import { handleToolsRequest } from "./toolsEndpoint.js";
|
|
12
20
|
export { ConfigurationError, IdentityError };
|
|
13
21
|
const requestIdentities = new WeakMap();
|
|
14
22
|
function envValue(env, key) {
|
|
@@ -19,7 +27,7 @@ function envValue(env, key) {
|
|
|
19
27
|
}
|
|
20
28
|
function configFrom(manifest, options = {}) {
|
|
21
29
|
return {
|
|
22
|
-
|
|
30
|
+
manifestAppId: manifest?.id,
|
|
23
31
|
issuer: options.issuer,
|
|
24
32
|
keysEnvVar: options.keysEnvVar ?? PUBLIC_KEYS_ENV,
|
|
25
33
|
publicKeys: options.publicKeys,
|
|
@@ -27,41 +35,62 @@ function configFrom(manifest, options = {}) {
|
|
|
27
35
|
now: options.now,
|
|
28
36
|
};
|
|
29
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* The app id: EVERYAPP_APP_ID, or a manifest passed to everyApp() for
|
|
40
|
+
* Workers without it; the two must agree when both are present.
|
|
41
|
+
*/
|
|
42
|
+
function appIdFor(env, config) {
|
|
43
|
+
const fromEnv = envValue(env, APP_ID_ENV);
|
|
44
|
+
if (fromEnv && config.manifestAppId && fromEnv !== config.manifestAppId) {
|
|
45
|
+
throw new ConfigurationError(`${APP_ID_ENV} ("${fromEnv}") does not match the manifest id ("${config.manifestAppId}").`);
|
|
46
|
+
}
|
|
47
|
+
return fromEnv ?? config.manifestAppId;
|
|
48
|
+
}
|
|
49
|
+
function devIdentitiesAllowed(env, config) {
|
|
50
|
+
const devEnv = envValue(env, DEV_ENV);
|
|
51
|
+
return (config.allowDevIdentities ??
|
|
52
|
+
(devEnv !== undefined &&
|
|
53
|
+
(devEnv === "1" || devEnv.toLowerCase() === "true")));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The audience identity tokens must carry: this Worker's name, from
|
|
57
|
+
* EVERYAPP_AUDIENCE. The gateway mints for the Worker, not the app id, so a
|
|
58
|
+
* token for one organization's copy of an app never opens another's. Only
|
|
59
|
+
* under the dev opt-in, where `everyapp dev` mints for the app id, does the
|
|
60
|
+
* app id stand in when EVERYAPP_AUDIENCE is unset.
|
|
61
|
+
*/
|
|
62
|
+
function audienceFor(env, config) {
|
|
63
|
+
const appId = appIdFor(env, config);
|
|
64
|
+
const audience = envValue(env, AUDIENCE_ENV);
|
|
65
|
+
if (audience)
|
|
66
|
+
return audience;
|
|
67
|
+
if (appId && devIdentitiesAllowed(env, config))
|
|
68
|
+
return appId;
|
|
69
|
+
throw new ConfigurationError(`${AUDIENCE_ENV} is not set — the app's cloudflare.config.ts must declare it (everyAppWorker() does at deploy).`);
|
|
70
|
+
}
|
|
30
71
|
function unauthorized(message) {
|
|
31
72
|
return Response.json({ error: "unauthenticated", message }, { status: 401 });
|
|
32
73
|
}
|
|
33
74
|
function misconfigured(message) {
|
|
34
75
|
return Response.json({ error: "misconfigured", message }, { status: 500 });
|
|
35
76
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
: undefined;
|
|
40
|
-
return getIdentityFromRequest(request, {
|
|
41
|
-
audience: config.audience,
|
|
77
|
+
function identityOptions(env, config, audience) {
|
|
78
|
+
return {
|
|
79
|
+
audience,
|
|
42
80
|
issuer: config.issuer ?? envValue(env, ISSUER_ENV),
|
|
43
81
|
publicKeys: config.publicKeys,
|
|
44
82
|
env: env,
|
|
45
83
|
keysEnvVar: config.keysEnvVar,
|
|
46
|
-
allowDevIdentities: config
|
|
47
|
-
(typeof devEnv === "string" &&
|
|
48
|
-
(devEnv === "1" || devEnv.toLowerCase() === "true")),
|
|
84
|
+
allowDevIdentities: devIdentitiesAllowed(env, config),
|
|
49
85
|
now: config.now,
|
|
50
|
-
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function resolveIdentity(request, env, config) {
|
|
89
|
+
return getIdentityFromRequest(request, identityOptions(env, config, audienceFor(env, config)));
|
|
51
90
|
}
|
|
52
91
|
function rememberIdentity(request, identity) {
|
|
53
92
|
requestIdentities.set(request, identity);
|
|
54
93
|
}
|
|
55
|
-
function helperConfigFromEnv(env) {
|
|
56
|
-
const audience = envValue(env, APP_ID_ENV);
|
|
57
|
-
if (!audience) {
|
|
58
|
-
throw new ConfigurationError(`${APP_ID_ENV} is not set — the CLI must inject the app id for identity verification.`);
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
audience,
|
|
62
|
-
keysEnvVar: PUBLIC_KEYS_ENV,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
94
|
/**
|
|
66
95
|
* Return the verified Every App user for this request, or null for a declared
|
|
67
96
|
* public request. Uses the request cache first, then verifies the identity
|
|
@@ -71,7 +100,9 @@ export async function getEveryAppUser(request, env) {
|
|
|
71
100
|
const cached = requestIdentities.get(request);
|
|
72
101
|
if (cached)
|
|
73
102
|
return cached.user;
|
|
74
|
-
const identity = await resolveIdentity(request, env,
|
|
103
|
+
const identity = await resolveIdentity(request, env, {
|
|
104
|
+
keysEnvVar: PUBLIC_KEYS_ENV,
|
|
105
|
+
});
|
|
75
106
|
rememberIdentity(request, identity);
|
|
76
107
|
return identity.user;
|
|
77
108
|
}
|
|
@@ -97,13 +128,46 @@ export async function requireEveryAppUser(request, env) {
|
|
|
97
128
|
export function hasScope(user, scope) {
|
|
98
129
|
return user.scopes.includes("*") || user.scopes.includes(scope);
|
|
99
130
|
}
|
|
100
|
-
|
|
131
|
+
function isManifest(value) {
|
|
132
|
+
return (typeof value === "object" &&
|
|
133
|
+
value !== null &&
|
|
134
|
+
typeof value.id === "string");
|
|
135
|
+
}
|
|
136
|
+
export function everyApp(handler, manifestOrOptions, legacyOptions = {}) {
|
|
137
|
+
const manifest = isManifest(manifestOrOptions)
|
|
138
|
+
? manifestOrOptions
|
|
139
|
+
: undefined;
|
|
140
|
+
const options = manifest || manifestOrOptions === undefined
|
|
141
|
+
? legacyOptions
|
|
142
|
+
: manifestOrOptions;
|
|
101
143
|
const config = configFrom(manifest, options);
|
|
102
144
|
return {
|
|
103
145
|
async fetch(request, env, ctx) {
|
|
146
|
+
let audience;
|
|
147
|
+
let appId;
|
|
148
|
+
try {
|
|
149
|
+
audience = audienceFor(env, config);
|
|
150
|
+
appId = appIdFor(env, config) ?? audience;
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
if (err instanceof ConfigurationError) {
|
|
154
|
+
console.error(err);
|
|
155
|
+
return misconfigured(err.message);
|
|
156
|
+
}
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
// The reserved tools contract carries its own gateway-minted tokens and
|
|
160
|
+
// never reaches the app's handler.
|
|
161
|
+
const toolsResponse = await handleToolsRequest(request, env, ctx, {
|
|
162
|
+
toolSet: options.tools,
|
|
163
|
+
appId,
|
|
164
|
+
identity: identityOptions(env, config, audience),
|
|
165
|
+
});
|
|
166
|
+
if (toolsResponse)
|
|
167
|
+
return toolsResponse;
|
|
104
168
|
let identity;
|
|
105
169
|
try {
|
|
106
|
-
identity = await
|
|
170
|
+
identity = await getIdentityFromRequest(request, identityOptions(env, config, audience));
|
|
107
171
|
rememberIdentity(request, identity);
|
|
108
172
|
}
|
|
109
173
|
catch (err) {
|
|
@@ -1,21 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
import { type GatewayCallFor } from "./attribution.js";
|
|
2
|
+
export declare const BINDING_ORIGIN = "http://every-app-gateway.internal";
|
|
3
|
+
export interface GatewayServiceBinding {
|
|
2
4
|
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
3
5
|
}
|
|
4
6
|
export interface GatewayFetchEnv {
|
|
5
7
|
EVERY_APP_GATEWAY?: GatewayServiceBinding;
|
|
6
8
|
EVERYAPP_DEV?: string | boolean;
|
|
9
|
+
/** `1` on a shared app's Workers (`everyAppWorker()` sets it). */
|
|
10
|
+
EVERYAPP_SHARED?: string;
|
|
7
11
|
OPENAI_API_KEY?: string;
|
|
12
|
+
OPENROUTER_API_KEY?: string;
|
|
13
|
+
/** Workers AI: an API token (Workers AI Read and Edit) and the account it bills. */
|
|
14
|
+
WORKERS_AI_API_TOKEN?: string;
|
|
15
|
+
CLOUDFLARE_ACCOUNT_ID?: string;
|
|
8
16
|
}
|
|
9
17
|
export interface CreateGatewayFetchOptions {
|
|
10
18
|
env: GatewayFetchEnv;
|
|
11
|
-
/**
|
|
12
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Whom the call is for: the inbound request (its user), or
|
|
21
|
+
* `{ background: true, organizationId }` for work no person started
|
|
22
|
+
* (crons, Workflows, queues). An organization's own app may omit it for
|
|
23
|
+
* background work, which is then the app's; a shared app's Worker must
|
|
24
|
+
* pass one or the other ({@link AttributionError}).
|
|
25
|
+
*/
|
|
26
|
+
for?: GatewayCallFor;
|
|
13
27
|
}
|
|
14
28
|
/**
|
|
15
|
-
* Create
|
|
16
|
-
* service binding. In local dev only, the
|
|
17
|
-
*
|
|
29
|
+
* Create a fetch for the gateway's AI providers (`/api/ai/<provider>/…`),
|
|
30
|
+
* backed by the private gateway service binding. In local dev only, the
|
|
31
|
+
* developer's own provider key from `.dev.vars` is a direct-provider
|
|
32
|
+
* fallback when no binding exists.
|
|
18
33
|
*/
|
|
19
|
-
export declare function createGatewayFetch({ env,
|
|
20
|
-
|
|
34
|
+
export declare function createGatewayFetch({ env, for: target, }: CreateGatewayFetchOptions): typeof fetch;
|
|
35
|
+
/** A copy of `source` aimed at `url`, streaming its body rather than buffering it. */
|
|
36
|
+
export declare function streamingRequest(url: string, source: Request, headers: Headers): Request;
|
|
21
37
|
//# sourceMappingURL=gatewayFetch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gatewayFetch.d.ts","sourceRoot":"","sources":["../../src/server/gatewayFetch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gatewayFetch.d.ts","sourceRoot":"","sources":["../../src/server/gatewayFetch.ts"],"names":[],"mappings":"AASA,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,eAAe;IAC9B,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;IAC1C,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,kEAAkE;IAClE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,eAAe,CAAC;IACrB;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,GAAG,EAAE,MAAM,GACZ,EAAE,yBAAyB,GAAG,OAAO,KAAK,CA8D1C;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,GACf,OAAO,CAUT"}
|