@cartridge/controller 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.turbo/turbo-build$colon$deps.log +52 -76
  2. package/.turbo/turbo-build.log +53 -77
  3. package/dist/controller.cjs +860 -0
  4. package/dist/controller.cjs.map +1 -0
  5. package/dist/controller.d.cts +33 -0
  6. package/dist/controller.d.ts +4 -4
  7. package/dist/controller.js +84 -68
  8. package/dist/controller.js.map +1 -1
  9. package/dist/index.cjs +2200 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +17 -0
  12. package/dist/index.d.ts +12 -7
  13. package/dist/index.js +161 -7601
  14. package/dist/index.js.map +1 -1
  15. package/dist/lookup.cjs +59 -0
  16. package/dist/lookup.cjs.map +1 -0
  17. package/dist/lookup.d.cts +4 -0
  18. package/dist/lookup.js +7 -7
  19. package/dist/lookup.js.map +1 -1
  20. package/dist/{provider.js → node/index.cjs} +499 -25
  21. package/dist/node/index.cjs.map +1 -0
  22. package/dist/node/index.d.cts +56 -0
  23. package/dist/node/index.d.ts +56 -0
  24. package/dist/{telegram/provider.js → node/index.js} +354 -135
  25. package/dist/node/index.js.map +1 -0
  26. package/dist/{policies.d.ts → policies-DD1aPjQ4.d.cts} +6 -4
  27. package/dist/policies-DD1aPjQ4.d.ts +21 -0
  28. package/dist/{types-CVnDQVqD.d.ts → provider-ap1C1ypF.d.cts} +27 -10
  29. package/dist/provider-ap1C1ypF.d.ts +201 -0
  30. package/dist/session/{provider.js → index.cjs} +82 -73
  31. package/dist/session/index.cjs.map +1 -0
  32. package/dist/session/{provider.d.ts → index.d.cts} +6 -3
  33. package/dist/session/index.d.ts +37 -8
  34. package/dist/session/index.js +47 -64
  35. package/dist/session/index.js.map +1 -1
  36. package/package.json +35 -16
  37. package/src/controller.ts +43 -15
  38. package/src/iframe/base.ts +1 -11
  39. package/src/node/account.ts +72 -0
  40. package/src/node/backend.ts +159 -0
  41. package/src/node/index.ts +4 -0
  42. package/src/node/provider.ts +178 -0
  43. package/src/node/server.ts +89 -0
  44. package/src/session/account.ts +1 -1
  45. package/src/session/provider.ts +0 -16
  46. package/src/types.ts +3 -6
  47. package/tsconfig.json +2 -1
  48. package/dist/__tests__/parseChainId.test.d.ts +0 -2
  49. package/dist/__tests__/parseChainId.test.js +0 -89
  50. package/dist/__tests__/parseChainId.test.js.map +0 -1
  51. package/dist/account.d.ts +0 -38
  52. package/dist/account.js +0 -110
  53. package/dist/account.js.map +0 -1
  54. package/dist/constants.d.ts +0 -5
  55. package/dist/constants.js +0 -10
  56. package/dist/constants.js.map +0 -1
  57. package/dist/errors.d.ts +0 -5
  58. package/dist/errors.js +0 -11
  59. package/dist/errors.js.map +0 -1
  60. package/dist/icon.d.ts +0 -3
  61. package/dist/icon.js +0 -6
  62. package/dist/icon.js.map +0 -1
  63. package/dist/iframe/base.d.ts +0 -5
  64. package/dist/iframe/base.js +0 -126
  65. package/dist/iframe/base.js.map +0 -1
  66. package/dist/iframe/index.d.ts +0 -5
  67. package/dist/iframe/index.js +0 -188
  68. package/dist/iframe/index.js.map +0 -1
  69. package/dist/iframe/keychain.d.ts +0 -5
  70. package/dist/iframe/keychain.js +0 -147
  71. package/dist/iframe/keychain.js.map +0 -1
  72. package/dist/iframe/profile.d.ts +0 -5
  73. package/dist/iframe/profile.js +0 -167
  74. package/dist/iframe/profile.js.map +0 -1
  75. package/dist/index.d-BbTUPBeO.d.ts +0 -68
  76. package/dist/mutex.d.ts +0 -14
  77. package/dist/mutex.js +0 -22
  78. package/dist/mutex.js.map +0 -1
  79. package/dist/policies.js +0 -26
  80. package/dist/policies.js.map +0 -1
  81. package/dist/provider.d.ts +0 -24
  82. package/dist/provider.js.map +0 -1
  83. package/dist/session/account.d.ts +0 -37
  84. package/dist/session/account.js +0 -94
  85. package/dist/session/account.js.map +0 -1
  86. package/dist/session/backend.d.ts +0 -60
  87. package/dist/session/backend.js +0 -39
  88. package/dist/session/backend.js.map +0 -1
  89. package/dist/session/provider.js.map +0 -1
  90. package/dist/telegram/backend.d.ts +0 -33
  91. package/dist/telegram/backend.js +0 -40
  92. package/dist/telegram/backend.js.map +0 -1
  93. package/dist/telegram/provider.d.ts +0 -27
  94. package/dist/telegram/provider.js.map +0 -1
  95. package/dist/types.d.ts +0 -5
  96. package/dist/types.js +0 -13
  97. package/dist/types.js.map +0 -1
  98. package/dist/utils.d.ts +0 -19
  99. package/dist/utils.js +0 -141
  100. package/dist/utils.js.map +0 -1
