@cartridge/controller 0.13.4 → 0.13.6

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 (40) hide show
  1. package/.turbo/turbo-build$colon$deps.log +41 -21
  2. package/.turbo/turbo-build.log +40 -20
  3. package/HEADLESS_MODE.md +113 -0
  4. package/dist/controller.d.ts +9 -2
  5. package/dist/errors.d.ts +10 -0
  6. package/dist/iframe/security.d.ts +10 -0
  7. package/dist/index-BdTFKueB.js +1072 -0
  8. package/dist/index-BdTFKueB.js.map +1 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.js +2273 -2524
  11. package/dist/index.js.map +1 -1
  12. package/dist/node/index.cjs +30 -5
  13. package/dist/node/index.cjs.map +1 -1
  14. package/dist/node/index.d.cts +11 -1
  15. package/dist/node/index.d.ts +11 -1
  16. package/dist/node/index.js +29 -7
  17. package/dist/node/index.js.map +1 -1
  18. package/dist/session/provider.d.ts +8 -2
  19. package/dist/session.js +141 -139
  20. package/dist/session.js.map +1 -1
  21. package/dist/stats.html +1 -1
  22. package/dist/types.d.ts +20 -1
  23. package/dist/utils.d.ts +5 -3
  24. package/package.json +4 -3
  25. package/src/__tests__/asWalletStandard.test.ts +87 -0
  26. package/src/__tests__/headlessConnectApproval.test.ts +97 -0
  27. package/src/__tests__/iframeSecurity.test.ts +84 -0
  28. package/src/__tests__/parseChainId.test.ts +1 -1
  29. package/src/__tests__/toWasmPolicies.test.ts +89 -40
  30. package/src/controller.ts +165 -13
  31. package/src/errors.ts +30 -0
  32. package/src/iframe/base.ts +14 -3
  33. package/src/iframe/keychain.ts +8 -5
  34. package/src/iframe/security.ts +48 -0
  35. package/src/index.ts +1 -0
  36. package/src/session/provider.ts +77 -48
  37. package/src/types.ts +30 -1
  38. package/src/utils.ts +21 -7
  39. package/dist/provider-DSqqvDee.js +0 -369
  40. package/dist/provider-DSqqvDee.js.map +0 -1
package/dist/session.js CHANGED
@@ -1,39 +1,39 @@
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";
1
+ import { WalletAccount as y, stark as u, ec as p, encode as l } from "starknet";
2
+ import { signerToGuid as h, subscribeCreateSession as f } from "@cartridge/controller-wasm";
3
3
  export * from "@cartridge/controller-wasm";
4
- import { n as g, B as v, K as w, A as K, c as I } from "./provider-DSqqvDee.js";
5
- import { a as P, E as J, F as H, I as E, N as z, R as F } from "./provider-DSqqvDee.js";
4
+ import { n as m, B as w, f as g, K as v, A as I, w as K, g as U, e as x } from "./index-BdTFKueB.js";
5
+ import { b as H, E as J, F as $, H as z, a as F, c as L, I as T, N as B, R as D } from "./index-BdTFKueB.js";
6
6
  import { CartridgeSessionAccount as O } from "@cartridge/controller-wasm/session";
