@icp-sdk/auth 8.0.3 → 9.0.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.
Files changed (85) hide show
  1. package/dist/esm/client/app-delegation-source.d.ts +65 -0
  2. package/dist/esm/client/app-delegation-source.js +58 -0
  3. package/dist/esm/client/app-delegation-source.js.map +1 -0
  4. package/dist/esm/client/app-lock.d.ts +63 -0
  5. package/dist/esm/client/app-lock.js +92 -0
  6. package/dist/esm/client/app-lock.js.map +1 -0
  7. package/dist/esm/client/auth-client.d.ts +270 -53
  8. package/dist/esm/client/auth-client.js +1017 -414
  9. package/dist/esm/client/auth-client.js.map +1 -1
  10. package/dist/esm/client/base64.d.ts +8 -0
  11. package/dist/esm/client/base64.js +28 -0
  12. package/dist/esm/client/base64.js.map +1 -0
  13. package/dist/esm/client/cookie-state-storage.d.ts +59 -0
  14. package/dist/esm/client/cookie-state-storage.js +245 -0
  15. package/dist/esm/client/cookie-state-storage.js.map +1 -0
  16. package/dist/esm/client/credential-storage.d.ts +48 -0
  17. package/dist/esm/client/credential-storage.js +2 -0
  18. package/dist/esm/client/credential-storage.js.map +1 -0
  19. package/dist/esm/client/db.d.ts +6 -1
  20. package/dist/esm/client/db.js +56 -15
  21. package/dist/esm/client/db.js.map +1 -1
  22. package/dist/esm/client/foreground-refresh.d.ts +35 -0
  23. package/dist/esm/client/foreground-refresh.js +83 -0
  24. package/dist/esm/client/foreground-refresh.js.map +1 -0
  25. package/dist/esm/client/idb-credential-storage.d.ts +25 -0
  26. package/dist/esm/client/idb-credential-storage.js +69 -0
  27. package/dist/esm/client/idb-credential-storage.js.map +1 -0
  28. package/dist/esm/client/index.d.ts +14 -3
  29. package/dist/esm/client/index.js +13 -3
  30. package/dist/esm/client/index.js.map +1 -1
  31. package/dist/esm/client/local-credential-storage.d.ts +26 -0
  32. package/dist/esm/client/local-credential-storage.js +59 -0
  33. package/dist/esm/client/local-credential-storage.js.map +1 -0
  34. package/dist/esm/client/memory-credential-storage.d.ts +22 -0
  35. package/dist/esm/client/memory-credential-storage.js +35 -0
  36. package/dist/esm/client/memory-credential-storage.js.map +1 -0
  37. package/dist/esm/client/session-delegation.d.ts +40 -0
  38. package/dist/esm/client/session-delegation.js +100 -0
  39. package/dist/esm/client/session-delegation.js.map +1 -0
  40. package/dist/esm/client/session-identity.d.ts +97 -0
  41. package/dist/esm/client/session-identity.js +392 -0
  42. package/dist/esm/client/session-identity.js.map +1 -0
  43. package/dist/esm/client/session-minter.d.ts +94 -0
  44. package/dist/esm/client/session-minter.js +185 -0
  45. package/dist/esm/client/session-minter.js.map +1 -0
  46. package/dist/esm/client/shared-memory-credential-storage.d.ts +44 -0
  47. package/dist/esm/client/shared-memory-credential-storage.js +243 -0
  48. package/dist/esm/client/shared-memory-credential-storage.js.map +1 -0
  49. package/dist/esm/client/slots.d.ts +59 -0
  50. package/dist/esm/client/slots.js +67 -0
  51. package/dist/esm/client/slots.js.map +1 -0
  52. package/dist/esm/client/sso.d.ts +33 -0
  53. package/dist/esm/client/sso.js +120 -0
  54. package/dist/esm/client/sso.js.map +1 -0
  55. package/dist/esm/client/state-storage.d.ts +135 -0
  56. package/dist/esm/client/state-storage.js +178 -0
  57. package/dist/esm/client/state-storage.js.map +1 -0
  58. package/package.json +2 -1
  59. package/src/client/app-delegation-source.ts +86 -0
  60. package/src/client/app-lock.ts +120 -0
  61. package/src/client/auth-client.ts +1300 -487
  62. package/src/client/base64.ts +28 -0
  63. package/src/client/cookie-state-storage.ts +277 -0
  64. package/src/client/credential-storage.ts +56 -0
  65. package/src/client/db.ts +56 -12
  66. package/src/client/foreground-refresh.ts +92 -0
  67. package/src/client/idb-credential-storage.ts +82 -0
  68. package/src/client/index.ts +24 -8
  69. package/src/client/local-credential-storage.ts +68 -0
  70. package/src/client/memory-credential-storage.ts +41 -0
  71. package/src/client/session-delegation.ts +138 -0
  72. package/src/client/session-identity.ts +510 -0
  73. package/src/client/session-minter.ts +286 -0
  74. package/src/client/shared-memory-credential-storage.ts +303 -0
  75. package/src/client/slots.ts +78 -0
  76. package/src/client/sso.ts +122 -0
  77. package/src/client/state-storage.ts +284 -0
  78. package/dist/esm/client/idle-manager.d.ts +0 -83
  79. package/dist/esm/client/idle-manager.js +0 -100
  80. package/dist/esm/client/idle-manager.js.map +0 -1
  81. package/dist/esm/client/storage.d.ts +0 -51
  82. package/dist/esm/client/storage.js +0 -90
  83. package/dist/esm/client/storage.js.map +0 -1
  84. package/src/client/idle-manager.ts +0 -162
  85. package/src/client/storage.ts +0 -114
