@cartridge/controller 0.5.0-alpha.4 → 0.5.0-alpha.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 (71) hide show
  1. package/.turbo/turbo-build$colon$deps.log +116 -4
  2. package/dist/account.d.ts +9 -6
  3. package/dist/account.js +84 -74
  4. package/dist/account.js.map +1 -1
  5. package/dist/constants.d.ts +4 -2
  6. package/dist/constants.js +7 -2
  7. package/dist/constants.js.map +1 -1
  8. package/dist/controller.d.ts +12 -5
  9. package/dist/controller.js +739 -182
  10. package/dist/controller.js.map +1 -1
  11. package/dist/errors.d.ts +3 -1
  12. package/dist/errors.js +10 -6
  13. package/dist/errors.js.map +1 -1
  14. package/dist/icon.d.ts +3 -1
  15. package/dist/icon.js +5 -1
  16. package/dist/icon.js.map +1 -1
  17. package/dist/iframe/base.d.ts +5 -23
  18. package/dist/iframe/base.js +272 -98
  19. package/dist/iframe/base.js.map +1 -1
  20. package/dist/iframe/index.d.ts +5 -3
  21. package/dist/iframe/index.js +331 -3
  22. package/dist/iframe/index.js.map +1 -1
  23. package/dist/iframe/keychain.d.ts +5 -7
  24. package/dist/iframe/keychain.js +294 -13
  25. package/dist/iframe/keychain.js.map +1 -1
  26. package/dist/iframe/profile.d.ts +5 -11
  27. package/dist/iframe/profile.js +308 -16
  28. package/dist/iframe/profile.js.map +1 -1
  29. package/dist/index.d.ts +9 -4
  30. package/dist/index.js +767 -4
  31. package/dist/index.js.map +1 -1
  32. package/dist/presets.d.ts +9 -2
  33. package/dist/presets.js +159 -146
  34. package/dist/presets.js.map +1 -1
  35. package/dist/provider.d.ts +9 -4
  36. package/dist/provider.js +138 -124
  37. package/dist/provider.js.map +1 -1
  38. package/dist/session/account.d.ts +14 -8
  39. package/dist/session/account.js +235 -27
  40. package/dist/session/account.js.map +1 -1
  41. package/dist/session/backend.d.ts +4 -2
  42. package/dist/session/backend.js +38 -37
  43. package/dist/session/backend.js.map +1 -1
  44. package/dist/session/index.d.ts +9 -5
  45. package/dist/session/index.js +467 -5
  46. package/dist/session/index.js.map +1 -1
  47. package/dist/session/provider.d.ts +12 -8
  48. package/dist/session/provider.js +281 -81
  49. package/dist/session/provider.js.map +1 -1
  50. package/dist/telegram/backend.d.ts +5 -2
  51. package/dist/telegram/backend.js +38 -37
  52. package/dist/telegram/backend.js.map +1 -1
  53. package/dist/telegram/provider.d.ts +7 -4
  54. package/dist/telegram/provider.js +283 -70
  55. package/dist/telegram/provider.js.map +1 -1
  56. package/dist/types-DIeWpu0p.d.ts +196 -0
  57. package/dist/types.d.ts +5 -159
  58. package/dist/types.js +12 -8
  59. package/dist/types.js.map +1 -1
  60. package/dist/utils.d.ts +7 -3
  61. package/dist/utils.js +12 -8
  62. package/dist/utils.js.map +1 -1
  63. package/package.json +17 -14
  64. package/src/controller.ts +13 -25
  65. package/src/iframe/base.ts +3 -0
  66. package/src/iframe/profile.ts +17 -9
  67. package/src/presets.ts +10 -1
  68. package/src/session/provider.ts +1 -2
  69. package/src/types.ts +3 -7
  70. package/tsconfig.json +4 -1
  71. package/tsconfig.tsbuildinfo +0 -1
