@every-app/sdk 0.3.0-rc.3 → 0.3.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cloudflare/catalogSettings.generated.d.ts +95 -0
- package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
- package/dist/cloudflare/catalogSettings.generated.js +221 -0
- package/dist/cloudflare/index.d.ts +2 -1
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +3 -0
- package/dist/cloudflare/sentinel.d.ts +21 -4
- package/dist/cloudflare/sentinel.d.ts.map +1 -1
- package/dist/cloudflare/sentinel.js +8 -4
- package/dist/cloudflare/worker.d.ts +195 -103
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +220 -137
- 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/capabilities.d.ts +1 -1
- package/dist/internal/catalog/index.d.ts +1 -1
- package/dist/internal/catalog/inference.d.ts +1 -1
- package/dist/internal/catalog/inference.js +3 -3
- package/dist/internal/events.d.ts +1 -1
- package/dist/internal/events.d.ts.map +1 -1
- package/dist/internal/events.js +23 -1
- package/dist/internal/gatewaySettings.d.ts +7 -1
- package/dist/internal/gatewaySettings.d.ts.map +1 -1
- package/dist/internal/gatewaySettings.js +12 -1
- package/dist/internal/identity.d.ts +29 -3
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +37 -9
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/internal/members.d.ts +3 -2
- package/dist/internal/members.d.ts.map +1 -1
- package/dist/internal/protocol.d.ts +25 -1
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +21 -1
- package/dist/manifest.d.ts +205 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +30 -0
- package/dist/server/ai.d.ts +21 -0
- package/dist/server/ai.d.ts.map +1 -1
- package/dist/server/ai.js +37 -8
- package/dist/server/aiBinding.d.ts +68 -0
- package/dist/server/aiBinding.d.ts.map +1 -0
- package/dist/server/aiBinding.js +294 -0
- package/dist/server/attribution.d.ts +9 -5
- package/dist/server/attribution.d.ts.map +1 -1
- package/dist/server/attribution.js +12 -4
- package/dist/server/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 +4 -4
- package/dist/server/env.d.ts +41 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +1 -0
- package/dist/server/everyApp.d.ts +27 -7
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +106 -5
- package/dist/server/fromMcpTools.d.ts +89 -0
- package/dist/server/fromMcpTools.d.ts.map +1 -0
- package/dist/server/fromMcpTools.js +192 -0
- package/dist/server/gatewayFetch.d.ts +24 -18
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +9 -9
- 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 +11 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +9 -2
- package/dist/server/integrationFetch.d.ts +28 -7
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +24 -28
- package/dist/server/listMembers.d.ts +1 -1
- package/dist/server/listMembers.d.ts.map +1 -1
- package/dist/server/listMembers.js +5 -8
- package/dist/server/sendEmail.d.ts +1 -1
- package/dist/server/sendEmail.d.ts.map +1 -1
- package/dist/server/sendEmail.js +4 -4
- package/dist/server/toolsEndpoint.d.ts.map +1 -1
- package/dist/server/toolsEndpoint.js +11 -5
- package/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 +25 -4
|
@@ -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 "./integrationFetch.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;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,
|
|
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,cAAc,EACnB,KAAK,EACL,IAAI,GACL,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAoBxC"}
|
package/dist/server/emit.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
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,
|
|
12
|
+
import { applyAttribution, attributionFor, } from "./attribution.js";
|
|
13
13
|
import { BINDING_ORIGIN } from "./gatewayFetch.js";
|
|
14
14
|
import { GatewayRefusalError, gatewayRefusal } from "./integrationFetch.js";
|
|
15
15
|
/**
|
|
@@ -36,8 +36,8 @@ 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
42
|
const binding = values["EVERY_APP_GATEWAY"];
|
|
43
43
|
if (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,41 @@
|
|
|
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
|
+
}
|
|
41
|
+
//# 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;CACjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -14,11 +14,21 @@
|
|
|
14
14
|
* `cloudflare.config.ts` imports from the Worker in dev).
|
|
15
15
|
* It also answers the gateway's internal tools contract
|
|
16
16
|
* (`/__everyapp/tools/*`) for the app's `defineTools()` catalog.
|
|
17
|
+
*
|
|
18
|
+
* Around the handler and around each tool call it opens the request
|
|
19
|
+
* context (context.ts): `currentUser()` reads the user anywhere below, and
|
|
20
|
+
* every call back to the Gateway is attributed to the request without a
|
|
21
|
+
* `for`. A deployed Worker is pinned to its organization
|
|
22
|
+
* (`EVERY_APP_ORG_ID`), and an identity for any other is refused on both
|
|
23
|
+
* paths. The response leaves without `Set-Cookie`: the perimeter strips
|
|
24
|
+
* every `Cookie` before a request reaches the app, so a cookie the app's
|
|
25
|
+
* framework sets could never come back, and one named like the Gateway's
|
|
26
|
+
* session cookie would lock the person out of the app host.
|
|
17
27
|
*/
|
|
18
|
-
import { ConfigurationError, IdentityError, type EveryAppUser, type IdentityResult } from "../internal/index.js";
|
|
28
|
+
import { ConfigurationError, IdentityError, isAdmin, type EveryAppUser, type IdentityResult, type OrgRole } from "../internal/index.js";
|
|
19
29
|
import type { ToolSet } from "./tools.js";
|
|
20
|
-
export { ConfigurationError, IdentityError };
|
|
21
|
-
export type { EveryAppUser, IdentityResult };
|
|
30
|
+
export { ConfigurationError, IdentityError, isAdmin };
|
|
31
|
+
export type { EveryAppUser, IdentityResult, OrgRole };
|
|
22
32
|
/**
|
|
23
33
|
* The runtime's `ExecutionContext`, which `everyApp()` passes to the handler
|
|
24
34
|
* as the Worker received it, so it goes on to Hono's `app.fetch(request,
|
|
@@ -60,15 +70,25 @@ interface EveryAppExport<TEnv, TCtx extends ExecutionContextLike> {
|
|
|
60
70
|
}
|
|
61
71
|
/**
|
|
62
72
|
* Return the verified Every App user for this request, or null for a declared
|
|
63
|
-
* public request.
|
|
64
|
-
*
|
|
73
|
+
* public request. `request` is the inbound `Request` or just its `Headers`
|
|
74
|
+
* (a framework that hands out headers alone needs no made-up Request).
|
|
75
|
+
* Answers from the request context or the per-request cache first, then
|
|
76
|
+
* verifies the identity headers from the audience and public keys in env.
|
|
77
|
+
* Inside a handler `everyApp()` serves, `currentUser()` is the shorter way.
|
|
65
78
|
*/
|
|
66
|
-
export declare function getEveryAppUser(request: Request, env: object): Promise<EveryAppUser | null>;
|
|
79
|
+
export declare function getEveryAppUser(request: Request | Headers, env: object): Promise<EveryAppUser | null>;
|
|
67
80
|
/**
|
|
68
81
|
* Return the verified user, or throw the same 401 JSON Response shape as
|
|
69
82
|
* everyApp() when the request is public or unauthenticated.
|
|
70
83
|
*/
|
|
71
|
-
export declare function requireEveryAppUser(request: Request, env: object): Promise<EveryAppUser>;
|
|
84
|
+
export declare function requireEveryAppUser(request: Request | Headers, env: object): Promise<EveryAppUser>;
|
|
85
|
+
/**
|
|
86
|
+
* The user of the request being served (`currentUser()`), or throw the
|
|
87
|
+
* same 401 JSON Response as `requireEveryAppUser()` on a public route.
|
|
88
|
+
* Outside a request (`withOrganization()` work, a handler not under
|
|
89
|
+
* `everyApp()`) it throws `RequestContextError`, as `currentUser()` does.
|
|
90
|
+
*/
|
|
91
|
+
export declare function requireCurrentUser(): EveryAppUser;
|
|
72
92
|
export declare function hasScope(user: EveryAppUser, scope: string): boolean;
|
|
73
93
|
/** Wrap a Worker fetch handler with Every App identity verification. */
|
|
74
94
|
export declare function everyApp<TEnv = Record<string, unknown>, TCtx extends ExecutionContextLike = ExecutionContext>(handler: EveryAppHandler<TEnv, TCtx>, options?: EveryAppOptions): EveryAppExport<TEnv, TCtx>;
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAGL,kBAAkB,EAElB,aAAa,EAMb,OAAO,EACP,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,OAAO,EAEb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;AAEtD;;;;;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;AAuKD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,GAAG,OAAO,EAC1B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW9B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,GAAG,OAAO,EAC1B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,CAAC,CAevB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAMjD;AA0BD,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
|
@@ -14,10 +14,21 @@
|
|
|
14
14
|
* `cloudflare.config.ts` imports from the Worker in dev).
|
|
15
15
|
* It also answers the gateway's internal tools contract
|
|
16
16
|
* (`/__everyapp/tools/*`) for the app's `defineTools()` catalog.
|
|
17
|
+
*
|
|
18
|
+
* Around the handler and around each tool call it opens the request
|
|
19
|
+
* context (context.ts): `currentUser()` reads the user anywhere below, and
|
|
20
|
+
* every call back to the Gateway is attributed to the request without a
|
|
21
|
+
* `for`. A deployed Worker is pinned to its organization
|
|
22
|
+
* (`EVERY_APP_ORG_ID`), and an identity for any other is refused on both
|
|
23
|
+
* paths. The response leaves without `Set-Cookie`: the perimeter strips
|
|
24
|
+
* every `Cookie` before a request reaches the app, so a cookie the app's
|
|
25
|
+
* framework sets could never come back, and one named like the Gateway's
|
|
26
|
+
* session cookie would lock the person out of the app host.
|
|
17
27
|
*/
|
|
18
|
-
import { APP_ID_ENV, AUDIENCE_ENV, ConfigurationError, DEV_ENV, IdentityError, ISSUER_ENV, PUBLIC_KEYS_ENV, getIdentityFromRequest, } from "../internal/index.js";
|
|
28
|
+
import { APP_ID_ENV, AUDIENCE_ENV, ConfigurationError, DEV_ENV, IdentityError, IDENTITY_HEADER, ISSUER_ENV, ORG_ID_ENV, PUBLIC_KEYS_ENV, getIdentityFromRequest, isAdmin, } from "../internal/index.js";
|
|
29
|
+
import { currentUser, serveRequest } from "./context.js";
|
|
19
30
|
import { handleToolsRequest } from "./toolsEndpoint.js";
|
|
20
|
-
export { ConfigurationError, IdentityError };
|
|
31
|
+
export { ConfigurationError, IdentityError, isAdmin };
|
|
21
32
|
const requestIdentities = new WeakMap();
|
|
22
33
|
function envValue(env, key) {
|
|
23
34
|
if (!env || typeof env !== "object")
|
|
@@ -68,6 +79,17 @@ function audienceFor(env, config) {
|
|
|
68
79
|
return appId;
|
|
69
80
|
throw new ConfigurationError(`${AUDIENCE_ENV} is not set — the app's cloudflare.config.ts must declare it (everyAppWorker() does at deploy).`);
|
|
70
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* The organization a deployed Worker serves ({@link ORG_ID_ENV}), which an
|
|
84
|
+
* identity must name. Under the dev opt-in there is none to enforce: the
|
|
85
|
+
* stub gateway's one organization is the only one, and `everyapp dev
|
|
86
|
+
* --mode mirror` signs real organizations in.
|
|
87
|
+
*/
|
|
88
|
+
function pinnedOrganization(env, config) {
|
|
89
|
+
if (devIdentitiesAllowed(env, config))
|
|
90
|
+
return undefined;
|
|
91
|
+
return envValue(env, ORG_ID_ENV);
|
|
92
|
+
}
|
|
71
93
|
function unauthorized(message) {
|
|
72
94
|
return Response.json({ error: "unauthenticated", message }, { status: 401 });
|
|
73
95
|
}
|
|
@@ -77,6 +99,7 @@ function misconfigured(message) {
|
|
|
77
99
|
function identityOptions(env, config, audience) {
|
|
78
100
|
return {
|
|
79
101
|
audience,
|
|
102
|
+
organizationId: pinnedOrganization(env, config),
|
|
80
103
|
issuer: config.issuer ?? envValue(env, ISSUER_ENV),
|
|
81
104
|
publicKeys: config.publicKeys,
|
|
82
105
|
env: env,
|
|
@@ -91,15 +114,54 @@ async function resolveIdentity(request, env, config) {
|
|
|
91
114
|
function rememberIdentity(request, identity) {
|
|
92
115
|
requestIdentities.set(request, identity);
|
|
93
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* The user the request context already verified, when `request` carries
|
|
119
|
+
* the same identity token: a framework that rebuilds the request (TanStack
|
|
120
|
+
* Start's `getRequest()`, a Hono context) still gets the one verification.
|
|
121
|
+
*/
|
|
122
|
+
function contextUserFor(request) {
|
|
123
|
+
const headers = "headers" in request ? request.headers : request;
|
|
124
|
+
const token = headers.get(IDENTITY_HEADER);
|
|
125
|
+
if (!token)
|
|
126
|
+
return null;
|
|
127
|
+
const scoped = servedRequestToken();
|
|
128
|
+
return scoped && scoped.token === token ? scoped.user : null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The served request's token and user, or null outside a request. Reads
|
|
132
|
+
* the context without throwing (currentUser() throws outside one).
|
|
133
|
+
*/
|
|
134
|
+
function servedRequestToken() {
|
|
135
|
+
let user;
|
|
136
|
+
try {
|
|
137
|
+
user = currentUser();
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
if (!user)
|
|
143
|
+
return null;
|
|
144
|
+
const served = servedRequests.get(user);
|
|
145
|
+
return served ? { token: served, user } : null;
|
|
146
|
+
}
|
|
147
|
+
// The identity token of each request everyApp() serves, by its user, so a
|
|
148
|
+
// second read of the same token answers from the context.
|
|
149
|
+
const servedRequests = new WeakMap();
|
|
94
150
|
/**
|
|
95
151
|
* Return the verified Every App user for this request, or null for a declared
|
|
96
|
-
* public request.
|
|
97
|
-
*
|
|
152
|
+
* public request. `request` is the inbound `Request` or just its `Headers`
|
|
153
|
+
* (a framework that hands out headers alone needs no made-up Request).
|
|
154
|
+
* Answers from the request context or the per-request cache first, then
|
|
155
|
+
* verifies the identity headers from the audience and public keys in env.
|
|
156
|
+
* Inside a handler `everyApp()` serves, `currentUser()` is the shorter way.
|
|
98
157
|
*/
|
|
99
158
|
export async function getEveryAppUser(request, env) {
|
|
100
159
|
const cached = requestIdentities.get(request);
|
|
101
160
|
if (cached)
|
|
102
161
|
return cached.user;
|
|
162
|
+
const fromContext = contextUserFor(request);
|
|
163
|
+
if (fromContext)
|
|
164
|
+
return fromContext;
|
|
103
165
|
const identity = await resolveIdentity(request, env, {
|
|
104
166
|
keysEnvVar: PUBLIC_KEYS_ENV,
|
|
105
167
|
});
|
|
@@ -125,6 +187,40 @@ export async function requireEveryAppUser(request, env) {
|
|
|
125
187
|
throw error;
|
|
126
188
|
}
|
|
127
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* The user of the request being served (`currentUser()`), or throw the
|
|
192
|
+
* same 401 JSON Response as `requireEveryAppUser()` on a public route.
|
|
193
|
+
* Outside a request (`withOrganization()` work, a handler not under
|
|
194
|
+
* `everyApp()`) it throws `RequestContextError`, as `currentUser()` does.
|
|
195
|
+
*/
|
|
196
|
+
export function requireCurrentUser() {
|
|
197
|
+
const user = currentUser();
|
|
198
|
+
if (!user) {
|
|
199
|
+
throw unauthorized("this request does not have an authenticated user");
|
|
200
|
+
}
|
|
201
|
+
return user;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* `response` without `Set-Cookie`: the perimeter strips every `Cookie`
|
|
205
|
+
* before a request reaches the app, so no cookie the app sets ever comes
|
|
206
|
+
* back, and one named like the Gateway's session cookie locks the person
|
|
207
|
+
* out of the app host (the perimeter refuses a session cookie sent twice).
|
|
208
|
+
* A WebSocket handshake (101) passes as it is: it can't be rebuilt from
|
|
209
|
+
* its body, and the perimeter drops its cookies' `Domain`.
|
|
210
|
+
*/
|
|
211
|
+
function withoutCookies(response) {
|
|
212
|
+
if (response.status === 101 || !response.headers.has("set-cookie")) {
|
|
213
|
+
return response;
|
|
214
|
+
}
|
|
215
|
+
console.warn("[everyapp] Dropped a Set-Cookie header: the Gateway never sends an app's cookies back to it.");
|
|
216
|
+
const headers = new Headers(response.headers);
|
|
217
|
+
headers.delete("set-cookie");
|
|
218
|
+
return new Response(response.body, {
|
|
219
|
+
status: response.status,
|
|
220
|
+
statusText: response.statusText,
|
|
221
|
+
headers,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
128
224
|
export function hasScope(user, scope) {
|
|
129
225
|
return user.scopes.includes("*") || user.scopes.includes(scope);
|
|
130
226
|
}
|
|
@@ -179,7 +275,12 @@ export function everyApp(handler, manifestOrOptions, legacyOptions = {}) {
|
|
|
179
275
|
return unauthorized(err.message);
|
|
180
276
|
throw err;
|
|
181
277
|
}
|
|
182
|
-
|
|
278
|
+
const { user, expiresAt } = identity;
|
|
279
|
+
if (user) {
|
|
280
|
+
servedRequests.set(user, request.headers.get(IDENTITY_HEADER) ?? "");
|
|
281
|
+
}
|
|
282
|
+
const response = await serveRequest({ request, user, expiresAt }, () => handler(request, env, ctx, user));
|
|
283
|
+
return withoutCookies(response);
|
|
183
284
|
},
|
|
184
285
|
};
|
|
185
286
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fromMcpTools()` — an app's existing MCP tools as `defineTools()` entries.
|
|
3
|
+
*
|
|
4
|
+
* const tools: McpToolLike[] = [];
|
|
5
|
+
* registerMyTools((name, config, handler) =>
|
|
6
|
+
* tools.push({ name, ...config, handler }),
|
|
7
|
+
* );
|
|
8
|
+
* export default everyApp(handler, {
|
|
9
|
+
* tools: defineTools(fromMcpTools(tools), { instructions }),
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* Takes the shape `McpServer.registerTool(name, config, handler)` is called
|
|
13
|
+
* with (or what a low-level server's `tools/list` returns, plus a handler),
|
|
14
|
+
* structurally: the SDK takes no dependency on `@modelcontextprotocol/sdk`,
|
|
15
|
+
* and a live `McpServer` keeps its registry private, so the app hands over
|
|
16
|
+
* the list it registers from.
|
|
17
|
+
*/
|
|
18
|
+
import { type ToolRisk } from "../internal/index.js";
|
|
19
|
+
import { type StandardSchemaWithJSON, type ToolContext, type ToolDefinition, type ToolSchema } from "./tools.js";
|
|
20
|
+
/** MCP tool annotations (all hints); only these are read. */
|
|
21
|
+
export interface McpToolAnnotationsLike {
|
|
22
|
+
title?: string;
|
|
23
|
+
readOnlyHint?: boolean;
|
|
24
|
+
destructiveHint?: boolean;
|
|
25
|
+
idempotentHint?: boolean;
|
|
26
|
+
openWorldHint?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** An MCP `CallToolResult`, structurally. */
|
|
29
|
+
export interface McpToolResultLike {
|
|
30
|
+
content?: ReadonlyArray<{
|
|
31
|
+
readonly type: string;
|
|
32
|
+
}>;
|
|
33
|
+
structuredContent?: unknown;
|
|
34
|
+
isError?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A tool schema as MCP servers write one: a {@link ToolSchema} (a full zod
|
|
38
|
+
* object, `{ jsonSchema, validate }`), a raw shape of Standard Schemas
|
|
39
|
+
* (`{ query: z.string() }`, what `McpServer.registerTool` takes), or a plain
|
|
40
|
+
* JSON Schema object (a low-level server's `tools/list`), which is described
|
|
41
|
+
* but not validated: the handler checks its own arguments, as it did before.
|
|
42
|
+
*/
|
|
43
|
+
export type McpToolSchemaLike = ToolSchema | Readonly<Record<string, StandardSchemaWithJSON>> | Readonly<Record<string, unknown>>;
|
|
44
|
+
/** One MCP tool: `registerTool`'s name, config and handler, flattened. */
|
|
45
|
+
export interface McpToolLike<TExtra = ToolContext> {
|
|
46
|
+
name: string;
|
|
47
|
+
title?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
/** Omitted: the tool takes no arguments. */
|
|
50
|
+
inputSchema?: McpToolSchemaLike;
|
|
51
|
+
outputSchema?: McpToolSchemaLike;
|
|
52
|
+
annotations?: McpToolAnnotationsLike;
|
|
53
|
+
/**
|
|
54
|
+
* Called with the validated arguments and the value of
|
|
55
|
+
* {@link FromMcpToolsOptions.context} (the call's {@link ToolContext} by
|
|
56
|
+
* default). Return a `CallToolResult`; throw {@link ToolError} for a message
|
|
57
|
+
* the model may read.
|
|
58
|
+
*/
|
|
59
|
+
handler: (args: never, extra: TExtra) => McpToolResultLike | Promise<McpToolResultLike>;
|
|
60
|
+
}
|
|
61
|
+
export interface FromMcpToolsOptions<TExtra = ToolContext> {
|
|
62
|
+
/**
|
|
63
|
+
* What each handler gets as its second argument, built per call from the
|
|
64
|
+
* verified caller (`user`, `env`, `request`, `callId`). Default: the
|
|
65
|
+
* {@link ToolContext} itself.
|
|
66
|
+
*/
|
|
67
|
+
context?: (context: ToolContext) => TExtra | Promise<TExtra>;
|
|
68
|
+
/**
|
|
69
|
+
* A tool's risk, overriding the default for the tools it returns a risk
|
|
70
|
+
* for. Default: `readOnlyHint: true` is `read`, `destructiveHint: true`
|
|
71
|
+
* is `destructive`, anything else `write`.
|
|
72
|
+
*/
|
|
73
|
+
risk?: (tool: McpToolLike<TExtra>) => ToolRisk | undefined;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Adapt MCP tools into `defineTools()` entries, keyed by tool name, to spread
|
|
77
|
+
* beside the app's own: `defineTools({ ...fromMcpTools(list), my_tool })`.
|
|
78
|
+
*
|
|
79
|
+
* - `title`, `description` (the name when absent), `idempotentHint` and
|
|
80
|
+
* `openWorldHint` carry over; risk as {@link FromMcpToolsOptions.risk}.
|
|
81
|
+
* - A result's text blocks, joined by a blank line, are what the model
|
|
82
|
+
* reads; `structuredContent` is sent as structured content (checked
|
|
83
|
+
* against `outputSchema` when there is one). Other blocks are dropped.
|
|
84
|
+
* - `isError: true` becomes a {@link ToolError} with the result's text.
|
|
85
|
+
*
|
|
86
|
+
* Names must already be lowercase snake_case; `defineTools()` checks them.
|
|
87
|
+
*/
|
|
88
|
+
export declare function fromMcpTools<TExtra = ToolContext>(tools: Iterable<McpToolLike<TExtra>>, options?: FromMcpToolsOptions<TExtra>): Record<string, ToolDefinition>;
|
|
89
|
+
//# sourceMappingURL=fromMcpTools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fromMcpTools.d.ts","sourceRoot":"","sources":["../../src/server/fromMcpTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAIpB,6DAA6D;AAC7D,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,GAChD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,WAAW,WAAW,CAAC,MAAM,GAAG,WAAW;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC;;;;;OAKG;IACH,OAAO,EAAE,CACP,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,MAAM,KACV,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,mBAAmB,CAAC,MAAM,GAAG,WAAW;IACvD;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK,QAAQ,GAAG,SAAS,CAAC;CAC5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,MAAM,GAAG,WAAW,EAC/C,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EACpC,OAAO,GAAE,mBAAmB,CAAC,MAAM,CAAM,GACxC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA+ChC"}
|