@cartridge/controller 0.12.1 → 0.13.3
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/.turbo/turbo-build$colon$deps.log +18 -18
- package/.turbo/turbo-build.log +18 -18
- package/dist/iframe/keychain.d.ts +4 -1
- package/dist/index.js +786 -761
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +25 -8
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +2 -2
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.js +25 -8
- package/dist/node/index.js.map +1 -1
- package/dist/policies.d.ts +2 -2
- package/dist/{provider-BQFas4CN.js → provider-bC9cKItb.js} +143 -128
- package/dist/provider-bC9cKItb.js.map +1 -0
- package/dist/session/provider.d.ts +14 -0
- package/dist/session.js +159 -125
- package/dist/session.js.map +1 -1
- package/dist/stats.html +1 -1
- package/dist/toast/types.d.ts +7 -3
- package/dist/types.d.ts +2 -0
- package/dist/utils.d.ts +8 -0
- package/package.json +30 -25
- package/src/__tests__/controllerDefaults.test.ts +8 -8
- package/src/__tests__/parseChainId.test.ts +12 -4
- package/src/__tests__/toWasmPolicies.test.ts +379 -0
- package/src/controller.ts +8 -15
- package/src/iframe/keychain.ts +32 -0
- package/src/policies.ts +2 -1
- package/src/session/account.ts +8 -1
- package/src/session/provider.ts +63 -9
- package/src/toast/types.ts +7 -3
- package/src/toast/variants/marketplace.ts +6 -3
- package/src/types.ts +2 -0
- package/src/utils.ts +68 -33
- package/LICENSE +0 -16
- package/dist/provider-BQFas4CN.js.map +0 -1
package/dist/session.js
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { WalletAccount as
|
|
2
|
-
import { signerToGuid as h, subscribeCreateSession as
|
|
1
|
+
import { WalletAccount as f, stark as p, ec as m, encode as u } from "starknet";
|
|
2
|
+
import { signerToGuid as h, subscribeCreateSession as _ } from "@cartridge/controller-wasm";
|
|
3
3
|
export * from "@cartridge/controller-wasm";
|
|
4
|
-
import { n as
|
|
5
|
-
import { a as
|
|
4
|
+
import { n as g, B as v, K as w, A as K, c as I } from "./provider-bC9cKItb.js";
|
|
5
|
+
import { a as P, E as J, F as H, I as E, N as z, R as F } from "./provider-bC9cKItb.js";
|
|
6
6
|
import { CartridgeSessionAccount as O } from "@cartridge/controller-wasm/session";
|
|
7
|
-
class
|
|
7
|
+
class x extends f {
|
|
8
8
|
controller;
|
|
9
|
-
constructor(
|
|
10
|
-
rpcUrl:
|
|
11
|
-
privateKey:
|
|
12
|
-
address:
|
|
9
|
+
constructor(e, {
|
|
10
|
+
rpcUrl: s,
|
|
11
|
+
privateKey: t,
|
|
12
|
+
address: r,
|
|
13
13
|
ownerGuid: i,
|
|
14
|
-
chainId:
|
|
15
|
-
expiresAt:
|
|
16
|
-
policies:
|
|
17
|
-
guardianKeyGuid:
|
|
18
|
-
metadataHash:
|
|
19
|
-
sessionKeyGuid:
|
|
14
|
+
chainId: c,
|
|
15
|
+
expiresAt: o,
|
|
16
|
+
policies: a,
|
|
17
|
+
guardianKeyGuid: l,
|
|
18
|
+
metadataHash: n,
|
|
19
|
+
sessionKeyGuid: d
|
|
20
20
|
}) {
|
|
21
21
|
super({
|
|
22
|
-
provider: { nodeUrl:
|
|
23
|
-
walletProvider:
|
|
24
|
-
address:
|
|
22
|
+
provider: { nodeUrl: s },
|
|
23
|
+
walletProvider: e,
|
|
24
|
+
address: r
|
|
25
25
|
}), this.controller = O.newAsRegistered(
|
|
26
|
-
r,
|
|
27
|
-
e,
|
|
28
26
|
s,
|
|
27
|
+
t,
|
|
28
|
+
r,
|
|
29
29
|
i,
|
|
30
|
-
|
|
30
|
+
c,
|
|
31
31
|
{
|
|
32
|
-
expiresAt:
|
|
33
|
-
policies:
|
|
34
|
-
guardianKeyGuid:
|
|
35
|
-
metadataHash:
|
|
36
|
-
sessionKeyGuid:
|
|
32
|
+
expiresAt: o,
|
|
33
|
+
policies: a,
|
|
34
|
+
guardianKeyGuid: l ?? "0x0",
|
|
35
|
+
metadataHash: n ?? "0x0",
|
|
36
|
+
sessionKeyGuid: d
|
|
37
37
|
}
|
|
38
38
|
);
|
|
39
39
|
}
|
|
@@ -49,11 +49,17 @@ class U extends y {
|
|
|
49
49
|
*
|
|
50
50
|
* @returns response from addTransaction
|
|
51
51
|
*/
|
|
52
|
-
async execute(
|
|
53
|
-
|
|
52
|
+
async execute(e) {
|
|
53
|
+
try {
|
|
54
|
+
return await this.controller.executeFromOutside(
|
|
55
|
+
g(e)
|
|
56
|
+
);
|
|
57
|
+
} catch {
|
|
58
|
+
return this.controller.execute(g(e));
|
|
59
|
+
}
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
|
-
class R extends
|
|
62
|
+
class R extends v {
|
|
57
63
|
id = "controller_session";
|
|
58
64
|
name = "Controller Session";
|
|
59
65
|
_chainId;
|
|
@@ -69,79 +75,105 @@ class R extends w {
|
|
|
69
75
|
_signupOptions;
|
|
70
76
|
reopenBrowser = !0;
|
|
71
77
|
constructor({
|
|
72
|
-
rpc:
|
|
73
|
-
chainId:
|
|
74
|
-
policies:
|
|
75
|
-
redirectUrl:
|
|
78
|
+
rpc: e,
|
|
79
|
+
chainId: s,
|
|
80
|
+
policies: t,
|
|
81
|
+
redirectUrl: r,
|
|
76
82
|
disconnectRedirectUrl: i,
|
|
77
|
-
keychainUrl:
|
|
78
|
-
apiUrl:
|
|
79
|
-
signupOptions:
|
|
83
|
+
keychainUrl: c,
|
|
84
|
+
apiUrl: o,
|
|
85
|
+
signupOptions: a
|
|
80
86
|
}) {
|
|
81
87
|
if (super(), this._policies = {
|
|
82
88
|
verified: !1,
|
|
83
|
-
contracts:
|
|
84
|
-
Object.entries(
|
|
85
|
-
|
|
89
|
+
contracts: t.contracts ? Object.fromEntries(
|
|
90
|
+
Object.entries(t.contracts).map(([n, d]) => [
|
|
91
|
+
n,
|
|
86
92
|
{
|
|
87
|
-
...
|
|
88
|
-
methods:
|
|
89
|
-
...
|
|
93
|
+
...d,
|
|
94
|
+
methods: d.methods.map((y) => ({
|
|
95
|
+
...y,
|
|
90
96
|
authorized: !0
|
|
91
97
|
}))
|
|
92
98
|
}
|
|
93
99
|
])
|
|
94
100
|
) : void 0,
|
|
95
|
-
messages:
|
|
96
|
-
...
|
|
101
|
+
messages: t.messages?.map((n) => ({
|
|
102
|
+
...n,
|
|
97
103
|
authorized: !0
|
|
98
104
|
}))
|
|
99
|
-
}, this._rpcUrl =
|
|
100
|
-
const
|
|
101
|
-
if (!
|
|
102
|
-
const
|
|
103
|
-
this._publicKey =
|
|
104
|
-
starknet: { privateKey: u.addHexPrefix(
|
|
105
|
+
}, this._rpcUrl = e, this._chainId = s, this._redirectUrl = r, this._disconnectRedirectUrl = i, this._keychainUrl = c || w, this._apiUrl = o ?? K, this._signupOptions = a, this.tryRetrieveFromQueryOrStorage()) {
|
|
106
|
+
const n = localStorage.getItem("sessionSigner");
|
|
107
|
+
if (!n) throw new Error("failed to get sessionSigner");
|
|
108
|
+
const d = JSON.parse(n);
|
|
109
|
+
this._publicKey = d.pubKey, this._sessionKeyGuid = h({
|
|
110
|
+
starknet: { privateKey: u.addHexPrefix(d.privKey) }
|
|
105
111
|
});
|
|
106
112
|
} else {
|
|
107
|
-
const
|
|
108
|
-
this._publicKey = m.starkCurve.getStarkKey(
|
|
113
|
+
const n = p.randomAddress();
|
|
114
|
+
this._publicKey = m.starkCurve.getStarkKey(n), localStorage.setItem(
|
|
109
115
|
"sessionSigner",
|
|
110
116
|
JSON.stringify({
|
|
111
|
-
privKey:
|
|
117
|
+
privKey: n,
|
|
112
118
|
pubKey: this._publicKey
|
|
113
119
|
})
|
|
114
120
|
), this._sessionKeyGuid = h({
|
|
115
|
-
starknet: { privateKey: u.addHexPrefix(
|
|
121
|
+
starknet: { privateKey: u.addHexPrefix(n) }
|
|
116
122
|
});
|
|
117
123
|
}
|
|
118
124
|
typeof window < "u" && (window.starknet_controller_session = this);
|
|
119
125
|
}
|
|
120
|
-
validatePoliciesSubset(
|
|
121
|
-
if (
|
|
122
|
-
if (!
|
|
123
|
-
for (const [
|
|
124
|
-
const i =
|
|
126
|
+
validatePoliciesSubset(e, s) {
|
|
127
|
+
if (e.contracts) {
|
|
128
|
+
if (!s.contracts) return !1;
|
|
129
|
+
for (const [t, r] of Object.entries(e.contracts)) {
|
|
130
|
+
const i = s.contracts[t];
|
|
125
131
|
if (!i) return !1;
|
|
126
|
-
for (const
|
|
127
|
-
const
|
|
128
|
-
(
|
|
132
|
+
for (const c of r.methods) {
|
|
133
|
+
const o = i.methods.find(
|
|
134
|
+
(a) => a.entrypoint === c.entrypoint
|
|
129
135
|
);
|
|
130
|
-
if (!
|
|
136
|
+
if (!o || !o.authorized) return !1;
|
|
131
137
|
}
|
|
132
138
|
}
|
|
133
139
|
}
|
|
134
|
-
if (
|
|
135
|
-
if (!
|
|
136
|
-
for (const
|
|
137
|
-
const
|
|
138
|
-
(i) => JSON.stringify(i.domain) === JSON.stringify(
|
|
140
|
+
if (e.messages) {
|
|
141
|
+
if (!s.messages) return !1;
|
|
142
|
+
for (const t of e.messages) {
|
|
143
|
+
const r = s.messages.find(
|
|
144
|
+
(i) => JSON.stringify(i.domain) === JSON.stringify(t.domain) && JSON.stringify(i.types) === JSON.stringify(t.types)
|
|
139
145
|
);
|
|
140
|
-
if (!
|
|
146
|
+
if (!r || !r.authorized) return !1;
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
149
|
return !0;
|
|
144
150
|
}
|
|
151
|
+
padBase64(e) {
|
|
152
|
+
const s = e.length % 4;
|
|
153
|
+
return s === 0 ? e : e + "=".repeat(4 - s);
|
|
154
|
+
}
|
|
155
|
+
normalizeSession(e) {
|
|
156
|
+
if (!(e.username === void 0 || e.address === void 0 || e.ownerGuid === void 0 || e.expiresAt === void 0))
|
|
157
|
+
return {
|
|
158
|
+
username: e.username,
|
|
159
|
+
address: e.address,
|
|
160
|
+
ownerGuid: e.ownerGuid,
|
|
161
|
+
transactionHash: e.transactionHash,
|
|
162
|
+
expiresAt: e.expiresAt,
|
|
163
|
+
guardianKeyGuid: e.guardianKeyGuid ?? "0x0",
|
|
164
|
+
metadataHash: e.metadataHash ?? "0x0",
|
|
165
|
+
sessionKeyGuid: e.sessionKeyGuid ?? this._sessionKeyGuid
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
ingestSessionFromRedirect(e) {
|
|
169
|
+
try {
|
|
170
|
+
const s = atob(this.padBase64(e)), t = JSON.parse(s), r = this.normalizeSession(t);
|
|
171
|
+
return r ? (localStorage.setItem("session", JSON.stringify(r)), r) : void 0;
|
|
172
|
+
} catch (s) {
|
|
173
|
+
console.error("Failed to ingest session redirect", s);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
145
177
|
async username() {
|
|
146
178
|
return await this.tryRetrieveFromQueryOrStorage(), this._username;
|
|
147
179
|
}
|
|
@@ -156,108 +188,110 @@ class R extends w {
|
|
|
156
188
|
localStorage.setItem("sessionPolicies", JSON.stringify(this._policies)), localStorage.setItem("lastUsedConnector", this.id);
|
|
157
189
|
try {
|
|
158
190
|
if (this.reopenBrowser) {
|
|
159
|
-
const
|
|
160
|
-
this._publicKey = m.starkCurve.getStarkKey(
|
|
191
|
+
const r = p.randomAddress();
|
|
192
|
+
this._publicKey = m.starkCurve.getStarkKey(r), localStorage.setItem(
|
|
161
193
|
"sessionSigner",
|
|
162
194
|
JSON.stringify({
|
|
163
|
-
privKey:
|
|
195
|
+
privKey: r,
|
|
164
196
|
pubKey: this._publicKey
|
|
165
197
|
})
|
|
166
198
|
), this._sessionKeyGuid = h({
|
|
167
|
-
starknet: { privateKey: u.addHexPrefix(
|
|
199
|
+
starknet: { privateKey: u.addHexPrefix(r) }
|
|
168
200
|
});
|
|
169
201
|
let i = `${this._keychainUrl}/session?public_key=${this._publicKey}&redirect_uri=${this._redirectUrl}&redirect_query_name=startapp&policies=${JSON.stringify(
|
|
170
202
|
this._policies
|
|
171
203
|
)}&rpc_url=${this._rpcUrl}`;
|
|
172
204
|
this._signupOptions && (i += `&signers=${encodeURIComponent(JSON.stringify(this._signupOptions))}`), window.open(i, "_blank");
|
|
173
205
|
}
|
|
174
|
-
const
|
|
206
|
+
const e = await _(
|
|
175
207
|
this._sessionKeyGuid,
|
|
176
208
|
this._apiUrl
|
|
177
|
-
),
|
|
178
|
-
username:
|
|
179
|
-
address:
|
|
180
|
-
ownerGuid:
|
|
181
|
-
expiresAt:
|
|
209
|
+
), s = e.authorization[1], t = {
|
|
210
|
+
username: e.controller.accountID,
|
|
211
|
+
address: e.controller.address,
|
|
212
|
+
ownerGuid: s,
|
|
213
|
+
expiresAt: e.expiresAt,
|
|
182
214
|
guardianKeyGuid: "0x0",
|
|
183
215
|
metadataHash: "0x0",
|
|
184
216
|
sessionKeyGuid: this._sessionKeyGuid
|
|
185
217
|
};
|
|
186
|
-
return localStorage.setItem("session", JSON.stringify(
|
|
187
|
-
} catch (
|
|
188
|
-
throw console.log(
|
|
218
|
+
return localStorage.setItem("session", JSON.stringify(t)), this.tryRetrieveFromQueryOrStorage(), this.account;
|
|
219
|
+
} catch (e) {
|
|
220
|
+
throw console.log(e), e;
|
|
189
221
|
}
|
|
190
222
|
}
|
|
191
|
-
switchStarknetChain(
|
|
223
|
+
switchStarknetChain(e) {
|
|
192
224
|
throw new Error("switchStarknetChain not implemented");
|
|
193
225
|
}
|
|
194
|
-
addStarknetChain(
|
|
226
|
+
addStarknetChain(e) {
|
|
195
227
|
throw new Error("addStarknetChain not implemented");
|
|
196
228
|
}
|
|
197
229
|
disconnect() {
|
|
198
230
|
localStorage.removeItem("sessionSigner"), localStorage.removeItem("session"), localStorage.removeItem("sessionPolicies"), localStorage.removeItem("lastUsedConnector"), this.account = void 0, this._username = void 0;
|
|
199
|
-
const
|
|
200
|
-
|
|
231
|
+
const e = new URL(`${this._keychainUrl}`);
|
|
232
|
+
e.pathname = "disconnect", this._disconnectRedirectUrl && e.searchParams.append(
|
|
201
233
|
"redirect_url",
|
|
202
234
|
this._disconnectRedirectUrl
|
|
203
235
|
);
|
|
204
|
-
const
|
|
205
|
-
if (
|
|
206
|
-
const { resolve:
|
|
236
|
+
const s = window.open(e);
|
|
237
|
+
if (s === null) return Promise.resolve();
|
|
238
|
+
const { resolve: t, promise: r } = Promise.withResolvers();
|
|
207
239
|
function i() {
|
|
208
|
-
|
|
240
|
+
s?.closed && (t(), clearInterval(c));
|
|
209
241
|
}
|
|
210
|
-
const
|
|
211
|
-
return
|
|
242
|
+
const c = setInterval(i, 500);
|
|
243
|
+
return r;
|
|
212
244
|
}
|
|
213
245
|
tryRetrieveFromQueryOrStorage() {
|
|
214
246
|
if (this.account)
|
|
215
247
|
return this.account;
|
|
216
|
-
const
|
|
217
|
-
let
|
|
218
|
-
const
|
|
219
|
-
if (
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const
|
|
227
|
-
|
|
248
|
+
const e = localStorage.getItem("sessionSigner"), s = e ? JSON.parse(e) : null;
|
|
249
|
+
let t = null;
|
|
250
|
+
const r = localStorage.getItem("session");
|
|
251
|
+
if (r) {
|
|
252
|
+
const o = JSON.parse(r), a = this.normalizeSession(o);
|
|
253
|
+
a ? (t = a, localStorage.setItem("session", JSON.stringify(t))) : this.clearStoredSession();
|
|
254
|
+
}
|
|
255
|
+
if (window.location.search.includes("startapp")) {
|
|
256
|
+
const o = new URLSearchParams(window.location.search), a = o.get("startapp");
|
|
257
|
+
if (a) {
|
|
258
|
+
const l = this.ingestSessionFromRedirect(a);
|
|
259
|
+
l && Number(l.expiresAt) !== Number(t?.expiresAt) && (t = l), o.delete("startapp");
|
|
260
|
+
const n = window.location.pathname + (o.toString() ? `?${o.toString()}` : "") + window.location.hash;
|
|
261
|
+
window.history.replaceState({}, document.title, n);
|
|
228
262
|
}
|
|
229
263
|
}
|
|
230
|
-
if (!
|
|
264
|
+
if (!t || !s)
|
|
231
265
|
return;
|
|
232
|
-
const i = parseInt(
|
|
266
|
+
const i = parseInt(t.expiresAt) * 1e3;
|
|
233
267
|
if (Date.now() >= i) {
|
|
234
268
|
this.clearStoredSession();
|
|
235
269
|
return;
|
|
236
270
|
}
|
|
237
|
-
const
|
|
238
|
-
if (
|
|
239
|
-
const
|
|
240
|
-
|
|
271
|
+
const c = localStorage.getItem("sessionPolicies");
|
|
272
|
+
if (c) {
|
|
273
|
+
const o = JSON.parse(
|
|
274
|
+
c
|
|
241
275
|
);
|
|
242
276
|
if (!this.validatePoliciesSubset(
|
|
243
277
|
this._policies,
|
|
244
|
-
|
|
278
|
+
o
|
|
245
279
|
)) {
|
|
246
280
|
this.clearStoredSession();
|
|
247
281
|
return;
|
|
248
282
|
}
|
|
249
283
|
}
|
|
250
|
-
return this._username =
|
|
284
|
+
return this._username = t.username, this.account = new x(this, {
|
|
251
285
|
rpcUrl: this._rpcUrl,
|
|
252
|
-
privateKey:
|
|
253
|
-
address:
|
|
254
|
-
ownerGuid:
|
|
286
|
+
privateKey: s.privKey,
|
|
287
|
+
address: t.address,
|
|
288
|
+
ownerGuid: t.ownerGuid,
|
|
255
289
|
chainId: this._chainId,
|
|
256
|
-
expiresAt: parseInt(
|
|
257
|
-
policies:
|
|
258
|
-
guardianKeyGuid:
|
|
259
|
-
metadataHash:
|
|
260
|
-
sessionKeyGuid:
|
|
290
|
+
expiresAt: parseInt(t.expiresAt),
|
|
291
|
+
policies: I(this._policies),
|
|
292
|
+
guardianKeyGuid: t.guardianKeyGuid,
|
|
293
|
+
metadataHash: t.metadataHash,
|
|
294
|
+
sessionKeyGuid: t.sessionKeyGuid
|
|
261
295
|
}), this.account;
|
|
262
296
|
}
|
|
263
297
|
clearStoredSession() {
|
|
@@ -265,12 +299,12 @@ class R extends w {
|
|
|
265
299
|
}
|
|
266
300
|
}
|
|
267
301
|
export {
|
|
268
|
-
|
|
302
|
+
P as ALL_AUTH_OPTIONS,
|
|
269
303
|
J as EMBEDDED_WALLETS,
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
304
|
+
H as FeeSource,
|
|
305
|
+
E as IMPLEMENTED_AUTH_OPTIONS,
|
|
306
|
+
z as NotReadyToConnect,
|
|
307
|
+
F as ResponseCodes,
|
|
274
308
|
R as default
|
|
275
309
|
};
|
|
276
310
|
//# sourceMappingURL=session.js.map
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sources":["../src/session/account.ts","../src/session/provider.ts"],"sourcesContent":["import { Policy } from \"@cartridge/controller-wasm\";\nimport { CartridgeSessionAccount } from \"@cartridge/controller-wasm/session\";\nimport { Call, InvokeFunctionResponse, WalletAccount } from \"starknet\";\n\nimport { normalizeCalls } from \"../utils\";\nimport BaseProvider from \"../provider\";\n\nexport * from \"../errors\";\nexport * from \"../types\";\n\nexport default class SessionAccount extends WalletAccount {\n public controller: CartridgeSessionAccount;\n\n constructor(\n provider: BaseProvider,\n {\n rpcUrl,\n privateKey,\n address,\n ownerGuid,\n chainId,\n expiresAt,\n policies,\n guardianKeyGuid,\n metadataHash,\n sessionKeyGuid,\n }: {\n rpcUrl: string;\n privateKey: string;\n address: string;\n ownerGuid: string;\n chainId: string;\n expiresAt: number;\n policies: Policy[];\n guardianKeyGuid: string;\n metadataHash: string;\n sessionKeyGuid: string;\n },\n ) {\n super({\n provider: { nodeUrl: rpcUrl },\n walletProvider: provider,\n address,\n });\n\n this.controller = CartridgeSessionAccount.newAsRegistered(\n rpcUrl,\n privateKey,\n address,\n ownerGuid,\n chainId,\n {\n expiresAt,\n policies,\n guardianKeyGuid: guardianKeyGuid ?? \"0x0\",\n metadataHash: metadataHash ?? \"0x0\",\n sessionKeyGuid: sessionKeyGuid,\n },\n );\n }\n\n /**\n * Invoke execute function in account contract\n *\n * @param calls the invocation object or an array of them, containing:\n * - contractAddress - the address of the contract\n * - entrypoint - the entrypoint of the contract\n * - calldata - (defaults to []) the calldata\n * - signature - (defaults to []) the signature\n * @param abis (optional) the abi of the contract for better displaying\n *\n * @returns response from addTransaction\n */\n async execute(calls: Call | Call[]): Promise<InvokeFunctionResponse> {\n return this.controller.execute(normalizeCalls(calls));\n }\n}\n","import { ec, stark, WalletAccount } from \"starknet\";\n\nimport {\n signerToGuid,\n subscribeCreateSession,\n} from \"@cartridge/controller-wasm\";\nimport { SessionPolicies } from \"@cartridge/presets\";\nimport { AddStarknetChainParameters } from \"@starknet-io/types-js\";\nimport { encode } from \"starknet\";\nimport { API_URL, KEYCHAIN_URL } from \"../constants\";\nimport { ParsedSessionPolicies } from \"../policies\";\nimport BaseProvider from \"../provider\";\nimport { AuthOptions } from \"../types\";\nimport { toWasmPolicies } from \"../utils\";\nimport SessionAccount from \"./account\";\n\ninterface SessionRegistration {\n username: string;\n address: string;\n ownerGuid: string;\n transactionHash?: string;\n expiresAt: string;\n guardianKeyGuid: string;\n metadataHash: string;\n sessionKeyGuid: string;\n}\n\nexport type SessionOptions = {\n rpc: string;\n chainId: string;\n policies: SessionPolicies;\n redirectUrl: string;\n disconnectRedirectUrl?: string;\n keychainUrl?: string;\n apiUrl?: string;\n signupOptions?: AuthOptions;\n};\n\nexport default class SessionProvider extends BaseProvider {\n public id = \"controller_session\";\n public name = \"Controller Session\";\n\n protected _chainId: string;\n protected _rpcUrl: string;\n protected _username?: string;\n protected _redirectUrl: string;\n protected _disconnectRedirectUrl?: string;\n protected _policies: ParsedSessionPolicies;\n protected _keychainUrl: string;\n protected _apiUrl: string;\n protected _publicKey: string;\n protected _sessionKeyGuid: string;\n protected _signupOptions?: AuthOptions;\n public reopenBrowser: boolean = true;\n\n constructor({\n rpc,\n chainId,\n policies,\n redirectUrl,\n disconnectRedirectUrl,\n keychainUrl,\n apiUrl,\n signupOptions,\n }: SessionOptions) {\n super();\n\n this._policies = {\n verified: false,\n contracts: policies.contracts\n ? Object.fromEntries(\n Object.entries(policies.contracts).map(([address, contract]) => [\n address,\n {\n ...contract,\n methods: contract.methods.map((method) => ({\n ...method,\n authorized: true,\n })),\n },\n ]),\n )\n : undefined,\n messages: policies.messages?.map((message) => ({\n ...message,\n authorized: true,\n })),\n };\n\n this._rpcUrl = rpc;\n this._chainId = chainId;\n this._redirectUrl = redirectUrl;\n this._disconnectRedirectUrl = disconnectRedirectUrl;\n this._keychainUrl = keychainUrl || KEYCHAIN_URL;\n this._apiUrl = apiUrl ?? API_URL;\n this._signupOptions = signupOptions;\n\n const account = this.tryRetrieveFromQueryOrStorage();\n if (!account) {\n const pk = stark.randomAddress();\n this._publicKey = ec.starkCurve.getStarkKey(pk);\n\n localStorage.setItem(\n \"sessionSigner\",\n JSON.stringify({\n privKey: pk,\n pubKey: this._publicKey,\n }),\n );\n this._sessionKeyGuid = signerToGuid({\n starknet: { privateKey: encode.addHexPrefix(pk) },\n });\n } else {\n const pk = localStorage.getItem(\"sessionSigner\");\n if (!pk) throw new Error(\"failed to get sessionSigner\");\n\n const jsonPk: {\n privKey: string;\n pubKey: string;\n } = JSON.parse(pk);\n\n this._publicKey = jsonPk.pubKey;\n this._sessionKeyGuid = signerToGuid({\n starknet: { privateKey: encode.addHexPrefix(jsonPk.privKey) },\n });\n }\n\n if (typeof window !== \"undefined\") {\n (window as any).starknet_controller_session = this;\n }\n }\n\n private validatePoliciesSubset(\n newPolicies: ParsedSessionPolicies,\n existingPolicies: ParsedSessionPolicies,\n ): boolean {\n if (newPolicies.contracts) {\n if (!existingPolicies.contracts) return false;\n\n for (const [address, contract] of Object.entries(newPolicies.contracts)) {\n const existingContract = existingPolicies.contracts[address];\n if (!existingContract) return false;\n\n for (const method of contract.methods) {\n const existingMethod = existingContract.methods.find(\n (m) => m.entrypoint === method.entrypoint,\n );\n if (!existingMethod || !existingMethod.authorized) return false;\n }\n }\n }\n\n if (newPolicies.messages) {\n if (!existingPolicies.messages) return false;\n\n for (const message of newPolicies.messages) {\n const existingMessage = existingPolicies.messages.find(\n (m) =>\n JSON.stringify(m.domain) === JSON.stringify(message.domain) &&\n JSON.stringify(m.types) === JSON.stringify(message.types),\n );\n if (!existingMessage || !existingMessage.authorized) return false;\n }\n }\n\n return true;\n }\n\n async username() {\n await this.tryRetrieveFromQueryOrStorage();\n return this._username;\n }\n\n async probe(): Promise<WalletAccount | undefined> {\n if (this.account) {\n return this.account;\n }\n\n this.account = this.tryRetrieveFromQueryOrStorage();\n return this.account;\n }\n\n async connect(): Promise<WalletAccount | undefined> {\n if (this.account) {\n return this.account;\n }\n\n this.account = this.tryRetrieveFromQueryOrStorage();\n if (this.account) {\n return this.account;\n }\n\n localStorage.setItem(\"sessionPolicies\", JSON.stringify(this._policies));\n localStorage.setItem(\"lastUsedConnector\", this.id);\n\n try {\n if (this.reopenBrowser) {\n const pk = stark.randomAddress();\n this._publicKey = ec.starkCurve.getStarkKey(pk);\n\n localStorage.setItem(\n \"sessionSigner\",\n JSON.stringify({\n privKey: pk,\n pubKey: this._publicKey,\n }),\n );\n this._sessionKeyGuid = signerToGuid({\n starknet: { privateKey: encode.addHexPrefix(pk) },\n });\n let url = `${\n this._keychainUrl\n }/session?public_key=${this._publicKey}&redirect_uri=${\n this._redirectUrl\n }&redirect_query_name=startapp&policies=${JSON.stringify(\n this._policies,\n )}&rpc_url=${this._rpcUrl}`;\n\n if (this._signupOptions) {\n url += `&signers=${encodeURIComponent(JSON.stringify(this._signupOptions))}`;\n }\n\n window.open(url, \"_blank\");\n }\n\n const sessionResult = await subscribeCreateSession(\n this._sessionKeyGuid,\n this._apiUrl,\n );\n\n // auth is: [shortstring!('authorization-by-registered'), owner_guid]\n const ownerGuid = sessionResult.authorization[1];\n const session: SessionRegistration = {\n username: sessionResult.controller.accountID,\n address: sessionResult.controller.address,\n ownerGuid,\n expiresAt: sessionResult.expiresAt,\n guardianKeyGuid: \"0x0\",\n metadataHash: \"0x0\",\n sessionKeyGuid: this._sessionKeyGuid,\n };\n localStorage.setItem(\"session\", JSON.stringify(session));\n\n this.tryRetrieveFromQueryOrStorage();\n\n return this.account;\n } catch (e) {\n console.log(e);\n throw e;\n }\n }\n\n switchStarknetChain(_chainId: string): Promise<boolean> {\n throw new Error(\"switchStarknetChain not implemented\");\n }\n\n addStarknetChain(_chain: AddStarknetChainParameters): Promise<boolean> {\n throw new Error(\"addStarknetChain not implemented\");\n }\n\n disconnect(): Promise<void> {\n localStorage.removeItem(\"sessionSigner\");\n localStorage.removeItem(\"session\");\n localStorage.removeItem(\"sessionPolicies\");\n localStorage.removeItem(\"lastUsedConnector\");\n this.account = undefined;\n this._username = undefined;\n const disconnectUrl = new URL(`${this._keychainUrl}`);\n disconnectUrl.pathname = \"disconnect\";\n\n this._disconnectRedirectUrl &&\n disconnectUrl.searchParams.append(\n \"redirect_url\",\n this._disconnectRedirectUrl,\n );\n\n const openedWindow = window.open(disconnectUrl);\n if (openedWindow === null) return Promise.resolve();\n\n const { resolve, promise } = Promise.withResolvers<void>();\n function onWindowClose() {\n if (openedWindow?.closed) {\n resolve();\n clearInterval(checkInterval);\n }\n }\n const checkInterval = setInterval(onWindowClose, 500);\n return promise;\n }\n\n tryRetrieveFromQueryOrStorage() {\n if (this.account) {\n return this.account;\n }\n\n const signerString = localStorage.getItem(\"sessionSigner\");\n const signer = signerString ? JSON.parse(signerString) : null;\n let sessionRegistration: SessionRegistration | null = null;\n\n const sessionString = localStorage.getItem(\"session\");\n if (sessionString) {\n sessionRegistration = JSON.parse(sessionString);\n }\n\n if (window.location.search.includes(\"startapp\")) {\n const params = new URLSearchParams(window.location.search);\n const session = params.get(\"startapp\");\n if (session) {\n const possibleNewSession: SessionRegistration = JSON.parse(\n atob(session),\n );\n\n if (\n Number(possibleNewSession.expiresAt) !==\n Number(sessionRegistration?.expiresAt)\n ) {\n sessionRegistration = possibleNewSession;\n localStorage.setItem(\"session\", JSON.stringify(sessionRegistration));\n }\n\n // Remove the session query parameter\n params.delete(\"startapp\");\n const newUrl =\n window.location.pathname +\n (params.toString() ? `?${params.toString()}` : \"\") +\n window.location.hash;\n window.history.replaceState({}, document.title, newUrl);\n }\n }\n\n if (!sessionRegistration || !signer) {\n return;\n }\n\n // Check expiration\n const expirationTime = parseInt(sessionRegistration.expiresAt) * 1000;\n if (Date.now() >= expirationTime) {\n this.clearStoredSession();\n return;\n }\n\n // Check stored policies\n const storedPoliciesStr = localStorage.getItem(\"sessionPolicies\");\n if (storedPoliciesStr) {\n const storedPolicies = JSON.parse(\n storedPoliciesStr,\n ) as ParsedSessionPolicies;\n\n const isValid = this.validatePoliciesSubset(\n this._policies,\n storedPolicies,\n );\n\n if (!isValid) {\n this.clearStoredSession();\n return;\n }\n }\n\n this._username = sessionRegistration.username;\n this.account = new SessionAccount(this, {\n rpcUrl: this._rpcUrl,\n privateKey: signer.privKey,\n address: sessionRegistration.address,\n ownerGuid: sessionRegistration.ownerGuid,\n chainId: this._chainId,\n expiresAt: parseInt(sessionRegistration.expiresAt),\n policies: toWasmPolicies(this._policies),\n guardianKeyGuid: sessionRegistration.guardianKeyGuid,\n metadataHash: sessionRegistration.metadataHash,\n sessionKeyGuid: sessionRegistration.sessionKeyGuid,\n });\n\n return this.account;\n }\n\n private clearStoredSession(): void {\n localStorage.removeItem(\"sessionSigner\");\n localStorage.removeItem(\"session\");\n localStorage.removeItem(\"sessionPolicies\");\n localStorage.removeItem(\"lastUsedConnector\");\n }\n}\n"],"names":["SessionAccount","WalletAccount","provider","rpcUrl","privateKey","address","ownerGuid","chainId","expiresAt","policies","guardianKeyGuid","metadataHash","sessionKeyGuid","CartridgeSessionAccount","calls","normalizeCalls","SessionProvider","BaseProvider","rpc","redirectUrl","disconnectRedirectUrl","keychainUrl","apiUrl","signupOptions","contract","method","message","KEYCHAIN_URL","API_URL","pk","jsonPk","signerToGuid","encode","stark","ec","newPolicies","existingPolicies","existingContract","existingMethod","m","existingMessage","url","sessionResult","subscribeCreateSession","session","e","_chainId","_chain","disconnectUrl","openedWindow","resolve","promise","onWindowClose","checkInterval","signerString","signer","sessionRegistration","sessionString","params","possibleNewSession","newUrl","expirationTime","storedPoliciesStr","storedPolicies","toWasmPolicies"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session.js","sources":["../src/session/account.ts","../src/session/provider.ts"],"sourcesContent":["import { Policy } from \"@cartridge/controller-wasm\";\nimport { CartridgeSessionAccount } from \"@cartridge/controller-wasm/session\";\nimport { Call, InvokeFunctionResponse, WalletAccount } from \"starknet\";\n\nimport { normalizeCalls } from \"../utils\";\nimport BaseProvider from \"../provider\";\n\nexport * from \"../errors\";\nexport * from \"../types\";\n\nexport default class SessionAccount extends WalletAccount {\n public controller: CartridgeSessionAccount;\n\n constructor(\n provider: BaseProvider,\n {\n rpcUrl,\n privateKey,\n address,\n ownerGuid,\n chainId,\n expiresAt,\n policies,\n guardianKeyGuid,\n metadataHash,\n sessionKeyGuid,\n }: {\n rpcUrl: string;\n privateKey: string;\n address: string;\n ownerGuid: string;\n chainId: string;\n expiresAt: number;\n policies: Policy[];\n guardianKeyGuid: string;\n metadataHash: string;\n sessionKeyGuid: string;\n },\n ) {\n super({\n provider: { nodeUrl: rpcUrl },\n walletProvider: provider,\n address,\n });\n\n this.controller = CartridgeSessionAccount.newAsRegistered(\n rpcUrl,\n privateKey,\n address,\n ownerGuid,\n chainId,\n {\n expiresAt,\n policies,\n guardianKeyGuid: guardianKeyGuid ?? \"0x0\",\n metadataHash: metadataHash ?? \"0x0\",\n sessionKeyGuid: sessionKeyGuid,\n },\n );\n }\n\n /**\n * Invoke execute function in account contract\n *\n * @param calls the invocation object or an array of them, containing:\n * - contractAddress - the address of the contract\n * - entrypoint - the entrypoint of the contract\n * - calldata - (defaults to []) the calldata\n * - signature - (defaults to []) the signature\n * @param abis (optional) the abi of the contract for better displaying\n *\n * @returns response from addTransaction\n */\n async execute(calls: Call | Call[]): Promise<InvokeFunctionResponse> {\n try {\n const res = await this.controller.executeFromOutside(\n normalizeCalls(calls),\n );\n return res;\n } catch (e) {\n return this.controller.execute(normalizeCalls(calls));\n }\n }\n}\n","import { ec, stark, WalletAccount } from \"starknet\";\n\nimport {\n signerToGuid,\n subscribeCreateSession,\n} from \"@cartridge/controller-wasm\";\nimport { SessionPolicies } from \"@cartridge/presets\";\nimport { AddStarknetChainParameters } from \"@starknet-io/types-js\";\nimport { encode } from \"starknet\";\nimport { API_URL, KEYCHAIN_URL } from \"../constants\";\nimport { ParsedSessionPolicies } from \"../policies\";\nimport BaseProvider from \"../provider\";\nimport { AuthOptions } from \"../types\";\nimport { toWasmPolicies } from \"../utils\";\nimport SessionAccount from \"./account\";\n\ninterface SessionRegistration {\n username: string;\n address: string;\n ownerGuid: string;\n transactionHash?: string;\n expiresAt: string;\n guardianKeyGuid: string;\n metadataHash: string;\n sessionKeyGuid: string;\n}\n\nexport type SessionOptions = {\n rpc: string;\n chainId: string;\n policies: SessionPolicies;\n redirectUrl: string;\n disconnectRedirectUrl?: string;\n keychainUrl?: string;\n apiUrl?: string;\n signupOptions?: AuthOptions;\n};\n\nexport default class SessionProvider extends BaseProvider {\n public id = \"controller_session\";\n public name = \"Controller Session\";\n\n protected _chainId: string;\n protected _rpcUrl: string;\n protected _username?: string;\n protected _redirectUrl: string;\n protected _disconnectRedirectUrl?: string;\n protected _policies: ParsedSessionPolicies;\n protected _keychainUrl: string;\n protected _apiUrl: string;\n protected _publicKey: string;\n protected _sessionKeyGuid: string;\n protected _signupOptions?: AuthOptions;\n public reopenBrowser: boolean = true;\n\n constructor({\n rpc,\n chainId,\n policies,\n redirectUrl,\n disconnectRedirectUrl,\n keychainUrl,\n apiUrl,\n signupOptions,\n }: SessionOptions) {\n super();\n\n this._policies = {\n verified: false,\n contracts: policies.contracts\n ? Object.fromEntries(\n Object.entries(policies.contracts).map(([address, contract]) => [\n address,\n {\n ...contract,\n methods: contract.methods.map((method) => ({\n ...method,\n authorized: true,\n })),\n },\n ]),\n )\n : undefined,\n messages: policies.messages?.map((message) => ({\n ...message,\n authorized: true,\n })),\n };\n\n this._rpcUrl = rpc;\n this._chainId = chainId;\n this._redirectUrl = redirectUrl;\n this._disconnectRedirectUrl = disconnectRedirectUrl;\n this._keychainUrl = keychainUrl || KEYCHAIN_URL;\n this._apiUrl = apiUrl ?? API_URL;\n this._signupOptions = signupOptions;\n\n const account = this.tryRetrieveFromQueryOrStorage();\n if (!account) {\n const pk = stark.randomAddress();\n this._publicKey = ec.starkCurve.getStarkKey(pk);\n\n localStorage.setItem(\n \"sessionSigner\",\n JSON.stringify({\n privKey: pk,\n pubKey: this._publicKey,\n }),\n );\n this._sessionKeyGuid = signerToGuid({\n starknet: { privateKey: encode.addHexPrefix(pk) },\n });\n } else {\n const pk = localStorage.getItem(\"sessionSigner\");\n if (!pk) throw new Error(\"failed to get sessionSigner\");\n\n const jsonPk: {\n privKey: string;\n pubKey: string;\n } = JSON.parse(pk);\n\n this._publicKey = jsonPk.pubKey;\n this._sessionKeyGuid = signerToGuid({\n starknet: { privateKey: encode.addHexPrefix(jsonPk.privKey) },\n });\n }\n\n if (typeof window !== \"undefined\") {\n (window as any).starknet_controller_session = this;\n }\n }\n\n private validatePoliciesSubset(\n newPolicies: ParsedSessionPolicies,\n existingPolicies: ParsedSessionPolicies,\n ): boolean {\n if (newPolicies.contracts) {\n if (!existingPolicies.contracts) return false;\n\n for (const [address, contract] of Object.entries(newPolicies.contracts)) {\n const existingContract = existingPolicies.contracts[address];\n if (!existingContract) return false;\n\n for (const method of contract.methods) {\n const existingMethod = existingContract.methods.find(\n (m) => m.entrypoint === method.entrypoint,\n );\n if (!existingMethod || !existingMethod.authorized) return false;\n }\n }\n }\n\n if (newPolicies.messages) {\n if (!existingPolicies.messages) return false;\n\n for (const message of newPolicies.messages) {\n const existingMessage = existingPolicies.messages.find(\n (m) =>\n JSON.stringify(m.domain) === JSON.stringify(message.domain) &&\n JSON.stringify(m.types) === JSON.stringify(message.types),\n );\n if (!existingMessage || !existingMessage.authorized) return false;\n }\n }\n\n return true;\n }\n\n private padBase64(value: string): string {\n const padding = value.length % 4;\n if (padding === 0) {\n return value;\n }\n return value + \"=\".repeat(4 - padding);\n }\n\n private normalizeSession(\n session: Partial<SessionRegistration>,\n ): SessionRegistration | undefined {\n if (\n session.username === undefined ||\n session.address === undefined ||\n session.ownerGuid === undefined ||\n session.expiresAt === undefined\n ) {\n return undefined;\n }\n\n return {\n username: session.username,\n address: session.address,\n ownerGuid: session.ownerGuid,\n transactionHash: session.transactionHash,\n expiresAt: session.expiresAt,\n guardianKeyGuid: session.guardianKeyGuid ?? \"0x0\",\n metadataHash: session.metadataHash ?? \"0x0\",\n sessionKeyGuid: session.sessionKeyGuid ?? this._sessionKeyGuid,\n };\n }\n\n public ingestSessionFromRedirect(\n encodedSession: string,\n ): SessionRegistration | undefined {\n try {\n const decoded = atob(this.padBase64(encodedSession));\n const parsed = JSON.parse(decoded) as Partial<SessionRegistration>;\n const normalized = this.normalizeSession(parsed);\n if (!normalized) {\n return undefined;\n }\n localStorage.setItem(\"session\", JSON.stringify(normalized));\n return normalized;\n } catch (e) {\n console.error(\"Failed to ingest session redirect\", e);\n return undefined;\n }\n }\n\n async username() {\n await this.tryRetrieveFromQueryOrStorage();\n return this._username;\n }\n\n async probe(): Promise<WalletAccount | undefined> {\n if (this.account) {\n return this.account;\n }\n\n this.account = this.tryRetrieveFromQueryOrStorage();\n return this.account;\n }\n\n async connect(): Promise<WalletAccount | undefined> {\n if (this.account) {\n return this.account;\n }\n\n this.account = this.tryRetrieveFromQueryOrStorage();\n if (this.account) {\n return this.account;\n }\n\n localStorage.setItem(\"sessionPolicies\", JSON.stringify(this._policies));\n localStorage.setItem(\"lastUsedConnector\", this.id);\n\n try {\n if (this.reopenBrowser) {\n const pk = stark.randomAddress();\n this._publicKey = ec.starkCurve.getStarkKey(pk);\n\n localStorage.setItem(\n \"sessionSigner\",\n JSON.stringify({\n privKey: pk,\n pubKey: this._publicKey,\n }),\n );\n this._sessionKeyGuid = signerToGuid({\n starknet: { privateKey: encode.addHexPrefix(pk) },\n });\n let url = `${\n this._keychainUrl\n }/session?public_key=${this._publicKey}&redirect_uri=${\n this._redirectUrl\n }&redirect_query_name=startapp&policies=${JSON.stringify(\n this._policies,\n )}&rpc_url=${this._rpcUrl}`;\n\n if (this._signupOptions) {\n url += `&signers=${encodeURIComponent(JSON.stringify(this._signupOptions))}`;\n }\n\n window.open(url, \"_blank\");\n }\n\n const sessionResult = await subscribeCreateSession(\n this._sessionKeyGuid,\n this._apiUrl,\n );\n\n // auth is: [shortstring!('authorization-by-registered'), owner_guid]\n const ownerGuid = sessionResult.authorization[1];\n const session: SessionRegistration = {\n username: sessionResult.controller.accountID,\n address: sessionResult.controller.address,\n ownerGuid,\n expiresAt: sessionResult.expiresAt,\n guardianKeyGuid: \"0x0\",\n metadataHash: \"0x0\",\n sessionKeyGuid: this._sessionKeyGuid,\n };\n localStorage.setItem(\"session\", JSON.stringify(session));\n\n this.tryRetrieveFromQueryOrStorage();\n\n return this.account;\n } catch (e) {\n console.log(e);\n throw e;\n }\n }\n\n switchStarknetChain(_chainId: string): Promise<boolean> {\n throw new Error(\"switchStarknetChain not implemented\");\n }\n\n addStarknetChain(_chain: AddStarknetChainParameters): Promise<boolean> {\n throw new Error(\"addStarknetChain not implemented\");\n }\n\n disconnect(): Promise<void> {\n localStorage.removeItem(\"sessionSigner\");\n localStorage.removeItem(\"session\");\n localStorage.removeItem(\"sessionPolicies\");\n localStorage.removeItem(\"lastUsedConnector\");\n this.account = undefined;\n this._username = undefined;\n const disconnectUrl = new URL(`${this._keychainUrl}`);\n disconnectUrl.pathname = \"disconnect\";\n\n this._disconnectRedirectUrl &&\n disconnectUrl.searchParams.append(\n \"redirect_url\",\n this._disconnectRedirectUrl,\n );\n\n const openedWindow = window.open(disconnectUrl);\n if (openedWindow === null) return Promise.resolve();\n\n const { resolve, promise } = Promise.withResolvers<void>();\n function onWindowClose() {\n if (openedWindow?.closed) {\n resolve();\n clearInterval(checkInterval);\n }\n }\n const checkInterval = setInterval(onWindowClose, 500);\n return promise;\n }\n\n tryRetrieveFromQueryOrStorage() {\n if (this.account) {\n return this.account;\n }\n\n const signerString = localStorage.getItem(\"sessionSigner\");\n const signer = signerString ? JSON.parse(signerString) : null;\n let sessionRegistration: SessionRegistration | null = null;\n\n const sessionString = localStorage.getItem(\"session\");\n if (sessionString) {\n const parsed = JSON.parse(sessionString) as Partial<SessionRegistration>;\n const normalized = this.normalizeSession(parsed);\n if (normalized) {\n sessionRegistration = normalized;\n localStorage.setItem(\"session\", JSON.stringify(sessionRegistration));\n } else {\n this.clearStoredSession();\n }\n }\n\n if (window.location.search.includes(\"startapp\")) {\n const params = new URLSearchParams(window.location.search);\n const session = params.get(\"startapp\");\n if (session) {\n const normalizedSession = this.ingestSessionFromRedirect(session);\n if (\n normalizedSession &&\n Number(normalizedSession.expiresAt) !==\n Number(sessionRegistration?.expiresAt)\n ) {\n sessionRegistration = normalizedSession;\n }\n\n // Remove the session query parameter\n params.delete(\"startapp\");\n const newUrl =\n window.location.pathname +\n (params.toString() ? `?${params.toString()}` : \"\") +\n window.location.hash;\n window.history.replaceState({}, document.title, newUrl);\n }\n }\n\n if (!sessionRegistration || !signer) {\n return;\n }\n\n // Check expiration\n const expirationTime = parseInt(sessionRegistration.expiresAt) * 1000;\n if (Date.now() >= expirationTime) {\n this.clearStoredSession();\n return;\n }\n\n // Check stored policies\n const storedPoliciesStr = localStorage.getItem(\"sessionPolicies\");\n if (storedPoliciesStr) {\n const storedPolicies = JSON.parse(\n storedPoliciesStr,\n ) as ParsedSessionPolicies;\n\n const isValid = this.validatePoliciesSubset(\n this._policies,\n storedPolicies,\n );\n\n if (!isValid) {\n this.clearStoredSession();\n return;\n }\n }\n\n this._username = sessionRegistration.username;\n this.account = new SessionAccount(this, {\n rpcUrl: this._rpcUrl,\n privateKey: signer.privKey,\n address: sessionRegistration.address,\n ownerGuid: sessionRegistration.ownerGuid,\n chainId: this._chainId,\n expiresAt: parseInt(sessionRegistration.expiresAt),\n policies: toWasmPolicies(this._policies),\n guardianKeyGuid: sessionRegistration.guardianKeyGuid,\n metadataHash: sessionRegistration.metadataHash,\n sessionKeyGuid: sessionRegistration.sessionKeyGuid,\n });\n\n return this.account;\n }\n\n private clearStoredSession(): void {\n localStorage.removeItem(\"sessionSigner\");\n localStorage.removeItem(\"session\");\n localStorage.removeItem(\"sessionPolicies\");\n localStorage.removeItem(\"lastUsedConnector\");\n }\n}\n"],"names":["SessionAccount","WalletAccount","provider","rpcUrl","privateKey","address","ownerGuid","chainId","expiresAt","policies","guardianKeyGuid","metadataHash","sessionKeyGuid","CartridgeSessionAccount","calls","normalizeCalls","SessionProvider","BaseProvider","rpc","redirectUrl","disconnectRedirectUrl","keychainUrl","apiUrl","signupOptions","contract","method","message","KEYCHAIN_URL","API_URL","pk","jsonPk","signerToGuid","encode","stark","ec","newPolicies","existingPolicies","existingContract","existingMethod","m","existingMessage","value","padding","session","encodedSession","decoded","parsed","normalized","e","url","sessionResult","subscribeCreateSession","_chainId","_chain","disconnectUrl","openedWindow","resolve","promise","onWindowClose","checkInterval","signerString","signer","sessionRegistration","sessionString","params","normalizedSession","newUrl","expirationTime","storedPoliciesStr","storedPolicies","toWasmPolicies"],"mappings":"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"}
|