@cartridge/controller 0.9.0 → 0.9.2

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/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Policy, SessionPolicies } from '@cartridge/presets';
2
2
  import { AddInvokeTransactionResult, ChainId, Signature, TypedData } from '@starknet-io/types-js';
3
3
  import { Abi, BigNumberish, Call, constants, InvocationsDetails } from 'starknet';
4
- import { KeychainIFrame, ProfileIFrame } from './iframe';
4
+ import { KeychainIFrame } from './iframe';
5
5
  import { ExternalWallet, ExternalWalletResponse, ExternalWalletType } from './wallets/types';
6
6
  export type Session = {
7
7
  chainId: constants.StarknetChainId;
@@ -53,7 +53,6 @@ export type DeployReply = {
53
53
  };
54
54
  export type IFrames = {
55
55
  keychain: KeychainIFrame;
56
- profile?: ProfileIFrame;
57
56
  version?: number;
58
57
  };
59
58
  export interface LookupRequest {
@@ -94,6 +93,7 @@ export interface Keychain {
94
93
  openExecute(calls: Call[]): Promise<void>;
95
94
  switchChain(rpcUrl: string): Promise<void>;
96
95
  openStarterPack(starterpackId: string): void;
96
+ navigate(path: string): Promise<void>;
97
97
  externalDetectWallets(): Promise<ExternalWallet[]>;
98
98
  externalConnectWallet(type: ExternalWalletType, address?: string): Promise<ExternalWalletResponse>;
99
99
  externalSignMessage(type: ExternalWalletType, message: string): Promise<ExternalWalletResponse>;
@@ -111,7 +111,7 @@ export interface Modal {
111
111
  /**
112
112
  * Options for configuring the controller
113
113
  */
114
- export type ControllerOptions = ProviderOptions & KeychainOptions & ProfileOptions;
114
+ export type ControllerOptions = ProviderOptions & KeychainOptions;
115
115
  export type IFrameOptions = {
116
116
  /** The ID of the starter pack to use */
117
117
  starterPackId?: string;
@@ -139,10 +139,6 @@ export type KeychainOptions = IFrameOptions & {
139
139
  signupOptions?: AuthOptions;
140
140
  /** When true, manually provided policies will override preset policies. Default is false. */
141
141
  shouldOverridePresetPolicies?: boolean;
142
- };
143
- export type ProfileOptions = IFrameOptions & {
144
- /** The URL of profile. Mainly for internal development purpose */
145
- profileUrl?: string;
146
142
  /** The project name of Slot instance. */
147
143
  slot?: string;
148
144
  /** The namespace to use to fetch trophies data from indexer. Will be mandatory once profile page is in production */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cartridge/controller",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Cartridge Controller",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "starknetkit": "^2.6.1"
29
29
  },
30
30
  "dependencies": {
31
- "@cartridge/controller-wasm": "0.2.1",
31
+ "@cartridge/controller-wasm": "^0.2.3",
32
32
  "@cartridge/penpal": "^6.2.4",
33
33
  "ethers": "^6.13.5",
34
34
  "@starknet-io/types-js": "^0.8.4",
@@ -53,7 +53,7 @@
53
53
  "vite-plugin-node-polyfills": "^0.23.0",
54
54
  "vite-plugin-top-level-await": "^1.4.4",
55
55
  "vite-plugin-wasm": "^3.4.1",
56
- "@cartridge/tsconfig": "0.9.0"
56
+ "@cartridge/tsconfig": "0.9.2"
57
57
  },
58
58
  "scripts": {
59
59
  "build:deps": "pnpm build",
@@ -61,6 +61,7 @@
61
61
  "build:browser": "vite build",
62
62
  "build:node": "tsup --config tsup.node.config.ts",
63
63
  "build": "pnpm build:browser && pnpm build:node",
64
+ "build:compat": "pnpm build:browser && pnpm build:node",
64
65
  "format": "prettier --write \"src/**/*.ts\"",
65
66
  "format:check": "prettier --check \"src/**/*.ts\"",
66
67
  "test": "jest",
package/src/controller.ts CHANGED
@@ -10,7 +10,7 @@ import { constants, shortString, WalletAccount } from "starknet";
10
10
  import { version } from "../package.json";
11
11
  import ControllerAccount from "./account";
12
12
  import { NotReadyToConnect } from "./errors";
13
- import { KeychainIFrame, ProfileIFrame } from "./iframe";
13
+ import { KeychainIFrame } from "./iframe";
14
14
  import BaseProvider from "./provider";
15
15
  import {
16
16
  Chain,
@@ -20,7 +20,6 @@ import {
20
20
  IFrames,
21
21
  Keychain,
22
22
  ProbeReply,
23
- Profile,
24
23
  ProfileContextTypeVariant,
25
24
  ResponseCodes,
26
25
  } from "./types";
@@ -28,7 +27,6 @@ import { parseChainId } from "./utils";
28
27
 
29
28
  export default class ControllerProvider extends BaseProvider {
30
29
  private keychain?: AsyncMethodReturns<Keychain>;
31
- private profile?: AsyncMethodReturns<Profile>;
32
30
  private options: ControllerOptions;
33
31
  private iframes: IFrames;
34
32
  private selectedChain: ChainId;
@@ -91,8 +89,12 @@ export default class ControllerProvider extends BaseProvider {
91
89
  iframes.forEach((iframe) => {
92
90
  const container = iframe.parentElement;
93
91
  if (container) {
94
- container.style.visibility = "hidden";
92
+ // Start fade-out transition
95
93
  container.style.opacity = "0";
94
+ // Set display: none after transition completes
95
+ setTimeout(() => {
96
+ container.style.display = "none";
97
+ }, 200);
96
98
  }
97
99
  });
98
100
 
@@ -135,26 +137,6 @@ export default class ControllerProvider extends BaseProvider {
135
137
  return;
136
138
  }
137
139
 
138
- if (!this.iframes.profile) {
139
- const username = await this.keychain.username();
140
-
141
- this.iframes.profile = new ProfileIFrame({
142
- ...this.options,
143
- onConnect: (profile) => {
144
- this.profile = profile;
145
- },
146
- methods: {
147
- openSettings: () => this.openSettings.bind(this),
148
- openPurchaseCredits: () => this.openPurchaseCredits.bind(this),
149
- openExecute: () => this.openExecute.bind(this),
150
- logout: () => this.logout.bind(this),
151
- },
152
- rpcUrl: this.rpcUrl(),
153
- username,
154
- version: this.version,
155
- });
156
- }
157
-
158
140
  return this.account;
159
141
  }
160
142
 
@@ -228,7 +210,6 @@ export default class ControllerProvider extends BaseProvider {
228
210
  }
229
211
 
230
212
  await this.keychain.switchChain(this.rpcUrl());
231
- await this.profile?.switchChain(this.rpcUrl());
232
213
  } catch (e) {
233
214
  console.error(e);
234
215
  return false;
@@ -260,22 +241,27 @@ export default class ControllerProvider extends BaseProvider {
260
241
  }
261
242
 
262
243
  async openProfile(tab: ProfileContextTypeVariant = "inventory") {
263
- if (!this.profile || !this.iframes.profile?.url) {
264
- console.error("Profile is not ready");
244
+ // Profile functionality is now integrated into keychain
245
+ // Navigate keychain iframe to profile page
246
+ if (!this.keychain || !this.iframes.keychain) {
247
+ console.error(new NotReadyToConnect().message);
265
248
  return;
266
249
  }
267
250
  if (!this.account) {
268
251
  console.error("Account is not ready");
269
252
  return;
270
253
  }
254
+ const username = await this.keychain.username();
271
255
 
272
- this.profile.navigate(`${this.iframes.profile.url?.pathname}/${tab}`);
273
- this.iframes.profile.open();
256
+ // Navigate first, then open to avoid flash
257
+ await this.keychain.navigate(`/account/${username}/${tab}`);
258
+ this.iframes.keychain.open();
274
259
  }
275
260
 
276
261
  async openProfileTo(to: string) {
277
- if (!this.profile || !this.iframes.profile?.url) {
278
- console.error("Profile is not ready");
262
+ // Profile functionality is now integrated into keychain
263
+ if (!this.keychain || !this.iframes.keychain) {
264
+ console.error(new NotReadyToConnect().message);
279
265
  return;
280
266
  }
281
267
  if (!this.account) {
@@ -283,13 +269,15 @@ export default class ControllerProvider extends BaseProvider {
283
269
  return;
284
270
  }
285
271
 
286
- this.profile.navigate(`${this.iframes.profile.url?.pathname}/${to}`);
287
- this.iframes.profile.open();
272
+ const username = await this.keychain.username();
273
+ await this.keychain.navigate(`/account/${username}/${to}`);
274
+ this.iframes.keychain.open();
288
275
  }
289
276
 
290
277
  async openProfileAt(at: string) {
291
- if (!this.profile || !this.iframes.profile?.url) {
292
- console.error("Profile is not ready");
278
+ // Profile functionality is now integrated into keychain
279
+ if (!this.keychain || !this.iframes.keychain) {
280
+ console.error(new NotReadyToConnect().message);
293
281
  return;
294
282
  }
295
283
  if (!this.account) {
@@ -297,28 +285,17 @@ export default class ControllerProvider extends BaseProvider {
297
285
  return;
298
286
  }
299
287
 
300
- this.profile.navigate(at);
301
- this.iframes.profile.open();
288
+ await this.keychain.navigate(at);
289
+ this.iframes.keychain.open();
302
290
  }
303
291
 
304
- async openSettings() {
292
+ openSettings() {
305
293
  if (!this.keychain || !this.iframes.keychain) {
306
294
  console.error(new NotReadyToConnect().message);
307
- return null;
308
- }
309
- if (this.iframes.profile?.sendBackward) {
310
- this.iframes.profile?.sendBackward();
311
- } else {
312
- this.iframes.profile?.close();
295
+ return;
313
296
  }
314
297
  this.iframes.keychain.open();
315
- const res = await this.keychain.openSettings();
316
- this.iframes.keychain.close();
317
- this.iframes.profile?.sendForward?.();
318
- if (res && (res as ConnectError).code === ResponseCodes.NOT_CONNECTED) {
319
- return false;
320
- }
321
- return true;
298
+ this.keychain.openSettings();
322
299
  }
323
300
 
324
301
  revoke(origin: string, _policy: Policy[]) {
@@ -357,11 +334,6 @@ export default class ControllerProvider extends BaseProvider {
357
334
  console.error(new NotReadyToConnect().message);
358
335
  return;
359
336
  }
360
- if (!this.iframes.profile) {
361
- console.error("Profile is not ready");
362
- return;
363
- }
364
- this.iframes.profile.close();
365
337
  this.iframes.keychain.open();
366
338
  this.keychain.openPurchaseCredits();
367
339
  }
@@ -371,13 +343,11 @@ export default class ControllerProvider extends BaseProvider {
371
343
  console.error(new NotReadyToConnect().message);
372
344
  return;
373
345
  }
374
- if (!this.iframes.profile) {
375
- console.error("Profile is not ready");
376
- return;
377
- }
378
- this.iframes.profile.close();
379
- this.iframes.keychain.open();
380
- this.keychain.openStarterPack(starterpackId);
346
+
347
+ // Navigate first, then open the iframe
348
+ this.keychain.navigate(`/starter-pack/${starterpackId}`).then(() => {
349
+ this.iframes.keychain.open();
350
+ });
381
351
  }
382
352
 
383
353
  async openExecute(calls: any, chainId?: string) {
@@ -385,25 +355,17 @@ export default class ControllerProvider extends BaseProvider {
385
355
  console.error(new NotReadyToConnect().message);
386
356
  return;
387
357
  }
388
- if (!this.iframes.profile) {
389
- console.error("Profile is not ready");
390
- return;
391
- }
392
358
  // Switch to the chain if provided
393
359
  let currentChainId = this.selectedChain;
394
360
  if (chainId) {
395
361
  this.switchStarknetChain(chainId);
396
362
  }
397
- // Switch iframes
398
- this.iframes.profile?.sendBackward();
363
+ // Open keychain
399
364
  this.iframes.keychain.open();
400
- this.iframes.profile?.close();
401
365
  // Invoke execute
402
366
  const res = await this.keychain.execute(calls, undefined, undefined, true);
403
- // Switch back iframes
404
- this.iframes.profile?.open();
367
+ // Close keychain
405
368
  this.iframes.keychain.close();
406
- this.iframes.profile?.sendForward();
407
369
  // Switch back to the original chain
408
370
  if (chainId) {
409
371
  this.switchStarknetChain(currentChainId);
@@ -15,6 +15,7 @@ export class IFrame<CallSender extends {}> implements Modal {
15
15
  private container?: HTMLDivElement;
16
16
  private onClose?: () => void;
17
17
  private child?: AsyncMethodReturns<CallSender>;
18
+ private closeTimeout?: NodeJS.Timeout;
18
19
 
19
20
  constructor({
20
21
  id,
@@ -64,12 +65,11 @@ export class IFrame<CallSender extends {}> implements Modal {
64
65
  container.style.left = "0";
65
66
  container.style.zIndex = "10000";
66
67
  container.style.backgroundColor = "rgba(0,0,0,0.6)";
67
- container.style.display = "flex";
68
+ container.style.display = "none"; // Use display: none to completely hide from password managers
68
69
  container.style.alignItems = "center";
69
70
  container.style.justifyContent = "center";
70
- container.style.visibility = "hidden";
71
- container.style.opacity = "0";
72
71
  container.style.transition = "opacity 0.2s ease";
72
+ container.style.opacity = "0";
73
73
  container.style.pointerEvents = "auto";
74
74
  container.appendChild(iframe);
75
75
 
@@ -94,22 +94,6 @@ export class IFrame<CallSender extends {}> implements Modal {
94
94
  iframe: this.iframe,
95
95
  methods: {
96
96
  close: (_origin: string) => () => this.close(),
97
- closeAll: (_origin: string) => () => {
98
- // Close all iframes
99
- const iframes = document.querySelectorAll(
100
- 'iframe[id^="controller-"]',
101
- );
102
- iframes.forEach((iframe) => {
103
- const container = iframe.parentElement;
104
- if (container) {
105
- container.style.visibility = "hidden";
106
- container.style.opacity = "0";
107
- }
108
- });
109
- if (document.body) {
110
- document.body.style.overflow = "auto";
111
- }
112
- },
113
97
  reload: (_origin: string) => () => window.location.reload(),
114
98
  ...methods,
115
99
  },
@@ -125,10 +109,7 @@ export class IFrame<CallSender extends {}> implements Modal {
125
109
  if (typeof document === "undefined") return;
126
110
  const existingController = document.getElementById("controller");
127
111
  if (document.body) {
128
- if (
129
- (id === "controller-keychain" && !existingController) ||
130
- id === "controller-profile"
131
- ) {
112
+ if (id === "controller-keychain" && !existingController) {
132
113
  document.body.appendChild(container);
133
114
  observer.disconnect();
134
115
  }
@@ -142,10 +123,7 @@ export class IFrame<CallSender extends {}> implements Modal {
142
123
 
143
124
  const existingController = document.getElementById("controller");
144
125
  if (document.body) {
145
- if (
146
- (id === "controller-keychain" && !existingController) ||
147
- id === "controller-profile"
148
- ) {
126
+ if (id === "controller-keychain" && !existingController) {
149
127
  document.body.appendChild(container);
150
128
  }
151
129
  }
@@ -156,10 +134,22 @@ export class IFrame<CallSender extends {}> implements Modal {
156
134
  open() {
157
135
  if (!this.container || typeof document === "undefined" || !document.body)
158
136
  return;
137
+
138
+ // Clear any pending close timeout to prevent race condition
139
+ if (this.closeTimeout) {
140
+ clearTimeout(this.closeTimeout);
141
+ this.closeTimeout = undefined;
142
+ }
143
+
159
144
  document.body.style.overflow = "hidden";
160
145
 
161
- this.container.style.visibility = "visible";
162
- this.container.style.opacity = "1";
146
+ this.container.style.display = "flex";
147
+ // Use requestAnimationFrame to ensure display change is processed before opacity change
148
+ requestAnimationFrame(() => {
149
+ if (this.container) {
150
+ this.container.style.opacity = "1";
151
+ }
152
+ });
163
153
  }
164
154
 
165
155
  close() {
@@ -169,8 +159,16 @@ export class IFrame<CallSender extends {}> implements Modal {
169
159
 
170
160
  document.body.style.overflow = "auto";
171
161
 
172
- this.container.style.visibility = "hidden";
162
+ // Start fade-out transition
173
163
  this.container.style.opacity = "0";
164
+
165
+ // Set display: none after transition completes (200ms)
166
+ this.closeTimeout = setTimeout(() => {
167
+ if (this.container) {
168
+ this.container.style.display = "none";
169
+ }
170
+ this.closeTimeout = undefined;
171
+ }, 200);
174
172
  }
175
173
 
176
174
  sendBackward() {
@@ -199,4 +197,8 @@ export class IFrame<CallSender extends {}> implements Modal {
199
197
  this.iframe.style.width = "432px";
200
198
  this.iframe.style.borderRadius = "8px";
201
199
  }
200
+
201
+ isOpen() {
202
+ return this.container?.style.display !== "none";
203
+ }
202
204
  }
@@ -1,3 +1,2 @@
1
1
  export * from "./base";
2
2
  export * from "./keychain";
3
- export * from "./profile";
@@ -15,6 +15,9 @@ export class KeychainIFrame extends IFrame<Keychain> {
15
15
  url,
16
16
  policies,
17
17
  version,
18
+ slot,
19
+ namespace,
20
+ tokens,
18
21
  ...iframeOptions
19
22
  }: KeychainIframeOptions) {
20
23
  const _url = new URL(url ?? KEYCHAIN_URL);
@@ -31,6 +34,21 @@ export class KeychainIFrame extends IFrame<Keychain> {
31
34
  _url.searchParams.set("v", encodeURIComponent(version));
32
35
  }
33
36
 
37
+ if (slot) {
38
+ _url.searchParams.set("ps", encodeURIComponent(slot));
39
+ }
40
+
41
+ if (namespace) {
42
+ _url.searchParams.set("ns", encodeURIComponent(namespace));
43
+ }
44
+
45
+ if (tokens?.erc20) {
46
+ _url.searchParams.set(
47
+ "erc20",
48
+ encodeURIComponent(tokens.erc20.toString()),
49
+ );
50
+ }
51
+
34
52
  super({
35
53
  ...iframeOptions,
36
54
  id: "controller-keychain",
package/src/types.ts CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  constants,
13
13
  InvocationsDetails,
14
14
  } from "starknet";
15
- import { KeychainIFrame, ProfileIFrame } from "./iframe";
15
+ import { KeychainIFrame } from "./iframe";
16
16
  import {
17
17
  ExternalWallet,
18
18
  ExternalWalletResponse,
@@ -85,7 +85,6 @@ export type DeployReply = {
85
85
 
86
86
  export type IFrames = {
87
87
  keychain: KeychainIFrame;
88
- profile?: ProfileIFrame;
89
88
  version?: number;
90
89
  };
91
90
 
@@ -149,6 +148,7 @@ export interface Keychain {
149
148
  openExecute(calls: Call[]): Promise<void>;
150
149
  switchChain(rpcUrl: string): Promise<void>;
151
150
  openStarterPack(starterpackId: string): void;
151
+ navigate(path: string): Promise<void>;
152
152
 
153
153
  // External wallet methods
154
154
  externalDetectWallets(): Promise<ExternalWallet[]>;
@@ -184,9 +184,7 @@ export interface Modal {
184
184
  /**
185
185
  * Options for configuring the controller
186
186
  */
187
- export type ControllerOptions = ProviderOptions &
188
- KeychainOptions &
189
- ProfileOptions;
187
+ export type ControllerOptions = ProviderOptions & KeychainOptions;
190
188
 
191
189
  export type IFrameOptions = {
192
190
  /** The ID of the starter pack to use */
@@ -218,11 +216,6 @@ export type KeychainOptions = IFrameOptions & {
218
216
  signupOptions?: AuthOptions;
219
217
  /** When true, manually provided policies will override preset policies. Default is false. */
220
218
  shouldOverridePresetPolicies?: boolean;
221
- };
222
-
223
- export type ProfileOptions = IFrameOptions & {
224
- /** The URL of profile. Mainly for internal development purpose */
225
- profileUrl?: string;
226
219
  /** The project name of Slot instance. */
227
220
  slot?: string;
228
221
  /** The namespace to use to fetch trophies data from indexer. Will be mandatory once profile page is in production */
@@ -1,12 +0,0 @@
1
- import { Profile, ProfileOptions } from '../types';
2
- import { IFrame, IFrameOptions } from './base';
3
- export type ProfileIFrameOptions = IFrameOptions<Profile> & ProfileOptions & {
4
- rpcUrl: string;
5
- version?: string;
6
- username: string;
7
- slot?: string;
8
- namespace?: string;
9
- };
10
- export declare class ProfileIFrame extends IFrame<Profile> {
11
- constructor({ profileUrl, rpcUrl, version, username, slot, namespace, tokens, ...iframeOptions }: ProfileIFrameOptions);
12
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider-B9Ikz5hr.js","sources":["../src/types.ts","../src/utils.ts","../src/errors.ts","../src/constants.ts","../../../node_modules/.pnpm/@starknet-io+types-js@0.8.4/node_modules/@starknet-io/types-js/dist/esm/wallet-api/constants.js","../src/icon.ts","../src/mutex.ts","../src/provider.ts"],"sourcesContent":["import { Policy, SessionPolicies } from \"@cartridge/presets\";\nimport {\n AddInvokeTransactionResult,\n ChainId,\n Signature,\n TypedData,\n} from \"@starknet-io/types-js\";\nimport {\n Abi,\n BigNumberish,\n Call,\n constants,\n InvocationsDetails,\n} from \"starknet\";\nimport { KeychainIFrame, ProfileIFrame } from \"./iframe\";\nimport {\n ExternalWallet,\n ExternalWalletResponse,\n ExternalWalletType,\n} from \"./wallets/types\";\n\nexport type Session = {\n chainId: constants.StarknetChainId;\n policies: Policy[];\n maxFee: BigNumberish;\n expiresAt: bigint;\n credentials: {\n authorization: string[];\n privateKey: string;\n };\n};\n\nexport type AuthOption =\n | \"webauthn\"\n | \"discord\"\n | \"walletconnect\"\n | ExternalWalletType;\n\nexport type AuthOptions = Omit<AuthOption, \"phantom\" | \"argent\">[];\n\nexport enum ResponseCodes {\n SUCCESS = \"SUCCESS\",\n NOT_CONNECTED = \"NOT_CONNECTED\",\n ERROR = \"ERROR\",\n CANCELED = \"CANCELED\",\n USER_INTERACTION_REQUIRED = \"USER_INTERACTION_REQUIRED\",\n}\n\nexport type ConnectError = {\n code: ResponseCodes;\n message: string;\n error?: ControllerError;\n};\n\nexport type ControllerError = {\n code: Number;\n message: string;\n data?: any;\n};\n\nexport type ConnectReply = {\n code: ResponseCodes.SUCCESS;\n address: string;\n policies?: SessionPolicies;\n};\n\nexport type ExecuteReply =\n | (AddInvokeTransactionResult & {\n code: ResponseCodes.SUCCESS;\n })\n | {\n code: ResponseCodes.USER_INTERACTION_REQUIRED;\n };\n\nexport type ProbeReply = {\n code: ResponseCodes.SUCCESS;\n address: string;\n rpcUrl?: string;\n};\n\nexport type DeployReply = {\n code: ResponseCodes.SUCCESS;\n transaction_hash: string;\n};\n\nexport type IFrames = {\n keychain: KeychainIFrame;\n profile?: ProfileIFrame;\n version?: number;\n};\n\nexport interface LookupRequest {\n usernames?: string[];\n addresses?: string[];\n}\n\nexport interface LookupResult {\n username: string;\n addresses: string[];\n}\n\nexport interface LookupResponse {\n results: LookupResult[];\n}\n\nexport enum FeeSource {\n PAYMASTER = \"PAYMASTER\",\n CREDITS = \"CREDITS\",\n}\n\ntype ContractAddress = string;\ntype CartridgeID = string;\nexport type ControllerAccounts = Record<ContractAddress, CartridgeID>;\n\nexport interface Keychain {\n probe(rpcUrl: string): Promise<ProbeReply | ConnectError>;\n connect(\n policies: SessionPolicies,\n rpcUrl: string,\n signupOptions?: AuthOptions,\n ): Promise<ConnectReply | ConnectError>;\n disconnect(): void;\n\n reset(): void;\n revoke(origin: string): void;\n\n deploy(): Promise<DeployReply | ConnectError>;\n execute(\n calls: Call | Call[],\n abis?: Abi[],\n transactionsDetail?: InvocationsDetails,\n sync?: boolean,\n feeSource?: any,\n error?: ControllerError,\n ): Promise<ExecuteReply | ConnectError>;\n signMessage(\n typedData: TypedData,\n account: string,\n async?: boolean,\n ): Promise<Signature | ConnectError>;\n openSettings(): Promise<void | ConnectError>;\n session(): Promise<Session>;\n sessions(): Promise<{\n [key: string]: Session;\n }>;\n delegateAccount(): string;\n username(): string;\n openPurchaseCredits(): void;\n openExecute(calls: Call[]): Promise<void>;\n switchChain(rpcUrl: string): Promise<void>;\n openStarterPack(starterpackId: string): void;\n\n // External wallet methods\n externalDetectWallets(): Promise<ExternalWallet[]>;\n externalConnectWallet(\n type: ExternalWalletType,\n address?: string,\n ): Promise<ExternalWalletResponse>;\n externalSignMessage(\n type: ExternalWalletType,\n message: string,\n ): Promise<ExternalWalletResponse>;\n externalSignTypedData(\n type: ExternalWalletType,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n data: any,\n ): Promise<ExternalWalletResponse>;\n externalGetBalance(\n type: ExternalWalletType,\n tokenAddress?: string,\n ): Promise<ExternalWalletResponse>;\n}\n\nexport interface Profile {\n navigate(path: string): void;\n switchChain(rpcUrl: string): Promise<void>;\n}\n\nexport interface Modal {\n open: () => void;\n close: () => void;\n}\n\n/**\n * Options for configuring the controller\n */\nexport type ControllerOptions = ProviderOptions &\n KeychainOptions &\n ProfileOptions;\n\nexport type IFrameOptions = {\n /** The ID of the starter pack to use */\n starterPackId?: string;\n /** The preset to use */\n preset?: string;\n};\n\nexport type Chain = {\n rpcUrl: string;\n};\n\nexport type ProviderOptions = {\n defaultChainId?: ChainId;\n chains?: Chain[];\n};\n\nexport type KeychainOptions = IFrameOptions & {\n policies?: SessionPolicies;\n /** The URL of keychain */\n url?: string;\n /** The origin of keychain */\n origin?: string;\n /** Propagate transaction errors back to caller instead of showing modal */\n propagateSessionErrors?: boolean;\n /** The fee source to use for execute from outside */\n feeSource?: FeeSource;\n /** Signup options (the order of the options is reflected in the UI. It's recommended to group socials and wallets together ) */\n signupOptions?: AuthOptions;\n /** When true, manually provided policies will override preset policies. Default is false. */\n shouldOverridePresetPolicies?: boolean;\n};\n\nexport type ProfileOptions = IFrameOptions & {\n /** The URL of profile. Mainly for internal development purpose */\n profileUrl?: string;\n /** The project name of Slot instance. */\n slot?: string;\n /** The namespace to use to fetch trophies data from indexer. Will be mandatory once profile page is in production */\n namespace?: string;\n /** The tokens to be listed on Inventory modal */\n tokens?: Tokens;\n};\n\nexport type ProfileContextTypeVariant =\n | \"inventory\"\n | \"trophies\"\n | \"achievements\"\n | \"leaderboard\"\n | \"activity\";\n\nexport type Token = \"eth\" | \"strk\" | \"lords\" | \"usdc\" | \"usdt\";\n\nexport type Tokens = {\n erc20?: Token[];\n};\n","import {\n addAddressPadding,\n Call,\n CallData,\n constants,\n getChecksumAddress,\n hash,\n shortString,\n typedData,\n TypedDataRevision,\n} from \"starknet\";\nimport { Policy } from \"@cartridge/controller-wasm/controller\";\nimport { Policies, SessionPolicies } from \"@cartridge/presets\";\nimport { ChainId } from \"@starknet-io/types-js\";\nimport { ParsedSessionPolicies } from \"./policies\";\n\n// Whitelist of allowed property names to prevent prototype pollution\nconst ALLOWED_PROPERTIES = new Set([\n \"contracts\",\n \"messages\",\n \"target\",\n \"method\",\n \"name\",\n \"description\",\n \"types\",\n \"domain\",\n \"primaryType\",\n]);\n\nfunction validatePropertyName(prop: string): void {\n if (!ALLOWED_PROPERTIES.has(prop)) {\n throw new Error(`Invalid property name: ${prop}`);\n }\n}\n\nfunction safeObjectAccess<T>(obj: any, prop: string): T {\n validatePropertyName(prop);\n return obj[prop];\n}\n\nexport function normalizeCalls(calls: Call | Call[]) {\n return toArray(calls).map((call) => {\n return {\n entrypoint: call.entrypoint,\n contractAddress: addAddressPadding(call.contractAddress),\n calldata: CallData.toHex(call.calldata),\n };\n });\n}\n\nexport function toSessionPolicies(policies: Policies): SessionPolicies {\n return Array.isArray(policies)\n ? policies.reduce<SessionPolicies>(\n (prev, p) => {\n if (safeObjectAccess<string>(p, \"target\")) {\n const target = getChecksumAddress(\n safeObjectAccess<string>(p, \"target\"),\n );\n const entrypoint = safeObjectAccess<string>(p, \"method\");\n const contracts = safeObjectAccess<Record<string, any>>(\n prev,\n \"contracts\",\n );\n const item = {\n name: humanizeString(entrypoint),\n entrypoint: entrypoint,\n description: safeObjectAccess<string>(p, \"description\"),\n };\n\n if (target in contracts) {\n const methods = toArray(contracts[target].methods);\n contracts[target] = {\n methods: [...methods, item],\n };\n } else {\n contracts[target] = {\n methods: [item],\n };\n }\n } else {\n const messages = safeObjectAccess<any[]>(prev, \"messages\");\n messages.push(p);\n }\n\n return prev;\n },\n { contracts: {}, messages: [] },\n )\n : policies;\n}\n\nexport function toWasmPolicies(policies: ParsedSessionPolicies): Policy[] {\n return [\n ...Object.entries(policies.contracts ?? {}).flatMap(\n ([target, { methods }]) =>\n toArray(methods).map((m) => ({\n target,\n method: m.entrypoint,\n authorized: m.authorized,\n })),\n ),\n ...(policies.messages ?? []).map((p) => {\n const domainHash = typedData.getStructHash(\n p.types,\n \"StarknetDomain\",\n p.domain,\n TypedDataRevision.ACTIVE,\n );\n const typeHash = typedData.getTypeHash(\n p.types,\n p.primaryType,\n TypedDataRevision.ACTIVE,\n );\n\n return {\n scope_hash: hash.computePoseidonHash(domainHash, typeHash),\n authorized: p.authorized,\n };\n }),\n ];\n}\n\nexport function toArray<T>(val: T | T[]): T[] {\n return Array.isArray(val) ? val : [val];\n}\n\nexport function humanizeString(str: string): string {\n return (\n str\n // Convert from camelCase or snake_case\n .replace(/([a-z])([A-Z])/g, \"$1 $2\") // camelCase to spaces\n .replace(/_/g, \" \") // snake_case to spaces\n .toLowerCase()\n // Capitalize first letter\n .replace(/^\\w/, (c) => c.toUpperCase())\n );\n}\n\nexport function parseChainId(url: URL): ChainId {\n const parts = url.pathname.split(\"/\");\n\n // Handle localhost URLs by making a synchronous call to getChainId\n if (\n url.hostname === \"localhost\" ||\n url.hostname === \"127.0.0.1\" ||\n url.hostname === \"0.0.0.0\"\n ) {\n // Check if we're in a browser environment\n if (typeof XMLHttpRequest === \"undefined\") {\n // In Node.js environment (like tests), we can't make synchronous HTTP calls\n // For now, we'll use a placeholder chainId for localhost in tests\n console.warn(\n `Cannot make synchronous HTTP call in Node.js environment for ${url.toString()}`,\n );\n return shortString.encodeShortString(\"LOCALHOST\") as ChainId;\n }\n\n // Use a synchronous XMLHttpRequest to get the chain ID\n const xhr = new XMLHttpRequest();\n xhr.open(\"POST\", url.toString(), false); // false makes it synchronous\n xhr.setRequestHeader(\"Content-Type\", \"application/json\");\n\n const requestBody = JSON.stringify({\n jsonrpc: \"2.0\",\n method: \"starknet_chainId\",\n params: [],\n id: 1,\n });\n\n try {\n xhr.send(requestBody);\n\n if (xhr.status === 200) {\n const response = JSON.parse(xhr.responseText);\n if (response.result) {\n return response.result as ChainId;\n }\n }\n\n throw new Error(\n `Failed to get chain ID from ${url.toString()}: ${xhr.status} ${xhr.statusText}`,\n );\n } catch (error) {\n throw new Error(`Failed to connect to ${url.toString()}: ${error}`);\n }\n }\n\n if (parts.includes(\"starknet\")) {\n if (parts.includes(\"mainnet\")) {\n return constants.StarknetChainId.SN_MAIN;\n } else if (parts.includes(\"sepolia\")) {\n return constants.StarknetChainId.SN_SEPOLIA;\n }\n } else if (parts.length >= 3) {\n const projectName = parts[2];\n if (parts.includes(\"katana\")) {\n return shortString.encodeShortString(\n `WP_${projectName.toUpperCase().replace(/-/g, \"_\")}`,\n ) as ChainId;\n } else if (parts.includes(\"mainnet\")) {\n return shortString.encodeShortString(\n `GG_${projectName.toUpperCase().replace(/-/g, \"_\")}`,\n ) as ChainId;\n }\n }\n\n throw new Error(`Chain ${url.toString()} not supported`);\n}\n","export class NotReadyToConnect extends Error {\n constructor() {\n super(\"Not ready to connect\");\n\n Object.setPrototypeOf(this, NotReadyToConnect.prototype);\n }\n}\n","export const KEYCHAIN_URL = \"https://x.cartridge.gg\";\nexport const PROFILE_URL = \"https://profile.cartridge.gg\";\nexport const API_URL = \"https://api.cartridge.gg\";\n","export const Permission = {\n ACCOUNTS: 'accounts',\n};\n//# sourceMappingURL=constants.js.map","export const icon =\n \"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAwIiBoZWlnaHQ9IjgwMCIgdmlld0JveD0iMCAwIDgwMCA4MDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfNTExMl83ODIpIj4KPHBhdGggZD0iTTQ2OS4yMzYgNzBDNDgyLjM5IDcwIDQ5My4wNTMgODAuNjYzIDQ5My4wNTMgOTMuODE2NFYxNDcuMTQ3TDUxNS4zMzggMTQ3LjE0N0w1MTUuNDI4IDE0Ny4xNDdMNTE1LjU1NCAxNDcuMTQ3TDUxNS44MjYgMTQ3LjE0OUM1MTYuMDE2IDE0Ny4xNTEgNTE2LjIyNSAxNDcuMTUzIDUxNi40NTEgMTQ3LjE1N0M1MTYuOTA0IDE0Ny4xNjQgNTE3LjQyOCAxNDcuMTc2IDUxOC4wMiAxNDcuMTk1QzUxOS4yMDEgMTQ3LjIzNCA1MjAuNjYgMTQ3LjMwNCA1MjIuMzYxIDE0Ny40MjRDNTI1Ljc0MSAxNDcuNjYzIDUzMC4xODUgMTQ4LjExNCA1MzUuMzYzIDE0OC45NjlDNTQ1LjAwMSAxNTAuNTYyIDU1OC41NTYgMTUzLjc4IDU3Mi45MTggMTYwLjYwM0w3MzAuNDIgMjI2LjY3MUw3MzIuMTAxIDIyNy41MDVDNzcxLjc4NyAyNDcuMTc3IDc4OS45OTMgMjg2LjI5NiA3ODkuOTkzIDMyMi4wMzZWNTg1Ljg2NUM3ODkuOTkzIDU4Ni4wNTQgNzg5Ljk5NCA1ODYuMjU0IDc4OS45OTQgNTg2LjQ2M0w3ODkuOTk2IDU4Ni45MTNDNzkwLjAzOCA1OTcuMDk2IDc5MC4xNjEgNjI2Ljk5NiA3NjQuMjMxIDY1Mi44MjNMNzE0Ljc2IDcwMi4wOTVMNzE0LjY0MSA3MDIuMjE1QzcwNC42MDEgNzEyLjI3NSA2OTIuMTIzIDcyMC42NTIgNjc2LjI4NCA3MjQuODc5QzY2NC4zOSA3MjguMDU0IDY1Mi44MjcgNzI3Ljk2NiA2NDguNjM3IDcyNy45MzRMNjQ4LjYxOSA3MjcuOTMzQzY0OC40MDkgNzI3LjkzMiA2NDguMjE5IDcyNy45MyA2NDguMDQ3IDcyNy45M0w2NDcuNzUyIDcyNy45MjlINDgwLjcyMUM0NzQuMDk0IDcyNy45MjkgNDY4LjcyMSA3MjIuNTU2IDQ2OC43MjEgNzE1LjkyOVY2NjguMzg4SDMyOC41ODZDMzI4LjU4NiA2NzIuNjI5IDMyOC41NzIgNjk4LjA1MiAzMjguNTYxIDcxNS45NDRDMzI4LjU1NyA3MjIuNTY5IDMyMy4xODYgNzI3LjkyOSAzMTYuNTYxIDcyNy45MjlIMTUyLjI0NkMxNTIuMTA0IDcyNy45MjkgMTUxLjk0MiA3MjcuOTI5IDE1MS43NjIgNzI3LjkzMUwxNTEuMzYyIDcyNy45MzRDMTQ3LjE3MiA3MjcuOTY2IDEzNS42MDkgNzI4LjA1NCAxMjMuNzE0IDcyNC44NzlDMTA3Ljg3MyA3MjAuNjUxIDk1LjM5MzggNzEyLjI3MiA4NS4zNTI5IDcwMi4yMUw4NS4yMzg2IDcwMi4wOTVMMzUuNjcgNjUyLjcyNUwzNS41NzIzIDY1Mi42MjdDOS44NjI0MiA2MjYuNzggOS45NjY3IDU5Ny4xODUgMTAuMDAzIDU4Ni44NzRDMTAuMDA0MyA1ODYuNTEzIDEwLjAwNTUgNTg2LjE3NyAxMC4wMDU1IDU4NS44NjVWMzIyLjAzNkMxMC4wMDU1IDI4Ni40MyAyOC4xNjYyIDI0Ny4xOTkgNjcuODk3NyAyMjcuNTA1TDY5LjU3OSAyMjYuNjcxTDIyNy4wODEgMTYwLjYwM0MyNDEuNDQzIDE1My43OCAyNTQuOTk4IDE1MC41NjIgMjY0LjYzNiAxNDguOTY5QzI2OS44MTQgMTQ4LjExNCAyNzQuMjU4IDE0Ny42NjMgMjc3LjYzOCAxNDcuNDI0QzI3OS4zMzggMTQ3LjMwNCAyODAuNzk4IDE0Ny4yMzQgMjgxLjk3OSAxNDcuMTk1QzI4Mi41NzEgMTQ3LjE3NiAyODMuMDk1IDE0Ny4xNjQgMjgzLjU0NyAxNDcuMTU3TDI4My45MTcgMTQ3LjE1MkwyODQuMTczIDE0Ny4xNDlMMjg0LjQ0NSAxNDcuMTQ3TDI4NC41NzEgMTQ3LjE0N0wyODQuNjYgMTQ3LjE0N0wzMDYuOTQyIDE0Ny4xNDdWOTMuODE2NEMzMDYuOTQyIDgwLjY2MyAzMTcuNjA1IDcwIDMzMC43NTggNzBINDY5LjIzNloiIGZpbGw9IiMxOTFBMUEiLz4KPHBhdGggZD0iTTM2Ni40ODMgMTI5LjU0SDQzMy41MTJWMjA2LjY4N0gzNjYuNDgzVjEyOS41NFoiIGZpbGw9IiNGQkNCNEEiLz4KPHBhdGggZD0iTTI2OS4wMSA2MDIuNDI5SDE0NC4wMDhDMTM1Ljc2OCA2MDIuNDI5IDEzNS43NjggNTk0LjE0NiAxMzUuNzY4IDU5NC4xNDZWMjgwLjg1QzEzNS43NjggMjgwLjg1IDEzNS43NjggMjcyLjY0NCAxNDQuMDA4IDI3Mi42NDRIMzY2LjQ4M0wzNjYuNDgzIDIwNi42ODdIMjg0LjY5QzI4NC42OSAyMDYuNjg3IDI2OC4xMzQgMjA2LjY4NyAyNTEuNTc5IDIxNC44OTNMOTQuMzQxNCAyODAuODVDNzcuNzg2MSAyODkuMDU3IDY5LjU0NjkgMzA1LjYyMyA2OS41NDY5IDMyMi4wMzVWNTg1Ljg2M0M2OS41NDY5IDU5NC4xNDcgNjkuNTQ2OSA2MDIuMzUzIDc3Ljc4NjEgNjEwLjYzNkwxMjcuNDUyIDY2MC4xMDRDMTM1LjY5MSA2NjguMzg3IDE0MS45MjggNjY4LjM4NyAxNTIuMjQ3IDY2OC4zODdIMjY5LjAyOUMyNjkuMDM3IDY0OC4zNCAyNjkuMDQ2IDYyNC42NTUgMjY5LjA1NCA2MDIuODg3SDUyOC4wMTNWNjY4LjM4N0g2NDcuNzUzQzY1OC4wNzEgNjY4LjM4NyA2NjQuMzA4IDY2OC4zODcgNjcyLjU0NyA2NjAuMTA0TDcyMi4yMTMgNjEwLjYzNkM3MzAuNDUzIDYwMi40MjkgNzMwLjQ1MyA1OTQuMTQ3IDczMC40NTMgNTg1Ljg2M1YzMjIuMDM1QzczMC40NTMgMzA1LjU0NiA3MjIuMjEzIDI4OS4wNTcgNzA1LjY1OCAyODAuODVMNTQ4LjQyMSAyMTQuODkzQzUzMS44NjUgMjA2LjY4NyA1MTUuMzEgMjA2LjY4NyA1MTUuMzEgMjA2LjY4N0g0MzMuNTEyTDQzMy41MTIgMjcyLjY0NEg2NTYuMDY5QzY2NC4zMDggMjcyLjY0NCA2NjQuMzA4IDI4MC44NSA2NjQuMzA4IDI4MC44NVY1OTQuMTQ2QzY2NC4zMDggNTk0LjE0NiA2NjQuMzA4IDYwMi40MjkgNjU2LjA2OSA2MDIuNDI5SDUyOC4yNjJWNTM3LjM5NkgyNjkuMDc1QzI2OS4wNzUgNTQzLjcwNyAyNjkuMDE3IDU5Ni45MTIgMjY5LjAxIDYwMi40MjlaIiBmaWxsPSIjRkJDQjRBIi8+CjxwYXRoIGQ9Ik0yNjkuMDA5IDQzNi4xNzJINTI4LjI2MlYzNzAuNjgxSDI2OS4wNzVDMjY5LjA3NSAzNzcuMzczIDI2OS4wMDkgNDM2Ljc4OCAyNjkuMDA5IDQzNi4xNzJaIiBmaWxsPSIjRkJDQjRBIi8+CjwvZz4KPGRlZnM+CjxmaWx0ZXIgaWQ9ImZpbHRlcjBfZF81MTEyXzc4MiIgeD0iLTQiIHk9IjAiIHdpZHRoPSI4MDgiIGhlaWdodD0iODA4IiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+CjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+CjxmZUNvbG9yTWF0cml4IGluPSJTb3VyY2VBbHBoYSIgdHlwZT0ibWF0cml4IiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIiByZXN1bHQ9ImhhcmRBbHBoYSIvPgo8ZmVPZmZzZXQgZHk9IjQiLz4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMiIvPgo8ZmVDb21wb3NpdGUgaW4yPSJoYXJkQWxwaGEiIG9wZXJhdG9yPSJvdXQiLz4KPGZlQ29sb3JNYXRyaXggdHlwZT0ibWF0cml4IiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMjUgMCIvPgo8ZmVCbGVuZCBtb2RlPSJub3JtYWwiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9ImVmZmVjdDFfZHJvcFNoYWRvd181MTEyXzc4MiIvPgo8ZmVCbGVuZCBtb2RlPSJub3JtYWwiIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9ImVmZmVjdDFfZHJvcFNoYWRvd181MTEyXzc4MiIgcmVzdWx0PSJzaGFwZSIvPgo8L2ZpbHRlcj4KPC9kZWZzPgo8L3N2Zz4K\";\n","function releaseStub() {}\n\n/**\n * A simple mutual exclusion lock. It allows you to obtain and release a lock,\n * ensuring that only one task can access a critical section at a time.\n */\nexport class Mutex {\n private m_lastPromise: Promise<void> = Promise.resolve();\n\n /**\n * Acquire lock\n * @param [bypass=false] option to skip lock acquisition\n */\n public async obtain(bypass = false): Promise<() => void> {\n let release = releaseStub;\n if (bypass) return release;\n const lastPromise = this.m_lastPromise;\n this.m_lastPromise = new Promise<void>((resolve) => (release = resolve));\n await lastPromise;\n return release;\n }\n}\n","import {\n AddInvokeTransactionParameters,\n AddStarknetChainParameters,\n Permission,\n RequestAccountsParameters,\n RequestFn,\n StarknetWindowObject,\n SwitchStarknetChainParameters,\n TypedData,\n UNEXPECTED_ERROR,\n WalletEventHandlers,\n WalletEventListener,\n WalletEvents,\n} from \"@starknet-io/types-js\";\nimport { WalletAccount } from \"starknet\";\nimport manifest from \"../package.json\";\n\nimport { icon } from \"./icon\";\nimport { Mutex } from \"./mutex\";\n\nconst mutex = new Mutex();\n\nexport default abstract class BaseProvider implements StarknetWindowObject {\n public id = \"controller\";\n public name = \"Controller\";\n public version = manifest.version;\n public icon = icon;\n\n public account?: WalletAccount;\n public subscriptions: WalletEvents[] = [];\n\n private _probePromise: Promise<WalletAccount | undefined> | null = null;\n\n protected async safeProbe(): Promise<WalletAccount | undefined> {\n // If we already have an account, return it\n if (this.account) {\n return this.account;\n }\n\n // If we're already probing, wait for the existing probe\n if (this._probePromise) {\n return this._probePromise;\n }\n\n const release = await mutex.obtain();\n return await new Promise<WalletAccount | undefined>(async (resolve) => {\n try {\n this._probePromise = this.probe();\n const result = await this._probePromise;\n resolve(result);\n } finally {\n this._probePromise = null;\n }\n }).finally(() => {\n release();\n });\n }\n\n request: RequestFn = async (call) => {\n switch (call.type) {\n case \"wallet_getPermissions\":\n await this.safeProbe();\n\n if (this.account) {\n return [Permission.ACCOUNTS];\n }\n\n return [];\n\n case \"wallet_requestAccounts\": {\n if (this.account) {\n return [this.account.address];\n }\n\n const silentMode =\n call.params && (call.params as RequestAccountsParameters).silent_mode;\n\n this.account = await this.safeProbe();\n\n if (!this.account && !silentMode) {\n this.account = await this.connect();\n }\n\n if (this.account) {\n return [this.account.address];\n }\n\n return [];\n }\n\n case \"wallet_watchAsset\":\n throw {\n code: 63,\n message: \"An unexpected error occurred\",\n data: \"wallet_watchAsset not implemented\",\n } as UNEXPECTED_ERROR;\n\n case \"wallet_addStarknetChain\": {\n let params = call.params as AddStarknetChainParameters;\n return this.addStarknetChain(params);\n }\n\n case \"wallet_switchStarknetChain\": {\n let params = call.params as SwitchStarknetChainParameters;\n return this.switchStarknetChain(params.chainId);\n }\n\n case \"wallet_requestChainId\":\n if (!this.account) {\n throw {\n code: 63,\n message: \"An unexpected error occurred\",\n data: \"Account not initialized\",\n } as UNEXPECTED_ERROR;\n }\n\n return await this.account.getChainId();\n\n case \"wallet_deploymentData\":\n throw {\n code: 63,\n message: \"An unexpected error occurred\",\n data: \"wallet_deploymentData not implemented\",\n } as UNEXPECTED_ERROR;\n\n case \"wallet_addInvokeTransaction\":\n if (!this.account) {\n throw {\n code: 63,\n message: \"An unexpected error occurred\",\n data: \"Account not initialized\",\n } as UNEXPECTED_ERROR;\n }\n\n let params = call.params as AddInvokeTransactionParameters;\n return await this.account.execute(\n params.calls.map((call) => ({\n contractAddress: call.contract_address,\n entrypoint: call.entry_point,\n calldata: call.calldata,\n })),\n );\n\n case \"wallet_addDeclareTransaction\":\n throw {\n code: 63,\n message: \"An unexpected error occurred\",\n data: \"wallet_addDeclareTransaction not implemented\",\n } as UNEXPECTED_ERROR;\n\n case \"wallet_signTypedData\": {\n if (!this.account) {\n throw {\n code: 63,\n message: \"An unexpected error occurred\",\n data: \"Account not initialized\",\n } as UNEXPECTED_ERROR;\n }\n\n return await this.account.signMessage(call.params as TypedData);\n }\n\n case \"wallet_supportedSpecs\":\n return [];\n case \"wallet_supportedWalletApi\":\n return [];\n default:\n throw {\n code: 63,\n message: \"An unexpected error occurred\",\n data: `Unknown RPC call type: ${call.type}`,\n } as UNEXPECTED_ERROR;\n }\n };\n\n on: WalletEventListener = <E extends keyof WalletEventHandlers>(\n event: E,\n handler: WalletEventHandlers[E],\n ): void => {\n if (event !== \"accountsChanged\" && event !== \"networkChanged\") {\n throw new Error(`Unknown event: ${event}`);\n }\n this.subscriptions.push({ type: event, handler } as WalletEvents);\n };\n\n off: WalletEventListener = <E extends keyof WalletEventHandlers>(\n event: E,\n handler: WalletEventHandlers[E],\n ): void => {\n if (event !== \"accountsChanged\" && event !== \"networkChanged\") {\n throw new Error(`Unknown event: ${event}`);\n }\n const idx = this.subscriptions.findIndex(\n (sub) => sub.type === event && sub.handler === handler,\n );\n if (idx >= 0) {\n this.subscriptions.splice(idx, 1);\n }\n };\n\n protected emitNetworkChanged(chainId: string) {\n this.subscriptions\n .filter((sub) => sub.type === \"networkChanged\")\n .forEach((sub) => {\n (sub.handler as WalletEventHandlers[\"networkChanged\"])(chainId);\n });\n }\n\n protected emitAccountsChanged(accounts: string[]) {\n this.subscriptions\n .filter((sub) => sub.type === \"accountsChanged\")\n .forEach((sub) => {\n (sub.handler as WalletEventHandlers[\"accountsChanged\"])(accounts);\n });\n }\n\n abstract probe(): Promise<WalletAccount | undefined>;\n abstract connect(): Promise<WalletAccount | undefined>;\n abstract switchStarknetChain(chainId: string): Promise<boolean>;\n abstract addStarknetChain(\n chain: AddStarknetChainParameters,\n ): Promise<boolean>;\n}\n"],"names":["ResponseCodes","FeeSource","ALLOWED_PROPERTIES","validatePropertyName","prop","safeObjectAccess","obj","normalizeCalls","calls","toArray","call","addAddressPadding","CallData","toSessionPolicies","policies","prev","p","target","getChecksumAddress","entrypoint","contracts","item","humanizeString","methods","toWasmPolicies","m","domainHash","typedData","TypedDataRevision","typeHash","hash","val","str","c","parseChainId","url","parts","shortString","xhr","requestBody","response","error","constants","projectName","NotReadyToConnect","KEYCHAIN_URL","PROFILE_URL","API_URL","Permission","icon","releaseStub","Mutex","bypass","release","lastPromise","resolve","mutex","BaseProvider","manifest","result","silentMode","params","event","handler","idx","sub","chainId","accounts"],"mappings":";;;;AAwCY,IAAAA,sBAAAA,OACVA,EAAA,UAAU,WACVA,EAAA,gBAAgB,iBAChBA,EAAA,QAAQ,SACRA,EAAA,WAAW,YACXA,EAAA,4BAA4B,6BALlBA,IAAAA,KAAA,CAAA,CAAA,GAiEAC,sBAAAA,OACVA,EAAA,YAAY,aACZA,EAAA,UAAU,WAFAA,IAAAA,KAAA,CAAA,CAAA;ACxFZ,MAAMC,wBAAyB,IAAI;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAASC,EAAqBC,GAAoB;AAChD,MAAI,CAACF,EAAmB,IAAIE,CAAI;AAC9B,UAAM,IAAI,MAAM,0BAA0BA,CAAI,EAAE;AAEpD;AAEA,SAASC,EAAoBC,GAAUF,GAAiB;AACtD,SAAAD,EAAqBC,CAAI,GAClBE,EAAIF,CAAI;AACjB;AAEO,SAASG,EAAeC,GAAsB;AACnD,SAAOC,EAAQD,CAAK,EAAE,IAAI,CAACE,OAClB;AAAA,IACL,YAAYA,EAAK;AAAA,IACjB,iBAAiBC,EAAkBD,EAAK,eAAe;AAAA,IACvD,UAAUE,EAAS,MAAMF,EAAK,QAAQ;AAAA,EACxC,EACD;AACH;AAEO,SAASG,EAAkBC,GAAqC;AACrE,SAAO,MAAM,QAAQA,CAAQ,IACzBA,EAAS;AAAA,IACP,CAACC,GAAMC,MAAM;AACP,UAAAX,EAAyBW,GAAG,QAAQ,GAAG;AACzC,cAAMC,IAASC;AAAA,UACbb,EAAyBW,GAAG,QAAQ;AAAA,QACtC,GACMG,IAAad,EAAyBW,GAAG,QAAQ,GACjDI,IAAYf;AAAA,UAChBU;AAAA,UACA;AAAA,QACF,GACMM,IAAO;AAAA,UACX,MAAMC,EAAeH,CAAU;AAAA,UAC/B,YAAAA;AAAA,UACA,aAAad,EAAyBW,GAAG,aAAa;AAAA,QACxD;AAEA,YAAIC,KAAUG,GAAW;AACvB,gBAAMG,IAAUd,EAAQW,EAAUH,CAAM,EAAE,OAAO;AACjD,UAAAG,EAAUH,CAAM,IAAI;AAAA,YAClB,SAAS,CAAC,GAAGM,GAASF,CAAI;AAAA,UAC5B;AAAA,QAAA;AAEA,UAAAD,EAAUH,CAAM,IAAI;AAAA,YAClB,SAAS,CAACI,CAAI;AAAA,UAChB;AAAA,MACF;AAGA,QADiBhB,EAAwBU,GAAM,UAAU,EAChD,KAAKC,CAAC;AAGV,aAAAD;AAAA,IACT;AAAA,IACA,EAAE,WAAW,IAAI,UAAU,CAAG,EAAA;AAAA,EAAA,IAEhCD;AACN;AAEO,SAASU,EAAeV,GAA2C;AACjE,SAAA;AAAA,IACL,GAAG,OAAO,QAAQA,EAAS,aAAa,CAAA,CAAE,EAAE;AAAA,MAC1C,CAAC,CAACG,GAAQ,EAAE,SAAAM,GAAS,MACnBd,EAAQc,CAAO,EAAE,IAAI,CAACE,OAAO;AAAA,QAC3B,QAAAR;AAAA,QACA,QAAQQ,EAAE;AAAA,QACV,YAAYA,EAAE;AAAA,MAAA,EACd;AAAA,IACN;AAAA,IACA,IAAIX,EAAS,YAAY,CAAI,GAAA,IAAI,CAACE,MAAM;AACtC,YAAMU,IAAaC,EAAU;AAAA,QAC3BX,EAAE;AAAA,QACF;AAAA,QACAA,EAAE;AAAA,QACFY,EAAkB;AAAA,MACpB,GACMC,IAAWF,EAAU;AAAA,QACzBX,EAAE;AAAA,QACFA,EAAE;AAAA,QACFY,EAAkB;AAAA,MACpB;AAEO,aAAA;AAAA,QACL,YAAYE,EAAK,oBAAoBJ,GAAYG,CAAQ;AAAA,QACzD,YAAYb,EAAE;AAAA,MAChB;AAAA,IACD,CAAA;AAAA,EACH;AACF;AAEO,SAASP,EAAWsB,GAAmB;AAC5C,SAAO,MAAM,QAAQA,CAAG,IAAIA,IAAM,CAACA,CAAG;AACxC;AAEO,SAAST,EAAeU,GAAqB;AAClD,SACEA,EAEG,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,MAAM,GAAG,EACjB,YAAA,EAEA,QAAQ,OAAO,CAACC,MAAMA,EAAE,aAAa;AAE5C;AAEO,SAASC,EAAaC,GAAmB;AAC9C,QAAMC,IAAQD,EAAI,SAAS,MAAM,GAAG;AAIlC,MAAAA,EAAI,aAAa,eACjBA,EAAI,aAAa,eACjBA,EAAI,aAAa,WACjB;AAEI,QAAA,OAAO,iBAAmB;AAGpB,qBAAA;AAAA,QACN,gEAAgEA,EAAI,UAAU;AAAA,MAChF,GACOE,EAAY,kBAAkB,WAAW;AAI5C,UAAAC,IAAM,IAAI,eAAe;AAC/B,IAAAA,EAAI,KAAK,QAAQH,EAAI,SAAA,GAAY,EAAK,GAClCG,EAAA,iBAAiB,gBAAgB,kBAAkB;AAEjD,UAAAC,IAAc,KAAK,UAAU;AAAA,MACjC,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ,CAAC;AAAA,MACT,IAAI;AAAA,IAAA,CACL;AAEG,QAAA;AAGE,UAFJD,EAAI,KAAKC,CAAW,GAEhBD,EAAI,WAAW,KAAK;AACtB,cAAME,IAAW,KAAK,MAAMF,EAAI,YAAY;AAC5C,YAAIE,EAAS;AACX,iBAAOA,EAAS;AAAA,MAClB;AAGF,YAAM,IAAI;AAAA,QACR,+BAA+BL,EAAI,UAAU,KAAKG,EAAI,MAAM,IAAIA,EAAI,UAAU;AAAA,MAChF;AAAA,aACOG,GAAO;AACR,YAAA,IAAI,MAAM,wBAAwBN,EAAI,UAAU,KAAKM,CAAK,EAAE;AAAA,IAAA;AAAA,EACpE;AAGE,MAAAL,EAAM,SAAS,UAAU,GAAG;AAC1B,QAAAA,EAAM,SAAS,SAAS;AAC1B,aAAOM,EAAU,gBAAgB;AACxB,QAAAN,EAAM,SAAS,SAAS;AACjC,aAAOM,EAAU,gBAAgB;AAAA,EACnC,WACSN,EAAM,UAAU,GAAG;AACtB,UAAAO,IAAcP,EAAM,CAAC;AACvB,QAAAA,EAAM,SAAS,QAAQ;AACzB,aAAOC,EAAY;AAAA,QACjB,MAAMM,EAAY,YAAA,EAAc,QAAQ,MAAM,GAAG,CAAC;AAAA,MACpD;AACS,QAAAP,EAAM,SAAS,SAAS;AACjC,aAAOC,EAAY;AAAA,QACjB,MAAMM,EAAY,YAAA,EAAc,QAAQ,MAAM,GAAG,CAAC;AAAA,MACpD;AAAA,EACF;AAGF,QAAM,IAAI,MAAM,SAASR,EAAI,SAAA,CAAU,gBAAgB;AACzD;AC/MO,MAAMS,UAA0B,MAAM;AAAA,EAC3C,cAAc;AACZ,UAAM,sBAAsB,GAErB,OAAA,eAAe,MAAMA,EAAkB,SAAS;AAAA,EAAA;AAE3D;ACNO,MAAMC,IAAe,0BACfC,IAAc,gCACdC,IAAU,4BCFVC,IAAa;AAAA,EACtB,UAAU;AACd,GCFaC,IACX;ACDF,SAASC,IAAc;AAAC;AAMjB,MAAMC,EAAM;AAAA,EACT,gBAA+B,QAAQ,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvD,MAAa,OAAOC,IAAS,IAA4B;AACvD,QAAIC,IAAUH;AACd,QAAIE,EAAe,QAAAC;AACnB,UAAMC,IAAc,KAAK;AACzB,gBAAK,gBAAgB,IAAI,QAAc,CAACC,MAAaF,IAAUE,CAAQ,GACjE,MAAAD,GACCD;AAAA,EAAA;AAEX;ACDA,MAAMG,IAAQ,IAAIL,EAAM;AAExB,MAA8BM,EAA6C;AAAA,EAClE,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAUC,EAAS;AAAA,EACnB,OAAOT;AAAA,EAEP;AAAA,EACA,gBAAgC,CAAC;AAAA,EAEhC,gBAA2D;AAAA,EAEnE,MAAgB,YAAgD;AAE9D,QAAI,KAAK;AACP,aAAO,KAAK;AAId,QAAI,KAAK;AACP,aAAO,KAAK;AAGR,UAAAI,IAAU,MAAMG,EAAM,OAAO;AACnC,WAAO,MAAM,IAAI,QAAmC,OAAOD,MAAY;AACjE,UAAA;AACG,aAAA,gBAAgB,KAAK,MAAM;AAC1B,cAAAI,IAAS,MAAM,KAAK;AAC1B,QAAAJ,EAAQI,CAAM;AAAA,MAAA,UACd;AACA,aAAK,gBAAgB;AAAA,MAAA;AAAA,IACvB,CACD,EAAE,QAAQ,MAAM;AACP,MAAAN,EAAA;AAAA,IAAA,CACT;AAAA,EAAA;AAAA,EAGH,UAAqB,OAAO3C,MAAS;AACnC,YAAQA,EAAK,MAAM;AAAA,MACjB,KAAK;AAGH,eAFA,MAAM,KAAK,UAAU,GAEjB,KAAK,UACA,CAACsC,EAAW,QAAQ,IAGtB,CAAC;AAAA,MAEV,KAAK,0BAA0B;AAC7B,YAAI,KAAK;AACA,iBAAA,CAAC,KAAK,QAAQ,OAAO;AAG9B,cAAMY,IACJlD,EAAK,UAAWA,EAAK,OAAqC;AAQ5D,eANK,KAAA,UAAU,MAAM,KAAK,UAAU,GAEhC,CAAC,KAAK,WAAW,CAACkD,MACf,KAAA,UAAU,MAAM,KAAK,QAAQ,IAGhC,KAAK,UACA,CAAC,KAAK,QAAQ,OAAO,IAGvB,CAAC;AAAA,MAAA;AAAA,MAGV,KAAK;AACG,cAAA;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,MAAM;AAAA,QACR;AAAA,MAEF,KAAK,2BAA2B;AAC9B,YAAIC,IAASnD,EAAK;AACX,eAAA,KAAK,iBAAiBmD,CAAM;AAAA,MAAA;AAAA,MAGrC,KAAK,8BAA8B;AACjC,YAAIA,IAASnD,EAAK;AACX,eAAA,KAAK,oBAAoBmD,EAAO,OAAO;AAAA,MAAA;AAAA,MAGhD,KAAK;AACC,YAAA,CAAC,KAAK;AACF,gBAAA;AAAA,YACJ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,MAAM;AAAA,UACR;AAGK,eAAA,MAAM,KAAK,QAAQ,WAAW;AAAA,MAEvC,KAAK;AACG,cAAA;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,MAAM;AAAA,QACR;AAAA,MAEF,KAAK;AACC,YAAA,CAAC,KAAK;AACF,gBAAA;AAAA,YACJ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,MAAM;AAAA,UACR;AAGF,YAAIA,IAASnD,EAAK;AACX,eAAA,MAAM,KAAK,QAAQ;AAAA,UACxBmD,EAAO,MAAM,IAAI,CAACnD,OAAU;AAAA,YAC1B,iBAAiBA,EAAK;AAAA,YACtB,YAAYA,EAAK;AAAA,YACjB,UAAUA,EAAK;AAAA,UAAA,EACf;AAAA,QACJ;AAAA,MAEF,KAAK;AACG,cAAA;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,MAAM;AAAA,QACR;AAAA,MAEF,KAAK,wBAAwB;AACvB,YAAA,CAAC,KAAK;AACF,gBAAA;AAAA,YACJ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,MAAM;AAAA,UACR;AAGF,eAAO,MAAM,KAAK,QAAQ,YAAYA,EAAK,MAAmB;AAAA,MAAA;AAAA,MAGhE,KAAK;AACH,eAAO,CAAC;AAAA,MACV,KAAK;AACH,eAAO,CAAC;AAAA,MACV;AACQ,cAAA;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,MAAM,0BAA0BA,EAAK,IAAI;AAAA,QAC3C;AAAA,IAAA;AAAA,EAEN;AAAA,EAEA,KAA0B,CACxBoD,GACAC,MACS;AACL,QAAAD,MAAU,qBAAqBA,MAAU;AAC3C,YAAM,IAAI,MAAM,kBAAkBA,CAAK,EAAE;AAE3C,SAAK,cAAc,KAAK,EAAE,MAAMA,GAAO,SAAAC,GAAyB;AAAA,EAClE;AAAA,EAEA,MAA2B,CACzBD,GACAC,MACS;AACL,QAAAD,MAAU,qBAAqBA,MAAU;AAC3C,YAAM,IAAI,MAAM,kBAAkBA,CAAK,EAAE;AAErC,UAAAE,IAAM,KAAK,cAAc;AAAA,MAC7B,CAACC,MAAQA,EAAI,SAASH,KAASG,EAAI,YAAYF;AAAA,IACjD;AACA,IAAIC,KAAO,KACJ,KAAA,cAAc,OAAOA,GAAK,CAAC;AAAA,EAEpC;AAAA,EAEU,mBAAmBE,GAAiB;AACvC,SAAA,cACF,OAAO,CAACD,MAAQA,EAAI,SAAS,gBAAgB,EAC7C,QAAQ,CAACA,MAAQ;AACf,MAAAA,EAAI,QAAkDC,CAAO;AAAA,IAAA,CAC/D;AAAA,EAAA;AAAA,EAGK,oBAAoBC,GAAoB;AAC3C,SAAA,cACF,OAAO,CAACF,MAAQA,EAAI,SAAS,iBAAiB,EAC9C,QAAQ,CAACA,MAAQ;AACf,MAAAA,EAAI,QAAmDE,CAAQ;AAAA,IAAA,CACjE;AAAA,EAAA;AASP;","x_google_ignoreList":[4]}
@@ -1,59 +0,0 @@
1
- import { PROFILE_URL } from "../constants";
2
- import { Profile, ProfileOptions } from "../types";
3
- import { IFrame, IFrameOptions } from "./base";
4
-
5
- export type ProfileIFrameOptions = IFrameOptions<Profile> &
6
- ProfileOptions & {
7
- rpcUrl: string;
8
- version?: string;
9
- username: string;
10
- slot?: string;
11
- namespace?: string;
12
- };
13
-
14
- export class ProfileIFrame extends IFrame<Profile> {
15
- constructor({
16
- profileUrl,
17
- rpcUrl,
18
- version,
19
- username,
20
- slot,
21
- namespace,
22
- tokens,
23
- ...iframeOptions
24
- }: ProfileIFrameOptions) {
25
- const _profileUrl = (profileUrl || PROFILE_URL).replace(/\/$/, "");
26
- let _url = new URL(
27
- slot
28
- ? `${_profileUrl}/account/${username}/slot/${slot}`
29
- : `${_profileUrl}/account/${username}`,
30
- );
31
-
32
- if (slot) {
33
- _url.searchParams.set("ps", encodeURIComponent(slot));
34
- }
35
-
36
- if (namespace) {
37
- _url.searchParams.set("ns", encodeURIComponent(namespace));
38
- }
39
-
40
- if (version) {
41
- _url.searchParams.set("v", encodeURIComponent(version));
42
- }
43
-
44
- _url.searchParams.set("rpcUrl", encodeURIComponent(rpcUrl));
45
-
46
- if (tokens?.erc20) {
47
- _url.searchParams.set(
48
- "erc20",
49
- encodeURIComponent(tokens.erc20.toString()),
50
- );
51
- }
52
-
53
- super({
54
- ...iframeOptions,
55
- id: "controller-profile",
56
- url: _url,
57
- });
58
- }
59
- }