@every-app/sdk 0.1.13 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/internal/identity.d.ts +73 -0
- package/dist/internal/identity.d.ts.map +1 -0
- package/dist/internal/identity.js +192 -0
- package/dist/internal/index.d.ts +3 -0
- package/dist/internal/index.d.ts.map +1 -0
- package/dist/internal/index.js +2 -0
- package/dist/internal/protocol.d.ts +111 -0
- package/dist/internal/protocol.d.ts.map +1 -0
- package/dist/internal/protocol.js +139 -0
- package/dist/server/everyApp.d.ts +55 -0
- package/dist/server/everyApp.d.ts.map +1 -0
- package/dist/server/everyApp.js +121 -0
- package/dist/server/gatewayFetch.d.ts +21 -0
- package/dist/server/gatewayFetch.d.ts.map +1 -0
- package/dist/server/gatewayFetch.js +70 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +8 -0
- package/dist/server/mcp.d.ts +66 -0
- package/dist/server/mcp.d.ts.map +1 -0
- package/dist/server/mcp.js +147 -0
- package/package.json +21 -44
- package/dist/cloudflare/getLocalD1Url.d.ts +0 -2
- package/dist/cloudflare/getLocalD1Url.d.ts.map +0 -1
- package/dist/cloudflare/getLocalD1Url.js +0 -40
- package/dist/cloudflare/index.d.ts +0 -2
- package/dist/cloudflare/index.d.ts.map +0 -1
- package/dist/cloudflare/index.js +0 -1
- package/dist/cloudflare/lazyInit.d.ts +0 -22
- package/dist/cloudflare/lazyInit.d.ts.map +0 -1
- package/dist/cloudflare/lazyInit.js +0 -65
- package/dist/cloudflare/server/gateway.d.ts +0 -29
- package/dist/cloudflare/server/gateway.d.ts.map +0 -1
- package/dist/cloudflare/server/gateway.js +0 -69
- package/dist/cloudflare/server/index.d.ts +0 -3
- package/dist/cloudflare/server/index.d.ts.map +0 -1
- package/dist/cloudflare/server/index.js +0 -2
- package/dist/core/authenticatedFetch.d.ts +0 -9
- package/dist/core/authenticatedFetch.d.ts.map +0 -1
- package/dist/core/authenticatedFetch.js +0 -31
- package/dist/core/index.d.ts +0 -4
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -2
- package/dist/core/sessionManager.d.ts +0 -58
- package/dist/core/sessionManager.d.ts.map +0 -1
- package/dist/core/sessionManager.js +0 -357
- package/dist/shared/bypassGatewayLocalOnly.d.ts +0 -14
- package/dist/shared/bypassGatewayLocalOnly.d.ts.map +0 -1
- package/dist/shared/bypassGatewayLocalOnly.js +0 -41
- package/dist/shared/parseMessagePayload.d.ts +0 -3
- package/dist/shared/parseMessagePayload.d.ts.map +0 -1
- package/dist/shared/parseMessagePayload.js +0 -18
- package/dist/tanstack/EmbeddedAppProvider.d.ts +0 -30
- package/dist/tanstack/EmbeddedAppProvider.d.ts.map +0 -1
- package/dist/tanstack/EmbeddedAppProvider.js +0 -57
- package/dist/tanstack/GatewayRequiredError.d.ts +0 -20
- package/dist/tanstack/GatewayRequiredError.d.ts.map +0 -1
- package/dist/tanstack/GatewayRequiredError.js +0 -91
- package/dist/tanstack/_internal/useEveryAppSession.d.ts +0 -18
- package/dist/tanstack/_internal/useEveryAppSession.d.ts.map +0 -1
- package/dist/tanstack/_internal/useEveryAppSession.js +0 -47
- package/dist/tanstack/index.d.ts +0 -4
- package/dist/tanstack/index.d.ts.map +0 -1
- package/dist/tanstack/index.js +0 -3
- package/dist/tanstack/server/authConfig.d.ts +0 -3
- package/dist/tanstack/server/authConfig.d.ts.map +0 -1
- package/dist/tanstack/server/authConfig.js +0 -13
- package/dist/tanstack/server/authenticateRequest.d.ts +0 -29
- package/dist/tanstack/server/authenticateRequest.d.ts.map +0 -1
- package/dist/tanstack/server/authenticateRequest.js +0 -82
- package/dist/tanstack/server/index.d.ts +0 -4
- package/dist/tanstack/server/index.d.ts.map +0 -1
- package/dist/tanstack/server/index.js +0 -2
- package/dist/tanstack/server/types.d.ts +0 -5
- package/dist/tanstack/server/types.d.ts.map +0 -1
- package/dist/tanstack/server/types.js +0 -1
- package/dist/tanstack/useEveryAppRouter.d.ts +0 -7
- package/dist/tanstack/useEveryAppRouter.d.ts.map +0 -1
- package/dist/tanstack/useEveryAppRouter.js +0 -66
- package/dist/tanstack/useSessionTokenClientMiddleware.d.ts +0 -2
- package/dist/tanstack/useSessionTokenClientMiddleware.d.ts.map +0 -1
- package/dist/tanstack/useSessionTokenClientMiddleware.js +0 -29
- package/src/cloudflare/getLocalD1Url.ts +0 -64
- package/src/cloudflare/index.ts +0 -1
- package/src/cloudflare/lazyInit.ts +0 -67
- package/src/cloudflare/server/gateway.test.ts +0 -262
- package/src/cloudflare/server/gateway.ts +0 -114
- package/src/cloudflare/server/index.ts +0 -2
- package/src/core/authenticatedFetch.ts +0 -54
- package/src/core/index.ts +0 -12
- package/src/core/sessionManager.test.ts +0 -939
- package/src/core/sessionManager.ts +0 -492
- package/src/env.d.ts +0 -13
- package/src/shared/bypassGatewayLocalOnly.ts +0 -55
- package/src/shared/parseMessagePayload.ts +0 -22
- package/src/tanstack/EmbeddedAppProvider.tsx +0 -96
- package/src/tanstack/GatewayRequiredError.tsx +0 -150
- package/src/tanstack/_internal/useEveryAppSession.test.ts +0 -40
- package/src/tanstack/_internal/useEveryAppSession.tsx +0 -74
- package/src/tanstack/index.ts +0 -3
- package/src/tanstack/server/authConfig.ts +0 -19
- package/src/tanstack/server/authenticateRequest.test.ts +0 -482
- package/src/tanstack/server/authenticateRequest.ts +0 -143
- package/src/tanstack/server/index.ts +0 -3
- package/src/tanstack/server/types.ts +0 -4
- package/src/tanstack/useEveryAppRouter.tsx +0 -83
- package/src/tanstack/useSessionTokenClientMiddleware.ts +0 -43
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, type EveryAppUser, type IdentityChannel } from "./protocol.js";
|
|
2
|
+
export { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, type EveryAppUser, type IdentityChannel, };
|
|
3
|
+
export declare class IdentityError extends Error {
|
|
4
|
+
readonly status = 401;
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class ConfigurationError extends Error {
|
|
8
|
+
readonly status = 500;
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse the public key set from an env var value. Accepts a JSON array of PEM
|
|
13
|
+
* strings, or a single PEM string. Returns at least one key or throws.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parsePublicKeys(envValue: string | undefined | null): string[];
|
|
16
|
+
export interface VerifyOptions {
|
|
17
|
+
/** SPKI PEM public keys (current + next). */
|
|
18
|
+
publicKeys: string[];
|
|
19
|
+
/** Expected `aud` — this app's id. */
|
|
20
|
+
audience: string;
|
|
21
|
+
/** Expected issuer (the gateway URL). Required for user identities. */
|
|
22
|
+
issuer?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Accept the dev identity kid ({@link IDENTITY_DEV_KEY_ID}). Set ONLY in
|
|
25
|
+
* local dev (driven by the {@link DEV_ENV} worker env var). Never true in
|
|
26
|
+
* production.
|
|
27
|
+
*/
|
|
28
|
+
allowDevIdentities?: boolean;
|
|
29
|
+
/** Override for tests. */
|
|
30
|
+
now?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Verify an identity JWT fail-closed. Throws {@link IdentityError} on any
|
|
34
|
+
* problem (bad alg/kid, `none`, wrong key, expired, wrong audience, missing
|
|
35
|
+
* claims).
|
|
36
|
+
*/
|
|
37
|
+
export declare function verifyIdentityJwt(token: string, options: VerifyOptions): Promise<EveryAppUser>;
|
|
38
|
+
/**
|
|
39
|
+
* Verify a public-route marker (the value of `x-everyapp-public`). The marker
|
|
40
|
+
* is a gateway-signed, app-scoped JWT with `pub: true` and `typ: "public"` —
|
|
41
|
+
* a bare header is NEVER a trust source, so a re-exposed app worker cannot be
|
|
42
|
+
* flipped into public mode by anyone who can type a header. Throws on any
|
|
43
|
+
* problem.
|
|
44
|
+
*/
|
|
45
|
+
export declare function verifyPublicMarkerJwt(token: string, options: VerifyOptions): Promise<void>;
|
|
46
|
+
export interface IdentityResult {
|
|
47
|
+
/** The verified user, or null for a declared public route. */
|
|
48
|
+
user: EveryAppUser | null;
|
|
49
|
+
/** True when the gateway marked this request as a public route. */
|
|
50
|
+
isPublic: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface RequestIdentityOptions {
|
|
53
|
+
audience: string;
|
|
54
|
+
/** Provide keys directly, or let {@link getIdentityFromRequest} read env. */
|
|
55
|
+
publicKeys?: string[];
|
|
56
|
+
/** Env bag to read {@link PUBLIC_KEYS_ENV} / {@link DEV_ENV} from. */
|
|
57
|
+
env?: Record<string, unknown>;
|
|
58
|
+
keysEnvVar?: string;
|
|
59
|
+
issuer?: string;
|
|
60
|
+
/** Force dev-kid acceptance. Defaults to reading {@link DEV_ENV} from env. */
|
|
61
|
+
allowDevIdentities?: boolean;
|
|
62
|
+
now?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve identity for an incoming proxied request. Public routes carry a
|
|
66
|
+
* gateway-SIGNED marker in `x-everyapp-public` and resolve to
|
|
67
|
+
* `{ user: null, isPublic: true }` only after the marker verifies. Everything
|
|
68
|
+
* else requires a valid identity JWT. Throws {@link IdentityError} on any
|
|
69
|
+
* problem — including a bare/forged public header — so a re-exposed worker
|
|
70
|
+
* fails closed.
|
|
71
|
+
*/
|
|
72
|
+
export declare function getIdentityFromRequest(request: Request, options: RequestIdentityOptions): Promise<IdentityResult>;
|
|
73
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/internal/identity.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,UAAU,EACV,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,UAAU,EACV,aAAa,EACb,eAAe,EACf,iBAAiB,EAIjB,KAAK,YAAY,EACjB,KAAK,eAAe,EAErB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,UAAU,EACV,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,UAAU,EACV,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,CAAC;AAEF,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,OAAO;gBACV,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,OAAO;gBACV,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CA8B7E;AAYD,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAUvB;AAmED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,cAAc,CAAC,CAqCzB"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every App identity JWT verification (the app side of the trust boundary).
|
|
3
|
+
*
|
|
4
|
+
* The gateway injects a short-lived RS256 JWT as `x-everyapp-identity`. This
|
|
5
|
+
* module verifies it **fail-closed**: the algorithm and key id are pinned,
|
|
6
|
+
* `none` is rejected, the audience must equal this app, and the verification
|
|
7
|
+
* key set arrives from an env var (current + next public keys) — never a
|
|
8
|
+
* runtime JWKS fetch. A bare header is never a trust source; only a token that
|
|
9
|
+
* survives verification produces a user.
|
|
10
|
+
*/
|
|
11
|
+
import { importSPKI, jwtVerify, decodeProtectedHeader, } from "jose";
|
|
12
|
+
import { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, assertPublicMarkerClaims, identityClaimsToEveryAppUser, ProtocolClaimsError, } from "./protocol.js";
|
|
13
|
+
export { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, };
|
|
14
|
+
export class IdentityError extends Error {
|
|
15
|
+
status = 401;
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "IdentityError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class ConfigurationError extends Error {
|
|
22
|
+
status = 500;
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "ConfigurationError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse the public key set from an env var value. Accepts a JSON array of PEM
|
|
30
|
+
* strings, or a single PEM string. Returns at least one key or throws.
|
|
31
|
+
*/
|
|
32
|
+
export function parsePublicKeys(envValue) {
|
|
33
|
+
if (!envValue || envValue.trim().length === 0) {
|
|
34
|
+
throw new ConfigurationError(`${PUBLIC_KEYS_ENV} is not set — the gateway must inject the identity public key set.`);
|
|
35
|
+
}
|
|
36
|
+
const trimmed = envValue.trim();
|
|
37
|
+
let keys;
|
|
38
|
+
if (trimmed.startsWith("[")) {
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(trimmed);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw new ConfigurationError(`${PUBLIC_KEYS_ENV} must be a JSON array of PEM strings: ${error.message}`);
|
|
45
|
+
}
|
|
46
|
+
if (!Array.isArray(parsed) || parsed.some((k) => typeof k !== "string")) {
|
|
47
|
+
throw new ConfigurationError(`${PUBLIC_KEYS_ENV} must be a JSON array of PEM strings.`);
|
|
48
|
+
}
|
|
49
|
+
keys = parsed.map((k) => k.replace(/\\n/g, "\n"));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
keys = [trimmed.replace(/\\n/g, "\n")];
|
|
53
|
+
}
|
|
54
|
+
if (keys.length === 0) {
|
|
55
|
+
throw new ConfigurationError(`${PUBLIC_KEYS_ENV} contained no keys.`);
|
|
56
|
+
}
|
|
57
|
+
return keys;
|
|
58
|
+
}
|
|
59
|
+
const keyCache = new Map();
|
|
60
|
+
function importKey(pem) {
|
|
61
|
+
let cached = keyCache.get(pem);
|
|
62
|
+
if (!cached) {
|
|
63
|
+
cached = importSPKI(pem, IDENTITY_ALG);
|
|
64
|
+
keyCache.set(pem, cached);
|
|
65
|
+
}
|
|
66
|
+
return cached;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Verify an identity JWT fail-closed. Throws {@link IdentityError} on any
|
|
70
|
+
* problem (bad alg/kid, `none`, wrong key, expired, wrong audience, missing
|
|
71
|
+
* claims).
|
|
72
|
+
*/
|
|
73
|
+
export async function verifyIdentityJwt(token, options) {
|
|
74
|
+
const payload = await verifyPinnedJwt(token, options, "user");
|
|
75
|
+
try {
|
|
76
|
+
return identityClaimsToEveryAppUser(payload);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof ProtocolClaimsError) {
|
|
80
|
+
throw new IdentityError(error.message);
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The shared fail-closed verification core: pinned alg/kid, `none` rejected,
|
|
87
|
+
* `aud` checked, multi-key (current + next). Returns the verified payload.
|
|
88
|
+
*/
|
|
89
|
+
async function verifyPinnedJwt(token, options, expectedTyp) {
|
|
90
|
+
if (!token)
|
|
91
|
+
throw new IdentityError("no identity token");
|
|
92
|
+
// Pin the header BEFORE attempting any signature work. This is what defeats
|
|
93
|
+
// `alg: none` and algorithm-confusion (e.g. an HS256 token forged with the
|
|
94
|
+
// public key as the HMAC secret).
|
|
95
|
+
let header;
|
|
96
|
+
try {
|
|
97
|
+
header = decodeProtectedHeader(token);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
throw new IdentityError("malformed identity token");
|
|
101
|
+
}
|
|
102
|
+
if (header.alg !== IDENTITY_ALG) {
|
|
103
|
+
throw new IdentityError(`unexpected alg "${header.alg}" (expected ${IDENTITY_ALG})`);
|
|
104
|
+
}
|
|
105
|
+
const allowedKids = options.allowDevIdentities
|
|
106
|
+
? [IDENTITY_KEY_ID, IDENTITY_DEV_KEY_ID]
|
|
107
|
+
: [IDENTITY_KEY_ID];
|
|
108
|
+
if (!header.kid || !allowedKids.includes(header.kid)) {
|
|
109
|
+
throw new IdentityError(`unexpected kid "${header.kid}"`);
|
|
110
|
+
}
|
|
111
|
+
if (expectedTyp === "user" && !options.issuer) {
|
|
112
|
+
throw new IdentityError(`${ISSUER_ENV} not configured — deploy with the Every App CLI or provide an explicit issuer.`);
|
|
113
|
+
}
|
|
114
|
+
const verifyOpts = {
|
|
115
|
+
algorithms: [IDENTITY_ALG],
|
|
116
|
+
audience: options.audience,
|
|
117
|
+
requiredClaims: ["exp"],
|
|
118
|
+
...(options.issuer ? { issuer: options.issuer } : {}),
|
|
119
|
+
...(options.now ? { currentDate: new Date(options.now) } : {}),
|
|
120
|
+
};
|
|
121
|
+
let lastErr;
|
|
122
|
+
for (const pem of options.publicKeys) {
|
|
123
|
+
try {
|
|
124
|
+
const key = await importKey(pem);
|
|
125
|
+
const { payload } = await jwtVerify(token, key, verifyOpts);
|
|
126
|
+
if (payload.typ !== expectedTyp) {
|
|
127
|
+
throw new IdentityError(`unexpected token typ "${payload.typ}" (expected ${expectedTyp})`);
|
|
128
|
+
}
|
|
129
|
+
return payload;
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
lastErr = err;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
throw new IdentityError(`identity verification failed: ${lastErr?.message ?? "no matching key"}`);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Verify a public-route marker (the value of `x-everyapp-public`). The marker
|
|
139
|
+
* is a gateway-signed, app-scoped JWT with `pub: true` and `typ: "public"` —
|
|
140
|
+
* a bare header is NEVER a trust source, so a re-exposed app worker cannot be
|
|
141
|
+
* flipped into public mode by anyone who can type a header. Throws on any
|
|
142
|
+
* problem.
|
|
143
|
+
*/
|
|
144
|
+
export async function verifyPublicMarkerJwt(token, options) {
|
|
145
|
+
const payload = await verifyPinnedJwt(token, options, "public");
|
|
146
|
+
try {
|
|
147
|
+
assertPublicMarkerClaims(payload);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error instanceof ProtocolClaimsError) {
|
|
151
|
+
throw new IdentityError(error.message);
|
|
152
|
+
}
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Resolve identity for an incoming proxied request. Public routes carry a
|
|
158
|
+
* gateway-SIGNED marker in `x-everyapp-public` and resolve to
|
|
159
|
+
* `{ user: null, isPublic: true }` only after the marker verifies. Everything
|
|
160
|
+
* else requires a valid identity JWT. Throws {@link IdentityError} on any
|
|
161
|
+
* problem — including a bare/forged public header — so a re-exposed worker
|
|
162
|
+
* fails closed.
|
|
163
|
+
*/
|
|
164
|
+
export async function getIdentityFromRequest(request, options) {
|
|
165
|
+
const publicKeys = options.publicKeys ??
|
|
166
|
+
parsePublicKeys(options.env?.[options.keysEnvVar ?? PUBLIC_KEYS_ENV] ?? null);
|
|
167
|
+
// Dev identities are accepted only when the worker env opts in (everyapp dev
|
|
168
|
+
// sets EVERYAPP_DEV in .dev.vars). Production never sets it.
|
|
169
|
+
const devEnv = options.env?.[DEV_ENV];
|
|
170
|
+
const allowDevIdentities = options.allowDevIdentities ??
|
|
171
|
+
(typeof devEnv === "string" &&
|
|
172
|
+
(devEnv === "1" || devEnv.toLowerCase() === "true"));
|
|
173
|
+
const verifyOptions = {
|
|
174
|
+
publicKeys,
|
|
175
|
+
audience: options.audience,
|
|
176
|
+
issuer: options.issuer ??
|
|
177
|
+
(options.env?.[ISSUER_ENV] || undefined),
|
|
178
|
+
allowDevIdentities,
|
|
179
|
+
now: options.now,
|
|
180
|
+
};
|
|
181
|
+
const publicMarker = request.headers.get(PUBLIC_HEADER);
|
|
182
|
+
if (publicMarker) {
|
|
183
|
+
await verifyPublicMarkerJwt(publicMarker, verifyOptions);
|
|
184
|
+
return { user: null, isPublic: true };
|
|
185
|
+
}
|
|
186
|
+
const token = request.headers.get(IDENTITY_HEADER);
|
|
187
|
+
if (!token) {
|
|
188
|
+
throw new IdentityError("request reached the app without an identity token (not proxied through the gateway?)");
|
|
189
|
+
}
|
|
190
|
+
const user = await verifyIdentityJwt(token, verifyOptions);
|
|
191
|
+
return { user, isPublic: false };
|
|
192
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from "./protocol.js";
|
|
2
|
+
export { ConfigurationError, IdentityError, getIdentityFromRequest, parsePublicKeys, verifyIdentityJwt, verifyPublicMarkerJwt, type IdentityResult, type RequestIdentityOptions, type VerifyOptions, } from "./identity.js";
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/internal/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @every-app/sdk/internal — Every App platform protocol internals.
|
|
3
|
+
*
|
|
4
|
+
* This subpath is for the Every App platform itself (gateway, perimeter, CLI),
|
|
5
|
+
* not for app authors. It owns the wire constants, claim shapes, claim codecs,
|
|
6
|
+
* and gateway-side JWT minters shared by the platform packages.
|
|
7
|
+
*/
|
|
8
|
+
import { type JWTPayload } from "jose";
|
|
9
|
+
export declare const IDENTITY_ALG = "RS256";
|
|
10
|
+
export declare const IDENTITY_KEY_ID = "everyapp-identity";
|
|
11
|
+
export declare const IDENTITY_DEV_KEY_ID = "everyapp-identity-dev";
|
|
12
|
+
export declare const IDENTITY_HEADER = "x-everyapp-identity";
|
|
13
|
+
export declare const PUBLIC_HEADER = "x-everyapp-public";
|
|
14
|
+
/** 120-second lifetime — caps revocation staleness while surviving clock skew. */
|
|
15
|
+
export declare const IDENTITY_TTL_SECONDS = 120;
|
|
16
|
+
/** Env var carrying the app id used as the expected identity audience. */
|
|
17
|
+
export declare const APP_ID_ENV = "EVERYAPP_APP_ID";
|
|
18
|
+
/** Default env var carrying a JSON array of SPKI PEM public keys. */
|
|
19
|
+
export declare const PUBLIC_KEYS_ENV = "EVERYAPP_IDENTITY_PUBLIC_KEYS";
|
|
20
|
+
/** Env var carrying the expected gateway issuer for user identity verification. */
|
|
21
|
+
export declare const ISSUER_ENV = "EVERYAPP_IDENTITY_ISSUER";
|
|
22
|
+
/** When set to `1` or `true` in the worker env, the dev identity kid is accepted. */
|
|
23
|
+
export declare const DEV_ENV = "EVERYAPP_DEV";
|
|
24
|
+
/** `sub` claim the gateway mints public-route markers with. */
|
|
25
|
+
export declare const PUBLIC_MARKER_SUB = "public";
|
|
26
|
+
export type IdentityChannel = "web" | "api" | "mcp" | "agent";
|
|
27
|
+
export type IdentityTokenType = "user" | "public";
|
|
28
|
+
/** The actor on whose behalf the request is made (user, MCP client, agent). */
|
|
29
|
+
export interface IdentityActor {
|
|
30
|
+
sub: string;
|
|
31
|
+
}
|
|
32
|
+
export interface IdentitySubject {
|
|
33
|
+
sub: string;
|
|
34
|
+
email: string;
|
|
35
|
+
orgId: string;
|
|
36
|
+
orgRole: string;
|
|
37
|
+
}
|
|
38
|
+
export interface EveryAppUser {
|
|
39
|
+
/** User id (the `sub` claim). */
|
|
40
|
+
id: string;
|
|
41
|
+
email: string;
|
|
42
|
+
orgId: string;
|
|
43
|
+
orgRole: string;
|
|
44
|
+
channel: IdentityChannel;
|
|
45
|
+
/** The acting principal (user, or `mcp:<client>` / agent). */
|
|
46
|
+
actor: IdentityActor;
|
|
47
|
+
scopes: string[];
|
|
48
|
+
jti: string;
|
|
49
|
+
}
|
|
50
|
+
export interface IdentityClaims extends JWTPayload {
|
|
51
|
+
typ: "user";
|
|
52
|
+
email: string;
|
|
53
|
+
org_id: string;
|
|
54
|
+
org_role: string;
|
|
55
|
+
chan: IdentityChannel;
|
|
56
|
+
act: IdentityActor;
|
|
57
|
+
scopes: string[];
|
|
58
|
+
jti: string;
|
|
59
|
+
}
|
|
60
|
+
export interface PublicMarkerClaims extends JWTPayload {
|
|
61
|
+
typ: "public";
|
|
62
|
+
pub: true;
|
|
63
|
+
jti: string;
|
|
64
|
+
}
|
|
65
|
+
export declare class ProtocolClaimsError extends Error {
|
|
66
|
+
constructor(message: string);
|
|
67
|
+
}
|
|
68
|
+
export declare function identitySubjectToClaims(subject: IdentitySubject, opts: {
|
|
69
|
+
channel?: IdentityChannel;
|
|
70
|
+
actor?: IdentityActor;
|
|
71
|
+
scopes?: string[];
|
|
72
|
+
jti: string;
|
|
73
|
+
}): IdentityClaims;
|
|
74
|
+
export declare function identityClaimsToEveryAppUser(payload: JWTPayload): EveryAppUser;
|
|
75
|
+
export declare function publicMarkerClaims(jti: string): PublicMarkerClaims;
|
|
76
|
+
export declare function assertPublicMarkerClaims(payload: JWTPayload): void;
|
|
77
|
+
export interface MintIdentityOptions {
|
|
78
|
+
subject: IdentitySubject;
|
|
79
|
+
/** The app id this token is scoped to — becomes the `aud` claim. */
|
|
80
|
+
audience: string;
|
|
81
|
+
issuer: string;
|
|
82
|
+
channel?: IdentityChannel;
|
|
83
|
+
actor?: IdentityActor;
|
|
84
|
+
scopes?: string[];
|
|
85
|
+
ttlSeconds?: number;
|
|
86
|
+
now?: number;
|
|
87
|
+
/** Header kid. Defaults to the production kid; dev mints with the dev kid. */
|
|
88
|
+
keyId?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Mint an identity JWT. Returns the compact JWS string to inject as
|
|
92
|
+
* `x-everyapp-identity`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function mintIdentityJwt(privateKeyPem: string, opts: MintIdentityOptions): Promise<string>;
|
|
95
|
+
export interface MintPublicMarkerOptions {
|
|
96
|
+
/** The app id this marker is scoped to — becomes the `aud` claim. */
|
|
97
|
+
audience: string;
|
|
98
|
+
issuer: string;
|
|
99
|
+
ttlSeconds?: number;
|
|
100
|
+
now?: number;
|
|
101
|
+
/** Header kid. Defaults to the production kid; dev mints with the dev kid. */
|
|
102
|
+
keyId?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Mint the public-route marker for `x-everyapp-public`. A bare header value
|
|
106
|
+
* is never a trust source, so the marker is a signed, short-lived, app-scoped
|
|
107
|
+
* JWT with `pub: true` and `typ: "public"` that the SDK verifies exactly like
|
|
108
|
+
* an identity token.
|
|
109
|
+
*/
|
|
110
|
+
export declare function mintPublicMarkerJwt(privateKeyPem: string, opts: MintPublicMarkerOptions): Promise<string>;
|
|
111
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/internal/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @every-app/sdk/internal — Every App platform protocol internals.
|
|
3
|
+
*
|
|
4
|
+
* This subpath is for the Every App platform itself (gateway, perimeter, CLI),
|
|
5
|
+
* not for app authors. It owns the wire constants, claim shapes, claim codecs,
|
|
6
|
+
* and gateway-side JWT minters shared by the platform packages.
|
|
7
|
+
*/
|
|
8
|
+
import { SignJWT, importPKCS8 } from "jose";
|
|
9
|
+
export const IDENTITY_ALG = "RS256";
|
|
10
|
+
export const IDENTITY_KEY_ID = "everyapp-identity";
|
|
11
|
+
export const IDENTITY_DEV_KEY_ID = "everyapp-identity-dev";
|
|
12
|
+
export const IDENTITY_HEADER = "x-everyapp-identity";
|
|
13
|
+
export const PUBLIC_HEADER = "x-everyapp-public";
|
|
14
|
+
/** 120-second lifetime — caps revocation staleness while surviving clock skew. */
|
|
15
|
+
export const IDENTITY_TTL_SECONDS = 120;
|
|
16
|
+
/** Env var carrying the app id used as the expected identity audience. */
|
|
17
|
+
export const APP_ID_ENV = "EVERYAPP_APP_ID";
|
|
18
|
+
/** Default env var carrying a JSON array of SPKI PEM public keys. */
|
|
19
|
+
export const PUBLIC_KEYS_ENV = "EVERYAPP_IDENTITY_PUBLIC_KEYS";
|
|
20
|
+
/** Env var carrying the expected gateway issuer for user identity verification. */
|
|
21
|
+
export const ISSUER_ENV = "EVERYAPP_IDENTITY_ISSUER";
|
|
22
|
+
/** When set to `1` or `true` in the worker env, the dev identity kid is accepted. */
|
|
23
|
+
export const DEV_ENV = "EVERYAPP_DEV";
|
|
24
|
+
/** `sub` claim the gateway mints public-route markers with. */
|
|
25
|
+
export const PUBLIC_MARKER_SUB = "public";
|
|
26
|
+
export class ProtocolClaimsError extends Error {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = "ProtocolClaimsError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function identitySubjectToClaims(subject, opts) {
|
|
33
|
+
return {
|
|
34
|
+
typ: "user",
|
|
35
|
+
email: subject.email,
|
|
36
|
+
org_id: subject.orgId,
|
|
37
|
+
org_role: subject.orgRole,
|
|
38
|
+
chan: opts.channel ?? "web",
|
|
39
|
+
act: opts.actor ?? { sub: subject.sub },
|
|
40
|
+
scopes: opts.scopes ?? ["*"],
|
|
41
|
+
jti: opts.jti,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function identityClaimsToEveryAppUser(payload) {
|
|
45
|
+
if (payload.typ !== "user") {
|
|
46
|
+
throw new ProtocolClaimsError("identity token has wrong typ");
|
|
47
|
+
}
|
|
48
|
+
const sub = payload.sub;
|
|
49
|
+
const email = payload.email;
|
|
50
|
+
const orgId = payload.org_id;
|
|
51
|
+
const orgRole = payload.org_role;
|
|
52
|
+
if (!sub || !email || !orgId || !orgRole) {
|
|
53
|
+
throw new ProtocolClaimsError("identity token missing required claims");
|
|
54
|
+
}
|
|
55
|
+
const chan = payload.chan ?? "web";
|
|
56
|
+
const act = payload.act ?? { sub };
|
|
57
|
+
const scopes = Array.isArray(payload.scopes)
|
|
58
|
+
? payload.scopes.filter((scope) => typeof scope === "string")
|
|
59
|
+
: ["*"];
|
|
60
|
+
return {
|
|
61
|
+
id: sub,
|
|
62
|
+
email,
|
|
63
|
+
orgId,
|
|
64
|
+
orgRole,
|
|
65
|
+
channel: chan,
|
|
66
|
+
actor: { sub: act.sub ?? sub },
|
|
67
|
+
scopes,
|
|
68
|
+
jti: payload.jti ?? "",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function publicMarkerClaims(jti) {
|
|
72
|
+
return { typ: "public", pub: true, jti };
|
|
73
|
+
}
|
|
74
|
+
export function assertPublicMarkerClaims(payload) {
|
|
75
|
+
if (payload.typ !== "public") {
|
|
76
|
+
throw new ProtocolClaimsError("public marker has wrong typ");
|
|
77
|
+
}
|
|
78
|
+
if (payload.pub !== true || payload.sub !== PUBLIC_MARKER_SUB) {
|
|
79
|
+
throw new ProtocolClaimsError("token is not a public-route marker");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
let cachedPrivateKey = null;
|
|
83
|
+
async function loadPrivateKey(privateKeyPem) {
|
|
84
|
+
const pem = privateKeyPem.replace(/\\n/g, "\n");
|
|
85
|
+
if (cachedPrivateKey && cachedPrivateKey.pem === pem) {
|
|
86
|
+
return cachedPrivateKey.key;
|
|
87
|
+
}
|
|
88
|
+
const key = await importPKCS8(pem, IDENTITY_ALG);
|
|
89
|
+
cachedPrivateKey = { pem, key };
|
|
90
|
+
return key;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Mint an identity JWT. Returns the compact JWS string to inject as
|
|
94
|
+
* `x-everyapp-identity`.
|
|
95
|
+
*/
|
|
96
|
+
export async function mintIdentityJwt(privateKeyPem, opts) {
|
|
97
|
+
const key = await loadPrivateKey(privateKeyPem);
|
|
98
|
+
const nowSec = Math.floor((opts.now ?? Date.now()) / 1000);
|
|
99
|
+
const ttl = opts.ttlSeconds ?? IDENTITY_TTL_SECONDS;
|
|
100
|
+
const jti = crypto.randomUUID();
|
|
101
|
+
return new SignJWT(identitySubjectToClaims(opts.subject, {
|
|
102
|
+
channel: opts.channel,
|
|
103
|
+
actor: opts.actor,
|
|
104
|
+
scopes: opts.scopes,
|
|
105
|
+
jti,
|
|
106
|
+
}))
|
|
107
|
+
.setProtectedHeader({
|
|
108
|
+
alg: IDENTITY_ALG,
|
|
109
|
+
kid: opts.keyId ?? IDENTITY_KEY_ID,
|
|
110
|
+
})
|
|
111
|
+
.setIssuer(opts.issuer)
|
|
112
|
+
.setSubject(opts.subject.sub)
|
|
113
|
+
.setAudience(opts.audience)
|
|
114
|
+
.setIssuedAt(nowSec)
|
|
115
|
+
.setExpirationTime(nowSec + ttl)
|
|
116
|
+
.sign(key);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Mint the public-route marker for `x-everyapp-public`. A bare header value
|
|
120
|
+
* is never a trust source, so the marker is a signed, short-lived, app-scoped
|
|
121
|
+
* JWT with `pub: true` and `typ: "public"` that the SDK verifies exactly like
|
|
122
|
+
* an identity token.
|
|
123
|
+
*/
|
|
124
|
+
export async function mintPublicMarkerJwt(privateKeyPem, opts) {
|
|
125
|
+
const key = await loadPrivateKey(privateKeyPem);
|
|
126
|
+
const nowSec = Math.floor((opts.now ?? Date.now()) / 1000);
|
|
127
|
+
const ttl = opts.ttlSeconds ?? IDENTITY_TTL_SECONDS;
|
|
128
|
+
return new SignJWT(publicMarkerClaims(crypto.randomUUID()))
|
|
129
|
+
.setProtectedHeader({
|
|
130
|
+
alg: IDENTITY_ALG,
|
|
131
|
+
kid: opts.keyId ?? IDENTITY_KEY_ID,
|
|
132
|
+
})
|
|
133
|
+
.setIssuer(opts.issuer)
|
|
134
|
+
.setSubject(PUBLIC_MARKER_SUB)
|
|
135
|
+
.setAudience(opts.audience)
|
|
136
|
+
.setIssuedAt(nowSec)
|
|
137
|
+
.setExpirationTime(nowSec + ttl)
|
|
138
|
+
.sign(key);
|
|
139
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `everyApp()` — the app-side identity boundary.
|
|
3
|
+
*
|
|
4
|
+
* import manifest from "../everyapp.config.js";
|
|
5
|
+
* export default everyApp(handler, manifest);
|
|
6
|
+
*
|
|
7
|
+
* The wrapper verifies the gateway-injected identity before app code runs,
|
|
8
|
+
* stores the result on the original Request, and then delegates to the
|
|
9
|
+
* worker-style handler.
|
|
10
|
+
*/
|
|
11
|
+
import { ConfigurationError, IdentityError, type EveryAppUser, type IdentityResult } from "../internal/index.js";
|
|
12
|
+
export { ConfigurationError, IdentityError };
|
|
13
|
+
export type { EveryAppUser, IdentityResult };
|
|
14
|
+
export interface ExecutionContextLike {
|
|
15
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
16
|
+
passThroughOnException?(): void;
|
|
17
|
+
}
|
|
18
|
+
export interface EveryAppManifestLike {
|
|
19
|
+
id: string;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface EveryAppOptions {
|
|
23
|
+
/** Optional expected issuer (gateway URL). Defaults to env.EVERYAPP_IDENTITY_ISSUER when set. */
|
|
24
|
+
issuer?: string;
|
|
25
|
+
/** Env var holding the public key set. Defaults to EVERYAPP_IDENTITY_PUBLIC_KEYS. */
|
|
26
|
+
keysEnvVar?: string;
|
|
27
|
+
/** Provide keys directly (tests / non-standard delivery). */
|
|
28
|
+
publicKeys?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Accept dev identity tokens. Defaults to reading EVERYAPP_DEV from env.
|
|
31
|
+
* Never enable this in production.
|
|
32
|
+
*/
|
|
33
|
+
allowDevIdentities?: boolean;
|
|
34
|
+
/** Override for tests. */
|
|
35
|
+
now?: number;
|
|
36
|
+
}
|
|
37
|
+
/** The handler accepted by everyApp, with the verified user as a 4th argument. */
|
|
38
|
+
export type EveryAppHandler<TEnv = Record<string, unknown>> = (request: Request, env: TEnv, ctx: ExecutionContextLike, user: EveryAppUser | null) => Response | Promise<Response>;
|
|
39
|
+
interface EveryAppExport<TEnv> {
|
|
40
|
+
fetch(request: Request, env: TEnv, ctx: ExecutionContextLike): Promise<Response>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Return the verified Every App user for this request, or null for a declared
|
|
44
|
+
* public request. Uses the request cache first, then verifies the identity
|
|
45
|
+
* headers from the app id and public keys configured in env.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getEveryAppUser(request: Request, env: object): Promise<EveryAppUser | null>;
|
|
48
|
+
/**
|
|
49
|
+
* Return the verified user, or throw the same 401 JSON Response shape as
|
|
50
|
+
* everyApp() when the request is public or unauthenticated.
|
|
51
|
+
*/
|
|
52
|
+
export declare function requireEveryAppUser(request: Request, env: object): Promise<EveryAppUser>;
|
|
53
|
+
export declare function hasScope(user: EveryAppUser, scope: string): boolean;
|
|
54
|
+
export declare function everyApp<TEnv = Record<string, unknown>>(handler: EveryAppHandler<TEnv>, manifest: EveryAppManifestLike, options?: EveryAppOptions): EveryAppExport<TEnv>;
|
|
55
|
+
//# sourceMappingURL=everyApp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"everyApp.d.ts","sourceRoot":"","sources":["../../src/server/everyApp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAEL,kBAAkB,EAElB,aAAa,EAIb,KAAK,YAAY,EACjB,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3C,sBAAsB,CAAC,IAAI,IAAI,CAAC;CACjC;AAED,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,0BAA0B;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,kFAAkF;AAClF,MAAM,MAAM,eAAe,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAC5D,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,oBAAoB,EACzB,IAAI,EAAE,YAAY,GAAG,IAAI,KACtB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,UAAU,cAAc,CAAC,IAAI;IAC3B,KAAK,CACH,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAiFD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW9B;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;AAED,wBAAgB,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrD,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,EAC9B,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,eAAoB,GAC5B,cAAc,CAAC,IAAI,CAAC,CAqBtB"}
|