@@ -0,0 +1,860 @@
1
+ 'use strict';
2
+
3
+ var starknet = require('starknet');
4
+ var penpal = require('@cartridge/penpal');
5
+ var typesJs = require('@starknet-io/types-js');
6
+
7
+ // src/account.ts
8
+ function toArray(val) {
9
+ return Array.isArray(val) ? val : [val];
10
+ }
11
+ function parseChainId(url) {
12
+ const parts = url.pathname.split("/");
13
+ if (parts.includes("starknet")) {
14
+ if (parts.includes("mainnet")) {
15
+ return starknet.constants.StarknetChainId.SN_MAIN;
16
+ } else if (parts.includes("sepolia")) {
17
+ return starknet.constants.StarknetChainId.SN_SEPOLIA;
18
+ }
19
+ } else if (parts.length >= 3) {
20
+ const projectName = parts[2];
21
+ if (parts.includes("katana")) {
22
+ return starknet.shortString.encodeShortString(
23
+ `WP_${projectName.toUpperCase().replace(/-/g, "_")}`
24
+ );
25
+ } else if (parts.includes("mainnet")) {
26
+ return starknet.shortString.encodeShortString(
27
+ `GG_${projectName.toUpperCase().replace(/-/g, "_")}`
28
+ );
29
+ }
30
+ }
31
+ throw new Error(`Chain ${url.toString()} not supported`);
32
+ }
33
+
34
+ // src/account.ts
35
+ var ControllerAccount = class extends starknet.WalletAccount {
36
+ address;
37
+ keychain;
38
+ modal;
39
+ options;
40
+ constructor(provider, rpcUrl, address, keychain, options, modal) {
41
+ super({ nodeUrl: rpcUrl }, provider);
42
+ this.address = address;
43
+ this.keychain = keychain;
44
+ this.options = options;
45
+ this.modal = modal;
46
+ }
47
+ /**
48
+ * Invoke execute function in account contract
49
+ *
50
+ * @param calls the invocation object or an array of them, containing:
51
+ * - contractAddress - the address of the contract
52
+ * - entrypoint - the entrypoint of the contract
53
+ * - calldata - (defaults to []) the calldata
54
+ * - signature - (defaults to []) the signature
55
+ * @param abis (optional) the abi of the contract for better displaying
56
+ *
57
+ * @returns response from addTransaction
58
+ */
59
+ async execute(calls) {
60
+ calls = toArray(calls);
61
+ return new Promise(async (resolve, reject) => {
62
+ const sessionExecute = await this.keychain.execute(
63
+ calls,
64
+ undefined,
65
+ undefined,
66
+ false
67
+ );
68
+ if (sessionExecute.code === "SUCCESS" /* SUCCESS */) {
69
+ resolve(sessionExecute);
70
+ return;
71
+ }
72
+ if (this.options?.propagateSessionErrors) {
73
+ reject(sessionExecute.error);
74
+ return;
75
+ }
76
+ this.modal.open();
77
+ const manualExecute = await this.keychain.execute(
78
+ calls,
79
+ undefined,
80
+ undefined,
81
+ true,
82
+ sessionExecute.error
83
+ );
84
+ if (manualExecute.code === "SUCCESS" /* SUCCESS */) {
85
+ resolve(manualExecute);
86
+ this.modal.close();
87
+ return;
88
+ }
89
+ reject(manualExecute.error);
90
+ return;
91
+ });
92
+ }
93
+ /**
94
+ * Sign an JSON object for off-chain usage with the starknet private key and return the signature
95
+ * This adds a message prefix so it cant be interchanged with transactions
96
+ *
97
+ * @param json - JSON object to be signed
98
+ * @returns the signature of the JSON object
99
+ * @throws {Error} if the JSON object is not a valid JSON
100
+ */
101
+ async signMessage(typedData2) {
102
+ return new Promise(async (resolve, reject) => {
103
+ const sessionSign = await this.keychain.signMessage(typedData2, "", true);
104
+ if (!("code" in sessionSign)) {
105
+ resolve(sessionSign);
106
+ return;
107
+ }
108
+ this.modal.open();
109
+ const manualSign = await this.keychain.signMessage(typedData2, "", false);
110
+ if (!("code" in manualSign)) {
111
+ resolve(manualSign);
112
+ } else {
113
+ reject(manualSign.error);
114
+ }
115
+ this.modal.close();
116
+ });
117
+ }
118
+ };
119
+ var account_default = ControllerAccount;
120
+ var IFrame = class {
121
+ url;
122
+ iframe;
123
+ container;
124
+ onClose;
125
+ constructor({
126
+ id,
127
+ url,
128
+ preset,
129
+ onClose,
130
+ onConnect,
131
+ methods = {}
132
+ }) {
133
+ if (typeof document === "undefined") {
134
+ return;
135
+ }
136
+ if (preset) {
137
+ url.searchParams.set("preset", preset);
138
+ }
139
+ this.url = url;
140
+ const iframe = document.createElement("iframe");
141
+ iframe.src = url.toString();
142
+ iframe.id = id;
143
+ iframe.style.border = "none";
144
+ iframe.sandbox.add("allow-forms");
145
+ iframe.sandbox.add("allow-popups");
146
+ iframe.sandbox.add("allow-scripts");
147
+ iframe.sandbox.add("allow-same-origin");
148
+ iframe.allow = "publickey-credentials-create *; publickey-credentials-get *; clipboard-write";
149
+ if (!!document.hasStorageAccess) {
150
+ iframe.sandbox.add("allow-storage-access-by-user-activation");
151
+ }
152
+ const container = document.createElement("div");
153
+ container.id = "controller";
154
+ container.style.position = "fixed";
155
+ container.style.height = "100%";
156
+ container.style.width = "100%";
157
+ container.style.top = "0";
158
+ container.style.left = "0";
159
+ container.style.zIndex = "10000";
160
+ container.style.backgroundColor = "rgba(0,0,0,0.6)";
161
+ container.style.display = "flex";
162
+ container.style.alignItems = "center";
163
+ container.style.justifyContent = "center";
164
+ container.style.visibility = "hidden";
165
+ container.style.opacity = "0";
166
+ container.style.transition = "opacity 0.2s ease";
167
+ container.appendChild(iframe);
168
+ this.iframe = iframe;
169
+ this.container = container;
170
+ penpal.connectToChild({
171
+ iframe: this.iframe,
172
+ methods: { close: () => this.close(), ...methods }
173
+ }).promise.then(onConnect);
174
+ this.resize();
175
+ window.addEventListener("resize", () => this.resize());
176
+ const observer = new MutationObserver(() => {
177
+ const existingController2 = document.getElementById("controller");
178
+ if (document.body) {
179
+ if (id === "controller-keychain" && !existingController2 || id === "controller-profile") {
180
+ document.body.appendChild(container);
181
+ observer.disconnect();
182
+ }
183
+ }
184
+ });
185
+ observer.observe(document.documentElement, {
186
+ childList: true,
187
+ subtree: true
188
+ });
189
+ const existingController = document.getElementById("controller");
190
+ if (document.body) {
191
+ if (id === "controller-keychain" && !existingController || id === "controller-profile") {
192
+ document.body.appendChild(container);
193
+ }
194
+ }
195
+ this.onClose = onClose;
196
+ }
197
+ open() {
198
+ if (!this.container) return;
199
+ document.body.style.overflow = "hidden";
200
+ this.container.style.visibility = "visible";
201
+ this.container.style.opacity = "1";
202
+ }
203
+ close() {
204
+ if (!this.container) return;
205
+ this.onClose?.();
206
+ document.body.style.overflow = "auto";
207
+ this.container.style.visibility = "hidden";
208
+ this.container.style.opacity = "0";
209
+ }
210
+ sendBackward() {
211
+ if (!this.container) return;
212
+ this.container.style.zIndex = "9999";
213
+ }
214
+ sendForward() {
215
+ if (!this.container) return;
216
+ this.container.style.zIndex = "10000";
217
+ }
218
+ resize() {
219
+ if (!this.iframe) return;
220
+ this.iframe.style.userSelect = "none";
221
+ if (window.innerWidth < 768) {
222
+ this.iframe.style.height = "100%";
223
+ this.iframe.style.width = "100%";
224
+ this.iframe.style.borderRadius = "0";
225
+ return;
226
+ }
227
+ this.iframe.style.height = "600px";
228
+ this.iframe.style.width = "432px";
229
+ this.iframe.style.borderRadius = "8px";
230
+ }
231
+ };
232
+
233
+ // src/constants.ts
234
+ var KEYCHAIN_URL = "https://x.cartridge.gg";
235
+ var PROFILE_URL = "https://profile.cartridge.gg";
236
+
237
+ // src/iframe/keychain.ts
238
+ var KeychainIFrame = class extends IFrame {
239
+ constructor({ url, policies, ...iframeOptions }) {
240
+ const _url = new URL(url ?? KEYCHAIN_URL);
241
+ if (policies) {
242
+ _url.searchParams.set(
243
+ "policies",
244
+ encodeURIComponent(JSON.stringify(policies))
245
+ );
246
+ }
247
+ super({
248
+ ...iframeOptions,
249
+ id: "controller-keychain",
250
+ url: _url
251
+ });
252
+ }
253
+ };
254
+
255
+ // src/iframe/profile.ts
256
+ var ProfileIFrame = class extends IFrame {
257
+ constructor({
258
+ profileUrl,
259
+ rpcUrl,
260
+ version,
261
+ username,
262
+ slot,
263
+ namespace,
264
+ tokens,
265
+ ...iframeOptions
266
+ }) {
267
+ const _profileUrl = (profileUrl || PROFILE_URL).replace(/\/$/, "");
268
+ let _url = new URL(
269
+ slot ? namespace ? `${_profileUrl}/account/${username}/slot/${slot}?ps=${encodeURIComponent(
270
+ slot
271
+ )}&ns=${encodeURIComponent(namespace)}` : `${_profileUrl}/account/${username}/slot/${slot}?ps=${encodeURIComponent(
272
+ slot
273
+ )}` : `${_profileUrl}/account/${username}`
274
+ );
275
+ if (version) {
276
+ _url.searchParams.set("v", encodeURIComponent(version));
277
+ }
278
+ _url.searchParams.set("rpcUrl", encodeURIComponent(rpcUrl));
279
+ if (tokens?.erc20) {
280
+ _url.searchParams.set(
281
+ "erc20",
282
+ encodeURIComponent(tokens.erc20.toString())
283
+ );
284
+ }
285
+ super({
286
+ ...iframeOptions,
287
+ id: "controller-profile",
288
+ url: _url
289
+ });
290
+ }
291
+ };
292
+
293
+ // src/errors.ts
294
+ var NotReadyToConnect = class _NotReadyToConnect extends Error {
295
+ constructor() {
296
+ super("Not ready to connect");
297
+ Object.setPrototypeOf(this, _NotReadyToConnect.prototype);
298
+ }
299
+ };
300
+
301
+ // package.json
302
+ var package_default = {
303
+ name: "@cartridge/controller",
304
+ version: "0.7.0",
305
+ description: "Cartridge Controller",
306
+ module: "dist/index.js",
307
+ types: "dist/index.d.ts",
308
+ type: "module",
309
+ scripts: {
310
+ "build:deps": "tsup",
311
+ build: "pnpm build:deps",
312
+ format: 'prettier --write "src/**/*.ts"',
313
+ "format:check": 'prettier --check "src/**/*.ts"',
314
+ test: "jest",
315
+ version: "pnpm pkg get version"
316
+ },
317
+ exports: {
318
+ ".": {
319
+ types: "./dist/index.d.ts",
320
+ import: "./dist/index.js",
321
+ require: "./dist/index.cjs"
322
+ },
323
+ "./session": {
324
+ types: "./dist/session/index.d.ts",
325
+ import: "./dist/session/index.js",
326
+ require: "./dist/session/index.cjs"
327
+ },
328
+ "./session/node": {
329
+ types: "./dist/node/index.d.ts",
330
+ import: "./dist/node/index.js",
331
+ require: "./dist/node/index.cjs"
332
+ },
333
+ "./provider": {
334
+ types: "./dist/provider/index.d.ts",
335
+ import: "./dist/provider/index.js"
336
+ },
337
+ "./types": {
338
+ types: "./dist/types/index.d.ts",
339
+ import: "./dist/types/index.js"
340
+ }
341
+ },
342
+ tsup: {
343
+ entry: [
344
+ "src/index.ts",
345
+ "src/controller.ts",
346
+ "src/lookup.ts",
347
+ "src/session/index.ts",
348
+ "src/node/index.ts"
349
+ ],
350
+ format: [
351
+ "esm",
352
+ "cjs"
353
+ ],
354
+ splitting: false,
355
+ sourcemap: true,
356
+ clean: true,
357
+ dts: true,
358
+ treeshake: {
359
+ preset: "recommended"
360
+ },
361
+ exports: "named"
362
+ },
363
+ peerDependencies: {
364
+ starknet: "catalog:",
365
+ open: "^10.1.0"
366
+ },
367
+ dependencies: {
368
+ "@cartridge/account-wasm": "workspace:*",
369
+ "@cartridge/penpal": "catalog:",
370
+ "@starknet-io/types-js": "catalog:",
371
+ "@telegram-apps/sdk": "^2.4.0",
372
+ base64url: "catalog:",
373
+ "cbor-x": "^1.5.0",
374
+ "fast-deep-equal": "catalog:"
375
+ },
376
+ devDependencies: {
377
+ "@cartridge/tsconfig": "workspace:*",
378
+ "@types/jest": "^29.5.14",
379
+ "@types/node": "catalog:",
380
+ jest: "^29.7.0",
381
+ prettier: "catalog:",
382
+ "ts-jest": "^29.2.5",
383
+ tsup: "catalog:",
384
+ typescript: "catalog:"
385
+ }
386
+ };
387
+
388
+ // src/icon.ts
389
+ var icon = "data:image/png;base64,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";
390
+
391
+ // src/mutex.ts
392
+ function releaseStub() {
393
+ }
394
+ var Mutex = class {
395
+ m_lastPromise = Promise.resolve();
396
+ /**
397
+ * Acquire lock
398
+ * @param [bypass=false] option to skip lock acquisition
399
+ */
400
+ async obtain(bypass = false) {
401
+ let release = releaseStub;
402
+ if (bypass) return release;
403
+ const lastPromise = this.m_lastPromise;
404
+ this.m_lastPromise = new Promise((resolve) => release = resolve);
405
+ await lastPromise;
406
+ return release;
407
+ }
408
+ };
409
+
410
+ // src/provider.ts
411
+ var mutex = new Mutex();
412
+ var BaseProvider = class {
413
+ id = "controller";
414
+ name = "Controller";
415
+ version = package_default.version;
416
+ icon = icon;
417
+ account;
418
+ subscriptions = [];
419
+ _probePromise = null;
420
+ async safeProbe() {
421
+ if (this.account) {
422
+ return this.account;
423
+ }
424
+ if (this._probePromise) {
425
+ return this._probePromise;
426
+ }
427
+ const release = await mutex.obtain();
428
+ return await new Promise(async (resolve) => {
429
+ try {
430
+ this._probePromise = this.probe();
431
+ const result = await this._probePromise;
432
+ resolve(result);
433
+ } finally {
434
+ this._probePromise = null;
435
+ }
436
+ }).finally(() => {
437
+ release();
438
+ });
439
+ }
440
+ request = async (call) => {
441
+ switch (call.type) {
442
+ case "wallet_getPermissions":
443
+ await this.safeProbe();
444
+ if (this.account) {
445
+ return [typesJs.Permission.ACCOUNTS];
446
+ }
447
+ return [];
448
+ case "wallet_requestAccounts": {
449
+ if (this.account) {
450
+ return [this.account.address];
451
+ }
452
+ const silentMode = call.params && call.params.silent_mode;
453
+ this.account = await this.safeProbe();
454
+ if (!this.account && !silentMode) {
455
+ this.account = await this.connect();
456
+ }
457
+ if (this.account) {
458
+ return [this.account.address];
459
+ }
460
+ return [];
461
+ }
462
+ case "wallet_watchAsset":
463
+ throw {
464
+ code: 63,
465
+ message: "An unexpected error occurred",
466
+ data: "wallet_watchAsset not implemented"
467
+ };
468
+ case "wallet_addStarknetChain": {
469
+ let params2 = call.params;
470
+ return this.addStarknetChain(params2);
471
+ }
472
+ case "wallet_switchStarknetChain": {
473
+ let params2 = call.params;
474
+ return this.switchStarknetChain(params2.chainId);
475
+ }
476
+ case "wallet_requestChainId":
477
+ if (!this.account) {
478
+ throw {
479
+ code: 63,
480
+ message: "An unexpected error occurred",
481
+ data: "Account not initialized"
482
+ };
483
+ }
484
+ return await this.account.getChainId();
485
+ case "wallet_deploymentData":
486
+ throw {
487
+ code: 63,
488
+ message: "An unexpected error occurred",
489
+ data: "wallet_deploymentData not implemented"
490
+ };
491
+ case "wallet_addInvokeTransaction":
492
+ if (!this.account) {
493
+ throw {
494
+ code: 63,
495
+ message: "An unexpected error occurred",
496
+ data: "Account not initialized"
497
+ };
498
+ }
499
+ let params = call.params;
500
+ return await this.account.execute(
501
+ params.calls.map((call2) => ({
502
+ contractAddress: call2.contract_address,
503
+ entrypoint: call2.entry_point,
504
+ calldata: call2.calldata
505
+ }))
506
+ );
507
+ case "wallet_addDeclareTransaction":
508
+ throw {
509
+ code: 63,
510
+ message: "An unexpected error occurred",
511
+ data: "wallet_addDeclareTransaction not implemented"
512
+ };
513
+ case "wallet_signTypedData": {
514
+ if (!this.account) {
515
+ throw {
516
+ code: 63,
517
+ message: "An unexpected error occurred",
518
+ data: "Account not initialized"
519
+ };
520
+ }
521
+ return await this.account.signMessage(call.params);
522
+ }
523
+ case "wallet_supportedSpecs":
524
+ return [];
525
+ case "wallet_supportedWalletApi":
526
+ return [];
527
+ default:
528
+ throw {
529
+ code: 63,
530
+ message: "An unexpected error occurred",
531
+ data: `Unknown RPC call type: ${call.type}`
532
+ };
533
+ }
534
+ };
535
+ on = (event, handler) => {
536
+ if (event !== "accountsChanged" && event !== "networkChanged") {
537
+ throw new Error(`Unknown event: ${event}`);
538
+ }
539
+ this.subscriptions.push({ type: event, handler });
540
+ };
541
+ off = (event, handler) => {
542
+ if (event !== "accountsChanged" && event !== "networkChanged") {
543
+ throw new Error(`Unknown event: ${event}`);
544
+ }
545
+ const idx = this.subscriptions.findIndex(
546
+ (sub) => sub.type === event && sub.handler === handler
547
+ );
548
+ if (idx >= 0) {
549
+ this.subscriptions.splice(idx, 1);
550
+ }
551
+ };
552
+ emitNetworkChanged(chainId) {
553
+ this.subscriptions.filter((sub) => sub.type === "networkChanged").forEach((sub) => {
554
+ sub.handler(chainId);
555
+ });
556
+ }
557
+ emitAccountsChanged(accounts) {
558
+ this.subscriptions.filter((sub) => sub.type === "accountsChanged").forEach((sub) => {
559
+ sub.handler(accounts);
560
+ });
561
+ }
562
+ };
563
+
564
+ // src/controller.ts
565
+ var ControllerProvider = class extends BaseProvider {
566
+ keychain;
567
+ profile;
568
+ options;
569
+ iframes;
570
+ selectedChain;
571
+ chains;
572
+ constructor(options) {
573
+ super();
574
+ const chains = /* @__PURE__ */ new Map();
575
+ for (const chain of options.chains) {
576
+ const url = new URL(chain.rpcUrl);
577
+ const chainId = parseChainId(url);
578
+ chains.set(chainId, chain);
579
+ }
580
+ if (options.policies?.messages?.length && options.policies.messages.length !== chains.size) {
581
+ console.warn(
582
+ "Each message policy is associated with a specific chain. The number of message policies does not match the number of chains specified - session message signing may not work on some chains."
583
+ );
584
+ }
585
+ this.chains = chains;
586
+ this.selectedChain = options.defaultChainId;
587
+ if (!this.chains.has(this.selectedChain)) {
588
+ throw new Error(
589
+ `Chain ${this.selectedChain} not found in configured chains`
590
+ );
591
+ }
592
+ this.iframes = {
593
+ keychain: new KeychainIFrame({
594
+ ...options,
595
+ onClose: this.keychain?.reset,
596
+ onConnect: (keychain) => {
597
+ this.keychain = keychain;
598
+ }
599
+ })
600
+ };
601
+ this.options = options;
602
+ if (typeof window !== "undefined") {
603
+ window.starknet_controller = this;
604
+ }
605
+ }
606
+ async probe() {
607
+ try {
608
+ await this.waitForKeychain();
609
+ if (!this.keychain) {
610
+ console.error(new NotReadyToConnect().message);
611
+ return;
612
+ }
613
+ const response = await this.keychain.probe(this.rpcUrl());
614
+ let rpcUrl = response?.rpcUrl || this.rpcUrl();
615
+ this.account = new account_default(
616
+ this,
617
+ rpcUrl,
618
+ response.address,
619
+ this.keychain,
620
+ this.options,
621
+ this.iframes.keychain
622
+ );
623
+ } catch (e) {
624
+ console.error(e);
625
+ return;
626
+ }
627
+ if (!this.iframes.profile) {
628
+ const username = await this.keychain.username();
629
+ this.iframes.profile = new ProfileIFrame({
630
+ ...this.options,
631
+ onConnect: (profile) => {
632
+ this.profile = profile;
633
+ },
634
+ methods: {
635
+ openSettings: () => this.openSettings.bind(this),
636
+ openPurchaseCredits: () => this.openPurchaseCredits.bind(this),
637
+ openExecute: () => this.openExecute.bind(this)
638
+ },
639
+ rpcUrl: this.rpcUrl(),
640
+ username,
641
+ version: this.version
642
+ });
643
+ }
644
+ return this.account;
645
+ }
646
+ async connect() {
647
+ if (this.account) {
648
+ return this.account;
649
+ }
650
+ if (!this.keychain || !this.iframes.keychain) {
651
+ console.error(new NotReadyToConnect().message);
652
+ return;
653
+ }
654
+ if (!!document.hasStorageAccess) {
655
+ const ok = await document.hasStorageAccess();
656
+ if (!ok) {
657
+ await document.requestStorageAccess();
658
+ }
659
+ }
660
+ this.iframes.keychain.open();
661
+ try {
662
+ let response = await this.keychain.connect(
663
+ this.options.policies || {},
664
+ this.rpcUrl()
665
+ );
666
+ if (response.code !== "SUCCESS" /* SUCCESS */) {
667
+ throw new Error(response.message);
668
+ }
669
+ response = response;
670
+ this.account = new account_default(
671
+ this,
672
+ this.rpcUrl(),
673
+ response.address,
674
+ this.keychain,
675
+ this.options,
676
+ this.iframes.keychain
677
+ );
678
+ return this.account;
679
+ } catch (e) {
680
+ console.log(e);
681
+ } finally {
682
+ this.iframes.keychain.close();
683
+ }
684
+ }
685
+ async switchStarknetChain(chainId) {
686
+ if (!this.keychain || !this.iframes.keychain) {
687
+ console.error(new NotReadyToConnect().message);
688
+ return false;
689
+ }
690
+ try {
691
+ this.selectedChain = chainId;
692
+ const response = await this.keychain.probe(this.rpcUrl());
693
+ if (response.rpcUrl === this.rpcUrl()) {
694
+ return true;
695
+ }
696
+ await this.keychain.switchChain(this.rpcUrl());
697
+ } catch (e) {
698
+ console.error(e);
699
+ return false;
700
+ }
701
+ this.emitNetworkChanged(chainId);
702
+ return true;
703
+ }
704
+ addStarknetChain(_chain) {
705
+ return Promise.resolve(true);
706
+ }
707
+ async disconnect() {
708
+ if (!this.keychain) {
709
+ console.error(new NotReadyToConnect().message);
710
+ return;
711
+ }
712
+ if (!!document.hasStorageAccess) {
713
+ const ok = await document.hasStorageAccess();
714
+ if (!ok) {
715
+ await document.requestStorageAccess();
716
+ }
717
+ }
718
+ this.account = undefined;
719
+ return this.keychain.disconnect();
720
+ }
721
+ async openProfile(tab = "inventory") {
722
+ if (!this.profile || !this.iframes.profile?.url) {
723
+ console.error("Profile is not ready");
724
+ return;
725
+ }
726
+ if (!this.account) {
727
+ console.error("Account is not ready");
728
+ return;
729
+ }
730
+ this.profile.navigate(`${this.iframes.profile.url?.pathname}/${tab}`);
731
+ this.iframes.profile.open();
732
+ }
733
+ async openProfileTo(to) {
734
+ if (!this.profile || !this.iframes.profile?.url) {
735
+ console.error("Profile is not ready");
736
+ return;
737
+ }
738
+ if (!this.account) {
739
+ console.error("Account is not ready");
740
+ return;
741
+ }
742
+ this.profile.navigate(`${this.iframes.profile.url?.pathname}/${to}`);
743
+ this.iframes.profile.open();
744
+ }
745
+ async openProfileAt(at) {
746
+ if (!this.profile || !this.iframes.profile?.url) {
747
+ console.error("Profile is not ready");
748
+ return;
749
+ }
750
+ if (!this.account) {
751
+ console.error("Account is not ready");
752
+ return;
753
+ }
754
+ this.profile.navigate(at);
755
+ this.iframes.profile.open();
756
+ }
757
+ async openSettings() {
758
+ if (!this.keychain || !this.iframes.keychain) {
759
+ console.error(new NotReadyToConnect().message);
760
+ return null;
761
+ }
762
+ if (this.iframes.profile?.sendBackward) {
763
+ this.iframes.profile?.sendBackward();
764
+ } else {
765
+ this.iframes.profile?.close();
766
+ }
767
+ this.iframes.keychain.open();
768
+ const res = await this.keychain.openSettings();
769
+ this.iframes.keychain.close();
770
+ this.iframes.profile?.sendForward?.();
771
+ if (res && res.code === "NOT_CONNECTED" /* NOT_CONNECTED */) {
772
+ return false;
773
+ }
774
+ return true;
775
+ }
776
+ revoke(origin, _policy) {
777
+ if (!this.keychain) {
778
+ console.error(new NotReadyToConnect().message);
779
+ return null;
780
+ }
781
+ return this.keychain.revoke(origin);
782
+ }
783
+ rpcUrl() {
784
+ return this.chains.get(this.selectedChain).rpcUrl;
785
+ }
786
+ username() {
787
+ if (!this.keychain) {
788
+ console.error(new NotReadyToConnect().message);
789
+ return;
790
+ }
791
+ return this.keychain.username();
792
+ }
793
+ openPurchaseCredits() {
794
+ if (!this.keychain || !this.iframes.keychain) {
795
+ console.error(new NotReadyToConnect().message);
796
+ return;
797
+ }
798
+ if (!this.iframes.profile) {
799
+ console.error("Profile is not ready");
800
+ return;
801
+ }
802
+ this.iframes.profile.close();
803
+ this.iframes.keychain.open();
804
+ this.keychain.openPurchaseCredits();
805
+ }
806
+ async openExecute(calls, chainId) {
807
+ if (!this.keychain || !this.iframes.keychain) {
808
+ console.error(new NotReadyToConnect().message);
809
+ return;
810
+ }
811
+ if (!this.iframes.profile) {
812
+ console.error("Profile is not ready");
813
+ return;
814
+ }
815
+ let currentChainId = this.selectedChain;
816
+ if (chainId) {
817
+ this.switchStarknetChain(chainId);
818
+ }
819
+ this.iframes.profile?.sendBackward();
820
+ this.iframes.keychain.open();
821
+ this.iframes.profile?.close();
822
+ const res = await this.keychain.execute(calls, undefined, undefined, true);
823
+ this.iframes.profile?.open();
824
+ this.iframes.keychain.close();
825
+ this.iframes.profile?.sendForward();
826
+ if (chainId) {
827
+ this.switchStarknetChain(currentChainId);
828
+ }
829
+ return !(res && (res.code === "NOT_CONNECTED" /* NOT_CONNECTED */ || res.code === "CANCELED" /* CANCELED */));
830
+ }
831
+ async delegateAccount() {
832
+ if (!this.keychain) {
833
+ console.error(new NotReadyToConnect().message);
834
+ return null;
835
+ }
836
+ return await this.keychain.delegateAccount();
837
+ }
838
+ waitForKeychain({
839
+ timeout = 5e4,
840
+ interval = 100
841
+ } = {}) {
842
+ return new Promise((resolve, reject) => {
843
+ const startTime = Date.now();
844
+ const id = setInterval(() => {
845
+ if (Date.now() - startTime > timeout) {
846
+ clearInterval(id);
847
+ reject(new Error("Timeout waiting for keychain"));
848
+ return;
849
+ }
850
+ if (!this.keychain) return;
851
+ clearInterval(id);
852
+ resolve();
853
+ }, interval);
854
+ });
855
+ }
856
+ };
857
+
858
+ module.exports = ControllerProvider;
859
+ //# sourceMappingURL=controller.cjs.map
860
+ //# sourceMappingURL=controller.cjs.map