Skip to content

Commit faa8e52

Browse files
committed
feat: setup session list with tests
have partially passing tests
1 parent 20a0477 commit faa8e52

File tree

12 files changed

+698
-82
lines changed

12 files changed

+698
-82
lines changed

packages/auth-server/components/session/row/Row.vue

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
11
<template>
22
<div class="session-row">
33
<div class="session-id-container">
4-
<div :title="sessionId">
5-
#{{ index }}
6-
</div>
7-
<a
8-
class="session-created-time-ago"
9-
:title="fullCreatedAtDate || ''"
10-
:href="`${defaultChain.blockExplorers?.native.url}/tx/${transactionHash}`"
11-
target="_blank"
4+
<div
5+
:title="sessionHash"
6+
class="truncate"
127
>
13-
{{ createdTimeAgo }}
14-
</a>
8+
{{ sessionHash.slice(0, 10) }}...{{ sessionHash.slice(-8) }}
9+
</div>
10+
<div class="session-signer text-xs text-neutral-500">
11+
Signer: {{ sessionSpec.signer.slice(0, 6) }}...{{ sessionSpec.signer.slice(-4) }}
12+
</div>
1513
</div>
1614
<div class="session-expiry-container">
1715
<SessionRowExpiry
1816
v-if="sessionState"
1917
:status="sessionState.status"
2018
:is-expired="isExpired"
21-
:created-at="timestamp"
19+
:created-at="0"
2220
:expires-at="expiresAt"
2321
:now="now"
2422
/>
2523
</div>
2624
<div class="session-spend-limit-container">
2725
<SessionRowSpendLimit
2826
v-if="sessionState"
29-
:config="session"
27+
:config="sessionSpec"
3028
:state="sessionState"
3129
:now="now"
3230
:is-inactive="isInactive"
@@ -54,24 +52,18 @@
5452

5553
<script setup lang="ts">
5654
import { HandRaisedIcon } from "@heroicons/vue/24/outline";
57-
import type { Hash } from "viem";
55+
import type { Hex } from "viem";
5856
import { SessionKeyValidatorAbi } from "zksync-sso-4337/abi";
5957
import { type SessionConfig, type SessionState, SessionStatus } from "zksync-sso-4337/client";
6058
6159
const props = defineProps<{
62-
session: SessionConfig;
63-
index: number;
64-
sessionId: Hash;
65-
transactionHash: Hash;
66-
blockNumber: bigint;
67-
timestamp: number;
60+
sessionHash: Hex;
61+
sessionSpec: SessionConfig;
6862
}>();
6963
7064
const _now = useNow({ interval: 1000 });
7165
const now = computed(() => _now.value.getTime());
72-
const createdTimeAgo = useTimeAgo(props.timestamp);
73-
const fullCreatedAtDate = computed(() => new Date(props.timestamp).toLocaleString());
74-
const expiresAt = computed<number>(() => bigintDateToDate(props.session.expiresAt).getTime());
66+
const expiresAt = computed<number>(() => bigintDateToDate(props.sessionSpec.expiresAt).getTime());
7567
const timeLeft = computed<number>(() => Math.max(0, expiresAt.value - now.value));
7668
const isExpired = computed(() => timeLeft.value <= 0);
7769
@@ -85,7 +77,7 @@ const {
8577
const client = getClient({ chainId: defaultChain.id });
8678
const paymasterAddress = contractsByChain[defaultChain.id].accountPaymaster;
8779
await client.revokeSession({
88-
sessionId: props.sessionId,
80+
sessionId: props.sessionHash,
8981
paymaster: {
9082
address: paymasterAddress,
9183
},
@@ -102,7 +94,7 @@ const {
10294
address: contractsByChain[defaultChain.id].session,
10395
abi: SessionKeyValidatorAbi,
10496
functionName: "sessionState",
105-
args: [address.value!, props.session],
97+
args: [address.value!, props.sessionSpec],
10698
});
10799
return res as SessionState;
108100
});
@@ -117,7 +109,7 @@ fetchSessionState();
117109
.session-row {
118110
@apply grid px-4 items-center text-sm;
119111
@apply grid-cols-2 gap-y-2 py-4 gap-x-8;
120-
@apply md:grid-cols-[6rem_1fr_1fr_45px] md:py-7 md:h-[100px];
112+
@apply md:grid-cols-[10rem_1fr_1fr_45px] md:py-7 md:h-[100px];
121113
122114
grid-template-areas:
123115
"session-id-container session-buttons-container"

packages/auth-server/composables/useAsync.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ export function useAsync<T extends any[], U>(asyncFunction: AsyncFunction<T, U>)
1616
result.value = response;
1717
return response;
1818
} catch (e) {
19-
const err = e instanceof Error ? e : new Error("An unexpected error occurred.");
19+
// Preserve the original error message and stack trace
20+
const err = e instanceof Error ? e : new Error(String(e) || "An unexpected error occurred.");
2021
error.value = err;
21-
if (err) {
22-
throw err;
23-
}
22+
// Log the error for debugging
23+
console.error("[useAsync] Error in async function:", err);
24+
throw err;
2425
} finally {
2526
inProgress.value = false;
2627
}

packages/auth-server/pages/dashboard/sessions.vue

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,29 @@
3636
</template>
3737
</CommonAlert>
3838

