@pattern-js/mod-identity 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/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/admin-routes.d.ts +30 -0
- package/dist/admin-routes.d.ts.map +1 -0
- package/dist/admin-routes.js +52 -0
- package/dist/admin-routes.js.map +1 -0
- package/dist/auth-provider.d.ts +16 -0
- package/dist/auth-provider.d.ts.map +1 -0
- package/dist/auth-provider.js +47 -0
- package/dist/auth-provider.js.map +1 -0
- package/dist/cookies.d.ts +19 -0
- package/dist/cookies.d.ts.map +1 -0
- package/dist/cookies.js +44 -0
- package/dist/cookies.js.map +1 -0
- package/dist/csrf.d.ts +19 -0
- package/dist/csrf.d.ts.map +1 -0
- package/dist/csrf.js +39 -0
- package/dist/csrf.js.map +1 -0
- package/dist/deliver.d.ts +28 -0
- package/dist/deliver.d.ts.map +1 -0
- package/dist/deliver.js +36 -0
- package/dist/deliver.js.map +1 -0
- package/dist/frontend.d.ts +10 -0
- package/dist/frontend.d.ts.map +1 -0
- package/dist/frontend.js +139 -0
- package/dist/frontend.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mod.d.ts +21 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +97 -0
- package/dist/mod.js.map +1 -0
- package/dist/ops.d.ts +26 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +379 -0
- package/dist/ops.js.map +1 -0
- package/dist/options.d.ts +53 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +22 -0
- package/dist/options.js.map +1 -0
- package/dist/pages/bootstrap.d.ts +13 -0
- package/dist/pages/bootstrap.d.ts.map +1 -0
- package/dist/pages/bootstrap.js +23 -0
- package/dist/pages/bootstrap.js.map +1 -0
- package/dist/pages/html.d.ts +16 -0
- package/dist/pages/html.d.ts.map +1 -0
- package/dist/pages/html.js +72 -0
- package/dist/pages/html.js.map +1 -0
- package/dist/pages/login.d.ts +17 -0
- package/dist/pages/login.d.ts.map +1 -0
- package/dist/pages/login.js +43 -0
- package/dist/pages/login.js.map +1 -0
- package/dist/pages/welcome.d.ts +13 -0
- package/dist/pages/welcome.d.ts.map +1 -0
- package/dist/pages/welcome.js +19 -0
- package/dist/pages/welcome.js.map +1 -0
- package/dist/service-key.d.ts +12 -0
- package/dist/service-key.d.ts.map +1 -0
- package/dist/service-key.js +16 -0
- package/dist/service-key.js.map +1 -0
- package/dist/service.d.ts +133 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +208 -0
- package/dist/service.js.map +1 -0
- package/dist/store/memory.d.ts +11 -0
- package/dist/store/memory.d.ts.map +1 -0
- package/dist/store/memory.js +0 -0
- package/dist/store/memory.js.map +1 -0
- package/dist/store/migrations.d.ts +21 -0
- package/dist/store/migrations.d.ts.map +1 -0
- package/dist/store/migrations.js +87 -0
- package/dist/store/migrations.js.map +1 -0
- package/dist/store/mutex.d.ts +13 -0
- package/dist/store/mutex.d.ts.map +1 -0
- package/dist/store/mutex.js +28 -0
- package/dist/store/mutex.js.map +1 -0
- package/dist/store/sqlite.d.ts +20 -0
- package/dist/store/sqlite.d.ts.map +1 -0
- package/dist/store/sqlite.js +254 -0
- package/dist/store/sqlite.js.map +1 -0
- package/dist/store/types.d.ts +135 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +23 -0
- package/dist/store/types.js.map +1 -0
- package/dist/tokens.d.ts +16 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +25 -0
- package/dist/tokens.js.map +1 -0
- package/dist/workflows.d.ts +14 -0
- package/dist/workflows.d.ts.map +1 -0
- package/dist/workflows.js +96 -0
- package/dist/workflows.js.map +1 -0
- package/docs/index.md +162 -0
- package/docs/ops/identity.bootstrap.page.md +5 -0
- package/docs/ops/identity.bootstrap.submit.md +5 -0
- package/docs/ops/identity.login.page.md +5 -0
- package/docs/ops/identity.logout.md +4 -0
- package/docs/ops/identity.sessions.list.md +5 -0
- package/docs/ops/identity.sessions.revoke.md +4 -0
- package/docs/ops/identity.settings.get.md +4 -0
- package/docs/ops/identity.settings.set.md +5 -0
- package/docs/ops/identity.token.callback.md +7 -0
- package/docs/ops/identity.users.get.md +5 -0
- package/docs/ops/identity.users.invite.md +7 -0
- package/docs/ops/identity.users.list.md +5 -0
- package/docs/ops/identity.users.loginLink.md +5 -0
- package/docs/ops/identity.users.revokeSessions.md +5 -0
- package/docs/ops/identity.users.runStats.md +7 -0
- package/docs/ops/identity.users.setRoles.md +5 -0
- package/docs/ops/identity.users.toggleDisabled.md +5 -0
- package/docs/ops/identity.welcome.page.md +5 -0
- package/docs/ops/identity.whoami.md +6 -0
- package/package.json +45 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-identity — public surface.
|
|
3
|
+
*
|
|
4
|
+
* `identityMod(options)` is the brick; everything else is the toolbox for
|
|
5
|
+
* provider mods (magic-link, oidc…) and apps that script identity directly.
|
|
6
|
+
*/
|
|
7
|
+
export { identityMod } from "./mod.js";
|
|
8
|
+
export { default } from "./mod.js";
|
|
9
|
+
export { resolveOptions, type IdentityOptions, type ResolvedIdentityOptions } from "./options.js";
|
|
10
|
+
export { DefaultIdentityService, type FindOrCreateInput, type IdentityService, type IssuedToken, type LoginMethod, type MintedSession, type ResolvedSession, } from "./service.js";
|
|
11
|
+
export { identityService, IDENTITY_SERVICE } from "./service-key.js";
|
|
12
|
+
export { sessionAuthProvider, SESSION_PROVIDER_NAME } from "./auth-provider.js";
|
|
13
|
+
export { deliverToken, absoluteUrl, DELIVER_TOKEN_HOOK, type DeliverInput, type DeliverResult } from "./deliver.js";
|
|
14
|
+
export { parseCookies, serializeSessionCookie, clearSessionCookie } from "./cookies.js";
|
|
15
|
+
export { isCrossSiteWrite, isStateChanging } from "./csrf.js";
|
|
16
|
+
export { randomToken, sha256hex, normalizeEmail, looksLikeEmail } from "./tokens.js";
|
|
17
|
+
export { renderLoginPage, renderSentPage } from "./pages/login.js";
|
|
18
|
+
export { layout, escapeHtml, safeNextPath } from "./pages/html.js";
|
|
19
|
+
export { memoryIdentityStores } from "./store/memory.js";
|
|
20
|
+
export { sqliteIdentityStores } from "./store/sqlite.js";
|
|
21
|
+
export { KeyedMutex } from "./store/mutex.js";
|
|
22
|
+
export { UniqueViolationError, type IdentityStores, type SessionRow, type SessionStore, type TokenPurpose, type TokenRow, type TokenStore, type UserRow, type UserStore, } from "./store/types.js";
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAClG,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACpH,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-identity — public surface.
|
|
3
|
+
*
|
|
4
|
+
* `identityMod(options)` is the brick; everything else is the toolbox for
|
|
5
|
+
* provider mods (magic-link, oidc…) and apps that script identity directly.
|
|
6
|
+
*/
|
|
7
|
+
export { identityMod } from "./mod.js";
|
|
8
|
+
export { default } from "./mod.js";
|
|
9
|
+
export { resolveOptions } from "./options.js";
|
|
10
|
+
export { DefaultIdentityService, } from "./service.js";
|
|
11
|
+
export { identityService, IDENTITY_SERVICE } from "./service-key.js";
|
|
12
|
+
export { sessionAuthProvider, SESSION_PROVIDER_NAME } from "./auth-provider.js";
|
|
13
|
+
export { deliverToken, absoluteUrl, DELIVER_TOKEN_HOOK } from "./deliver.js";
|
|
14
|
+
export { parseCookies, serializeSessionCookie, clearSessionCookie } from "./cookies.js";
|
|
15
|
+
export { isCrossSiteWrite, isStateChanging } from "./csrf.js";
|
|
16
|
+
export { randomToken, sha256hex, normalizeEmail, looksLikeEmail } from "./tokens.js";
|
|
17
|
+
export { renderLoginPage, renderSentPage } from "./pages/login.js";
|
|
18
|
+
export { layout, escapeHtml, safeNextPath } from "./pages/html.js";
|
|
19
|
+
export { memoryIdentityStores } from "./store/memory.js";
|
|
20
|
+
export { sqliteIdentityStores } from "./store/sqlite.js";
|
|
21
|
+
export { KeyedMutex } from "./store/mutex.js";
|
|
22
|
+
export { UniqueViolationError, } from "./store/types.js";
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,cAAc,EAAsD,MAAM,cAAc,CAAC;AAClG,OAAO,EACL,sBAAsB,GAOvB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAyC,MAAM,cAAc,CAAC;AACpH,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,oBAAoB,GASrB,MAAM,kBAAkB,CAAC"}
|
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-identity — the mod (§9).
|
|
3
|
+
*
|
|
4
|
+
* `setup` opens the stores (sqlite at `./.pattern-data/identity.db` by
|
|
5
|
+
* default — gitignored, never `.pattern/`), builds the service and registers
|
|
6
|
+
* it under core's IDENTITY_SERVICE key plus the login URL under
|
|
7
|
+
* AUTH_LOGIN_URL (hosts redirect unauthenticated HTML there). The session
|
|
8
|
+
* AuthProvider and the `identity.deliverToken` hook ride the PatternMod
|
|
9
|
+
* fields; routes are ordinary endpoint workflows.
|
|
10
|
+
*
|
|
11
|
+
* `ready` runs after the whole mod batch: if the user store is empty, it
|
|
12
|
+
* mints a one-time bootstrap token and prints the setup URL to the console —
|
|
13
|
+
* the same single-use-token primitive as login and invites.
|
|
14
|
+
*/
|
|
15
|
+
import { type PatternMod } from "@pattern-js/core";
|
|
16
|
+
import { type IdentityOptions } from "./options.js";
|
|
17
|
+
export declare function identityMod(options?: IdentityOptions): PatternMod;
|
|
18
|
+
/** A ready-to-use identity mod with defaults (for `loadMods`/`engine.use`). */
|
|
19
|
+
declare const _default: PatternMod;
|
|
20
|
+
export default _default;
|
|
21
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,EAA+D,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAChH,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAuBpE,wBAAgB,WAAW,CAAC,OAAO,GAAE,eAAoB,GAAG,UAAU,CAwDrE;AAED,+EAA+E;;AAC/E,wBAA6B"}
|
package/dist/mod.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-identity — the mod (§9).
|
|
3
|
+
*
|
|
4
|
+
* `setup` opens the stores (sqlite at `./.pattern-data/identity.db` by
|
|
5
|
+
* default — gitignored, never `.pattern/`), builds the service and registers
|
|
6
|
+
* it under core's IDENTITY_SERVICE key plus the login URL under
|
|
7
|
+
* AUTH_LOGIN_URL (hosts redirect unauthenticated HTML there). The session
|
|
8
|
+
* AuthProvider and the `identity.deliverToken` hook ride the PatternMod
|
|
9
|
+
* fields; routes are ordinary endpoint workflows.
|
|
10
|
+
*
|
|
11
|
+
* `ready` runs after the whole mod batch: if the user store is empty, it
|
|
12
|
+
* mints a one-time bootstrap token and prints the setup URL to the console —
|
|
13
|
+
* the same single-use-token primitive as login and invites.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync } from "node:fs";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { localFs, provideFilesystem } from "@pattern-js/runtime-node";
|
|
18
|
+
import { AUTH_LOGIN_URL, IDENTITY_SERVICE, defineMod, z } from "@pattern-js/core";
|
|
19
|
+
import { resolveOptions } from "./options.js";
|
|
20
|
+
import { DefaultIdentityService } from "./service.js";
|
|
21
|
+
import { sessionAuthProvider } from "./auth-provider.js";
|
|
22
|
+
import { identityOps } from "./ops.js";
|
|
23
|
+
import { endpointWorkflows } from "./workflows.js";
|
|
24
|
+
import { identityAdminRoutes } from "./admin-routes.js";
|
|
25
|
+
import { identityFrontend } from "./frontend.js";
|
|
26
|
+
import { memoryIdentityStores } from "./store/memory.js";
|
|
27
|
+
import { sqliteIdentityStores } from "./store/sqlite.js";
|
|
28
|
+
import { DELIVER_TOKEN_HOOK } from "./deliver.js";
|
|
29
|
+
/** Create the identity mod (a configured `PatternMod`). */
|
|
30
|
+
/** The packaged docs/ chapter (the `docs` contribution points at "identity-docs"). */
|
|
31
|
+
function packagedDocs(engine) {
|
|
32
|
+
try {
|
|
33
|
+
const dir = fileURLToPath(new URL("../docs", import.meta.url));
|
|
34
|
+
if (existsSync(dir))
|
|
35
|
+
provideFilesystem(engine, "identity-docs", localFs(dir));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* packaged without docs — the contribution is simply skipped */
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function identityMod(options = {}) {
|
|
42
|
+
const opts = resolveOptions(options);
|
|
43
|
+
// Created in `setup`; the auth provider closes over it via the thunk so the
|
|
44
|
+
// provider can be declared on the mod before the stores are open.
|
|
45
|
+
let service;
|
|
46
|
+
return defineMod({
|
|
47
|
+
name: "@pattern-js/mod-identity",
|
|
48
|
+
docs: { filesystem: "identity-docs", title: "Identity", order: 40 },
|
|
49
|
+
ops: identityOps,
|
|
50
|
+
// Auth-page routes + the admin Access screens' dedicated routes (one
|
|
51
|
+
// purposeful endpoint per screen and action, replacing the invoke path).
|
|
52
|
+
workflows: [...endpointWorkflows(opts.mount), ...identityAdminRoutes()],
|
|
53
|
+
authProviders: [sessionAuthProvider(() => service)],
|
|
54
|
+
hooks: [
|
|
55
|
+
{
|
|
56
|
+
name: DELIVER_TOKEN_HOOK,
|
|
57
|
+
payload: z
|
|
58
|
+
.object({
|
|
59
|
+
email: z.string(),
|
|
60
|
+
url: z.string(),
|
|
61
|
+
purpose: z.string(),
|
|
62
|
+
delivered: z.boolean(),
|
|
63
|
+
})
|
|
64
|
+
.loose(),
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
frontend: identityFrontend(),
|
|
68
|
+
setup: async (engine) => {
|
|
69
|
+
packagedDocs(engine);
|
|
70
|
+
const stores = opts.storage === "memory" ? memoryIdentityStores() : await sqliteIdentityStores(opts.storage);
|
|
71
|
+
service = new DefaultIdentityService(stores, opts, engine.connections);
|
|
72
|
+
engine.provideService(IDENTITY_SERVICE, service);
|
|
73
|
+
engine.provideService(AUTH_LOGIN_URL, `${opts.mount}/login`);
|
|
74
|
+
},
|
|
75
|
+
ready: async () => {
|
|
76
|
+
if (!service)
|
|
77
|
+
return;
|
|
78
|
+
// Bootstrap-on-empty: the first admin signs up through a one-time link.
|
|
79
|
+
const count = await service.listUsers().then((u) => u.length);
|
|
80
|
+
if (count > 0)
|
|
81
|
+
return;
|
|
82
|
+
const issued = await service.issueToken({
|
|
83
|
+
purpose: "bootstrap",
|
|
84
|
+
ttlMs: 24 * 60 * 60 * 1000,
|
|
85
|
+
data: { roles: opts.bootstrapRoles },
|
|
86
|
+
});
|
|
87
|
+
const path = `${opts.mount}/bootstrap?t=${issued.token}`;
|
|
88
|
+
const guess = `http://localhost:${process.env.PORT ?? 3000}${path}`;
|
|
89
|
+
console.log(`\n[pattern] ◆ No users yet — create the first admin with this one-time link (valid 24h):\n` +
|
|
90
|
+
`[pattern] ${guess}\n` +
|
|
91
|
+
`[pattern] (path: ${path} — adjust host/port if your app serves elsewhere)\n`);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/** A ready-to-use identity mod with defaults (for `loadMods`/`engine.use`). */
|
|
96
|
+
export default identityMod();
|
|
97
|
+
//# sourceMappingURL=mod.js.map
|
package/dist/mod.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
|
package/dist/ops.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-identity — the `identity.*` op catalog.
|
|
3
|
+
*
|
|
4
|
+
* Two authoring shapes:
|
|
5
|
+
* - **json ops** (single `out`) — whoami + the admin-screen surface
|
|
6
|
+
* (users/sessions). The privileged ones are PURE: they never check scopes
|
|
7
|
+
* in-op. Authorization is the trigger's job — their admin routes stamp
|
|
8
|
+
* `requireAuth: { scopes: ["admin"] }` — and a `sensitivity: "privileged"`
|
|
9
|
+
* tag lets the validator warn if a route ever forgets the gate.
|
|
10
|
+
* - **http ops** ({ status, headers, body }) — the auth pages and redirects
|
|
11
|
+
* (login page, token callback, logout, bootstrap), where Set-Cookie and
|
|
12
|
+
* Location ARE the result.
|
|
13
|
+
*
|
|
14
|
+
* The security kernel stays in code on purpose: token consumption and session
|
|
15
|
+
* minting are not editable in the admin; the *delivery* of tokens is the
|
|
16
|
+
* customizable part (the `identity.deliverToken` hook).
|
|
17
|
+
*/
|
|
18
|
+
import { type OpDefinition } from "@pattern-js/core";
|
|
19
|
+
/** Per-op route I/O for the auth pages — which request fields each reads. */
|
|
20
|
+
export declare const authOpRoutes: Record<string, {
|
|
21
|
+
query: string[];
|
|
22
|
+
body: string[];
|
|
23
|
+
userAgent: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
export declare const identityOps: OpDefinition[];
|
|
26
|
+
//# sourceMappingURL=ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAuE9F,6EAA6E;AAC7E,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAM,CAAC;AA2bxG,eAAO,MAAM,WAAW,EAAE,YAAY,EAoBrC,CAAC"}
|
package/dist/ops.js
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-identity — the `identity.*` op catalog.
|
|
3
|
+
*
|
|
4
|
+
* Two authoring shapes:
|
|
5
|
+
* - **json ops** (single `out`) — whoami + the admin-screen surface
|
|
6
|
+
* (users/sessions). The privileged ones are PURE: they never check scopes
|
|
7
|
+
* in-op. Authorization is the trigger's job — their admin routes stamp
|
|
8
|
+
* `requireAuth: { scopes: ["admin"] }` — and a `sensitivity: "privileged"`
|
|
9
|
+
* tag lets the validator warn if a route ever forgets the gate.
|
|
10
|
+
* - **http ops** ({ status, headers, body }) — the auth pages and redirects
|
|
11
|
+
* (login page, token callback, logout, bootstrap), where Set-Cookie and
|
|
12
|
+
* Location ARE the result.
|
|
13
|
+
*
|
|
14
|
+
* The security kernel stays in code on purpose: token consumption and session
|
|
15
|
+
* minting are not editable in the admin; the *delivery* of tokens is the
|
|
16
|
+
* customizable part (the `identity.deliverToken` hook).
|
|
17
|
+
*/
|
|
18
|
+
import { AUTH_HOME_URL, value, z } from "@pattern-js/core";
|
|
19
|
+
import { identityService } from "./service-key.js";
|
|
20
|
+
import { deliverToken } from "./deliver.js";
|
|
21
|
+
import { looksLikeEmail } from "./tokens.js";
|
|
22
|
+
import { renderLoginPage, renderSentPage } from "./pages/login.js";
|
|
23
|
+
import { renderBootstrapPage } from "./pages/bootstrap.js";
|
|
24
|
+
import { renderWelcomePage } from "./pages/welcome.js";
|
|
25
|
+
import { safeNextPath } from "./pages/html.js";
|
|
26
|
+
/**
|
|
27
|
+
* A JSON op: discrete named inputs in, a single `out` value out — a PURE domain
|
|
28
|
+
* function. Each is fronted by its own dedicated admin route (see
|
|
29
|
+
* `./admin-routes.ts`) that decomposes the request onto these ports and carries
|
|
30
|
+
* the auth; workflows may also wire them (an automation listing users, or a CLI
|
|
31
|
+
* trigger with no session at all — which is exactly why the op stays scope-free).
|
|
32
|
+
*/
|
|
33
|
+
function jsonOp(type, description, io, handler, opts = {}) {
|
|
34
|
+
const inSpec = io.in ?? {};
|
|
35
|
+
return {
|
|
36
|
+
type,
|
|
37
|
+
title: type,
|
|
38
|
+
inputs: Object.fromEntries(Object.entries(inSpec).map(([k, s]) => [k, value(s)])),
|
|
39
|
+
outputs: { [io.out]: value() },
|
|
40
|
+
description,
|
|
41
|
+
// Pure: no scope check in-op. Authorization is the trigger's job (the admin
|
|
42
|
+
// routes stamp `requireAuth: { scopes: ["admin"] }`); `privileged` only flags
|
|
43
|
+
// the data so the validator catches a route that forgets the gate.
|
|
44
|
+
...(opts.sensitivity ? { sensitivity: opts.sensitivity } : {}),
|
|
45
|
+
execute: async (ctx) => {
|
|
46
|
+
const args = {};
|
|
47
|
+
await Promise.all(Object.keys(inSpec).map(async (k) => void (args[k] = ctx.input.has(k) ? await ctx.input.value(k) : undefined)));
|
|
48
|
+
return { [io.out]: await handler(args, identityService(ctx), ctx) };
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Per-op route I/O for the auth pages — which request fields each reads. */
|
|
53
|
+
export const authOpRoutes = {};
|
|
54
|
+
/**
|
|
55
|
+
* An auth-page / redirect op as a PURE function: discrete inputs (the query/body
|
|
56
|
+
* fields it reads + the user-agent for session minting — all decomposed by the
|
|
57
|
+
* workflow), and discrete outputs { body, redirect, cookies, status } the route
|
|
58
|
+
* wires onto boundary.http.response. The op reads the resolved principal +
|
|
59
|
+
* advertised home from ctx — never HTTP shape.
|
|
60
|
+
*/
|
|
61
|
+
function authOp(type, description, io, handler) {
|
|
62
|
+
const query = io.query ?? [];
|
|
63
|
+
const body = io.body ?? [];
|
|
64
|
+
authOpRoutes[type] = { query, body, userAgent: Boolean(io.userAgent) };
|
|
65
|
+
const inputs = {};
|
|
66
|
+
for (const k of [...query, ...body])
|
|
67
|
+
inputs[k] = value(z.string().optional());
|
|
68
|
+
if (io.userAgent)
|
|
69
|
+
inputs.userAgent = value(z.string().optional());
|
|
70
|
+
return {
|
|
71
|
+
type,
|
|
72
|
+
title: type,
|
|
73
|
+
description,
|
|
74
|
+
reusable: false,
|
|
75
|
+
inputs,
|
|
76
|
+
outputs: {
|
|
77
|
+
body: value(),
|
|
78
|
+
redirect: value(z.string()),
|
|
79
|
+
cookies: value(z.record(z.string(), z.unknown())),
|
|
80
|
+
status: value(z.number()),
|
|
81
|
+
},
|
|
82
|
+
execute: async (ctx) => {
|
|
83
|
+
const args = {};
|
|
84
|
+
for (const k of [...query, ...body, ...(io.userAgent ? ["userAgent"] : [])]) {
|
|
85
|
+
args[k] = ctx.input.has(k) ? await ctx.input.value(k) : undefined;
|
|
86
|
+
}
|
|
87
|
+
const svc = identityService(ctx);
|
|
88
|
+
const advertisedHome = ctx.services[AUTH_HOME_URL];
|
|
89
|
+
const req = {
|
|
90
|
+
principal: ctx.principal,
|
|
91
|
+
home: typeof advertisedHome === "string" ? advertisedHome : `${svc.options.mount}/welcome`,
|
|
92
|
+
ctx,
|
|
93
|
+
};
|
|
94
|
+
const r = await handler(args, svc, req);
|
|
95
|
+
return { body: r.body ?? null, redirect: r.redirect ?? null, cookies: r.cookies ?? null, status: r.status ?? null };
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** The session cookie as a structured value the out-gate serializes (HttpOnly + SameSite=Lax by default). */
|
|
100
|
+
const sessionCookie = (svc, token) => ({
|
|
101
|
+
[svc.options.cookieName]: { value: token, maxAge: Math.floor(svc.options.sessionTtlMs / 1000), secure: svc.options.cookieSecure },
|
|
102
|
+
});
|
|
103
|
+
const clearCookie = (svc) => ({
|
|
104
|
+
[svc.options.cookieName]: { value: "", maxAge: 0, secure: svc.options.cookieSecure },
|
|
105
|
+
});
|
|
106
|
+
const page = (body, status) => (status !== undefined ? { body, status } : { body });
|
|
107
|
+
const redirectTo = (location, cookies) => cookies ? { redirect: location, cookies } : { redirect: location };
|
|
108
|
+
const publicUser = (u) => ({
|
|
109
|
+
id: u.id,
|
|
110
|
+
email: u.email,
|
|
111
|
+
name: u.name,
|
|
112
|
+
roles: u.roles.join(", "),
|
|
113
|
+
disabled: u.disabled,
|
|
114
|
+
created: new Date(u.createdAt).toISOString(),
|
|
115
|
+
});
|
|
116
|
+
/* ── whoami ────────────────────────────────────────────────────────────── */
|
|
117
|
+
const whoami = jsonOp("identity.whoami", "The current principal: kind, id, email, roles, scopes.", { out: "whoami" }, (_args, _svc, ctx) => {
|
|
118
|
+
const p = ctx.principal;
|
|
119
|
+
if (p.kind !== "user")
|
|
120
|
+
return { kind: "anonymous" };
|
|
121
|
+
return {
|
|
122
|
+
kind: "user",
|
|
123
|
+
id: p.id,
|
|
124
|
+
email: p.claims?.email,
|
|
125
|
+
name: p.claims?.name,
|
|
126
|
+
roles: p.claims?.roles ?? [],
|
|
127
|
+
scopes: p.scopes ?? [],
|
|
128
|
+
sessionId: p.claims?.sessionId,
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
/* ── admin-surface ops (pure; gated by their routes, tagged `privileged`) ── */
|
|
132
|
+
const usersList = jsonOp("identity.users.list", "List users (admin). Roles flattened for table rendering.", { out: "users" }, async (_args, svc) => (await svc.listUsers()).map(publicUser), { sensitivity: "privileged" });
|
|
133
|
+
const usersInvite = jsonOp("identity.users.invite", 'Invite a user by email (admin): mints an invite token and delivers it via the "identity.deliverToken" hook (console fallback). Args { email, roles? (array or comma string) }.', { in: { email: z.string(), roles: z.unknown().optional() }, out: "result" }, async (args, svc, ctx) => {
|
|
134
|
+
const email = String(args.email ?? "").trim();
|
|
135
|
+
if (!looksLikeEmail(email))
|
|
136
|
+
throw new Error("invalid email");
|
|
137
|
+
const roles = Array.isArray(args.roles)
|
|
138
|
+
? args.roles
|
|
139
|
+
: String(args.roles ?? "")
|
|
140
|
+
.split(",")
|
|
141
|
+
.map((r) => r.trim())
|
|
142
|
+
.filter(Boolean);
|
|
143
|
+
const issued = await svc.issueToken({
|
|
144
|
+
purpose: "invite",
|
|
145
|
+
email,
|
|
146
|
+
ttlMs: 7 * 24 * 60 * 60 * 1000, // invites get a week, not 15 minutes
|
|
147
|
+
data: { roles },
|
|
148
|
+
});
|
|
149
|
+
const { delivered, url } = await deliverToken(ctx, { email, path: issued.path, purpose: "invite" });
|
|
150
|
+
// Undelivered (no email channel): hand the link to the inviting admin —
|
|
151
|
+
// `copy` renders as a copyable field in the admin's result view.
|
|
152
|
+
return { ok: true, email, roles, delivered, ...(delivered ? {} : { copy: url }) };
|
|
153
|
+
}, { sensitivity: "privileged" });
|
|
154
|
+
const usersSetRoles = jsonOp("identity.users.setRoles", "Set a user's roles (admin). Ends the user's sessions — privilege changes re-login. Args { userId, roles }.", { in: { userId: z.string(), roles: z.unknown().optional() }, out: "user" }, async (args, svc) => {
|
|
155
|
+
const roles = Array.isArray(args.roles)
|
|
156
|
+
? args.roles
|
|
157
|
+
: String(args.roles ?? "")
|
|
158
|
+
.split(",")
|
|
159
|
+
.map((r) => r.trim())
|
|
160
|
+
.filter(Boolean);
|
|
161
|
+
return publicUser(await svc.setRoles(String(args.userId), roles));
|
|
162
|
+
}, { sensitivity: "privileged" });
|
|
163
|
+
const usersToggleDisabled = jsonOp("identity.users.toggleDisabled", "Disable / re-enable a user (admin). Disabling revokes all sessions. Args { userId }.", { in: { userId: z.string() }, out: "user" }, async (args, svc) => {
|
|
164
|
+
const user = await svc.getUser(String(args.userId));
|
|
165
|
+
if (!user)
|
|
166
|
+
throw new Error("user not found");
|
|
167
|
+
return publicUser(await svc.setDisabled(user.id, !user.disabled));
|
|
168
|
+
}, { sensitivity: "privileged" });
|
|
169
|
+
const usersRevokeSessions = jsonOp("identity.users.revokeSessions", "Revoke every session of a user (admin) — logs them out everywhere, closes their sockets. Args { userId }.", { in: { userId: z.string() }, out: "result" }, async (args, svc) => {
|
|
170
|
+
await svc.revokeAllForUser(String(args.userId));
|
|
171
|
+
return { ok: true };
|
|
172
|
+
}, { sensitivity: "privileged" });
|
|
173
|
+
const canReadRuns = (s) => typeof s?.list === "function";
|
|
174
|
+
const usersGet = jsonOp("identity.users.get", "One user's profile for the details page (admin). Args { userId }.", { in: { userId: z.string() }, out: "user" }, async (args, svc) => {
|
|
175
|
+
const user = await svc.getUser(String(args.userId));
|
|
176
|
+
if (!user)
|
|
177
|
+
throw new Error("user not found");
|
|
178
|
+
const sessions = await svc.listSessions(user.id);
|
|
179
|
+
const active = sessions.filter((s) => s.revokedAt == null && s.expiresAt > Date.now());
|
|
180
|
+
return {
|
|
181
|
+
email: user.email,
|
|
182
|
+
name: user.name ?? "—",
|
|
183
|
+
roles: user.roles.join(", ") || "—",
|
|
184
|
+
scopes: svc.scopesForRoles(user.roles).join(", ") || "—",
|
|
185
|
+
disabled: user.disabled,
|
|
186
|
+
created: new Date(user.createdAt).toLocaleString(),
|
|
187
|
+
"active sessions": active.length,
|
|
188
|
+
"user id": user.id,
|
|
189
|
+
};
|
|
190
|
+
}, { sensitivity: "privileged" });
|
|
191
|
+
const usersRunStats = jsonOp("identity.users.runStats", "Per-workflow run counts for a user, from the admin's retained run window (admin). Args { userId }.", { in: { userId: z.string() }, out: "stats" }, async (args, svc, ctx) => {
|
|
192
|
+
const user = await svc.getUser(String(args.userId));
|
|
193
|
+
if (!user)
|
|
194
|
+
throw new Error("user not found");
|
|
195
|
+
// The trace sink is the ADMIN's service — feature-detected, so this op
|
|
196
|
+
// degrades to an empty list when the admin isn't installed. Stats cover
|
|
197
|
+
// the sink's retained window (bounded ring buffer), not all time.
|
|
198
|
+
const sink = ctx.services["adminTraceSink"];
|
|
199
|
+
if (!canReadRuns(sink))
|
|
200
|
+
return [];
|
|
201
|
+
const runs = (await sink.list({ limit: 10_000 }))
|
|
202
|
+
// The admin's declarative-page data fetches (`*.route.admin.*`) and other
|
|
203
|
+
// `__`-prefixed plumbing are not the user's workflows — exclude them so
|
|
204
|
+
// they don't drown the real numbers when an admin views their own page.
|
|
205
|
+
.filter((r) => r.principal?.kind === "user" &&
|
|
206
|
+
r.principal.id === user.id &&
|
|
207
|
+
!r.workflowId.startsWith("__") &&
|
|
208
|
+
!r.workflowId.includes(".route.admin."));
|
|
209
|
+
const byWorkflow = new Map();
|
|
210
|
+
for (const r of runs) {
|
|
211
|
+
const agg = byWorkflow.get(r.workflowId) ?? { workflow: r.workflowId, runs: 0, errors: 0, lastRun: 0, totalMs: 0, timed: 0 };
|
|
212
|
+
agg.runs++;
|
|
213
|
+
if (r.status === "error")
|
|
214
|
+
agg.errors++;
|
|
215
|
+
if (r.startTime > agg.lastRun)
|
|
216
|
+
agg.lastRun = r.startTime;
|
|
217
|
+
if (r.durationMs != null) {
|
|
218
|
+
agg.totalMs += r.durationMs;
|
|
219
|
+
agg.timed++;
|
|
220
|
+
}
|
|
221
|
+
byWorkflow.set(r.workflowId, agg);
|
|
222
|
+
}
|
|
223
|
+
return [...byWorkflow.values()]
|
|
224
|
+
.sort((a, b) => b.runs - a.runs)
|
|
225
|
+
.map((a) => ({
|
|
226
|
+
workflow: a.workflow,
|
|
227
|
+
runs: a.runs,
|
|
228
|
+
errors: a.errors,
|
|
229
|
+
"avg ms": a.timed ? Math.round(a.totalMs / a.timed) : "—",
|
|
230
|
+
"last run": new Date(a.lastRun).toLocaleString(),
|
|
231
|
+
}));
|
|
232
|
+
}, { sensitivity: "privileged" });
|
|
233
|
+
const usersLoginLink = jsonOp("identity.users.loginLink", "Mint a single-use sign-in link for a user (admin) — for handing over manually when no email/SMS delivery is wired. Args { userId }.", { in: { userId: z.string() }, out: "result" }, async (args, svc) => {
|
|
234
|
+
const user = await svc.getUser(String(args.userId));
|
|
235
|
+
if (!user)
|
|
236
|
+
throw new Error("user not found");
|
|
237
|
+
if (user.disabled)
|
|
238
|
+
throw new Error("user is disabled — re-enable them first");
|
|
239
|
+
const issued = await svc.issueToken({ purpose: "login", email: user.email });
|
|
240
|
+
return {
|
|
241
|
+
// `copy` is the result-view convention: rendered as a copyable field
|
|
242
|
+
// (the admin prepends its origin for absolute links).
|
|
243
|
+
copy: issued.path,
|
|
244
|
+
email: user.email,
|
|
245
|
+
"valid until": new Date(issued.expiresAt).toLocaleString(),
|
|
246
|
+
note: "single use — send it over any channel",
|
|
247
|
+
};
|
|
248
|
+
}, { sensitivity: "privileged" });
|
|
249
|
+
const settingsGet = jsonOp("identity.settings.get", "Current identity settings (admin): the effective signup policy.", { out: "settings" }, async (_args, svc) => ({ signup: await svc.getSignup() }), { sensitivity: "privileged" });
|
|
250
|
+
const settingsSet = jsonOp("identity.settings.set", 'Update identity settings (admin). Args { signup: "open" | "invite" }. Persisted — survives restarts.', { in: { signup: z.string().optional() }, out: "result" }, async (args, svc) => {
|
|
251
|
+
if (args.signup !== undefined)
|
|
252
|
+
await svc.setSignup(args.signup);
|
|
253
|
+
return { signup: await svc.getSignup() };
|
|
254
|
+
}, { sensitivity: "privileged" });
|
|
255
|
+
const sessionsList = jsonOp("identity.sessions.list", "List sessions, newest first (admin). Args { userId? }.", { in: { userId: z.string().optional() }, out: "sessions" }, async (args, svc) => {
|
|
256
|
+
const sessions = await svc.listSessions(args.userId ? String(args.userId) : undefined);
|
|
257
|
+
const emails = new Map();
|
|
258
|
+
for (const s of sessions) {
|
|
259
|
+
if (!emails.has(s.userId))
|
|
260
|
+
emails.set(s.userId, (await svc.getUser(s.userId))?.email ?? s.userId);
|
|
261
|
+
}
|
|
262
|
+
return sessions.map((s) => ({
|
|
263
|
+
id: s.id,
|
|
264
|
+
user: emails.get(s.userId),
|
|
265
|
+
created: new Date(s.createdAt).toISOString(),
|
|
266
|
+
lastSeen: new Date(s.lastSeenAt).toISOString(),
|
|
267
|
+
status: s.revokedAt != null ? "revoked" : s.expiresAt <= Date.now() ? "expired" : "active",
|
|
268
|
+
userAgent: s.userAgent ?? "",
|
|
269
|
+
}));
|
|
270
|
+
}, { sensitivity: "privileged" });
|
|
271
|
+
const sessionsRevoke = jsonOp("identity.sessions.revoke", "Revoke one session (admin): it stops resolving and its WS sockets close. Args { sessionId }.", { in: { sessionId: z.string() }, out: "result" }, async (args, svc) => {
|
|
272
|
+
await svc.revokeSession(String(args.sessionId));
|
|
273
|
+
return { ok: true };
|
|
274
|
+
}, { sensitivity: "privileged" });
|
|
275
|
+
/* ── auth pages & flows ────────────────────────────────────────────────── */
|
|
276
|
+
const loginPage = authOp("identity.login.page", "Render the login page from the registered login methods. Query { next?, error?, sent? }.", { query: ["next", "error", "sent"] }, (args, svc) => {
|
|
277
|
+
if (args.sent)
|
|
278
|
+
return page(renderSentPage(String(args.sent)));
|
|
279
|
+
return page(renderLoginPage({
|
|
280
|
+
methods: svc.loginMethods(),
|
|
281
|
+
next: args.next,
|
|
282
|
+
error: args.error ? String(args.error) : undefined,
|
|
283
|
+
}));
|
|
284
|
+
});
|
|
285
|
+
const tokenCallback = authOp("identity.token.callback", "The login/invite callback: consumes a single-use token, finds-or-creates the user per the signup policy, mints a session and redirects with the cookie set.", { query: ["t", "next"], userAgent: true }, async (args, svc, req) => {
|
|
286
|
+
const loginUrl = `${svc.options.mount}/login`;
|
|
287
|
+
const raw = String(args.t ?? "");
|
|
288
|
+
if (!raw)
|
|
289
|
+
return redirectTo(`${loginUrl}?error=invalid-token`);
|
|
290
|
+
const token = await svc.consumeToken(raw);
|
|
291
|
+
if (!token || token.purpose === "bootstrap" || !token.emailNorm) {
|
|
292
|
+
// Bootstrap tokens have their own flow; never silently upgrade them here.
|
|
293
|
+
return redirectTo(`${loginUrl}?error=invalid-token`);
|
|
294
|
+
}
|
|
295
|
+
const data = token.data ?? {};
|
|
296
|
+
const invite = token.purpose === "invite";
|
|
297
|
+
const user = await svc.findOrCreateByIdentity({
|
|
298
|
+
provider: typeof data.provider === "string" ? data.provider : "magic-link",
|
|
299
|
+
subject: token.emailNorm,
|
|
300
|
+
email: token.emailNorm,
|
|
301
|
+
// The EFFECTIVE policy (admin-toggleable), not the construction-time option.
|
|
302
|
+
allowCreate: invite || (await svc.getSignup()) === "open",
|
|
303
|
+
roles: invite && Array.isArray(data.roles) ? data.roles : undefined,
|
|
304
|
+
});
|
|
305
|
+
if (!user)
|
|
306
|
+
return redirectTo(`${loginUrl}?error=signup-closed`);
|
|
307
|
+
if (user.disabled)
|
|
308
|
+
return redirectTo(`${loginUrl}?error=account-disabled`);
|
|
309
|
+
const minted = await svc.mintSession(user.id, { userAgent: args.userAgent ?? null });
|
|
310
|
+
const next = safeNextPath(args.next ?? data.next ?? req.home);
|
|
311
|
+
return redirectTo(next, sessionCookie(svc, minted.token));
|
|
312
|
+
});
|
|
313
|
+
const logout = authOp("identity.logout", "Revoke the current session and clear the cookie. POST (same-origin; the CSRF guard makes forged logouts inert).", {}, async (_args, svc, req) => {
|
|
314
|
+
const sessionId = req.principal.kind === "user" ? req.principal.claims?.sessionId : undefined;
|
|
315
|
+
if (typeof sessionId === "string")
|
|
316
|
+
await svc.revokeSession(sessionId);
|
|
317
|
+
return redirectTo(`${svc.options.mount}/login`, clearCookie(svc));
|
|
318
|
+
});
|
|
319
|
+
const welcomePage = authOp("identity.welcome.page", "Post-login landing of last resort (no AUTH_HOME_URL advertised): who you are + sign-out.", {}, (_args, svc, req) => {
|
|
320
|
+
if (req.principal.kind !== "user")
|
|
321
|
+
return redirectTo(`${svc.options.mount}/login`);
|
|
322
|
+
const claims = req.principal.claims ?? {};
|
|
323
|
+
return page(renderWelcomePage({
|
|
324
|
+
email: typeof claims.email === "string" ? claims.email : req.principal.id,
|
|
325
|
+
name: typeof claims.name === "string" ? claims.name : null,
|
|
326
|
+
mount: svc.options.mount,
|
|
327
|
+
}));
|
|
328
|
+
});
|
|
329
|
+
const bootstrapPage = authOp("identity.bootstrap.page", "The first-admin setup form, reached via the one-time URL printed on first boot. Query { t }.", { query: ["t"] }, (args, svc) => {
|
|
330
|
+
const t = String(args.t ?? "");
|
|
331
|
+
if (!t)
|
|
332
|
+
return redirectTo(`${svc.options.mount}/login?error=invalid-token`);
|
|
333
|
+
return page(renderBootstrapPage({ token: t, mount: svc.options.mount }));
|
|
334
|
+
});
|
|
335
|
+
const bootstrapSubmit = authOp("identity.bootstrap.submit", "Consume the bootstrap token, create the first user (bootstrap roles) and sign them in.", { body: ["t", "email", "name"], userAgent: true }, async (args, svc, req) => {
|
|
336
|
+
const t = String(args.t ?? "");
|
|
337
|
+
const email = String(args.email ?? "").trim();
|
|
338
|
+
if (!looksLikeEmail(email)) {
|
|
339
|
+
return page(renderBootstrapPage({ token: t, mount: svc.options.mount, error: "invalid-email" }), 400);
|
|
340
|
+
}
|
|
341
|
+
const token = await svc.consumeToken(t, "bootstrap");
|
|
342
|
+
if (!token)
|
|
343
|
+
return redirectTo(`${svc.options.mount}/login?error=invalid-token`);
|
|
344
|
+
const roles = Array.isArray(token.data?.roles) ? token.data.roles : ["admin"];
|
|
345
|
+
const user = await svc.findOrCreateByIdentity({
|
|
346
|
+
provider: "bootstrap",
|
|
347
|
+
subject: email.toLowerCase(),
|
|
348
|
+
email,
|
|
349
|
+
name: args.name ? String(args.name) : undefined,
|
|
350
|
+
allowCreate: true,
|
|
351
|
+
roles,
|
|
352
|
+
});
|
|
353
|
+
if (!user)
|
|
354
|
+
return redirectTo(`${svc.options.mount}/login?error=invalid-token`);
|
|
355
|
+
const minted = await svc.mintSession(user.id, { userAgent: args.userAgent ?? null });
|
|
356
|
+
return redirectTo(safeNextPath(token.data?.next ?? req.home), sessionCookie(svc, minted.token));
|
|
357
|
+
});
|
|
358
|
+
export const identityOps = [
|
|
359
|
+
whoami,
|
|
360
|
+
usersList,
|
|
361
|
+
usersInvite,
|
|
362
|
+
usersSetRoles,
|
|
363
|
+
usersToggleDisabled,
|
|
364
|
+
usersRevokeSessions,
|
|
365
|
+
usersGet,
|
|
366
|
+
usersRunStats,
|
|
367
|
+
usersLoginLink,
|
|
368
|
+
settingsGet,
|
|
369
|
+
settingsSet,
|
|
370
|
+
sessionsList,
|
|
371
|
+
sessionsRevoke,
|
|
372
|
+
loginPage,
|
|
373
|
+
tokenCallback,
|
|
374
|
+
logout,
|
|
375
|
+
welcomePage,
|
|
376
|
+
bootstrapPage,
|
|
377
|
+
bootstrapSubmit,
|
|
378
|
+
];
|
|
379
|
+
//# sourceMappingURL=ops.js.map
|
package/dist/ops.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.js","sourceRoot":"","sources":["../src/ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,EAAqC,MAAM,kBAAkB,CAAC;AAC9F,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAU/C;;;;;;GAMG;AACH,SAAS,MAAM,CACb,IAAY,EACZ,WAAmB,EACnB,EAAmD,EACnD,OAAoB,EACpB,OAAuC,EAAE;IAEzC,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;IAC3B,OAAO;QACL,IAAI;QACJ,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE;QAC9B,WAAW;QACX,4EAA4E;QAC5E,8EAA8E;QAC9E,mEAAmE;QACnE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACrB,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAClI,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACtE,CAAC;KACF,CAAC;AACJ,CAAC;AAsBD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,YAAY,GAA4E,EAAE,CAAC;AAExG;;;;;;GAMG;AACH,SAAS,MAAM,CACb,IAAY,EACZ,WAAmB,EACnB,EAA8D,EAC9D,OAAoB;IAEpB,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;IAC3B,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;IACvE,MAAM,MAAM,GAA6C,EAAE,CAAC;IAC5D,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;QAAE,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9E,IAAI,EAAE,CAAC,SAAS;QAAE,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;IAClE,OAAO;QACL,IAAI;QACJ,KAAK,EAAE,IAAI;QACX,WAAW;QACX,QAAQ,EAAE,KAAK;QACf,MAAM;QACN,OAAO,EAAE;YACP,IAAI,EAAE,KAAK,EAAE;YACb,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YAC3B,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACjD,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SAC1B;QACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACrB,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC5E,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACpE,CAAC;YACD,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YACnD,MAAM,GAAG,GAAY;gBACnB,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,IAAI,EAAE,OAAO,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,UAAU;gBAC1F,GAAG;aACJ,CAAC;YACF,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACxC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;QACtH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,6GAA6G;AAC7G,MAAM,aAAa,GAAG,CAAC,GAAoB,EAAE,KAAa,EAA2B,EAAE,CAAC,CAAC;IACvF,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE;CAClI,CAAC,CAAC;AACH,MAAM,WAAW,GAAG,CAAC,GAAoB,EAA2B,EAAE,CAAC,CAAC;IACtE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE;CACrF,CAAC,CAAC;AAEH,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,MAAe,EAAgB,EAAE,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACnH,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,OAAiC,EAAgB,EAAE,CACvF,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAErE,MAAM,UAAU,GAAG,CAAC,CAA4G,EAAE,EAAE,CAAC,CAAC;IACpI,EAAE,EAAE,CAAC,CAAC,EAAE;IACR,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,IAAI,EAAE,CAAC,CAAC,IAAI;IACZ,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC,QAAQ;IACpB,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;CAC7C,CAAC,CAAC;AAEH,8EAA8E;AAE9E,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,EAAE,wDAAwD,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IACzI,MAAM,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC;IACxB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACpD,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK;QACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI;QACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;QACtB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS;KAC/B,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,gFAAgF;AAEhF,MAAM,SAAS,GAAG,MAAM,CACtB,qBAAqB,EACrB,0DAA0D,EAC1D,EAAE,GAAG,EAAE,OAAO,EAAE,EAChB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAC7D,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,WAAW,GAAG,MAAM,CACxB,uBAAuB,EACvB,gLAAgL,EAChL,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EAC3E,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACvB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IAC7D,MAAM,KAAK,GACT,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QACvB,CAAC,CAAE,IAAI,CAAC,KAAkB;QAC1B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;aACrB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC;QAClC,OAAO,EAAE,QAAQ;QACjB,KAAK;QACL,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,qCAAqC;QACrE,IAAI,EAAE,EAAE,KAAK,EAAE;KAChB,CAAC,CAAC;IACH,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IACpG,wEAAwE;IACxE,iEAAiE;IACjE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AACpF,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,aAAa,GAAG,MAAM,CAC1B,yBAAyB,EACzB,4GAA4G,EAC5G,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAC1E,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QACrC,CAAC,CAAE,IAAI,CAAC,KAAkB;QAC1B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;aACrB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACpE,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,mBAAmB,GAAG,MAAM,CAChC,+BAA+B,EAC/B,sFAAsF,EACtF,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAC3C,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC7C,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACpE,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,mBAAmB,GAAG,MAAM,CAChC,+BAA+B,EAC/B,2GAA2G,EAC3G,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EAC7C,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,MAAM,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAcF,MAAM,WAAW,GAAG,CAAC,CAAU,EAAqB,EAAE,CAAC,OAAQ,CAA8B,EAAE,IAAI,KAAK,UAAU,CAAC;AAEnH,MAAM,QAAQ,GAAG,MAAM,CACrB,oBAAoB,EACpB,mEAAmE,EACnE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAC3C,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACvF,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,GAAG;QACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG;QACnC,MAAM,EAAE,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG;QACxD,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE;QAClD,iBAAiB,EAAE,MAAM,CAAC,MAAM;QAChC,SAAS,EAAE,IAAI,CAAC,EAAE;KACnB,CAAC;AACJ,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,aAAa,GAAG,MAAM,CAC1B,yBAAyB,EACzB,oGAAoG,EACpG,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAC5C,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACvB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC7C,uEAAuE;IACvE,wEAAwE;IACxE,kEAAkE;IAClE,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAC5C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/C,0EAA0E;QAC1E,wEAAwE;QACxE,wEAAwE;SACvE,MAAM,CACL,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,SAAS,EAAE,IAAI,KAAK,MAAM;QAC5B,CAAC,CAAC,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE;QAC1B,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC;QAC9B,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,CAC1C,CAAC;IACJ,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+G,CAAC;IAC1I,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC7H,GAAG,CAAC,IAAI,EAAE,CAAC;QACX,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO;YAAE,GAAG,CAAC,MAAM,EAAE,CAAC;QACvC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,OAAO;YAAE,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC;QACzD,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;YACzB,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,UAAU,CAAC;YAC5B,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;SAC5B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG;QACzD,UAAU,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE;KACjD,CAAC,CAAC,CAAC;AACR,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,CAC3B,0BAA0B,EAC1B,qIAAqI,EACrI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EAC7C,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC7C,IAAI,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7E,OAAO;QACL,qEAAqE;QACrE,sDAAsD;QACtD,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,aAAa,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE;QAC1D,IAAI,EAAE,uCAAuC;KAC9C,CAAC;AACJ,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,WAAW,GAAG,MAAM,CACxB,uBAAuB,EACvB,iEAAiE,EACjE,EAAE,GAAG,EAAE,UAAU,EAAE,EACnB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,EACzD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,WAAW,GAAG,MAAM,CACxB,uBAAuB,EACvB,sGAAsG,EACtG,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EACxD,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAA2B,CAAC,CAAC;IACrF,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC;AAC3C,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,YAAY,GAAG,MAAM,CACzB,wBAAwB,EACxB,wDAAwD,EACxD,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,EAC1D,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;IACpG,CAAC;IACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1B,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1B,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;QAC5C,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE;QAC9C,MAAM,EAAE,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;QAC1F,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE;KAC7B,CAAC,CAAC,CAAC;AACN,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,CAC3B,0BAA0B,EAC1B,8FAA8F,EAC9F,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,EAChD,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAClB,MAAM,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAChD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC,EACD,EAAE,WAAW,EAAE,YAAY,EAAE,CAC9B,CAAC;AAEF,8EAA8E;AAE9E,MAAM,SAAS,GAAG,MAAM,CACtB,qBAAqB,EACrB,0FAA0F,EAC1F,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,EACpC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACZ,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,IAAI,CACT,eAAe,CAAC;QACd,OAAO,EAAE,GAAG,CAAC,YAAY,EAAE;QAC3B,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;KACnD,CAAC,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,MAAM,aAAa,GAAG,MAAM,CAC1B,yBAAyB,EACzB,6JAA6J,EAC7J,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EACzC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACvB,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,IAAI,CAAC,GAAG;QAAE,OAAO,UAAU,CAAC,GAAG,QAAQ,sBAAsB,CAAC,CAAC;IAE/D,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,WAAW,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QAChE,0EAA0E;QAC1E,OAAO,UAAU,CAAC,GAAG,QAAQ,sBAAsB,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC;IAC1C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,sBAAsB,CAAC;QAC5C,QAAQ,EAAE,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY;QAC1E,OAAO,EAAE,KAAK,CAAC,SAAS;QACxB,KAAK,EAAE,KAAK,CAAC,SAAS;QACtB,6EAA6E;QAC7E,WAAW,EAAE,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC,KAAK,MAAM;QACzD,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,KAAkB,CAAC,CAAC,CAAC,SAAS;KAClF,CAAC,CAAC;IACH,IAAI,CAAC,IAAI;QAAE,OAAO,UAAU,CAAC,GAAG,QAAQ,sBAAsB,CAAC,CAAC;IAChE,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,UAAU,CAAC,GAAG,QAAQ,yBAAyB,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAG,IAAI,CAAC,SAAoB,IAAI,IAAI,EAAE,CAAC,CAAC;IACjG,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9D,OAAO,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC,CACF,CAAC;AAEF,MAAM,MAAM,GAAG,MAAM,CACnB,iBAAiB,EACjB,iHAAiH,EACjH,EAAE,EACF,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACxB,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9F,IAAI,OAAO,SAAS,KAAK,QAAQ;QAAE,MAAM,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACtE,OAAO,UAAU,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AACpE,CAAC,CACF,CAAC;AAEF,MAAM,WAAW,GAAG,MAAM,CACxB,uBAAuB,EACvB,0FAA0F,EAC1F,EAAE,EACF,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IAClB,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC;IAC1C,OAAO,IAAI,CACT,iBAAiB,CAAC;QAChB,KAAK,EAAE,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;QACzE,IAAI,EAAE,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;QAC1D,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK;KACzB,CAAC,CACH,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,MAAM,aAAa,GAAG,MAAM,CAC1B,yBAAyB,EACzB,8FAA8F,EAC9F,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,EAChB,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,4BAA4B,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,mBAAmB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC3E,CAAC,CACF,CAAC;AAEF,MAAM,eAAe,GAAG,MAAM,CAC5B,2BAA2B,EAC3B,wFAAwF,EACxF,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EACjD,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACvB,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,mBAAmB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;IACxG,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,CAAC,KAAK;QAAE,OAAO,UAAU,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,4BAA4B,CAAC,CAAC;IAEhF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAE,KAAK,CAAC,IAAI,CAAC,KAAkB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC5F,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,sBAAsB,CAAC;QAC5C,QAAQ,EAAE,WAAW;QACrB,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE;QAC5B,KAAK;QACL,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAC/C,WAAW,EAAE,IAAI;QACjB,KAAK;KACN,CAAC,CAAC;IACH,IAAI,CAAC,IAAI;QAAE,OAAO,UAAU,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,4BAA4B,CAAC,CAAC;IAE/E,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAG,IAAI,CAAC,SAAoB,IAAI,IAAI,EAAE,CAAC,CAAC;IACjG,OAAO,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAClG,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAmB;IACzC,MAAM;IACN,SAAS;IACT,WAAW;IACX,aAAa;IACb,mBAAmB;IACnB,mBAAmB;IACnB,QAAQ;IACR,aAAa;IACb,cAAc;IACd,WAAW;IACX,WAAW;IACX,YAAY;IACZ,cAAc;IACd,SAAS;IACT,aAAa;IACb,MAAM;IACN,WAAW;IACX,aAAa;IACb,eAAe;CAChB,CAAC"}
|