@@ -0,0 +1,65 @@
1
+ import type { DerEncodedPublicKey } from '@icp-sdk/core/agent';
2
+ import type { DelegationChain } from '@icp-sdk/core/identity';
3
+ /**
4
+ * Thrown when the canister has no session behind the caller: revoked, expired,
5
+ * pruned, or never one at all.
6
+ *
7
+ * This is the one terminal outcome. Everything else a mint can fail with, a
8
+ * transport error or an internal canister error, leaves the session alone and is
9
+ * worth retrying, so only this type may end a session.
10
+ */
11
+ export declare class SessionGoneError extends Error {
12
+ constructor(message?: string);
13
+ }
14
+ /**
15
+ * Thrown when the session is one this library cannot act for, however healthy it
16
+ * is.
17
+ *
18
+ * The third outcome, and the reason it is not either of the others: the session
19
+ * is neither gone nor worth retrying. Retrying returns the same answer forever,
20
+ * and reporting it as gone would retract a record for a sign-in that is alive,
21
+ * signing every tab on the domain out of it.
22
+ */
23
+ export declare class SessionUnsupportedError extends Error {
24
+ constructor(message: string);
25
+ }
26
+ /**
27
+ * Thrown when a mint answers for an account the caller was not expecting.
28
+ *
29
+ * The session is healthy and the mint succeeded; it is the pairing that is
30
+ * wrong. So it is neither gone nor retryable — asking again returns the same
31
+ * account — and the caller's own record is what has to give way.
32
+ */
33
+ export declare class AccountMismatchError extends Error {
34
+ constructor();
35
+ }
36
+ /**
37
+ * Where {@link SessionIdentity} gets an app delegation from.
38
+ *
39
+ * The identity decides *when* to mint; this decides *how*. Splitting them is
40
+ * what lets the timing be tested without a replica, and what keeps the identity
41
+ * free of any agent or canister id.
42
+ */
43
+ export interface AppDelegationSource {
44
+ /**
45
+ * Mint a delegation from the session to `appPublicKey`.
46
+ *
47
+ * Three outcomes. {@link SessionGoneError} where the session no longer
48
+ * exists, {@link SessionUnsupportedError} where it exists but this library
49
+ * cannot act for it, and anything else where the attempt may be worth
50
+ * repeating.
51
+ */
52
+ mint(appPublicKey: DerEncodedPublicKey): Promise<DelegationChain>;
53
+ }
54
+ /** Whether two DER-encoded keys are the same bytes. */
55
+ export declare const sameKey: (a: Uint8Array, b: Uint8Array) => boolean;
56
+ /** The leaf of a chain: the key it authorises. */
57
+ export declare const delegatesTo: (chain: DelegationChain) => Uint8Array | undefined;
58
+ /**
59
+ * Whether a chain's leaf authorises `keyDer` — the key that would sign with it.
60
+ *
61
+ * A chain paired with a key it does not authorise signs nothing the replica will
62
+ * accept, and fails with a signature error that points at neither half. Every
63
+ * place that holds both halves checks this.
64
+ */
65
+ export declare const chainAuthorisesKey: (chain: DelegationChain, keyDer: Uint8Array) => boolean;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Thrown when the canister has no session behind the caller: revoked, expired,
3
+ * pruned, or never one at all.
4
+ *
5
+ * This is the one terminal outcome. Everything else a mint can fail with, a
6
+ * transport error or an internal canister error, leaves the session alone and is
7
+ * worth retrying, so only this type may end a session.
8
+ */
9
+ export class SessionGoneError extends Error {
10
+ constructor(message = 'The session behind this identity no longer exists') {
11
+ super(message);
12
+ this.name = 'SessionGoneError';
13
+ }
14
+ }
15
+ /**
16
+ * Thrown when the session is one this library cannot act for, however healthy it
17
+ * is.
18
+ *
19
+ * The third outcome, and the reason it is not either of the others: the session
20
+ * is neither gone nor worth retrying. Retrying returns the same answer forever,
21
+ * and reporting it as gone would retract a record for a sign-in that is alive,
22
+ * signing every tab on the domain out of it.
23
+ */
24
+ export class SessionUnsupportedError extends Error {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = 'SessionUnsupportedError';
28
+ }
29
+ }
30
+ /**
31
+ * Thrown when a mint answers for an account the caller was not expecting.
32
+ *
33
+ * The session is healthy and the mint succeeded; it is the pairing that is
34
+ * wrong. So it is neither gone nor retryable — asking again returns the same
35
+ * account — and the caller's own record is what has to give way.
36
+ */
37
+ export class AccountMismatchError extends Error {
38
+ constructor() {
39
+ super('The minted delegation is not for the account this origin acts as');
40
+ this.name = 'AccountMismatchError';
41
+ }
42
+ }
43
+ /** Whether two DER-encoded keys are the same bytes. */
44
+ export const sameKey = (a, b) => a.length === b.length && a.every((byte, i) => byte === b[i]);
45
+ /** The leaf of a chain: the key it authorises. */
46
+ export const delegatesTo = (chain) => chain.delegations[chain.delegations.length - 1]?.delegation.pubkey;
47
+ /**
48
+ * Whether a chain's leaf authorises `keyDer` — the key that would sign with it.
49
+ *
50
+ * A chain paired with a key it does not authorise signs nothing the replica will
51
+ * accept, and fails with a signature error that points at neither half. Every
52
+ * place that holds both halves checks this.
53
+ */
54
+ export const chainAuthorisesKey = (chain, keyDer) => {
55
+ const leaf = delegatesTo(chain);
56
+ return leaf !== undefined && sameKey(new Uint8Array(leaf), new Uint8Array(keyDer));
57
+ };
58
+ //# sourceMappingURL=app-delegation-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-delegation-source.js","sourceRoot":"","sources":["../../../src/client/app-delegation-source.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAO,GAAG,mDAAmD;QACvE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C;QACE,KAAK,CAAC,kEAAkE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAqBD,uDAAuD;AACvD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAa,EAAE,CAAa,EAAW,EAAE,CAC/D,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/D,kDAAkD;AAClD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAsB,EAA0B,EAAE,CAC5E,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAsB,EAAE,MAAkB,EAAW,EAAE;IACxF,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACrF,CAAC,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Runs `mint` while holding a named lock, where the environment has one.
3
+ *
4
+ * The lock is the library coordinating with itself rather than anything a store
5
+ * provides, so a store answers only whether another tab can read it and needs to
6
+ * know nothing about the Web Locks API.
7
+ *
8
+ * Where there is no lock — an older browser, or a store no other tab reads —
9
+ * `mint` runs straight away and every tab mints for itself. That costs calls and
10
+ * never correctness: coordination may only ever suppress a mint, never be
11
+ * required for one.
12
+ *
13
+ * `mint` is handed a signal that fires when the lock is taken away by
14
+ * {@link stealMintLock}. It is the only thing a mint can act on, because a call
15
+ * already sent cannot be recalled: the mint runs to completion and the signal is
16
+ * what tells it to throw away the result rather than store it.
17
+ * @param name - The lock to hold, or `null` to run without one.
18
+ * @param mint - The work to serialise, taking the signal described above.
19
+ */
20
+ export declare function withMintLock<T>(name: string | null, mint: (stolen: AbortSignal) => Promise<T>): Promise<T>;
21
+ /**
22
+ * Takes the lock away from whoever holds it, without waiting for them.
23
+ *
24
+ * What signing out does. Queueing would make a sign-out the user asked for wait
25
+ * on a canister call in another tab, and a mint that finished afterwards would
26
+ * write a credential into the slot the sign-out had just cleared.
27
+ * @param name - The lock to take, or `null` where none is held.
28
+ */
29
+ export declare function stealMintLock(name: string | null): Promise<void>;
30
+ /**
31
+ * A lock this holder keeps until it gives it up, and a signal for losing it.
32
+ *
33
+ * Unlike {@link withMintLock}, what needs guarding here is not one call but a
34
+ * span — a ceremony is several calls and then several writes — so the lock is
35
+ * held across it and released by the holder rather than by a callback returning.
36
+ */
37
+ export interface HeldLock {
38
+ /** Fires when someone else takes this lock away. */
39
+ readonly stolen: AbortSignal;
40
+ /**
41
+ * Gives the lock up.
42
+ *
43
+ * Idempotent, and safe to call after it was stolen: releasing a lock this
44
+ * holder no longer has does nothing.
45
+ */
46
+ release(): void;
47
+ }
48
+ /**
49
+ * Takes a lock away from whoever holds it and keeps it until released.
50
+ *
51
+ * Taken rather than queued for, like {@link stealMintLock} and for the same
52
+ * reason: the newer intent is the one to honour. A user who presses sign in
53
+ * again means the second press, and an origin has one signer window, so the two
54
+ * cannot both proceed anyway. The incumbent finds out through {@link
55
+ * HeldLock.stolen} and throws its result away instead of writing it.
56
+ *
57
+ * Where there is no lock — an older browser, or a caller that passes `null`
58
+ * because nothing else could be holding one — the result never reports a steal
59
+ * and releasing does nothing. That costs coordination, never correctness:
60
+ * coordination may only ever suppress work, never be required for it.
61
+ * @param name - The lock to take, or `null` to take none.
62
+ */
63
+ export declare function stealLock(name: string | null): HeldLock;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Runs `mint` while holding a named lock, where the environment has one.
3
+ *
4
+ * The lock is the library coordinating with itself rather than anything a store
5
+ * provides, so a store answers only whether another tab can read it and needs to
6
+ * know nothing about the Web Locks API.
7
+ *
8
+ * Where there is no lock — an older browser, or a store no other tab reads —
9
+ * `mint` runs straight away and every tab mints for itself. That costs calls and
10
+ * never correctness: coordination may only ever suppress a mint, never be
11
+ * required for one.
12
+ *
13
+ * `mint` is handed a signal that fires when the lock is taken away by
14
+ * {@link stealMintLock}. It is the only thing a mint can act on, because a call
15
+ * already sent cannot be recalled: the mint runs to completion and the signal is
16
+ * what tells it to throw away the result rather than store it.
17
+ * @param name - The lock to hold, or `null` to run without one.
18
+ * @param mint - The work to serialise, taking the signal described above.
19
+ */
20
+ export function withMintLock(name, mint) {
21
+ const locks = globalThis.navigator?.locks;
22
+ if (name === null || locks === undefined) {
23
+ // Nothing can take a lock that was never held, so the signal never fires.
24
+ return mint(new AbortController().signal);
25
+ }
26
+ const stolen = new AbortController();
27
+ const held = locks.request(name, () => mint(stolen.signal));
28
+ // A steal releases this tab's lock and rejects this promise, in this document.
29
+ // That rejection is the only notice another tab's sign-out can deliver, so it
30
+ // is turned into the signal `mint` was given rather than being surfaced: the
31
+ // mint decides what to do about it, and the caller sees whatever it returns.
32
+ held.catch(() => stolen.abort());
33
+ return held;
34
+ }
35
+ /**
36
+ * Takes the lock away from whoever holds it, without waiting for them.
37
+ *
38
+ * What signing out does. Queueing would make a sign-out the user asked for wait
39
+ * on a canister call in another tab, and a mint that finished afterwards would
40
+ * write a credential into the slot the sign-out had just cleared.
41
+ * @param name - The lock to take, or `null` where none is held.
42
+ */
43
+ export async function stealMintLock(name) {
44
+ const locks = globalThis.navigator?.locks;
45
+ if (name === null || locks === undefined)
46
+ return;
47
+ // Granted at once, and released at once: holding it would only make the caller
48
+ // the next thing a queued mint waits for.
49
+ await locks.request(name, { steal: true }, () => undefined).catch(() => undefined);
50
+ }
51
+ /**
52
+ * Takes a lock away from whoever holds it and keeps it until released.
53
+ *
54
+ * Taken rather than queued for, like {@link stealMintLock} and for the same
55
+ * reason: the newer intent is the one to honour. A user who presses sign in
56
+ * again means the second press, and an origin has one signer window, so the two
57
+ * cannot both proceed anyway. The incumbent finds out through {@link
58
+ * HeldLock.stolen} and throws its result away instead of writing it.
59
+ *
60
+ * Where there is no lock — an older browser, or a caller that passes `null`
61
+ * because nothing else could be holding one — the result never reports a steal
62
+ * and releasing does nothing. That costs coordination, never correctness:
63
+ * coordination may only ever suppress work, never be required for it.
64
+ * @param name - The lock to take, or `null` to take none.
65
+ */
66
+ export function stealLock(name) {
67
+ const stolen = new AbortController();
68
+ const locks = globalThis.navigator?.locks;
69
+ if (name === null || locks === undefined) {
70
+ return { stolen: stolen.signal, release: () => { } };
71
+ }
72
+ // The callback holds the lock for as long as what it returns is pending, so
73
+ // this is what `release` settles. A steal rejects the `request` promise in this
74
+ // document, which is the only notice the platform gives.
75
+ let release = () => { };
76
+ const held = new Promise((resolve) => {
77
+ release = resolve;
78
+ });
79
+ void locks
80
+ .request(name, { steal: true }, () => held)
81
+ .catch((error) => {
82
+ // Only a steal, which arrives as an `AbortError`. A request can fail for
83
+ // reasons that are nothing to do with another holder — a frame going away
84
+ // takes its callback with it — and reporting one of those as a steal would
85
+ // tell the caller its work was superseded when nothing had superseded it.
86
+ if (error instanceof DOMException && error.name === 'AbortError') {
87
+ stolen.abort();
88
+ }
89
+ });
90
+ return { stolen: stolen.signal, release: () => release() };
91
+ }
92
+ //# sourceMappingURL=app-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-lock.js","sourceRoot":"","sources":["../../../src/client/app-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAmB,EACnB,IAAyC;IAEzC,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzC,0EAA0E;QAC1E,OAAO,IAAI,CAAC,IAAI,eAAe,EAAE,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAe,CAAC;IAE1E,+EAA+E;IAC/E,8EAA8E;IAC9E,6EAA6E;IAC7E,6EAA6E;IAC7E,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAmB;IACrD,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO;IAEjD,+EAA+E;IAC/E,0CAA0C;IAC1C,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;AACrF,CAAC;AAsBD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAC,IAAmB;IAC3C,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IACtD,CAAC;IAED,4EAA4E;IAC5E,gFAAgF;IAChF,yDAAyD;IACzD,IAAI,OAAO,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QACzC,OAAO,GAAG,OAAO,CAAC;IACpB,CAAC,CAAC,CAAC;IACH,KAAK,KAAK;SACP,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC;SAC1C,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,yEAAyE;QACzE,0EAA0E;QAC1E,2EAA2E;QAC3E,0EAA0E;QAC1E,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjE,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;AAC7D,CAAC"}