@seamless-auth/core 0.5.1-beta.20260523222121 → 0.5.1
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 +69 -0
- package/dist/handlers/oauthHandlers.d.ts +39 -0
- package/dist/handlers/oauthHandlers.d.ts.map +1 -0
- package/dist/handlers/oauthHandlers.js +77 -0
- package/dist/handlers/oauthHandlers.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/scopedRoles.d.ts +3 -0
- package/dist/scopedRoles.d.ts.map +1 -0
- package/dist/scopedRoles.js +39 -0
- package/dist/scopedRoles.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ If you are building a custom adapter (Express, Fastify, Next.js, Hono, etc.), th
|
|
|
23
23
|
- Core authentication state machine
|
|
24
24
|
- Cookie validation and refresh logic
|
|
25
25
|
- Service-token–based API ↔ Auth Server communication
|
|
26
|
+
- Framework-agnostic OAuth provider discovery/start/callback helpers
|
|
26
27
|
- Stateless, cryptographically verifiable flows
|
|
27
28
|
|
|
28
29
|
This package **does not**:
|
|
@@ -87,6 +88,10 @@ Key exports include:
|
|
|
87
88
|
- `refreshAccessToken(...)` – rotates expired access sessions
|
|
88
89
|
- `verifyCookieJwt(...)` – verifies signed cookie payloads
|
|
89
90
|
- `createServiceToken(...)` – creates short-lived M2M assertions
|
|
91
|
+
- `hasScopedRole(...)` – checks scoped role grants such as `admin:read`
|
|
92
|
+
- `listOAuthProvidersHandler(...)` – retrieves public OAuth provider metadata
|
|
93
|
+
- `startOAuthLoginHandler(...)` – starts an OAuth authorization-code login
|
|
94
|
+
- `finishOAuthLoginHandler(...)` – finishes OAuth login and returns cookie instructions
|
|
90
95
|
|
|
91
96
|
These functions return **descriptive results**, not HTTP responses.
|
|
92
97
|
|
|
@@ -121,6 +126,70 @@ if (result.type === "error") {
|
|
|
121
126
|
|
|
122
127
|
---
|
|
123
128
|
|
|
129
|
+
## OAuth Helper Flow
|
|
130
|
+
|
|
131
|
+
The core OAuth helpers are designed for framework adapters. They do not redirect, set cookies, or
|
|
132
|
+
read secrets. They proxy to the Seamless Auth API and return plain result objects that your adapter
|
|
133
|
+
turns into HTTP responses.
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const providers = await listOAuthProvidersHandler({
|
|
137
|
+
authServerUrl: "https://auth.example.com",
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const started = await startOAuthLoginHandler(
|
|
141
|
+
{
|
|
142
|
+
providerId: "google",
|
|
143
|
+
body: {
|
|
144
|
+
redirectUri: "https://app.example.com/oauth/callback",
|
|
145
|
+
returnTo: "https://app.example.com/dashboard",
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{ authServerUrl: "https://auth.example.com" },
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const finished = await finishOAuthLoginHandler(
|
|
152
|
+
{
|
|
153
|
+
providerId: "google",
|
|
154
|
+
body: {
|
|
155
|
+
code: "provider-code",
|
|
156
|
+
state: "signed-state-from-start",
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
authServerUrl: "https://auth.example.com",
|
|
161
|
+
accessCookieName: "seamless-access",
|
|
162
|
+
refreshCookieName: "seamless-refresh",
|
|
163
|
+
},
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
if (finished.setCookies) {
|
|
167
|
+
// adapter signs and applies access/refresh cookies
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The Seamless Auth API handles state validation, provider token exchange, userinfo lookup, and
|
|
172
|
+
provider identity linking. Core and adapter code never store provider access tokens.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Scoped Roles
|
|
177
|
+
|
|
178
|
+
Core exports `hasScopedRole` and `roleGrantsAccess` for framework adapters and custom servers that
|
|
179
|
+
need the same authorization semantics as `@seamless-auth/express`.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { hasScopedRole } from "@seamless-auth/core";
|
|
183
|
+
|
|
184
|
+
hasScopedRole(["admin:write"], "admin:read"); // true
|
|
185
|
+
hasScopedRole(["admin:read"], "admin:write"); // false
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Plain roles remain backwards compatible. `admin` grants `admin:read` and `admin:write`, while
|
|
189
|
+
`admin:read` does not satisfy a plain `admin` check.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
124
193
|
## Testing
|
|
125
194
|
|
|
126
195
|
All logic in this package is tested against compiled output (`dist/`),
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CookiePayload } from "../ensureCookies.js";
|
|
2
|
+
export interface OAuthHandlerOptions {
|
|
3
|
+
authServerUrl: string;
|
|
4
|
+
cookieDomain?: string;
|
|
5
|
+
accessCookieName: string;
|
|
6
|
+
refreshCookieName: string;
|
|
7
|
+
}
|
|
8
|
+
export interface OAuthRequestInput {
|
|
9
|
+
providerId?: string;
|
|
10
|
+
body?: unknown;
|
|
11
|
+
forwardedClientIp?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface OAuthHandlerResult {
|
|
14
|
+
status: number;
|
|
15
|
+
body?: unknown;
|
|
16
|
+
error?: unknown;
|
|
17
|
+
setCookies?: {
|
|
18
|
+
name: string;
|
|
19
|
+
value: CookiePayload;
|
|
20
|
+
ttl: number;
|
|
21
|
+
domain?: string;
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
export declare function listOAuthProvidersHandler(opts: Pick<OAuthHandlerOptions, "authServerUrl">): Promise<{
|
|
25
|
+
body: any;
|
|
26
|
+
status: number;
|
|
27
|
+
} | {
|
|
28
|
+
error: any;
|
|
29
|
+
status: number;
|
|
30
|
+
}>;
|
|
31
|
+
export declare function startOAuthLoginHandler(input: OAuthRequestInput, opts: Pick<OAuthHandlerOptions, "authServerUrl">): Promise<{
|
|
32
|
+
body: any;
|
|
33
|
+
status: number;
|
|
34
|
+
} | {
|
|
35
|
+
error: any;
|
|
36
|
+
status: number;
|
|
37
|
+
}>;
|
|
38
|
+
export declare function finishOAuthLoginHandler(input: OAuthRequestInput, opts: OAuthHandlerOptions): Promise<OAuthHandlerResult>;
|
|
39
|
+
//# sourceMappingURL=oauthHandlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthHandlers.d.ts","sourceRoot":"","sources":["../../src/handlers/oauthHandlers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,aAAa,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,EAAE,CAAC;CACL;AAED,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,eAAe,CAAC;;;;;;GAYjD;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,eAAe,CAAC;;;;;;GAiBjD;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAiE7B"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { authFetch } from "../authFetch.js";
|
|
2
|
+
import { verifySignedAuthResponse } from "../verifySignedAuthResponse.js";
|
|
3
|
+
export async function listOAuthProvidersHandler(opts) {
|
|
4
|
+
const up = await authFetch(`${opts.authServerUrl}/oauth/providers`, {
|
|
5
|
+
method: "GET",
|
|
6
|
+
});
|
|
7
|
+
const data = await up.json();
|
|
8
|
+
return {
|
|
9
|
+
status: up.status,
|
|
10
|
+
...(up.ok ? { body: data } : { error: data }),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export async function startOAuthLoginHandler(input, opts) {
|
|
14
|
+
const up = await authFetch(`${opts.authServerUrl}/oauth/${encodeURIComponent(input.providerId)}/start`, {
|
|
15
|
+
method: "POST",
|
|
16
|
+
body: input.body,
|
|
17
|
+
forwardedClientIp: input.forwardedClientIp,
|
|
18
|
+
});
|
|
19
|
+
const data = await up.json();
|
|
20
|
+
return {
|
|
21
|
+
status: up.status,
|
|
22
|
+
...(up.ok ? { body: data } : { error: data }),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export async function finishOAuthLoginHandler(input, opts) {
|
|
26
|
+
const up = await authFetch(`${opts.authServerUrl}/oauth/${encodeURIComponent(input.providerId)}/callback`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
body: input.body,
|
|
29
|
+
forwardedClientIp: input.forwardedClientIp,
|
|
30
|
+
});
|
|
31
|
+
const data = await up.json();
|
|
32
|
+
if (!up.ok) {
|
|
33
|
+
return {
|
|
34
|
+
status: up.status,
|
|
35
|
+
error: data,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const verifiedAccessToken = await verifySignedAuthResponse(data.token, opts.authServerUrl);
|
|
39
|
+
if (!verifiedAccessToken) {
|
|
40
|
+
throw new Error("Invalid signed response from Auth Server");
|
|
41
|
+
}
|
|
42
|
+
if (verifiedAccessToken.sub !== data.sub) {
|
|
43
|
+
throw new Error("Signature mismatch with data payload");
|
|
44
|
+
}
|
|
45
|
+
const sessionId = typeof verifiedAccessToken.sid === "string"
|
|
46
|
+
? verifiedAccessToken.sid
|
|
47
|
+
: undefined;
|
|
48
|
+
return {
|
|
49
|
+
status: up.status,
|
|
50
|
+
body: data,
|
|
51
|
+
setCookies: [
|
|
52
|
+
{
|
|
53
|
+
name: opts.accessCookieName,
|
|
54
|
+
value: {
|
|
55
|
+
sub: data.sub,
|
|
56
|
+
...(sessionId === undefined ? {} : { sessionId }),
|
|
57
|
+
roles: data.roles,
|
|
58
|
+
email: data.email,
|
|
59
|
+
phone: data.phone,
|
|
60
|
+
organizationId: data.organizationId ?? null,
|
|
61
|
+
},
|
|
62
|
+
ttl: data.ttl,
|
|
63
|
+
domain: opts.cookieDomain,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: opts.refreshCookieName,
|
|
67
|
+
value: {
|
|
68
|
+
sub: data.sub,
|
|
69
|
+
refreshToken: data.refreshToken,
|
|
70
|
+
},
|
|
71
|
+
ttl: data.refreshTtl,
|
|
72
|
+
domain: opts.cookieDomain,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=oauthHandlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthHandlers.js","sourceRoot":"","sources":["../../src/handlers/oauthHandlers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./verifyCookieJwt.js";
|
|
|
5
5
|
export * from "./refreshAccessToken.js";
|
|
6
6
|
export * from "./getSeamlessUser.js";
|
|
7
7
|
export * from "./createServiceToken.js";
|
|
8
|
+
export * from "./scopedRoles.js";
|
|
8
9
|
export * from "./handlers/login.js";
|
|
9
10
|
export * from "./handlers/finishLogin.js";
|
|
10
11
|
export * from "./handlers/register.js";
|
|
@@ -17,4 +18,5 @@ export * from "./handlers/verifyMagicLinkHandler.js";
|
|
|
17
18
|
export * from "./handlers/requestMagicLinkHandler.js";
|
|
18
19
|
export * from "./handlers/pollMagicLinkConfirmationHandler.js";
|
|
19
20
|
export * from "./handlers/switchOrganizationHandler.js";
|
|
21
|
+
export * from "./handlers/oauthHandlers.js";
|
|
20
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./verifyCookieJwt.js";
|
|
|
5
5
|
export * from "./refreshAccessToken.js";
|
|
6
6
|
export * from "./getSeamlessUser.js";
|
|
7
7
|
export * from "./createServiceToken.js";
|
|
8
|
+
export * from "./scopedRoles.js";
|
|
8
9
|
export * from "./handlers/login.js";
|
|
9
10
|
export * from "./handlers/finishLogin.js";
|
|
10
11
|
export * from "./handlers/register.js";
|
|
@@ -17,4 +18,5 @@ export * from "./handlers/verifyMagicLinkHandler.js";
|
|
|
17
18
|
export * from "./handlers/requestMagicLinkHandler.js";
|
|
18
19
|
export * from "./handlers/pollMagicLinkConfirmationHandler.js";
|
|
19
20
|
export * from "./handlers/switchOrganizationHandler.js";
|
|
21
|
+
export * from "./handlers/oauthHandlers.js";
|
|
20
22
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopedRoles.d.ts","sourceRoot":"","sources":["../src/scopedRoles.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAsCnF;AAED,wBAAgB,aAAa,CAC3B,YAAY,EAAE,OAAO,EACrB,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAC/B,OAAO,CAaT"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function roleGrantsAccess(grantedRole, requiredRole) {
|
|
2
|
+
const granted = grantedRole.trim();
|
|
3
|
+
const required = requiredRole.trim();
|
|
4
|
+
if (!granted || !required) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
if (granted === required) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
if (granted.endsWith(":*")) {
|
|
11
|
+
const prefix = granted.slice(0, -2);
|
|
12
|
+
return required === prefix || required.startsWith(`${prefix}:`);
|
|
13
|
+
}
|
|
14
|
+
if (!required.includes(":")) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (!granted.includes(":")) {
|
|
18
|
+
return required.startsWith(`${granted}:`);
|
|
19
|
+
}
|
|
20
|
+
const grantedParts = granted.split(":");
|
|
21
|
+
const requiredParts = required.split(":");
|
|
22
|
+
const grantedAction = grantedParts.at(-1);
|
|
23
|
+
const requiredAction = requiredParts.at(-1);
|
|
24
|
+
const grantedPrefix = grantedParts.slice(0, -1);
|
|
25
|
+
const requiredPrefix = requiredParts.slice(0, -1);
|
|
26
|
+
return (grantedAction === "write" &&
|
|
27
|
+
requiredAction === "read" &&
|
|
28
|
+
grantedPrefix.length === requiredPrefix.length &&
|
|
29
|
+
grantedPrefix.every((part, index) => part === requiredPrefix[index]));
|
|
30
|
+
}
|
|
31
|
+
export function hasScopedRole(grantedRoles, requiredRoles) {
|
|
32
|
+
if (!Array.isArray(grantedRoles)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
const granted = grantedRoles.filter((role) => typeof role === "string");
|
|
36
|
+
const required = Array.isArray(requiredRoles) ? requiredRoles : [requiredRoles];
|
|
37
|
+
return required.some((requiredRole) => granted.some((grantedRole) => roleGrantsAccess(grantedRole, requiredRole)));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=scopedRoles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopedRoles.js","sourceRoot":"","sources":["../src/scopedRoles.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,YAAoB;IACxE,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;IAErC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpC,OAAO,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,cAAc,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAElD,OAAO,CACL,aAAa,KAAK,OAAO;QACzB,cAAc,KAAK,MAAM;QACzB,aAAa,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM;QAC9C,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,cAAc,CAAC,KAAK,CAAC,CAAC,CACrE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,YAAqB,EACrB,aAAgC;IAEhC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CACjC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CACnD,CAAC;IACF,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAEhF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CACpC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED