@every-app/sdk 0.3.0-rc.1 → 0.3.0-rc.11
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 +62 -64
- package/dist/cloudflare/catalogSettings.generated.d.ts +84 -0
- package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
- package/dist/cloudflare/catalogSettings.generated.js +175 -0
- package/dist/cloudflare/index.d.ts +3 -2
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +4 -1
- package/dist/cloudflare/sentinel.d.ts +60 -2
- package/dist/cloudflare/sentinel.d.ts.map +1 -1
- package/dist/cloudflare/sentinel.js +37 -2
- package/dist/cloudflare/worker.d.ts +391 -63
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +394 -108
- package/dist/dev/index.d.ts +1 -1
- package/dist/dev/index.d.ts.map +1 -1
- package/dist/dev/index.js +1 -1
- package/dist/dev/keypair.d.ts +2 -0
- package/dist/dev/keypair.d.ts.map +1 -1
- package/dist/dev/keypair.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/internal/aiDefault.d.ts +205 -0
- package/dist/internal/aiDefault.d.ts.map +1 -0
- package/dist/internal/aiDefault.js +335 -0
- package/dist/internal/aiProviders.d.ts +7 -2
- package/dist/internal/aiProviders.d.ts.map +1 -1
- package/dist/internal/aiProviders.js +19 -6
- package/dist/internal/appSettings.d.ts +82 -4
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +204 -29
- package/dist/internal/audit.d.ts +108 -0
- package/dist/internal/audit.d.ts.map +1 -0
- package/dist/internal/audit.js +235 -0
- package/dist/internal/capabilities.d.ts +2261 -815
- package/dist/internal/capabilities.d.ts.map +1 -1
- package/dist/internal/capabilities.js +122 -1034
- package/dist/internal/catalog/commerce.d.ts +394 -0
- package/dist/internal/catalog/commerce.d.ts.map +1 -0
- package/dist/internal/catalog/commerce.js +477 -0
- package/dist/internal/catalog/comms.d.ts +375 -0
- package/dist/internal/catalog/comms.d.ts.map +1 -0
- package/dist/internal/catalog/comms.js +520 -0
- package/dist/internal/catalog/index.d.ts +2008 -0
- package/dist/internal/catalog/index.d.ts.map +1 -0
- package/dist/internal/catalog/index.js +19 -0
- package/dist/internal/catalog/inference.d.ts +393 -0
- package/dist/internal/catalog/inference.d.ts.map +1 -0
- package/dist/internal/catalog/inference.js +460 -0
- package/dist/internal/catalog/infra.d.ts +458 -0
- package/dist/internal/catalog/infra.d.ts.map +1 -0
- package/dist/internal/catalog/infra.js +608 -0
- package/dist/internal/catalog/search.d.ts +400 -0
- package/dist/internal/catalog/search.d.ts.map +1 -0
- package/dist/internal/catalog/search.js +463 -0
- package/dist/internal/devProviders.d.ts +2 -2
- package/dist/internal/devProviders.d.ts.map +1 -1
- package/dist/internal/devProviders.js +19 -1
- package/dist/internal/events.d.ts +65 -3
- package/dist/internal/events.d.ts.map +1 -1
- package/dist/internal/events.js +110 -5
- package/dist/internal/gatewaySettings.d.ts +3 -2
- package/dist/internal/gatewaySettings.d.ts.map +1 -1
- package/dist/internal/gatewaySettings.js +12 -6
- package/dist/internal/identity.d.ts +41 -4
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +48 -10
- package/dist/internal/index.d.ts +6 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +6 -1
- package/dist/internal/members.d.ts +3 -2
- package/dist/internal/members.d.ts.map +1 -1
- package/dist/internal/oauthBuiltIns.d.ts +101 -0
- package/dist/internal/oauthBuiltIns.d.ts.map +1 -0
- package/dist/internal/oauthBuiltIns.js +122 -0
- package/dist/internal/oauthClient.d.ts +8 -50
- package/dist/internal/oauthClient.d.ts.map +1 -1
- package/dist/internal/oauthClient.js +2 -177
- package/dist/internal/oauthPresets.d.ts +32 -0
- package/dist/internal/oauthPresets.d.ts.map +1 -0
- package/dist/internal/oauthPresets.js +253 -0
- package/dist/internal/oauthScopes.d.ts +43 -100
- package/dist/internal/oauthScopes.d.ts.map +1 -1
- package/dist/internal/oauthScopes.js +83 -382
- package/dist/internal/oauthSpec.d.ts +103 -0
- package/dist/internal/oauthSpec.d.ts.map +1 -0
- package/dist/internal/oauthSpec.js +520 -0
- package/dist/internal/protocol.d.ts +97 -5
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +89 -1
- package/dist/internal/providerRegistry.d.ts +17 -6
- package/dist/internal/providerRegistry.d.ts.map +1 -1
- package/dist/internal/providerRegistry.js +71 -8
- package/dist/internal/providerSpec.d.ts +18 -7
- package/dist/internal/providerSpec.d.ts.map +1 -1
- package/dist/internal/providerSpec.js +420 -34
- package/dist/internal/remoteMcp.d.ts.map +1 -1
- package/dist/internal/remoteMcp.js +1 -5
- package/dist/internal/signInProviders.d.ts +104 -0
- package/dist/internal/signInProviders.d.ts.map +1 -0
- package/dist/internal/signInProviders.js +245 -0
- package/dist/internal/tools.d.ts +5 -4
- package/dist/internal/tools.d.ts.map +1 -1
- package/dist/internal/tools.js +4 -3
- package/dist/manifest.d.ts +267 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +30 -0
- package/dist/server/ai.d.ts +111 -0
- package/dist/server/ai.d.ts.map +1 -0
- package/dist/server/ai.js +145 -0
- package/dist/server/aiBinding.d.ts +68 -0
- package/dist/server/aiBinding.d.ts.map +1 -0
- package/dist/server/aiBinding.js +294 -0
- package/dist/server/attribution.d.ts +18 -5
- package/dist/server/attribution.d.ts.map +1 -1
- package/dist/server/attribution.js +19 -5
- package/dist/server/connectUrl.d.ts +16 -0
- package/dist/server/connectUrl.d.ts.map +1 -0
- package/dist/server/connectUrl.js +40 -0
- package/dist/server/context.d.ts +68 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +117 -0
- package/dist/server/emailBinding.d.ts +72 -0
- package/dist/server/emailBinding.d.ts.map +1 -0
- package/dist/server/emailBinding.js +124 -0
- package/dist/server/emit.d.ts +1 -1
- package/dist/server/emit.d.ts.map +1 -1
- package/dist/server/emit.js +7 -7
- package/dist/server/env.d.ts +44 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +1 -0
- package/dist/server/eventsEndpoint.d.ts +48 -0
- package/dist/server/eventsEndpoint.d.ts.map +1 -0
- package/dist/server/eventsEndpoint.js +145 -0
- package/dist/server/everyApp.d.ts +40 -11
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +116 -6
- package/dist/server/fromMcpTools.d.ts +89 -0
- package/dist/server/fromMcpTools.d.ts.map +1 -0
- package/dist/server/fromMcpTools.js +192 -0
- package/dist/server/gatewayFetch.d.ts +42 -18
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +138 -19
- package/dist/server/gatewayUrl.d.ts +13 -0
- package/dist/server/gatewayUrl.d.ts.map +1 -0
- package/dist/server/gatewayUrl.js +34 -0
- package/dist/server/index.d.ts +16 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +13 -3
- package/dist/server/integrationFetch.d.ts +92 -73
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +206 -319
- package/dist/server/listMembers.d.ts +1 -1
- package/dist/server/listMembers.d.ts.map +1 -1
- package/dist/server/listMembers.js +8 -11
- package/dist/server/refusal.d.ts +55 -0
- package/dist/server/refusal.d.ts.map +1 -0
- package/dist/server/refusal.js +193 -0
- package/dist/server/sendEmail.d.ts +1 -1
- package/dist/server/sendEmail.d.ts.map +1 -1
- package/dist/server/sendEmail.js +7 -7
- package/dist/server/tools.d.ts +7 -2
- package/dist/server/tools.d.ts.map +1 -1
- package/dist/server/tools.js +2 -1
- package/dist/server/toolsEndpoint.d.ts +3 -1
- package/dist/server/toolsEndpoint.d.ts.map +1 -1
- package/dist/server/toolsEndpoint.js +19 -7
- package/dist/server/webhooks.d.ts +56 -0
- package/dist/server/webhooks.d.ts.map +1 -0
- package/dist/server/webhooks.js +205 -0
- package/dist/tanstack-start/index.d.ts +9 -0
- package/dist/tanstack-start/index.d.ts.map +1 -0
- package/dist/tanstack-start/index.js +29 -0
- package/dist/testing/index.d.ts +93 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +156 -0
- package/package.json +35 -14
- package/dist/server/authorizeUrl.d.ts +0 -43
- package/dist/server/authorizeUrl.d.ts.map +0 -1
- package/dist/server/authorizeUrl.js +0 -110
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gatewayEmailBinding(env)`: the Gateway's `email` capability as a
|
|
3
|
+
* `send_email` binding, for code written against `env.EMAIL.send(message)`.
|
|
4
|
+
*
|
|
5
|
+
* An app on Every App binds no `send_email` of its own: the Gateway sends
|
|
6
|
+
* with its sender, checks `from` against the installation's senders and
|
|
7
|
+
* keeps the mail budgets. Code that already calls `env.EMAIL.send()` gets
|
|
8
|
+
* this object in its place:
|
|
9
|
+
*
|
|
10
|
+
* const EMAIL = gatewayEmailBinding(env, { for: request });
|
|
11
|
+
* await EMAIL.send({ from, to, subject, text });
|
|
12
|
+
*
|
|
13
|
+
* Each `send()` is a `sendEmail()` (the manifest lists `capabilities: {
|
|
14
|
+
* email: { access: "write" } }`), so local development works the same way:
|
|
15
|
+
* checked and printed, or sent with the developer's own Email Sending
|
|
16
|
+
* account (EMAIL_REST_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, EMAIL_FROM).
|
|
17
|
+
*/
|
|
18
|
+
import { type SendEmailMessage } from "../internal/index.js";
|
|
19
|
+
import type { GatewayCallFor } from "./attribution.js";
|
|
20
|
+
export interface GatewayEmailBindingOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Whom the mail is for: the inbound request, or `{ background: true,
|
|
23
|
+
* organizationId }` (sendEmail's `for`).
|
|
24
|
+
*/
|
|
25
|
+
for?: GatewayCallFor;
|
|
26
|
+
}
|
|
27
|
+
/** `name <email>` or a bare address, as the binding takes them. */
|
|
28
|
+
type BindingAddress = string | {
|
|
29
|
+
email: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
};
|
|
32
|
+
type BindingRecipients = BindingAddress | BindingAddress[];
|
|
33
|
+
/** The structured message `send_email`'s `send()` takes (`EmailMessageBuilder`). */
|
|
34
|
+
export interface GatewayEmailBindingMessage {
|
|
35
|
+
from: BindingAddress;
|
|
36
|
+
to?: BindingRecipients;
|
|
37
|
+
cc?: BindingRecipients;
|
|
38
|
+
bcc?: BindingRecipients;
|
|
39
|
+
subject: string;
|
|
40
|
+
replyTo?: BindingAddress;
|
|
41
|
+
headers?: Record<string, string>;
|
|
42
|
+
text?: string;
|
|
43
|
+
html?: string;
|
|
44
|
+
attachments?: {
|
|
45
|
+
disposition?: "inline" | "attachment";
|
|
46
|
+
contentId?: string;
|
|
47
|
+
filename: string;
|
|
48
|
+
type: string;
|
|
49
|
+
content: string | ArrayBuffer | ArrayBufferView;
|
|
50
|
+
}[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A `send_email` binding (`SendEmail`) over the Gateway: pass it where code
|
|
54
|
+
* takes `env.EMAIL`. `send()` takes the structured message (`from`, `to`,
|
|
55
|
+
* `cc`, `bcc`, `subject`, `text`, `html`, `replyTo`, `headers`,
|
|
56
|
+
* `attachments`) and resolves `{ messageId }`. A raw MIME `EmailMessage`
|
|
57
|
+
* (`new EmailMessage(from, to, raw)`) is refused with `GatewayRefusalError`
|
|
58
|
+
* `email_invalid_message`: the Gateway takes structured mail only.
|
|
59
|
+
*
|
|
60
|
+
* Errors are sendEmail()'s: `GatewayRefusalError` with the Gateway's code
|
|
61
|
+
* (`email_sender_not_allowed`, `email_budget_exhausted`,
|
|
62
|
+
* `integration_not_configured`, …) and `ConfigurationError` with neither a
|
|
63
|
+
* binding nor `everyapp dev`. Nothing is checked when the binding is made.
|
|
64
|
+
*/
|
|
65
|
+
export declare function gatewayEmailBinding(env: object, options?: GatewayEmailBindingOptions): SendEmail;
|
|
66
|
+
/**
|
|
67
|
+
* The binding's message as sendEmail()'s: recipients as bare addresses,
|
|
68
|
+
* `from` and `replyTo` with their display names, attachments base64.
|
|
69
|
+
*/
|
|
70
|
+
export declare function toSendEmailMessage(message: unknown): SendEmailMessage;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=emailBinding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailBinding.d.ts","sourceRoot":"","sources":["../../src/server/emailBinding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIvD,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;AAED,mEAAmE;AACnE,KAAK,cAAc,GAAG,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAChE,KAAK,iBAAiB,GAAG,cAAc,GAAG,cAAc,EAAE,CAAC;AAE3D,oFAAoF;AACpF,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE;QACZ,WAAW,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;QACtC,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,eAAe,CAAC;KACjD,EAAE,CAAC;CACL;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,0BAA+B,GACvC,SAAS,CAcX;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CA6BrE"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gatewayEmailBinding(env)`: the Gateway's `email` capability as a
|
|
3
|
+
* `send_email` binding, for code written against `env.EMAIL.send(message)`.
|
|
4
|
+
*
|
|
5
|
+
* An app on Every App binds no `send_email` of its own: the Gateway sends
|
|
6
|
+
* with its sender, checks `from` against the installation's senders and
|
|
7
|
+
* keeps the mail budgets. Code that already calls `env.EMAIL.send()` gets
|
|
8
|
+
* this object in its place:
|
|
9
|
+
*
|
|
10
|
+
* const EMAIL = gatewayEmailBinding(env, { for: request });
|
|
11
|
+
* await EMAIL.send({ from, to, subject, text });
|
|
12
|
+
*
|
|
13
|
+
* Each `send()` is a `sendEmail()` (the manifest lists `capabilities: {
|
|
14
|
+
* email: { access: "write" } }`), so local development works the same way:
|
|
15
|
+
* checked and printed, or sent with the developer's own Email Sending
|
|
16
|
+
* account (EMAIL_REST_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, EMAIL_FROM).
|
|
17
|
+
*/
|
|
18
|
+
import { ConfigurationError, } from "../internal/index.js";
|
|
19
|
+
import { GatewayRefusalError } from "./refusal.js";
|
|
20
|
+
import { sendEmail } from "./sendEmail.js";
|
|
21
|
+
/**
|
|
22
|
+
* A `send_email` binding (`SendEmail`) over the Gateway: pass it where code
|
|
23
|
+
* takes `env.EMAIL`. `send()` takes the structured message (`from`, `to`,
|
|
24
|
+
* `cc`, `bcc`, `subject`, `text`, `html`, `replyTo`, `headers`,
|
|
25
|
+
* `attachments`) and resolves `{ messageId }`. A raw MIME `EmailMessage`
|
|
26
|
+
* (`new EmailMessage(from, to, raw)`) is refused with `GatewayRefusalError`
|
|
27
|
+
* `email_invalid_message`: the Gateway takes structured mail only.
|
|
28
|
+
*
|
|
29
|
+
* Errors are sendEmail()'s: `GatewayRefusalError` with the Gateway's code
|
|
30
|
+
* (`email_sender_not_allowed`, `email_budget_exhausted`,
|
|
31
|
+
* `integration_not_configured`, …) and `ConfigurationError` with neither a
|
|
32
|
+
* binding nor `everyapp dev`. Nothing is checked when the binding is made.
|
|
33
|
+
*/
|
|
34
|
+
export function gatewayEmailBinding(env, options = {}) {
|
|
35
|
+
const binding = {
|
|
36
|
+
async send(message) {
|
|
37
|
+
const result = await sendEmail({
|
|
38
|
+
env,
|
|
39
|
+
...(options.for === undefined ? {} : { for: options.for }),
|
|
40
|
+
message: toSendEmailMessage(message),
|
|
41
|
+
});
|
|
42
|
+
return { messageId: result.messageId ?? "" };
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
// `SendEmail` is the app's own Workers types' interface, whose `send()`
|
|
46
|
+
// overloads change with the version; this `send()` takes both forms.
|
|
47
|
+
return binding;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The binding's message as sendEmail()'s: recipients as bare addresses,
|
|
51
|
+
* `from` and `replyTo` with their display names, attachments base64.
|
|
52
|
+
*/
|
|
53
|
+
export function toSendEmailMessage(message) {
|
|
54
|
+
if (!message || typeof message !== "object") {
|
|
55
|
+
throw new ConfigurationError("EMAIL.send() takes a message object.");
|
|
56
|
+
}
|
|
57
|
+
if (!("subject" in message)) {
|
|
58
|
+
throw new GatewayRefusalError({
|
|
59
|
+
status: 400,
|
|
60
|
+
code: "email_invalid_message",
|
|
61
|
+
message: "Raw MIME messages can't be sent through the Every App gateway; send a structured message ({ from, to, subject, text or html }).",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const m = message;
|
|
65
|
+
return {
|
|
66
|
+
to: addresses(m.to) ?? [],
|
|
67
|
+
...(m.cc === undefined ? {} : { cc: addresses(m.cc) }),
|
|
68
|
+
...(m.bcc === undefined ? {} : { bcc: addresses(m.bcc) }),
|
|
69
|
+
subject: m.subject,
|
|
70
|
+
...(m.text ? { text: m.text } : {}),
|
|
71
|
+
...(m.html ? { html: m.html } : {}),
|
|
72
|
+
from: named(m.from),
|
|
73
|
+
...(m.replyTo ? { replyTo: named(m.replyTo) } : {}),
|
|
74
|
+
...(m.headers && Object.keys(m.headers).length > 0
|
|
75
|
+
? { headers: m.headers }
|
|
76
|
+
: {}),
|
|
77
|
+
...(m.attachments?.length
|
|
78
|
+
? { attachments: m.attachments.map(attachment) }
|
|
79
|
+
: {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* One attachment in the Gateway's shape. An inline part without a content
|
|
84
|
+
* id can't be referenced (and the Gateway refuses it), so it goes as an
|
|
85
|
+
* ordinary attachment.
|
|
86
|
+
*/
|
|
87
|
+
function attachment(a) {
|
|
88
|
+
const contentId = a.contentId?.trim();
|
|
89
|
+
return {
|
|
90
|
+
filename: a.filename,
|
|
91
|
+
contentType: a.type,
|
|
92
|
+
content: base64(a.content),
|
|
93
|
+
...(a.disposition === "inline" && contentId
|
|
94
|
+
? { disposition: "inline", contentId }
|
|
95
|
+
: {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function named(address) {
|
|
99
|
+
if (typeof address === "string")
|
|
100
|
+
return { address };
|
|
101
|
+
return {
|
|
102
|
+
address: address.email,
|
|
103
|
+
...(address.name?.trim() ? { name: address.name } : {}),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function addresses(recipients) {
|
|
107
|
+
if (recipients === undefined)
|
|
108
|
+
return undefined;
|
|
109
|
+
const of = (a) => (typeof a === "string" ? a : a.email);
|
|
110
|
+
return Array.isArray(recipients) ? recipients.map(of) : of(recipients);
|
|
111
|
+
}
|
|
112
|
+
/** Strings are taken as base64 already, as the binding takes them; bytes are encoded. */
|
|
113
|
+
function base64(content) {
|
|
114
|
+
if (typeof content === "string")
|
|
115
|
+
return content;
|
|
116
|
+
const bytes = content instanceof ArrayBuffer
|
|
117
|
+
? new Uint8Array(content)
|
|
118
|
+
: new Uint8Array(content.buffer, content.byteOffset, content.byteLength);
|
|
119
|
+
let binary = "";
|
|
120
|
+
for (let i = 0; i < bytes.length; i += 0x8000) {
|
|
121
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
|
|
122
|
+
}
|
|
123
|
+
return btoa(binary);
|
|
124
|
+
}
|
package/dist/server/emit.d.ts
CHANGED
|
@@ -59,5 +59,5 @@ export interface EmitOptions {
|
|
|
59
59
|
* the gateway checks it, printed, and answered `{ id: "dev-…", type }`;
|
|
60
60
|
* nothing is delivered.
|
|
61
61
|
*/
|
|
62
|
-
export declare function emit({ env, for:
|
|
62
|
+
export declare function emit({ env, for: explicitTarget, event, data, }: EmitOptions): Promise<EmitEventResult>;
|
|
63
63
|
//# sourceMappingURL=emit.d.ts.map
|
|
@@ -1 +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;
|
|
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;AAQ1B,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,cAAc,EACnB,KAAK,EACL,IAAI,GACL,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAkBxC"}
|
package/dist/server/emit.js
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* two can't drift.
|
|
10
10
|
*/
|
|
11
11
|
import { APP_EVENT_DATA_MAX_BYTES, APP_ID_ENV, ConfigurationError, EVENTS_EMIT_PATH, appEventNameProblem, appEventType, checkEventData, } from "../internal/index.js";
|
|
12
|
-
import { applyAttribution,
|
|
13
|
-
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
14
|
-
import { GatewayRefusalError, gatewayRefusal } from "./
|
|
12
|
+
import { applyAttribution, attributionFor, } from "./attribution.js";
|
|
13
|
+
import { BINDING_ORIGIN, gatewayBinding, } from "./gatewayFetch.js";
|
|
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
|
|
@@ -36,10 +36,10 @@ import { GatewayRefusalError, gatewayRefusal } from "./integrationFetch.js";
|
|
|
36
36
|
* the gateway checks it, printed, and answered `{ id: "dev-…", type }`;
|
|
37
37
|
* nothing is delivered.
|
|
38
38
|
*/
|
|
39
|
-
export async function emit({ env, for:
|
|
40
|
-
|
|
39
|
+
export async function emit({ env, for: explicitTarget, event, data, }) {
|
|
40
|
+
const target = attributionFor(env, explicitTarget, "emit");
|
|
41
41
|
const values = env;
|
|
42
|
-
const binding =
|
|
42
|
+
const binding = gatewayBinding(env);
|
|
43
43
|
if (binding) {
|
|
44
44
|
if (typeof binding.fetch !== "function") {
|
|
45
45
|
throw new ConfigurationError("EVERY_APP_GATEWAY is configured but is not a valid service binding.");
|
|
@@ -66,7 +66,7 @@ async function emitThroughGateway(binding, target, body) {
|
|
|
66
66
|
throw new GatewayRefusalError({
|
|
67
67
|
status: response.status,
|
|
68
68
|
code: "event_emit_failed",
|
|
69
|
-
message: `The
|
|
69
|
+
message: `The EveryApp gateway answered ${response.status} to the event.`,
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
return (await response.json());
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `EveryAppEnv`: what Every App puts in an app Worker's `env`, for an app
|
|
3
|
+
* that types its env by hand. An app built with `everyAppWorker()` needs
|
|
4
|
+
* none of it: `cf workers types` writes the same names into `Env` from the
|
|
5
|
+
* Worker's definition.
|
|
6
|
+
*/
|
|
7
|
+
import type { EveryAppManifest } from "../manifest.js";
|
|
8
|
+
/** The `env` keys Every App sets on an app's Worker, deployed and under `everyapp dev`. */
|
|
9
|
+
export interface EveryAppEnv<M extends EveryAppManifest = EveryAppManifest> {
|
|
10
|
+
/** The manifest's `id`. */
|
|
11
|
+
EVERYAPP_APP_ID: string;
|
|
12
|
+
/**
|
|
13
|
+
* The manifest (`everyapp.config.ts`) as JSON: what the app asked for,
|
|
14
|
+
* for a page that shows it. `EveryAppEnv<typeof manifest>` types it as
|
|
15
|
+
* the app's own.
|
|
16
|
+
*/
|
|
17
|
+
EVERYAPP_MANIFEST: M;
|
|
18
|
+
/** The Gateway's URL; links back to it go through `gatewayUrl(env)`. */
|
|
19
|
+
GATEWAY_URL: string;
|
|
20
|
+
/** The identity tokens' issuer: the Gateway's URL, or the dev issuer. */
|
|
21
|
+
EVERYAPP_IDENTITY_ISSUER: string;
|
|
22
|
+
/** The public keys (JSON array of PEMs) `everyApp()` verifies identities with. */
|
|
23
|
+
EVERYAPP_IDENTITY_PUBLIC_KEYS: string;
|
|
24
|
+
/** Deployed: the Worker's name, the identity tokens' audience. */
|
|
25
|
+
EVERYAPP_AUDIENCE?: string;
|
|
26
|
+
/** Deployed: the organization the app is installed for. */
|
|
27
|
+
EVERY_APP_ORG_ID?: string;
|
|
28
|
+
/** Deployed, on an app installed for every organization: `"1"`. */
|
|
29
|
+
EVERYAPP_SHARED?: string;
|
|
30
|
+
/** Deployed: the service binding to the Gateway, which capabilities, AI and email go through. */
|
|
31
|
+
EVERY_APP_GATEWAY?: Fetcher;
|
|
32
|
+
/** `"1"` under `everyapp dev`, absent when deployed. */
|
|
33
|
+
EVERYAPP_DEV?: string;
|
|
34
|
+
/** Under `everyapp dev`: the manifest's `capabilities`, as JSON, for the SDK's dev fallbacks. */
|
|
35
|
+
EVERYAPP_DEV_CAPABILITIES?: string;
|
|
36
|
+
/** Under `everyapp dev`: the app's `.everyapp/providers/*.json`, as JSON. */
|
|
37
|
+
EVERYAPP_DEV_PROVIDERS?: string;
|
|
38
|
+
/** Under `everyapp dev`, from `.dev.vars`: the senders standing in for `everyapp email set --sender`. */
|
|
39
|
+
EVERYAPP_EMAIL_SENDERS?: string;
|
|
40
|
+
/** Under `everyapp dev --gateway` (linked dev): the gateway-lite's forwarder, which the SDK's services call the real Gateway through, and the run's nonce. */
|
|
41
|
+
EVERYAPP_LINKED_DEV_URL?: string;
|
|
42
|
+
EVERYAPP_LINKED_DEV_NONCE?: string;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/server/env.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,2FAA2F;AAC3F,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IACxE,2BAA2B;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,CAAC;IACrB,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,wBAAwB,EAAE,MAAM,CAAC;IACjC,kFAAkF;IAClF,6BAA6B,EAAE,MAAM,CAAC;IACtC,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iGAAiG;IACjG,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,6EAA6E;IAC7E,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,yGAAyG;IACzG,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,8JAA8J;IAC9J,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app side of the `app` event sink (docs/design/2026-11-birds-decisions/app-event-sink.md).
|
|
3
|
+
*
|
|
4
|
+
* `everyApp()` answers the reserved `POST /__everyapp/events` here, before
|
|
5
|
+
* any app code runs and whether or not the app passed `events`:
|
|
6
|
+
*
|
|
7
|
+
* - the request needs the Gateway's system token for this app (purpose
|
|
8
|
+
* `events.deliver`), whose `bh` claim is the SHA-256 of this exact body,
|
|
9
|
+
* so a token opens one delivery and nothing else;
|
|
10
|
+
* - the envelope must name the organization this Worker serves
|
|
11
|
+
* (`EVERY_APP_ORG_ID`), when it is pinned;
|
|
12
|
+
* - only then is `events.on` called, under `withOrganization()`, so every
|
|
13
|
+
* Gateway call it makes is that organization's background work.
|
|
14
|
+
*
|
|
15
|
+
* The perimeter refuses the path from outside and strips inbound
|
|
16
|
+
* `x-everyapp-*` headers, so only the Gateway's event bus reaches it, over
|
|
17
|
+
* the service binding.
|
|
18
|
+
*/
|
|
19
|
+
import { type AppEventEnvelope, type RequestIdentityOptions } from "../internal/index.js";
|
|
20
|
+
import type { ExecutionContextLike } from "./everyApp.js";
|
|
21
|
+
/** One event the Gateway delivered: the webhook envelope, plus the delivery's id and attempt. */
|
|
22
|
+
export interface AppEvent extends AppEventEnvelope {
|
|
23
|
+
delivery: {
|
|
24
|
+
id: string;
|
|
25
|
+
attempt: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export type AppEventHandler<TEnv = unknown> = (event: AppEvent, env: TEnv, ctx: ExecutionContextLike) => unknown | Promise<unknown>;
|
|
29
|
+
/**
|
|
30
|
+
* `everyApp(handler, { events: { on } })`. `on` is one function for every
|
|
31
|
+
* event, or one per exact type (`"member.removed"`). An event with no
|
|
32
|
+
* handler is acknowledged and dropped. A handler that throws answers 500,
|
|
33
|
+
* and the Gateway retries the delivery with its usual backoff.
|
|
34
|
+
*/
|
|
35
|
+
export interface AppEventsOptions<TEnv = unknown> {
|
|
36
|
+
on: AppEventHandler<TEnv> | Partial<Record<string, AppEventHandler<TEnv>>>;
|
|
37
|
+
}
|
|
38
|
+
export interface EventsEndpointOptions {
|
|
39
|
+
events?: AppEventsOptions<never>;
|
|
40
|
+
/** How to verify the Gateway's token (keys, issuer, audience, dev opt-in). */
|
|
41
|
+
identity: RequestIdentityOptions;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Answer a request to the reserved events path, or return null for any
|
|
45
|
+
* other path so the app's own handler runs.
|
|
46
|
+
*/
|
|
47
|
+
export declare function handleEventsRequest(request: Request, env: unknown, ctx: ExecutionContextLike, options: EventsEndpointOptions): Promise<Response | null>;
|
|
48
|
+
//# sourceMappingURL=eventsEndpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventsEndpoint.d.ts","sourceRoot":"","sources":["../../src/server/eventsEndpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EASL,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,iGAAiG;AACjG,MAAM,WAAW,QAAS,SAAQ,gBAAgB;IAChD,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,MAAM,MAAM,eAAe,CAAC,IAAI,GAAG,OAAO,IAAI,CAC5C,KAAK,EAAE,QAAQ,EACf,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,oBAAoB,KACtB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,OAAO;IAC9C,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACjC,8EAA8E;IAC9E,QAAQ,EAAE,sBAAsB,CAAC;CAClC;AAwCD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,oBAAoB,EACzB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA4F1B"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The app side of the `app` event sink (docs/design/2026-11-birds-decisions/app-event-sink.md).
|
|
3
|
+
*
|
|
4
|
+
* `everyApp()` answers the reserved `POST /__everyapp/events` here, before
|
|
5
|
+
* any app code runs and whether or not the app passed `events`:
|
|
6
|
+
*
|
|
7
|
+
* - the request needs the Gateway's system token for this app (purpose
|
|
8
|
+
* `events.deliver`), whose `bh` claim is the SHA-256 of this exact body,
|
|
9
|
+
* so a token opens one delivery and nothing else;
|
|
10
|
+
* - the envelope must name the organization this Worker serves
|
|
11
|
+
* (`EVERY_APP_ORG_ID`), when it is pinned;
|
|
12
|
+
* - only then is `events.on` called, under `withOrganization()`, so every
|
|
13
|
+
* Gateway call it makes is that organization's background work.
|
|
14
|
+
*
|
|
15
|
+
* The perimeter refuses the path from outside and strips inbound
|
|
16
|
+
* `x-everyapp-*` headers, so only the Gateway's event bus reaches it, over
|
|
17
|
+
* the service binding.
|
|
18
|
+
*/
|
|
19
|
+
import { APP_EVENTS_PATH, ConfigurationError, EVENT_HEADERS, IdentityError, SYSTEM_HEADER, bodyHash, resolveVerifyOptions, verifySystemJwt, } from "../internal/index.js";
|
|
20
|
+
import { withOrganization } from "./context.js";
|
|
21
|
+
/** The most body the endpoint reads: an envelope's data is at most 16 KiB. */
|
|
22
|
+
const MAX_BODY_BYTES = 64 * 1024;
|
|
23
|
+
function answer(status, body) {
|
|
24
|
+
return Response.json(body, {
|
|
25
|
+
status,
|
|
26
|
+
headers: { "cache-control": "no-store" },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function isEnvelope(value) {
|
|
30
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const v = value;
|
|
34
|
+
const org = v.organization;
|
|
35
|
+
return (typeof v.id === "string" &&
|
|
36
|
+
typeof v.type === "string" &&
|
|
37
|
+
typeof v.version === "number" &&
|
|
38
|
+
typeof v.time === "string" &&
|
|
39
|
+
!!org &&
|
|
40
|
+
typeof org === "object" &&
|
|
41
|
+
typeof org.id === "string" &&
|
|
42
|
+
!!v.data &&
|
|
43
|
+
typeof v.data === "object" &&
|
|
44
|
+
!Array.isArray(v.data));
|
|
45
|
+
}
|
|
46
|
+
function handlerFor(on, type) {
|
|
47
|
+
if (typeof on === "function")
|
|
48
|
+
return on;
|
|
49
|
+
return Object.prototype.hasOwnProperty.call(on, type) ? on[type] : undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Answer a request to the reserved events path, or return null for any
|
|
53
|
+
* other path so the app's own handler runs.
|
|
54
|
+
*/
|
|
55
|
+
export async function handleEventsRequest(request, env, ctx, options) {
|
|
56
|
+
const { pathname } = new URL(request.url);
|
|
57
|
+
if (pathname !== APP_EVENTS_PATH)
|
|
58
|
+
return null;
|
|
59
|
+
if (request.method !== "POST") {
|
|
60
|
+
return answer(405, { error: "method_not_allowed" });
|
|
61
|
+
}
|
|
62
|
+
let verify;
|
|
63
|
+
try {
|
|
64
|
+
verify = resolveVerifyOptions(options.identity);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof ConfigurationError) {
|
|
68
|
+
console.error(error);
|
|
69
|
+
return answer(500, { error: "misconfigured", message: error.message });
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
let claims;
|
|
74
|
+
try {
|
|
75
|
+
claims = await verifySystemJwt(request.headers.get(SYSTEM_HEADER) ?? "", {
|
|
76
|
+
...verify,
|
|
77
|
+
purpose: "events.deliver",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error instanceof IdentityError) {
|
|
82
|
+
return answer(401, { error: "unauthenticated", message: error.message });
|
|
83
|
+
}
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
const declared = Number(request.headers.get("content-length") ?? "0");
|
|
87
|
+
if (declared > MAX_BODY_BYTES) {
|
|
88
|
+
return answer(413, { error: "too_large" });
|
|
89
|
+
}
|
|
90
|
+
const body = await request.text();
|
|
91
|
+
if (body.length > MAX_BODY_BYTES) {
|
|
92
|
+
return answer(413, { error: "too_large" });
|
|
93
|
+
}
|
|
94
|
+
// The token was minted for this exact body: another body, even one the
|
|
95
|
+
// Gateway sent, is refused.
|
|
96
|
+
if (claims.bh !== (await bodyHash(body))) {
|
|
97
|
+
return answer(401, {
|
|
98
|
+
error: "unauthenticated",
|
|
99
|
+
message: "the token was minted for another delivery",
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
let parsed;
|
|
103
|
+
try {
|
|
104
|
+
parsed = JSON.parse(body);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
parsed = undefined;
|
|
108
|
+
}
|
|
109
|
+
if (!isEnvelope(parsed)) {
|
|
110
|
+
return answer(400, { error: "invalid_request" });
|
|
111
|
+
}
|
|
112
|
+
const pinned = options.identity.organizationId;
|
|
113
|
+
if (pinned && parsed.organization.id !== pinned) {
|
|
114
|
+
return answer(403, {
|
|
115
|
+
error: "forbidden",
|
|
116
|
+
message: `the event is for organization "${parsed.organization.id}", and this Worker serves "${pinned}"`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (!options.events) {
|
|
120
|
+
// The manifest subscribes, but the Worker passes no `events` to
|
|
121
|
+
// everyApp(): say so, and let the Gateway retry once it does.
|
|
122
|
+
return answer(404, {
|
|
123
|
+
error: "no_handler",
|
|
124
|
+
message: "everyApp() was given no events: { on }",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const handler = handlerFor(options.events.on, parsed.type);
|
|
128
|
+
if (!handler)
|
|
129
|
+
return answer(200, { ok: true, handled: false });
|
|
130
|
+
const event = {
|
|
131
|
+
...parsed,
|
|
132
|
+
delivery: {
|
|
133
|
+
id: request.headers.get(EVENT_HEADERS.delivery) ?? "",
|
|
134
|
+
attempt: Number(request.headers.get(EVENT_HEADERS.attempt) ?? "0") || 0,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
try {
|
|
138
|
+
await withOrganization(parsed.organization.id, () => handler(event, env, ctx));
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.error(error);
|
|
142
|
+
return answer(500, { error: "handler_failed" });
|
|
143
|
+
}
|
|
144
|
+
return answer(200, { ok: true, handled: true });
|
|
145
|
+
}
|
|
@@ -13,12 +13,24 @@
|
|
|
13
13
|
* `everyapp.config.ts` (the Cloudflare Vite plugin hides every file
|
|
14
14
|
* `cloudflare.config.ts` imports from the Worker in dev).
|
|
15
15
|
* It also answers the gateway's internal tools contract
|
|
16
|
-
* (`/__everyapp/tools/*`) for the app's `defineTools()` catalog
|
|
16
|
+
* (`/__everyapp/tools/*`) for the app's `defineTools()` catalog, and the
|
|
17
|
+
* event sink's deliveries (`/__everyapp/events`) for `events: { on }`.
|
|
18
|
+
*
|
|
19
|
+
* Around the handler and around each tool call it opens the request
|
|
20
|
+
* context (context.ts): `currentUser()` reads the user anywhere below, and
|
|
21
|
+
* every call back to the Gateway is attributed to the request without a
|
|
22
|
+
* `for`. A deployed Worker is pinned to its organization
|
|
23
|
+
* (`EVERY_APP_ORG_ID`), and an identity for any other is refused on both
|
|
24
|
+
* paths. The response leaves without `Set-Cookie`: the perimeter strips
|
|
25
|
+
* every `Cookie` before a request reaches the app, so a cookie the app's
|
|
26
|
+
* framework sets could never come back, and one named like the Gateway's
|
|
27
|
+
* session cookie would lock the person out of the app host.
|
|
17
28
|
*/
|
|
18
|
-
import { ConfigurationError, IdentityError, type EveryAppUser, type IdentityResult } from "../internal/index.js";
|
|
29
|
+
import { ConfigurationError, IdentityError, isAdmin, isAgentCall, type EveryAppUser, type IdentityResult, type OrgRole } from "../internal/index.js";
|
|
19
30
|
import type { ToolSet } from "./tools.js";
|
|
20
|
-
|
|
21
|
-
export
|
|
31
|
+
import { type AppEventsOptions } from "./eventsEndpoint.js";
|
|
32
|
+
export { ConfigurationError, IdentityError, isAdmin, isAgentCall };
|
|
33
|
+
export type { EveryAppUser, IdentityResult, OrgRole };
|
|
22
34
|
/**
|
|
23
35
|
* The runtime's `ExecutionContext`, which `everyApp()` passes to the handler
|
|
24
36
|
* as the Worker received it, so it goes on to Hono's `app.fetch(request,
|
|
@@ -30,7 +42,7 @@ export interface EveryAppManifestLike {
|
|
|
30
42
|
id: string;
|
|
31
43
|
[key: string]: unknown;
|
|
32
44
|
}
|
|
33
|
-
export interface EveryAppOptions {
|
|
45
|
+
export interface EveryAppOptions<TEnv = Record<string, unknown>> {
|
|
34
46
|
/** Optional expected issuer (gateway URL). Defaults to env.EVERYAPP_IDENTITY_ISSUER when set. */
|
|
35
47
|
issuer?: string;
|
|
36
48
|
/** Env var holding the public key set. Defaults to EVERYAPP_IDENTITY_PUBLIC_KEYS. */
|
|
@@ -47,6 +59,13 @@ export interface EveryAppOptions {
|
|
|
47
59
|
* and serves them to MCP clients; see `defineTools`.
|
|
48
60
|
*/
|
|
49
61
|
tools?: ToolSet;
|
|
62
|
+
/**
|
|
63
|
+
* The Gateway's events this app subscribes to (`events.subscribe` in its
|
|
64
|
+
* manifest), delivered to `on` over the service binding: one function, or
|
|
65
|
+
* one per type. The SDK verifies the Gateway's `events.deliver` token
|
|
66
|
+
* before `on` runs.
|
|
67
|
+
*/
|
|
68
|
+
events?: AppEventsOptions<TEnv>;
|
|
50
69
|
/** Override for tests. */
|
|
51
70
|
now?: number;
|
|
52
71
|
}
|
|
@@ -60,22 +79,32 @@ interface EveryAppExport<TEnv, TCtx extends ExecutionContextLike> {
|
|
|
60
79
|
}
|
|
61
80
|
/**
|
|
62
81
|
* Return the verified Every App user for this request, or null for a declared
|
|
63
|
-
* public request.
|
|
64
|
-
*
|
|
82
|
+
* public request. `request` is the inbound `Request` or just its `Headers`
|
|
83
|
+
* (a framework that hands out headers alone needs no made-up Request).
|
|
84
|
+
* Answers from the request context or the per-request cache first, then
|
|
85
|
+
* verifies the identity headers from the audience and public keys in env.
|
|
86
|
+
* Inside a handler `everyApp()` serves, `currentUser()` is the shorter way.
|
|
65
87
|
*/
|
|
66
|
-
export declare function getEveryAppUser(request: Request, env: object): Promise<EveryAppUser | null>;
|
|
88
|
+
export declare function getEveryAppUser(request: Request | Headers, env: object): Promise<EveryAppUser | null>;
|
|
67
89
|
/**
|
|
68
90
|
* Return the verified user, or throw the same 401 JSON Response shape as
|
|
69
91
|
* everyApp() when the request is public or unauthenticated.
|
|
70
92
|
*/
|
|
71
|
-
export declare function requireEveryAppUser(request: Request, env: object): Promise<EveryAppUser>;
|
|
93
|
+
export declare function requireEveryAppUser(request: Request | Headers, env: object): Promise<EveryAppUser>;
|
|
94
|
+
/**
|
|
95
|
+
* The user of the request being served (`currentUser()`), or throw the
|
|
96
|
+
* same 401 JSON Response as `requireEveryAppUser()` on a public route.
|
|
97
|
+
* Outside a request (`withOrganization()` work, a handler not under
|
|
98
|
+
* `everyApp()`) it throws `RequestContextError`, as `currentUser()` does.
|
|
99
|
+
*/
|
|
100
|
+
export declare function requireCurrentUser(): EveryAppUser;
|
|
72
101
|
export declare function hasScope(user: EveryAppUser, scope: string): boolean;
|
|
73
102
|
/** 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>;
|
|
103
|
+
export declare function everyApp<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext>(handler: EveryAppHandler<TEnv, TCtx>, options?: EveryAppOptions<TEnv>): EveryAppExport<TEnv, TCtx>;
|
|
75
104
|
/**
|
|
76
105
|
* @deprecated Drop the manifest: the app id now comes from
|
|
77
106
|
* `env.EVERYAPP_APP_ID` and the audience from `env.EVERYAPP_AUDIENCE`.
|
|
78
107
|
* When passed, it must match the app id.
|
|
79
108
|
*/
|
|
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>;
|
|
109
|
+
export declare function everyApp<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext>(handler: EveryAppHandler<TEnv, TCtx>, manifest: EveryAppManifestLike | undefined, options?: EveryAppOptions<TEnv>): EveryAppExport<TEnv, TCtx>;
|
|
81
110
|
//# 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":"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"}
|