7
- class x extends f {
7
+ class N extends y {
8
8
  controller;
9
9
  constructor(e, {
10
- rpcUrl: s,
11
- privateKey: t,
12
- address: r,
13
- ownerGuid: i,
14
- chainId: c,
10
+ rpcUrl: t,
11
+ privateKey: s,
12
+ address: i,
13
+ ownerGuid: r,
14
+ chainId: a,
15
15
  expiresAt: o,
16
- policies: a,
17
- guardianKeyGuid: l,
18
- metadataHash: n,
19
- sessionKeyGuid: d
16
+ policies: n,
17
+ guardianKeyGuid: c,
18
+ metadataHash: d,
19
+ sessionKeyGuid: _
20
20
  }) {
21
21
  super({
22
- provider: { nodeUrl: s },
22
+ provider: { nodeUrl: t },
23
23
  walletProvider: e,
24
- address: r
24
+ address: i
25
25
  }), this.controller = O.newAsRegistered(
26
- s,
27
26
  t,
28
- r,
27
+ s,
29
28
  i,
30
- c,
29
+ r,
30
+ a,
31
31
  {
32
32
  expiresAt: o,
33
- policies: a,
34
- guardianKeyGuid: l ?? "0x0",
35
- metadataHash: n ?? "0x0",
36
- sessionKeyGuid: d
33
+ policies: n,
34
+ guardianKeyGuid: c ?? "0x0",
35
+ metadataHash: d ?? "0x0",
36
+ sessionKeyGuid: _
37
37
  }
38
38
  );
39
39
  }
@@ -52,14 +52,14 @@ class x extends f {
52
52
  async execute(e) {
53
53
  try {
54
54
  return await this.controller.executeFromOutside(
55
- g(e)
55
+ m(e)
56
56
  );
57
57
  } catch {
58
- return this.controller.execute(g(e));
58
+ return this.controller.execute(m(e));
59
59
  }
60
60
  }
61
61
  }
62
- class R extends v {
62
+ class k extends w {
63
63
  id = "controller_session";
64
64
  name = "Controller Session";
65
65
  _chainId;
@@ -68,6 +68,8 @@ class R extends v {
68
68
  _redirectUrl;
69
69
  _disconnectRedirectUrl;
70
70
  _policies;
71
+ _preset;
72
+ _ready;
71
73
  _keychainUrl;
72
74
  _apiUrl;
73
75
  _publicKey;
@@ -76,81 +78,82 @@ class R extends v {
76
78
  reopenBrowser = !0;
77
79
  constructor({
78
80
  rpc: e,
79
- chainId: s,
80
- policies: t,
81
- redirectUrl: r,
82
- disconnectRedirectUrl: i,
83
- keychainUrl: c,
84
- apiUrl: o,
85
- signupOptions: a
81
+ chainId: t,
82
+ policies: s,
83
+ preset: i,
84
+ shouldOverridePresetPolicies: r,
85
+ redirectUrl: a,
86
+ disconnectRedirectUrl: o,
87
+ keychainUrl: n,
88
+ apiUrl: c,
89
+ signupOptions: d
86
90
  }) {
87
- if (super(), this._policies = {
88
- verified: !1,
89
- contracts: t.contracts ? Object.fromEntries(
90
- Object.entries(t.contracts).map(([n, d]) => [
91
- n,
92
- {
93
- ...d,
94
- methods: d.methods.map((y) => ({
95
- ...y,
96
- authorized: !0
97
- }))
98
- }
99
- ])
100
- ) : void 0,
101
- messages: t.messages?.map((n) => ({
102
- ...n,
103
- authorized: !0
104
- }))
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) }
91
+ if (super(), !s && !i)
92
+ throw new Error("Either `policies` or `preset` must be provided");
93
+ (!i || r) && s ? this._policies = g(s) : (this._preset = i, s && console.warn(
94
+ "[Controller] Both `preset` and `policies` provided to SessionProvider. Policies are ignored when preset is set. Use `shouldOverridePresetPolicies: true` to override."
95
+ ), this._policies = { verified: !1 }), this._rpcUrl = e, this._chainId = t, this._redirectUrl = a, this._disconnectRedirectUrl = o, this._keychainUrl = n || v, this._apiUrl = c ?? I, this._signupOptions = d, this._ready = this._init(), typeof window < "u" && (window.starknet_controller_session = this);
96
+ }
97
+ async _init() {
98
+ if (this._preset) {
99
+ const t = await K(this._preset);
100
+ if (!t)
101
+ throw new Error(`Failed to load preset: ${this._preset}`);
102
+ const s = U(t, this._chainId);
103
+ if (!s)
104
+ throw new Error(
105
+ `No policies found for chain ${this._chainId} in preset ${this._preset}`
106
+ );
107
+ this._policies = g(s);
108
+ }
109
+ if (this.tryRetrieveFromQueryOrStorage()) {
110
+ const t = localStorage.getItem("sessionSigner");
111
+ if (!t) throw new Error("failed to get sessionSigner");
112
+ const s = JSON.parse(t);
113
+ this._publicKey = s.pubKey, this._sessionKeyGuid = h({
114
+ starknet: { privateKey: l.addHexPrefix(s.privKey) }
111
115
  });
112
116
  } else {
113
- const n = p.randomAddress();
114
- this._publicKey = m.starkCurve.getStarkKey(n), localStorage.setItem(
117
+ const t = u.randomAddress();
118
+ this._publicKey = p.starkCurve.getStarkKey(t), localStorage.setItem(
115
119
  "sessionSigner",
116
120
  JSON.stringify({
117
- privKey: n,
121
+ privKey: t,
118
122
  pubKey: this._publicKey
119
123
  })
120
124
  ), this._sessionKeyGuid = h({
121
- starknet: { privateKey: u.addHexPrefix(n) }
125
+ starknet: { privateKey: l.addHexPrefix(t) }
122
126
  });
123
127
  }
124
- typeof window < "u" && (window.starknet_controller_session = this);
125
128
  }
126
- validatePoliciesSubset(e, s) {
129
+ validatePoliciesSubset(e, t) {
127
130
  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];
131
- if (!i) return !1;
132
- for (const c of r.methods) {
133
- const o = i.methods.find(
134
- (a) => a.entrypoint === c.entrypoint
131
+ if (!t.contracts) return !1;
132
+ for (const [s, i] of Object.entries(e.contracts)) {
133
+ const r = t.contracts[s];
134
+ if (!r) return !1;
135
+ for (const a of i.methods) {
136
+ const o = r.methods.find(
137
+ (n) => n.entrypoint === a.entrypoint
135
138
  );
136
139
  if (!o || !o.authorized) return !1;
137
140
  }
138
141
  }
139
142
  }
140
143
  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)
144
+ if (!t.messages) return !1;
145
+ for (const s of e.messages) {
146
+ const i = t.messages.find(
147
+ (r) => JSON.stringify(r.domain) === JSON.stringify(s.domain) && JSON.stringify(r.types) === JSON.stringify(s.types)
145
148
  );
146
- if (!r || !r.authorized) return !1;
149
+ if (!i || !i.authorized) return !1;
147
150
  }
148
151
  }
149
152
  return !0;
150
153
  }
151
154
  padBase64(e) {
152
- const s = e.length % 4;
153
- return s === 0 ? e : e + "=".repeat(4 - s);
155
+ const t = e.length % 4;
156
+ return t === 0 ? e : e + "=".repeat(4 - t);
154
157
  }
155
158
  normalizeSession(e) {
156
159
  if (!(e.username === void 0 || e.address === void 0 || e.ownerGuid === void 0 || e.expiresAt === void 0))
@@ -167,55 +170,51 @@ class R extends v {
167
170
  }
168
171
  ingestSessionFromRedirect(e) {
169
172
  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);
173
+ const t = atob(this.padBase64(e)), s = JSON.parse(t), i = this.normalizeSession(s);
174
+ return i ? (localStorage.setItem("session", JSON.stringify(i)), i) : void 0;
175
+ } catch (t) {
176
+ console.error("Failed to ingest session redirect", t);
174
177
  return;
175
178
  }
176
179
  }
177
180
  async username() {
178
- return await this.tryRetrieveFromQueryOrStorage(), this._username;
181
+ return await this._ready, this._username;
179
182
  }
180
183
  async probe() {
181
- return this.account ? this.account : (this.account = this.tryRetrieveFromQueryOrStorage(), this.account);
184
+ return await this._ready, this.account;
182
185
  }
183
186
  async connect() {
184
- if (this.account)
185
- return this.account;
186
- if (this.account = this.tryRetrieveFromQueryOrStorage(), this.account)
187
+ if (await this._ready, this.account)
187
188
  return this.account;
188
189
  localStorage.setItem("sessionPolicies", JSON.stringify(this._policies)), localStorage.setItem("lastUsedConnector", this.id);
189
190
  try {
190
191
  if (this.reopenBrowser) {
191
- const r = p.randomAddress();
192
- this._publicKey = m.starkCurve.getStarkKey(r), localStorage.setItem(
192
+ const i = u.randomAddress();
193
+ this._publicKey = p.starkCurve.getStarkKey(i), localStorage.setItem(
193
194
  "sessionSigner",
194
195
  JSON.stringify({
195
- privKey: r,
196
+ privKey: i,
196
197
  pubKey: this._publicKey
197
198
  })
198
199
  ), this._sessionKeyGuid = h({
199
- starknet: { privateKey: u.addHexPrefix(r) }
200
+ starknet: { privateKey: l.addHexPrefix(i) }
200
201
  });
201
- let i = `${this._keychainUrl}/session?public_key=${this._publicKey}&redirect_uri=${this._redirectUrl}&redirect_query_name=startapp&policies=${JSON.stringify(
202
- this._policies
203
- )}&rpc_url=${this._rpcUrl}`;
204
- this._signupOptions && (i += `&signers=${encodeURIComponent(JSON.stringify(this._signupOptions))}`), window.open(i, "_blank");
202
+ let r = `${this._keychainUrl}/session?public_key=${this._publicKey}&redirect_uri=${this._redirectUrl}&redirect_query_name=startapp&rpc_url=${this._rpcUrl}`;
203
+ this._preset ? r += `&preset=${encodeURIComponent(this._preset)}` : r += `&policies=${encodeURIComponent(JSON.stringify(this._policies))}`, this._signupOptions && (r += `&signers=${encodeURIComponent(JSON.stringify(this._signupOptions))}`), window.open(r, "_blank");
205
204
  }
206
- const e = await _(
205
+ const e = await f(
207
206
  this._sessionKeyGuid,
208
207
  this._apiUrl
209
- ), s = e.authorization[1], t = {
208
+ ), t = e.authorization[1], s = {
210
209
  username: e.controller.accountID,
211
210
  address: e.controller.address,
212
- ownerGuid: s,
211
+ ownerGuid: t,
213
212
  expiresAt: e.expiresAt,
214
213
  guardianKeyGuid: "0x0",
215
214
  metadataHash: "0x0",
216
215
  sessionKeyGuid: this._sessionKeyGuid
217
216
  };
218
- return localStorage.setItem("session", JSON.stringify(t)), this.tryRetrieveFromQueryOrStorage(), this.account;
217
+ return localStorage.setItem("session", JSON.stringify(s)), this.tryRetrieveFromQueryOrStorage(), this.account;
219
218
  } catch (e) {
220
219
  throw console.log(e), e;
221
220
  }
@@ -227,51 +226,51 @@ class R extends v {
227
226
  throw new Error("addStarknetChain not implemented");
228
227
  }
229
228
  disconnect() {
230
- localStorage.removeItem("sessionSigner"), localStorage.removeItem("session"), localStorage.removeItem("sessionPolicies"), localStorage.removeItem("lastUsedConnector"), this.account = void 0, this._username = void 0;
229
+ localStorage.removeItem("sessionSigner"), localStorage.removeItem("session"), localStorage.removeItem("sessionPolicies"), localStorage.removeItem("lastUsedConnector"), this.account = void 0, this.emitAccountsChanged([]), this._username = void 0;
231
230
  const e = new URL(`${this._keychainUrl}`);
232
231
  e.pathname = "disconnect", this._disconnectRedirectUrl && e.searchParams.append(
233
232
  "redirect_url",
234
233
  this._disconnectRedirectUrl
235
234
  );
236
- const s = window.open(e);
237
- if (s === null) return Promise.resolve();
238
- const { resolve: t, promise: r } = Promise.withResolvers();
239
- function i() {
240
- s?.closed && (t(), clearInterval(c));
235
+ const t = window.open(e);
236
+ if (t === null) return Promise.resolve();
237
+ const { resolve: s, promise: i } = Promise.withResolvers();
238
+ function r() {
239
+ t?.closed && (s(), clearInterval(a));
241
240
  }
242
- const c = setInterval(i, 500);
243
- return r;
241
+ const a = setInterval(r, 500);
242
+ return i;
244
243
  }
245
244
  tryRetrieveFromQueryOrStorage() {
246
245
  if (this.account)
247
246
  return this.account;
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();
247
+ const e = localStorage.getItem("sessionSigner"), t = e ? JSON.parse(e) : null;
248
+ let s = null;
249
+ const i = localStorage.getItem("session");
250
+ if (i) {
251
+ const o = JSON.parse(i), n = this.normalizeSession(o);
252
+ n ? (s = n, localStorage.setItem("session", JSON.stringify(s))) : this.clearStoredSession();
254
253
  }
255
254
  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);
255
+ const o = new URLSearchParams(window.location.search), n = o.get("startapp");
256
+ if (n) {
257
+ const c = this.ingestSessionFromRedirect(n);
258
+ c && Number(c.expiresAt) !== Number(s?.expiresAt) && (s = c), o.delete("startapp");
259
+ const d = window.location.pathname + (o.toString() ? `?${o.toString()}` : "") + window.location.hash;
260
+ window.history.replaceState({}, document.title, d);
262
261
  }
263
262
  }
264
- if (!t || !s)
263
+ if (!s || !t)
265
264
  return;
266
- const i = parseInt(t.expiresAt) * 1e3;
267
- if (Date.now() >= i) {
265
+ const r = parseInt(s.expiresAt) * 1e3;
266
+ if (Date.now() >= r) {
268
267
  this.clearStoredSession();
269
268
  return;
270
269
  }
271
- const c = localStorage.getItem("sessionPolicies");
272
- if (c) {
270
+ const a = localStorage.getItem("sessionPolicies");
271
+ if (a) {
273
272
  const o = JSON.parse(
274
- c
273
+ a
275
274
  );
276
275
  if (!this.validatePoliciesSubset(
277
276
  this._policies,
@@ -281,17 +280,17 @@ class R extends v {
281
280
  return;
282
281
  }
283
282
  }
284
- return this._username = t.username, this.account = new x(this, {
283
+ return this._username = s.username, this.account = new N(this, {
285
284
  rpcUrl: this._rpcUrl,
286
- privateKey: s.privKey,
287
- address: t.address,
288
- ownerGuid: t.ownerGuid,
285
+ privateKey: t.privKey,
286
+ address: s.address,
287
+ ownerGuid: s.ownerGuid,
289
288
  chainId: this._chainId,
290
- expiresAt: parseInt(t.expiresAt),
291
- policies: I(this._policies),
292
- guardianKeyGuid: t.guardianKeyGuid,
293
- metadataHash: t.metadataHash,
294
- sessionKeyGuid: t.sessionKeyGuid
289
+ expiresAt: parseInt(s.expiresAt),
290
+ policies: x(this._policies),
291
+ guardianKeyGuid: s.guardianKeyGuid,
292
+ metadataHash: s.metadataHash,
293
+ sessionKeyGuid: s.sessionKeyGuid
295
294
  }), this.account;
296
295
  }
297
296
  clearStoredSession() {
@@ -299,12 +298,15 @@ class R extends v {
299
298
  }
300
299
  }
301
300
  export {
302
- P as ALL_AUTH_OPTIONS,
301
+ H as ALL_AUTH_OPTIONS,
303
302
  J as EMBEDDED_WALLETS,
304
- H as FeeSource,
305
- E as IMPLEMENTED_AUTH_OPTIONS,
306
- z as NotReadyToConnect,
307
- F as ResponseCodes,
308
- R as default
303
+ $ as FeeSource,
304
+ z as HeadlessAuthenticationError,
305
+ F as HeadlessModeNotSupportedError,
306
+ L as IMPLEMENTED_AUTH_OPTIONS,
307
+ T as InvalidCredentialsError,
308
+ B as NotReadyToConnect,
309
+ D as ResponseCodes,
310
+ k as default
309
311
  };
310
312
  //# sourceMappingURL=session.js.map
@@ -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 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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"}
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 { loadConfig, SessionPolicies } from \"@cartridge/presets\";\nimport { AddStarknetChainParameters } from \"@starknet-io/types-js\";\nimport { encode } from \"starknet\";\nimport { API_URL, KEYCHAIN_URL } from \"../constants\";\nimport { parsePolicies, ParsedSessionPolicies } from \"../policies\";\nimport BaseProvider from \"../provider\";\nimport { AuthOptions } from \"../types\";\nimport { getPresetSessionPolicies, 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 allowedPoliciesRoot?: string;\n}\n\nexport type SessionOptions = {\n rpc: string;\n chainId: string;\n policies?: SessionPolicies;\n preset?: string;\n shouldOverridePresetPolicies?: boolean;\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 _preset?: string;\n private _ready: Promise<void>;\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 preset,\n shouldOverridePresetPolicies,\n redirectUrl,\n disconnectRedirectUrl,\n keychainUrl,\n apiUrl,\n signupOptions,\n }: SessionOptions) {\n super();\n\n if (!policies && !preset) {\n throw new Error(\"Either `policies` or `preset` must be provided\");\n }\n\n // Policy precedence logic (matching ControllerProvider):\n // 1. If shouldOverridePresetPolicies is true and policies are provided, use policies\n // 2. Otherwise, if preset is defined, resolve policies from preset\n // 3. Otherwise, use provided policies\n if ((!preset || shouldOverridePresetPolicies) && policies) {\n this._policies = parsePolicies(policies);\n } else {\n this._preset = preset;\n if (policies) {\n console.warn(\n \"[Controller] Both `preset` and `policies` provided to SessionProvider. \" +\n \"Policies are ignored when preset is set. \" +\n \"Use `shouldOverridePresetPolicies: true` to override.\",\n );\n }\n this._policies = { verified: false };\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 // Eagerly start async init: resolve preset policies (if any),\n // then try to restore an existing session from storage.\n // All public async methods await this before proceeding.\n this._ready = this._init();\n\n if (typeof window !== \"undefined\") {\n (window as any).starknet_controller_session = this;\n }\n }\n\n private async _init(): Promise<void> {\n if (this._preset) {\n const config = await loadConfig(this._preset);\n if (!config) {\n throw new Error(`Failed to load preset: ${this._preset}`);\n }\n\n const sessionPolicies = getPresetSessionPolicies(config, this._chainId);\n if (!sessionPolicies) {\n throw new Error(\n `No policies found for chain ${this._chainId} in preset ${this._preset}`,\n );\n }\n\n this._policies = parsePolicies(sessionPolicies);\n }\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\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._ready;\n return this._username;\n }\n\n async probe(): Promise<WalletAccount | undefined> {\n await this._ready;\n return this.account;\n }\n\n async connect(): Promise<WalletAccount | undefined> {\n await this._ready;\n\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}` +\n `&redirect_uri=${this._redirectUrl}` +\n `&redirect_query_name=startapp` +\n `&rpc_url=${this._rpcUrl}`;\n\n if (this._preset) {\n url += `&preset=${encodeURIComponent(this._preset)}`;\n } else {\n url += `&policies=${encodeURIComponent(JSON.stringify(this._policies))}`;\n }\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.emitAccountsChanged([]);\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","preset","shouldOverridePresetPolicies","redirectUrl","disconnectRedirectUrl","keychainUrl","apiUrl","signupOptions","parsePolicies","KEYCHAIN_URL","API_URL","config","loadConfig","sessionPolicies","getPresetSessionPolicies","pk","jsonPk","signerToGuid","encode","stark","ec","newPolicies","existingPolicies","contract","existingContract","method","existingMethod","m","message","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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"}