@@ -1,196 +1,753 @@
1
- import ControllerAccount from "./account";
2
- import { KeychainIFrame, ProfileIFrame } from "./iframe";
3
- import { NotReadyToConnect } from "./errors";
4
- import { ResponseCodes, } from "./types";
5
- import BaseProvider from "./provider";
6
- export default class ControllerProvider extends BaseProvider {
7
- constructor(options) {
8
- const { rpc } = options;
9
- super({ rpc });
10
- this.iframes = {
11
- keychain: new KeychainIFrame({
12
- ...options,
13
- onClose: this.keychain?.reset,
14
- onConnect: (keychain) => {
15
- this.keychain = keychain;
16
- },
17
- }),
18
- };
19
- this.options = options;
20
- if (typeof window !== "undefined") {
21
- window.starknet_controller = this;
22
- }
1
+ // src/account.ts
2
+ import {
3
+ WalletAccount
4
+ } from "starknet";
5
+ var ControllerAccount = class extends WalletAccount {
6
+ constructor(provider, address, keychain, options, modal) {
7
+ super({ nodeUrl: provider.rpc.toString() }, provider);
8
+ this.address = address;
9
+ this.keychain = keychain;
10
+ this.options = options;
11
+ this.modal = modal;
12
+ }
13
+ /**
14
+ * Invoke execute function in account contract
15
+ *
16
+ * @param calls the invocation object or an array of them, containing:
17
+ * - contractAddress - the address of the contract
18
+ * - entrypoint - the entrypoint of the contract
19
+ * - calldata - (defaults to []) the calldata
20
+ * - signature - (defaults to []) the signature
21
+ * @param abis (optional) the abi of the contract for better displaying
22
+ *
23
+ * @returns response from addTransaction
24
+ */
25
+ async execute(calls) {
26
+ calls = Array.isArray(calls) ? calls : [calls];
27
+ return new Promise(async (resolve, reject) => {
28
+ const sessionExecute = await this.keychain.execute(
29
+ calls,
30
+ void 0,
31
+ void 0,
32
+ false
33
+ );
34
+ if (sessionExecute.code === "SUCCESS" /* SUCCESS */) {
35
+ resolve(sessionExecute);
36
+ return;
37
+ }
38
+ if (this.options?.propagateSessionErrors) {
39
+ reject(sessionExecute.error);
40
+ return;
41
+ }
42
+ this.modal.open();
43
+ const manualExecute = await this.keychain.execute(
44
+ calls,
45
+ void 0,
46
+ void 0,
47
+ true,
48
+ sessionExecute.error
49
+ );
50
+ if (manualExecute.code === "SUCCESS" /* SUCCESS */) {
51
+ resolve(manualExecute);
52
+ this.modal.close();
53
+ return;
54
+ }
55
+ reject(manualExecute.error);
56
+ return;
57
+ });
58
+ }
59
+ /**
60
+ * Sign an JSON object for off-chain usage with the starknet private key and return the signature
61
+ * This adds a message prefix so it cant be interchanged with transactions
62
+ *
63
+ * @param json - JSON object to be signed
64
+ * @returns the signature of the JSON object
65
+ * @throws {Error} if the JSON object is not a valid JSON
66
+ */
67
+ async signMessage(typedData) {
68
+ try {
69
+ this.modal.open();
70
+ const res = await this.keychain.signMessage(typedData, "");
71
+ this.modal.close();
72
+ if ("code" in res) {
73
+ throw res;
74
+ }
75
+ return res;
76
+ } catch (e) {
77
+ console.error(e);
78
+ throw e;
23
79
  }
24
- async probe() {
25
- try {
26
- await this.waitForKeychain();
27
- if (!this.keychain) {
28
- console.error(new NotReadyToConnect().message);
29
- return;
30
- }
31
- const response = (await this.keychain.probe(this.rpc.toString()));
32
- this.account = new ControllerAccount(this, response.address, this.keychain, this.options, this.iframes.keychain);
33
- }
34
- catch (e) {
35
- console.error(e);
36
- return;
37
- }
38
- if (this.options.profileUrl &&
39
- this.options.indexerUrl &&
40
- this.options.namespace &&
41
- !this.iframes.profile) {
42
- const username = await this.keychain.username();
43
- this.iframes.profile = new ProfileIFrame({
44
- profileUrl: this.options.profileUrl,
45
- indexerUrl: this.options.indexerUrl,
46
- username,
47
- namespace: this.options.namespace,
48
- rpcUrl: this.rpc.toString(),
49
- tokens: this.options.tokens,
50
- onConnect: (profile) => {
51
- this.profile = profile;
52
- },
53
- methods: {
54
- openPurchaseCredits: this.openPurchaseCredits.bind(this),
55
- },
56
- });
57
- }
58
- return this.account;
80
+ }
81
+ };
82
+ var account_default = ControllerAccount;
83
+
84
+ // src/iframe/base.ts
85
+ import { connectToChild } from "@cartridge/penpal";
86
+
87
+ // src/presets.ts
88
+ var defaultPresets = {
89
+ cartridge: {
90
+ id: "cartridge",
91
+ name: "Cartridge",
92
+ icon: "/whitelabel/cartridge/icon.svg",
93
+ cover: {
94
+ light: "/whitelabel/cartridge/cover-light.png",
95
+ dark: "/whitelabel/cartridge/cover-dark.png"
59
96
  }
60
- async connect() {
61
- if (this.account) {
62
- return this.account;
63
- }
64
- if (!this.keychain || !this.iframes.keychain) {
65
- console.error(new NotReadyToConnect().message);
66
- return;
67
- }
68
- if (!!document.hasStorageAccess) {
69
- const ok = await document.hasStorageAccess();
70
- if (!ok) {
71
- await document.requestStorageAccess();
72
- }
73
- }
74
- this.iframes.keychain.open();
75
- try {
76
- let response = await this.keychain.connect(this.options.policies || [], this.rpc.toString());
77
- if (response.code !== ResponseCodes.SUCCESS) {
78
- throw new Error(response.message);
79
- }
80
- response = response;
81
- this.account = new ControllerAccount(this, response.address, this.keychain, this.options, this.iframes.keychain);
82
- return this.account;
83
- }
84
- catch (e) {
85
- console.log(e);
86
- }
87
- finally {
88
- this.iframes.keychain.close();
89
- }
97
+ },
98
+ "force-prime": {
99
+ id: "force-prime",
100
+ name: "Force Prime",
101
+ icon: "/whitelabel/force-prime/icon.png",
102
+ cover: "/whitelabel/force-prime/cover.png",
103
+ colors: {
104
+ primary: "#E1CC89"
90
105
  }
91
- async disconnect() {
92
- if (!this.keychain) {
93
- console.error(new NotReadyToConnect().message);
94
- return;
95
- }
96
- if (!!document.hasStorageAccess) {
97
- const ok = await document.hasStorageAccess();
98
- if (!ok) {
99
- await document.requestStorageAccess();
100
- }
101
- }
102
- this.account = undefined;
103
- return this.keychain.disconnect();
106
+ },
107
+ paved: {
108
+ id: "paved",
109
+ name: "Paved",
110
+ icon: "/whitelabel/paved/icon.svg",
111
+ cover: "/whitelabel/paved/cover.png",
112
+ colors: {
113
+ primary: "#B0CAF8"
104
114
  }
105
- async openProfile(tab = "inventory") {
106
- if (!this.options.indexerUrl) {
107
- console.error("`indexerUrl` option is required to open profile");
108
- return;
109
- }
110
- if (!this.options.namespace) {
111
- console.error("`namespace` option is required to open profile");
112
- return;
113
- }
114
- if (!this.profile || !this.iframes.profile) {
115
- console.error("Profile is not ready");
116
- return;
115
+ },
116
+ eternum: {
117
+ id: "eternum",
118
+ name: "Eternum",
119
+ icon: "/whitelabel/eternum/icon.gif",
120
+ cover: "/whitelabel/eternum/cover.png",
121
+ colors: {
122
+ primary: "#CE9822"
123
+ }
124
+ },
125
+ pistols: {
126
+ id: "pistols",
127
+ name: "Pistols at Ten Blocks",
128
+ icon: "/whitelabel/pistols/icon.png",
129
+ cover: "/whitelabel/pistols/cover.png",
130
+ colors: {
131
+ primary: "#EF9758"
132
+ }
133
+ },
134
+ pixelaw: {
135
+ id: "pixelaw",
136
+ name: "Pixelaw",
137
+ icon: "/whitelabel/pixelaw/icon.svg",
138
+ cover: "/whitelabel/pixelaw/cover.png",
139
+ colors: {
140
+ primary: "#7C00B1",
141
+ primaryForeground: "white"
142
+ }
143
+ },
144
+ "dope-wars": {
145
+ id: "dope-wars",
146
+ name: "Dope Wars",
147
+ icon: "/whitelabel/dope-wars/icon.png",
148
+ cover: "/whitelabel/dope-wars/cover.png",
149
+ colors: {
150
+ primary: "#11ED83"
151
+ }
152
+ },
153
+ zkastle: {
154
+ id: "zkastle",
155
+ name: "zKastle",
156
+ icon: "/whitelabel/zkastle/icon.svg",
157
+ cover: "/whitelabel/zkastle/cover.png",
158
+ colors: {
159
+ primary: "#E50D2C"
160
+ }
161
+ },
162
+ "loot-survivor": {
163
+ id: "loot-survivor",
164
+ name: "Loot Survivor",
165
+ icon: "/whitelabel/loot-survivor/icon.png",
166
+ cover: "/whitelabel/loot-survivor/cover.png",
167
+ colors: {
168
+ primary: "#33FF33"
169
+ }
170
+ },
171
+ "tale-weaver": {
172
+ id: "tale-weaver",
173
+ name: "Tale Weaver",
174
+ icon: "/whitelabel/tale-weaver/icon.png",
175
+ cover: "/whitelabel/tale-weaver/cover.png",
176
+ colors: {
177
+ primary: "#fce377"
178
+ }
179
+ },
180
+ "realm-of-ra": {
181
+ id: "realm-of-ra",
182
+ name: "Realm of Ra",
183
+ icon: "/whitelabel/realm-of-ra/icon.png",
184
+ cover: "/whitelabel/realm-of-ra/cover.png",
185
+ colors: {
186
+ primary: "#de9534"
187
+ }
188
+ },
189
+ "jokers-of-neon": {
190
+ id: "jokers-of-neon",
191
+ name: "Jokers of Neon",
192
+ icon: "/whitelabel/jokers-of-neon/icon.png",
193
+ cover: "/whitelabel/jokers-of-neon/cover.png",
194
+ colors: {
195
+ primary: "#A144B2"
196
+ }
197
+ },
198
+ flippyflop: {
199
+ id: "flippyflop",
200
+ name: "FlippyFlop",
201
+ icon: "/whitelabel/flippyflop/icon.png",
202
+ cover: "/whitelabel/flippyflop/cover.png",
203
+ colors: {
204
+ primary: "#F38332"
205
+ }
206
+ },
207
+ "savage-summit": {
208
+ id: "savage-summit",
209
+ name: "Savage Summit",
210
+ icon: "/whitelabel/savage-summit/icon.png",
211
+ cover: "/whitelabel/savage-summit/cover.png",
212
+ colors: {
213
+ primary: "#fbf7da"
214
+ }
215
+ },
216
+ "dark-shuffle": {
217
+ id: "dark-shuffle",
218
+ name: "Dark Shuffle",
219
+ icon: "/whitelabel/dark-shuffle/icon.svg",
220
+ cover: "/whitelabel/dark-shuffle/cover.png",
221
+ colors: {
222
+ primary: "#F59100"
223
+ }
224
+ },
225
+ "blob-arena": {
226
+ id: "blob-arena",
227
+ name: "Blob Arena",
228
+ icon: "/whitelabel/blob-arena/icon.png",
229
+ cover: "/whitelabel/blob-arena/cover.png",
230
+ colors: {
231
+ primary: "#980f06"
232
+ }
233
+ },
234
+ zkube: {
235
+ id: "zkube",
236
+ name: "zKube",
237
+ icon: "/whitelabel/zkube/icon.png",
238
+ cover: "/whitelabel/zkube/cover.png",
239
+ colors: {
240
+ primary: "#5bc3e6"
241
+ }
242
+ }
243
+ };
244
+
245
+ // src/iframe/base.ts
246
+ var IFrame = class {
247
+ constructor({
248
+ id,
249
+ url,
250
+ theme,
251
+ config,
252
+ colorMode,
253
+ onClose,
254
+ onConnect,
255
+ methods = {}
256
+ }) {
257
+ if (typeof document === "undefined") {
258
+ return;
259
+ }
260
+ url.searchParams.set(
261
+ "theme",
262
+ encodeURIComponent(
263
+ JSON.stringify(
264
+ config?.presets?.[theme ?? "cartridge"] ?? defaultPresets.cartridge
265
+ )
266
+ )
267
+ );
268
+ if (colorMode) {
269
+ url.searchParams.set("colorMode", colorMode);
270
+ }
271
+ this.url = url;
272
+ const iframe = document.createElement("iframe");
273
+ iframe.src = url.toString();
274
+ iframe.id = id;
275
+ iframe.style.border = "none";
276
+ iframe.sandbox.add("allow-forms");
277
+ iframe.sandbox.add("allow-popups");
278
+ iframe.sandbox.add("allow-scripts");
279
+ iframe.sandbox.add("allow-same-origin");
280
+ iframe.allow = "publickey-credentials-create *; publickey-credentials-get *; clipboard-write";
281
+ if (!!document.hasStorageAccess) {
282
+ iframe.sandbox.add("allow-storage-access-by-user-activation");
283
+ }
284
+ const container = document.createElement("div");
285
+ container.id = "controller";
286
+ container.style.position = "fixed";
287
+ container.style.height = "100%";
288
+ container.style.width = "100%";
289
+ container.style.top = "0";
290
+ container.style.left = "0";
291
+ container.style.zIndex = "10000";
292
+ container.style.backgroundColor = "rgba(0,0,0,0.6)";
293
+ container.style.display = "flex";
294
+ container.style.alignItems = "center";
295
+ container.style.justifyContent = "center";
296
+ container.style.visibility = "hidden";
297
+ container.style.opacity = "0";
298
+ container.style.transition = "opacity 0.2s ease";
299
+ container.appendChild(iframe);
300
+ this.iframe = iframe;
301
+ this.container = container;
302
+ connectToChild({
303
+ iframe: this.iframe,
304
+ methods: { close: () => this.close(), ...methods }
305
+ }).promise.then(onConnect);
306
+ this.resize();
307
+ window.addEventListener("resize", () => this.resize());
308
+ const observer = new MutationObserver(() => {
309
+ const existingController2 = document.getElementById("controller");
310
+ if (document.body) {
311
+ if (id === "controller-keychain" && !existingController2 || id === "controller-profile") {
312
+ document.body.appendChild(container);
313
+ observer.disconnect();
117
314
  }
118
- if (!this.account) {
119
- console.error("Account is not ready");
120
- return;
315
+ }
316
+ });
317
+ observer.observe(document.documentElement, {
318
+ childList: true,
319
+ subtree: true
320
+ });
321
+ const existingController = document.getElementById("controller");
322
+ if (document.body) {
323
+ if (id === "controller-keychain" && !existingController || id === "controller-profile") {
324
+ document.body.appendChild(container);
325
+ }
326
+ }
327
+ this.onClose = onClose;
328
+ }
329
+ open() {
330
+ if (!this.container) return;
331
+ document.body.style.overflow = "hidden";
332
+ this.container.style.visibility = "visible";
333
+ this.container.style.opacity = "1";
334
+ }
335
+ close() {
336
+ if (!this.container) return;
337
+ this.onClose?.();
338
+ document.body.style.overflow = "auto";
339
+ this.container.style.visibility = "hidden";
340
+ this.container.style.opacity = "0";
341
+ }
342
+ resize() {
343
+ if (!this.iframe) return;
344
+ this.iframe.style.userSelect = "none";
345
+ if (window.innerWidth < 768) {
346
+ this.iframe.style.height = "100%";
347
+ this.iframe.style.width = "100%";
348
+ this.iframe.style.borderRadius = "0";
349
+ return;
350
+ }
351
+ this.iframe.style.height = "600px";
352
+ this.iframe.style.width = "432px";
353
+ this.iframe.style.borderRadius = "8px";
354
+ }
355
+ };
356
+
357
+ // src/constants.ts
358
+ var KEYCHAIN_URL = "https://x.cartridge.gg";
359
+ var PROFILE_URL = "https://profile.cartridge.gg";
360
+
361
+ // src/iframe/keychain.ts
362
+ var KeychainIFrame = class extends IFrame {
363
+ constructor({ url, policies, ...iframeOptions }) {
364
+ const _url = new URL(url ?? KEYCHAIN_URL);
365
+ if (policies) {
366
+ _url.searchParams.set(
367
+ "policies",
368
+ encodeURIComponent(JSON.stringify(policies))
369
+ );
370
+ }
371
+ super({
372
+ ...iframeOptions,
373
+ id: "controller-keychain",
374
+ url: _url
375
+ });
376
+ }
377
+ };
378
+
379
+ // src/iframe/profile.ts
380
+ var ProfileIFrame = class extends IFrame {
381
+ constructor({
382
+ profileUrl,
383
+ rpcUrl,
384
+ namespace,
385
+ slot,
386
+ username,
387
+ tokens,
388
+ ...iframeOptions
389
+ }) {
390
+ const _profileUrl = profileUrl || PROFILE_URL;
391
+ const _url = new URL(
392
+ slot ? namespace ? `${_profileUrl}/account/${username}/slot/${slot}?ns=${encodeURIComponent(
393
+ namespace
394
+ )}` : `${_profileUrl}/account/${username}/slot/${slot}` : `${_profileUrl}/account/${username}`
395
+ );
396
+ _url.searchParams.set("rpcUrl", encodeURIComponent(rpcUrl));
397
+ if (tokens?.erc20) {
398
+ _url.searchParams.set(
399
+ "erc20",
400
+ encodeURIComponent(tokens.erc20.toString())
401
+ );
402
+ }
403
+ super({
404
+ ...iframeOptions,
405
+ id: "controller-profile",
406
+ url: _url
407
+ });
408
+ }
409
+ };
410
+
411
+ // src/errors.ts
412
+ var NotReadyToConnect = class _NotReadyToConnect extends Error {
413
+ constructor() {
414
+ super("Not ready to connect");
415
+ Object.setPrototypeOf(this, _NotReadyToConnect.prototype);
416
+ }
417
+ };
418
+
419
+ // src/provider.ts
420
+ import {
421
+ Permission
422
+ } from "@starknet-io/types-js";
423
+
424
+ // src/icon.ts
425
+ var icon = "data:image/png;base64,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";
426
+
427
+ // src/provider.ts
428
+ var BaseProvider = class {
429
+ constructor(options) {
430
+ this.id = "controller";
431
+ this.name = "Controller";
432
+ this.version = "0.4.0";
433
+ this.icon = icon;
434
+ this.subscriptions = [];
435
+ this.request = async (call) => {
436
+ switch (call.type) {
437
+ case "wallet_getPermissions":
438
+ await this.probe();
439
+ if (this.account) {
440
+ return [Permission.ACCOUNTS];
441
+ }
442
+ return [];
443
+ case "wallet_requestAccounts": {
444
+ if (this.account) {
445
+ return [this.account.address];
446
+ }
447
+ this.account = await this.probe();
448
+ if (!this.account) {
449
+ this.account = await this.connect();
450
+ }
451
+ if (this.account) {
452
+ return [this.account.address];
453
+ }
454
+ return [];
121
455
  }
122
- const username = await this.username();
123
- this.profile.navigate(`/account/${username}/${tab}`);
124
- this.iframes.profile.open();
125
- }
126
- async openSettings() {
127
- if (!this.keychain || !this.iframes.keychain) {
128
- console.error(new NotReadyToConnect().message);
129
- return null;
456
+ case "wallet_watchAsset":
457
+ throw {
458
+ code: 63,
459
+ message: "An unexpected error occurred",
460
+ data: "wallet_watchAsset not implemented"
461
+ };
462
+ case "wallet_addStarknetChain":
463
+ throw {
464
+ code: 63,
465
+ message: "An unexpected error occurred",
466
+ data: "wallet_addStarknetChain not implemented"
467
+ };
468
+ case "wallet_switchStarknetChain":
469
+ throw {
470
+ code: 63,
471
+ message: "An unexpected error occurred",
472
+ data: "wallet_switchStarknetChain not implemented"
473
+ };
474
+ case "wallet_requestChainId":
475
+ if (!this.account) {
476
+ throw {
477
+ code: 63,
478
+ message: "An unexpected error occurred",
479
+ data: "wallet_deploymentData not implemented"
480
+ };
481
+ }
482
+ return await this.account.getChainId();
483
+ case "wallet_deploymentData":
484
+ throw {
485
+ code: 63,
486
+ message: "An unexpected error occurred",
487
+ data: "wallet_deploymentData not implemented"
488
+ };
489
+ case "wallet_addInvokeTransaction":
490
+ if (!this.account) {
491
+ throw {
492
+ code: 63,
493
+ message: "An unexpected error occurred",
494
+ data: "wallet_deploymentData not implemented"
495
+ };
496
+ }
497
+ let params = call.params;
498
+ return await this.account.execute(
499
+ params.calls.map((call2) => ({
500
+ contractAddress: call2.contract_address,
501
+ entrypoint: call2.entry_point,
502
+ calldata: call2.calldata
503
+ }))
504
+ );
505
+ case "wallet_addDeclareTransaction":
506
+ throw {
507
+ code: 63,
508
+ message: "An unexpected error occurred",
509
+ data: "wallet_addDeclareTransaction not implemented"
510
+ };
511
+ case "wallet_signTypedData": {
512
+ if (!this.account) {
513
+ throw {
514
+ code: 63,
515
+ message: "An unexpected error occurred",
516
+ data: "Account not initialized"
517
+ };
518
+ }
519
+ return await this.account.signMessage(call.params);
130
520
  }
131
- this.iframes.keychain.open();
132
- const res = await this.keychain.openSettings();
133
- this.iframes.keychain.close();
134
- if (res && res.code === ResponseCodes.NOT_CONNECTED) {
135
- return false;
521
+ case "wallet_supportedSpecs":
522
+ return [];
523
+ case "wallet_supportedWalletApi":
524
+ return [];
525
+ default:
526
+ throw {
527
+ code: 63,
528
+ message: "An unexpected error occurred",
529
+ data: `Unknown RPC call type: ${call.type}`
530
+ };
531
+ }
532
+ };
533
+ this.on = (event, handler) => {
534
+ if (event !== "accountsChanged" && event !== "networkChanged") {
535
+ throw new Error(`Unknown event: ${event}`);
536
+ }
537
+ this.subscriptions.push({ type: event, handler });
538
+ };
539
+ this.off = (event, handler) => {
540
+ if (event !== "accountsChanged" && event !== "networkChanged") {
541
+ throw new Error(`Unknown event: ${event}`);
542
+ }
543
+ const idx = this.subscriptions.findIndex(
544
+ (sub) => sub.type === event && sub.handler === handler
545
+ );
546
+ if (idx >= 0) {
547
+ this.subscriptions.splice(idx, 1);
548
+ }
549
+ };
550
+ const { rpc } = options;
551
+ this.rpc = new URL(rpc);
552
+ }
553
+ };
554
+
555
+ // src/controller.ts
556
+ var ControllerProvider = class extends BaseProvider {
557
+ constructor(options) {
558
+ const { rpc } = options;
559
+ super({ rpc });
560
+ this.iframes = {
561
+ keychain: new KeychainIFrame({
562
+ ...options,
563
+ onClose: this.keychain?.reset,
564
+ onConnect: (keychain) => {
565
+ this.keychain = keychain;
136
566
  }
137
- return true;
567
+ })
568
+ };
569
+ this.options = options;
570
+ if (typeof window !== "undefined") {
571
+ window.starknet_controller = this;
138
572
  }
139
- revoke(origin, _policy) {
140
- if (!this.keychain) {
141
- console.error(new NotReadyToConnect().message);
142
- return null;
143
- }
144
- return this.keychain.revoke(origin);
573
+ }
574
+ async probe() {
575
+ try {
576
+ await this.waitForKeychain();
577
+ if (!this.keychain) {
578
+ console.error(new NotReadyToConnect().message);
579
+ return;
580
+ }
581
+ const response = await this.keychain.probe(
582
+ this.rpc.toString()
583
+ );
584
+ this.account = new account_default(
585
+ this,
586
+ response.address,
587
+ this.keychain,
588
+ this.options,
589
+ this.iframes.keychain
590
+ );
591
+ } catch (e) {
592
+ console.error(e);
593
+ return;
145
594
  }
146
- username() {
147
- if (!this.keychain) {
148
- console.error(new NotReadyToConnect().message);
149
- return;
150
- }
151
- return this.keychain.username();
595
+ if (this.options.profileUrl && !this.iframes.profile) {
596
+ const username = await this.keychain.username();
597
+ this.iframes.profile = new ProfileIFrame({
598
+ onConnect: (profile) => {
599
+ this.profile = profile;
600
+ },
601
+ methods: {
602
+ openPurchaseCredits: this.openPurchaseCredits.bind(this)
603
+ },
604
+ profileUrl: this.options.profileUrl,
605
+ rpcUrl: this.rpc.toString(),
606
+ username,
607
+ slot: this.options.slot,
608
+ namespace: this.options.namespace,
609
+ tokens: this.options.tokens
610
+ });
152
611
  }
153
- fetchControllers(contractAddresses) {
154
- if (!this.keychain) {
155
- throw new NotReadyToConnect().message;
156
- }
157
- return this.keychain.fetchControllers(contractAddresses);
612
+ return this.account;
613
+ }
614
+ async connect() {
615
+ if (this.account) {
616
+ return this.account;
158
617
  }
159
- openPurchaseCredits() {
160
- if (!this.keychain || !this.iframes.keychain) {
161
- console.error(new NotReadyToConnect().message);
162
- return;
163
- }
164
- if (!this.iframes.profile) {
165
- console.error("Profile is not ready");
166
- return;
167
- }
168
- this.iframes.profile.close();
169
- this.iframes.keychain.open();
170
- this.keychain.openPurchaseCredits();
171
- }
172
- async delegateAccount() {
173
- if (!this.keychain) {
174
- console.error(new NotReadyToConnect().message);
175
- return null;
618
+ if (!this.keychain || !this.iframes.keychain) {
619
+ console.error(new NotReadyToConnect().message);
620
+ return;
621
+ }
622
+ if (!!document.hasStorageAccess) {
623
+ const ok = await document.hasStorageAccess();
624
+ if (!ok) {
625
+ await document.requestStorageAccess();
626
+ }
627
+ }
628
+ this.iframes.keychain.open();
629
+ try {
630
+ let response = await this.keychain.connect(
631
+ this.options.policies || [],
632
+ this.rpc.toString()
633
+ );
634
+ if (response.code !== "SUCCESS" /* SUCCESS */) {
635
+ throw new Error(response.message);
636
+ }
637
+ response = response;
638
+ this.account = new account_default(
639
+ this,
640
+ response.address,
641
+ this.keychain,
642
+ this.options,
643
+ this.iframes.keychain
644
+ );
645
+ return this.account;
646
+ } catch (e) {
647
+ console.log(e);
648
+ } finally {
649
+ this.iframes.keychain.close();
650
+ }
651
+ }
652
+ async disconnect() {
653
+ if (!this.keychain) {
654
+ console.error(new NotReadyToConnect().message);
655
+ return;
656
+ }
657
+ if (!!document.hasStorageAccess) {
658
+ const ok = await document.hasStorageAccess();
659
+ if (!ok) {
660
+ await document.requestStorageAccess();
661
+ }
662
+ }
663
+ this.account = void 0;
664
+ return this.keychain.disconnect();
665
+ }
666
+ async openProfile(tab = "inventory") {
667
+ if (!this.profile || !this.iframes.profile?.url) {
668
+ console.error("Profile is not ready");
669
+ return;
670
+ }
671
+ if (!this.account) {
672
+ console.error("Account is not ready");
673
+ return;
674
+ }
675
+ this.profile.navigate(`${this.iframes.profile.url?.pathname}/${tab}`);
676
+ this.iframes.profile.open();
677
+ }
678
+ async openSettings() {
679
+ if (!this.keychain || !this.iframes.keychain) {
680
+ console.error(new NotReadyToConnect().message);
681
+ return null;
682
+ }
683
+ this.iframes.keychain.open();
684
+ const res = await this.keychain.openSettings();
685
+ this.iframes.keychain.close();
686
+ if (res && res.code === "NOT_CONNECTED" /* NOT_CONNECTED */) {
687
+ return false;
688
+ }
689
+ return true;
690
+ }
691
+ revoke(origin, _policy) {
692
+ if (!this.keychain) {
693
+ console.error(new NotReadyToConnect().message);
694
+ return null;
695
+ }
696
+ return this.keychain.revoke(origin);
697
+ }
698
+ username() {
699
+ if (!this.keychain) {
700
+ console.error(new NotReadyToConnect().message);
701
+ return;
702
+ }
703
+ return this.keychain.username();
704
+ }
705
+ fetchControllers(contractAddresses) {
706
+ if (!this.keychain) {
707
+ throw new NotReadyToConnect().message;
708
+ }
709
+ return this.keychain.fetchControllers(contractAddresses);
710
+ }
711
+ openPurchaseCredits() {
712
+ if (!this.keychain || !this.iframes.keychain) {
713
+ console.error(new NotReadyToConnect().message);
714
+ return;
715
+ }
716
+ if (!this.iframes.profile) {
717
+ console.error("Profile is not ready");
718
+ return;
719
+ }
720
+ this.iframes.profile.close();
721
+ this.iframes.keychain.open();
722
+ this.keychain.openPurchaseCredits();
723
+ }
724
+ async delegateAccount() {
725
+ if (!this.keychain) {
726
+ console.error(new NotReadyToConnect().message);
727
+ return null;
728
+ }
729
+ return await this.keychain.delegateAccount();
730
+ }
731
+ waitForKeychain({
732
+ timeout = 5e3,
733
+ interval = 100
734
+ } = {}) {
735
+ return new Promise((resolve, reject) => {
736
+ const startTime = Date.now();
737
+ const id = setInterval(() => {
738
+ if (Date.now() - startTime > timeout) {
739
+ clearInterval(id);
740
+ reject(new Error("Timeout waiting for keychain"));
741
+ return;
176
742
  }
177
- return await this.keychain.delegateAccount();
178
- }
179
- waitForKeychain({ timeout = 5000, interval = 100, } = {}) {
180
- return new Promise((resolve, reject) => {
181
- const startTime = Date.now();
182
- const id = setInterval(() => {
183
- if (Date.now() - startTime > timeout) {
184
- clearInterval(id);
185
- reject(new Error("Timeout waiting for keychain"));
186
- return;
187
- }
188
- if (!this.keychain)
189
- return;
190
- clearInterval(id);
191
- resolve();
192
- }, interval);
193
- });
194
- }
195
- }
743
+ if (!this.keychain) return;
744
+ clearInterval(id);
745
+ resolve();
746
+ }, interval);
747
+ });
748
+ }
749
+ };
750
+ export {
751
+ ControllerProvider as default
752
+ };
196
753
  //# sourceMappingURL=controller.js.map