39+
<CommonAlert
40+
v-if="sessionsFetchError"
41+
class="mb-4"
42+
type="error"
43+
>
44+
<template #icon>
45+
<InformationCircleIcon aria-hidden="true" />
46+
</template>
47+
<template #default>
48+
<p class="text-sm font-semibold">
49+
Failed to load sessions
50+
</p>
51+
<p class="text-xs mt-1">
52+
{{ sessionsFetchError.message }}
53+
</p>
54+
</template>
55+
</CommonAlert>
56+
3957
<span
40-
v-if="!sessions?.length && !sessionsInProgress"
41-
class="font-thin block text-2xl text-neutral-500 text-center"
42-
>No sessions yet...</span>
58+
v-if="!sessions?.length && !sessionsInProgress && !sessionsFetchError"
59+
data-testid="empty-sessions-message"
60+
class="font-thin block text 2xl text-neutral-500 text-center"
61+
>No active sessions...</span>
4362
<div
4463
v-else
4564
class="border rounded-3xl divide-y bg-white border-neutral-200 divide-neutral-200 dark:bg-neutral-950 dark:border-neutral-900 dark:divide-neutral-900"
@@ -52,76 +71,54 @@
5271
</template>
5372
<template v-else>
5473
<SessionRow
55-
v-for="(item, index) in (sessions || [])"
56-
:key="item.sessionId"
57-
:index="((sessions?.length || 0) - index)"
58-
:session-id="item.sessionId"
59-
:session="item.session"
60-
:transaction-hash="item.transactionHash"
61-
:block-number="item.blockNumber"
62-
:timestamp="item.timestamp"
74+
v-for="item in (sessions || [])"
75+
:key="item.sessionHash"
76+
:session-hash="item.sessionHash"
77+
:session-spec="item.sessionSpec"
6378
/>
6479
</template>
6580
</div>
66-
67-
<CommonAlert
68-
v-if="defaultChain.id === localhost.id && sessions?.length"
69-
class="mt-4"
70-
>
71-
<template #icon>
72-
<InformationCircleIcon aria-hidden="true" />
73-
</template>
74-
<template #default>
75-
<p class="text-sm">
76-
Timestamps on {{ localhost.name }} start from 0 and incremented by 1 with each block. Therefore session time isn't accurate.
77-
</p>
78-
</template>
79-
</CommonAlert>
8081
</div>
8182
</template>
8283

8384
<script setup lang="ts">
8485
import { InformationCircleIcon } from "@heroicons/vue/20/solid";
8586
import type { Hex } from "viem";
86-
import { localhost } from "viem/chains";
87-
import { SessionKeyValidatorAbi } from "zksync-sso-4337/abi";
87+
import { listActiveSessions } from "zksync-sso-4337";
8888
import type { SessionConfig } from "zksync-sso-4337/client";
8989
90-
const { defaultChain, getPublicClient } = useClientStore();
90+
const { defaultChain } = useClientStore();
9191
const { address } = storeToRefs(useAccountStore());
9292
9393
const {
9494
result: sessions,
9595
inProgress: sessionsInProgress,
96-
// error: sessionsFetchError,
96+
error: sessionsFetchError,
9797
execute: sessionsFetch,
9898
} = useAsync(async () => {
9999
const contracts = contractsByChain[defaultChain.id];
100-
const publicClient = getPublicClient({ chainId: defaultChain.id });
101-
const logs = await publicClient.getContractEvents({
102-
abi: SessionKeyValidatorAbi,
103-
address: contracts.session,
104-
eventName: "SessionCreated",
105-
args: {
106-
account: address.value,
100+
101+
// Get RPC URL from the chain configuration
102+
const rpcUrl = defaultChain.rpcUrls.default.http[0];
103+
104+
// Use the new listActiveSessions function from the SDK
105+
const { sessions: activeSessions } = await listActiveSessions({
106+
account: address.value,
107+
rpcUrl,
108+
contracts: {
109+
sessionValidator: contracts.sessionValidator,
110+
entryPoint: "0x0000000071727De22E5E9d8BAf0edAc6f37da032", // Standard EntryPoint v0.8
111+
accountFactory: contracts.factory,
112+
webauthnValidator: contracts.webauthnValidator,
113+
eoaValidator: contracts.eoaValidator,
114+
guardianExecutor: contracts.guardianExecutor || "0x0000000000000000000000000000000000000000",
107115
},
108-
fromBlock: 0n,
109116
});
110-
const data = logs
111-
.filter((log) => log.args.sessionSpec && log.args.sessionHash)
112-
.map((log) => ({
113-
session: log.args.sessionSpec! as SessionConfig,
114-
sessionId: log.args.sessionHash!,
115-
transactionHash: log.transactionHash,
116-
blockNumber: log.blockNumber,
117-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
118-
timestamp: new Date(parseInt((log as any).blockTimestamp as Hex, 16) * 1000).getTime(),
119-
})).sort((a, b) => {
120-
if (a.blockNumber < b.blockNumber) return 1;
121-
if (a.blockNumber > b.blockNumber) return -1;
122-
return 0;
123-
});
124-
return data;
117+
118+
return activeSessions.map((item: { sessionHash: Hex; sessionSpec: SessionConfig }) => ({
119+
sessionHash: item.sessionHash,
120+
sessionSpec: item.sessionSpec,
121+
}));
125122
});
126123
127124
sessionsFetch();

packages/auth-server/project.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@
9393
"command": "PW_TEST_HTML_REPORT_OPEN=never pnpm exec playwright test guardian.spec.ts --config playwright.config.ts"
9494
},
9595
"dependsOn": ["build:local"]
96+
},
97+
"e2e:session": {
98+
"executor": "nx:run-commands",
99+
"options": {
100+
"cwd": "packages/auth-server",
101+
"command": "PW_TEST_HTML_REPORT_OPEN=never pnpm exec playwright test sessions.spec.ts --config playwright.config.ts"
102+
},
103+
"dependsOn": ["build:local"]
96104
}
97105
}
98106
}

0 commit comments

Comments
 (0)