@cartridge/controller 0.6.0 → 0.7.1

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
package/src/controller.ts CHANGED
@@ -88,9 +88,11 @@ export default class ControllerProvider extends BaseProvider {
88
88
 
89
89
  const response = (await this.keychain.probe(this.rpcUrl())) as ProbeReply;
90
90
 
91
+ // For backwards compat with controller <=0.6.0
92
+ let rpcUrl = response?.rpcUrl || this.rpcUrl();
91
93
  this.account = new ControllerAccount(
92
94
  this,
93
- this.rpcUrl(),
95
+ rpcUrl,
94
96
  response.address,
95
97
  this.keychain,
96
98
  this.options,
@@ -170,12 +172,20 @@ export default class ControllerProvider extends BaseProvider {
170
172
  }
171
173
 
172
174
  async switchStarknetChain(chainId: string): Promise<boolean> {
175
+ if (!this.keychain || !this.iframes.keychain) {
176
+ console.error(new NotReadyToConnect().message);
177
+ return false;
178
+ }
179
+
173
180
  try {
174
181
  this.selectedChain = chainId;
175
- this.account = await this.probe();
176
- if (!this.account) {
177
- this.account = await this.connect();
182
+ const response = (await this.keychain.probe(this.rpcUrl())) as ProbeReply;
183
+
184
+ if (response.rpcUrl === this.rpcUrl()) {
185
+ return true;
178
186
  }
187
+
188
+ await this.keychain.switchChain(this.rpcUrl());
179
189
  } catch (e) {
180
190
  console.error(e);
181
191
  return false;
@@ -220,6 +230,34 @@ export default class ControllerProvider extends BaseProvider {
220
230
  this.iframes.profile.open();
221
231
  }
222
232
 
233
+ async openProfileTo(to: string) {
234
+ if (!this.profile || !this.iframes.profile?.url) {
235
+ console.error("Profile is not ready");
236
+ return;
237
+ }
238
+ if (!this.account) {
239
+ console.error("Account is not ready");
240
+ return;
241
+ }
242
+
243
+ this.profile.navigate(`${this.iframes.profile.url?.pathname}/${to}`);
244
+ this.iframes.profile.open();
245
+ }
246
+
247
+ async openProfileAt(at: string) {
248
+ if (!this.profile || !this.iframes.profile?.url) {
249
+ console.error("Profile is not ready");
250
+ return;
251
+ }
252
+ if (!this.account) {
253
+ console.error("Account is not ready");
254
+ return;
255
+ }
256
+
257
+ this.profile.navigate(at);
258
+ this.iframes.profile.open();
259
+ }
260
+
223
261
  async openSettings() {
224
262
  if (!this.keychain || !this.iframes.keychain) {
225
263
  console.error(new NotReadyToConnect().message);
@@ -262,16 +300,6 @@ export default class ControllerProvider extends BaseProvider {
262
300
  return this.keychain.username();
263
301
  }
264
302
 
265
- fetchControllers(
266
- contractAddresses: string[],
267
- ): Promise<Record<string, string>> {
268
- if (!this.keychain) {
269
- throw new NotReadyToConnect().message;
270
- }
271
-
272
- return this.keychain.fetchControllers(contractAddresses);
273
- }
274
-
275
303
  openPurchaseCredits() {
276
304
  if (!this.keychain || !this.iframes.keychain) {
277
305
  console.error(new NotReadyToConnect().message);
@@ -331,7 +359,7 @@ export default class ControllerProvider extends BaseProvider {
331
359
  }
332
360
 
333
361
  private waitForKeychain({
334
- timeout = 5000,
362
+ timeout = 50000,
335
363
  interval = 100,
336
364
  }:
337
365
  | {
@@ -19,12 +19,10 @@ export class IFrame<CallSender extends {}> implements Modal {
19
19
  id,
20
20
  url,
21
21
  preset,
22
- theme,
23
- colorMode,
24
22
  onClose,
25
23
  onConnect,
26
24
  methods = {},
27
- }: Pick<ControllerOptions, "theme" | "preset" | "colorMode"> & {
25
+ }: Pick<ControllerOptions, "preset"> & {
28
26
  id: string;
29
27
  url: URL;
30
28
  onClose?: () => void;
@@ -35,18 +33,10 @@ export class IFrame<CallSender extends {}> implements Modal {
35
33
  return;
36
34
  }
37
35
 
38
- if (theme) {
39
- url.searchParams.set("theme", theme);
40
- }
41
-
42
36
  if (preset) {
43
37
  url.searchParams.set("preset", preset);
44
38
  }
45
39
 
46
- if (colorMode) {
47
- url.searchParams.set("colorMode", colorMode);
48
- }
49
-
50
40
  this.url = url;
51
41
 
52
42
  const iframe = document.createElement("iframe");
@@ -0,0 +1,72 @@
1
+ import { Policy } from "@cartridge/account-wasm";
2
+ import { CartridgeSessionAccount } from "@cartridge/account-wasm/session";
3
+ import { Call, InvokeFunctionResponse, WalletAccount } from "starknet";
4
+
5
+ import { normalizeCalls } from "../utils";
6
+ import BaseProvider from "../provider";
7
+
8
+ export * from "../errors";
9
+ export * from "../types";
10
+
11
+ export default class SessionAccount extends WalletAccount {
12
+ public controller: CartridgeSessionAccount;
13
+
14
+ constructor(
15
+ provider: BaseProvider,
16
+ {
17
+ rpcUrl,
18
+ privateKey,
19
+ address,
20
+ ownerGuid,
21
+ chainId,
22
+ expiresAt,
23
+ policies,
24
+ }: {
25
+ rpcUrl: string;
26
+ privateKey: string;
27
+ address: string;
28
+ ownerGuid: string;
29
+ chainId: string;
30
+ expiresAt: number;
31
+ policies: Policy[];
32
+ },
33
+ ) {
34
+ super({ nodeUrl: rpcUrl }, provider);
35
+
36
+ this.address = address;
37
+ this.controller = CartridgeSessionAccount.newAsRegistered(
38
+ rpcUrl,
39
+ privateKey,
40
+ address,
41
+ ownerGuid,
42
+ chainId,
43
+ {
44
+ expiresAt,
45
+ policies,
46
+ },
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Invoke execute function in account contract
52
+ *
53
+ * @param calls the invocation object or an array of them, containing:
54
+ * - contractAddress - the address of the contract
55
+ * - entrypoint - the entrypoint of the contract
56
+ * - calldata - (defaults to []) the calldata
57
+ * - signature - (defaults to []) the signature
58
+ *
59
+ * @returns response from addTransaction
60
+ */
61
+ async execute(calls: Call | Call[]): Promise<InvokeFunctionResponse> {
62
+ try {
63
+ const res = await this.controller.executeFromOutside(
64
+ normalizeCalls(calls),
65
+ );
66
+
67
+ return res;
68
+ } catch (e) {
69
+ return this.controller.execute(normalizeCalls(calls));
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,159 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+ import { CallbackServer } from "./server";
4
+
5
+ interface SessionSigner {
6
+ privKey: string;
7
+ pubKey: string;
8
+ }
9
+
10
+ interface SessionInfo {
11
+ username: string;
12
+ address: string;
13
+ ownerGuid: string;
14
+ transactionHash?: string;
15
+ expiresAt: string;
16
+ }
17
+
18
+ interface SessionData {
19
+ signer?: SessionSigner;
20
+ session?: SessionInfo;
21
+ policies?: any;
22
+ lastUsedConnector?: string;
23
+ [key: string]: any;
24
+ }
25
+
26
+ /**
27
+ * Implements a file system backend.
28
+ * This is designed for Node.js environments to store session data on the filesystem.
29
+ */
30
+ export class NodeBackend {
31
+ private basePath: string;
32
+ private sessionFile: string;
33
+ private data: SessionData = {};
34
+ private callbackServer?: CallbackServer;
35
+
36
+ constructor(basePath: string) {
37
+ if (!basePath) {
38
+ throw new Error("basePath is required for NodeBackend");
39
+ }
40
+ this.basePath = basePath;
41
+ this.sessionFile = path.join(this.basePath, "session.json");
42
+ }
43
+
44
+ private async ensureDirectoryExists(): Promise<void> {
45
+ try {
46
+ await fs.access(this.basePath);
47
+ } catch {
48
+ try {
49
+ await fs.mkdir(this.basePath, { recursive: true });
50
+ } catch (error: any) {
51
+ throw new Error(
52
+ `Failed to create directory ${this.basePath}: ${error.message}`,
53
+ );
54
+ }
55
+ }
56
+ }
57
+
58
+ private async loadData(): Promise<void> {
59
+ try {
60
+ const content = await fs.readFile(this.sessionFile, "utf-8");
61
+ const parsed = JSON.parse(content);
62
+
63
+ if (typeof parsed !== "object" || parsed === null) {
64
+ throw new Error("Invalid session data format");
65
+ }
66
+
67
+ this.data = parsed;
68
+ } catch (error: unknown) {
69
+ if (error instanceof Error) {
70
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
71
+ throw new Error(`Failed to load session data: ${error.message}`);
72
+ }
73
+ }
74
+ this.data = {};
75
+ }
76
+ }
77
+
78
+ private async saveData(): Promise<void> {
79
+ try {
80
+ await this.ensureDirectoryExists();
81
+ await fs.writeFile(
82
+ this.sessionFile,
83
+ JSON.stringify(this.data, null, 2),
84
+ "utf-8",
85
+ );
86
+ } catch (error: unknown) {
87
+ if (error instanceof Error) {
88
+ throw new Error(`Failed to save session data: ${error.message}`);
89
+ }
90
+ throw error;
91
+ }
92
+ }
93
+
94
+ async get(key: string): Promise<string | null> {
95
+ if (!key) {
96
+ throw new Error("Key is required");
97
+ }
98
+
99
+ await this.loadData();
100
+ return this.data[key] ? JSON.stringify(this.data[key]) : null;
101
+ }
102
+
103
+ async set(key: string, value: string): Promise<void> {
104
+ if (!key) {
105
+ throw new Error("Key is required");
106
+ }
107
+ if (!value) {
108
+ throw new Error("Value is required");
109
+ }
110
+
111
+ await this.loadData();
112
+ try {
113
+ this.data[key] = JSON.parse(value);
114
+ await this.saveData();
115
+ } catch (error: unknown) {
116
+ if (error instanceof Error) {
117
+ throw new Error(`Failed to set ${key}: ${error.message}`);
118
+ }
119
+ throw error;
120
+ }
121
+ }
122
+
123
+ async delete(key: string): Promise<void> {
124
+ if (!key) {
125
+ throw new Error("Key is required");
126
+ }
127
+
128
+ await this.loadData();
129
+ delete this.data[key];
130
+ await this.saveData();
131
+ }
132
+
133
+ async getRedirectUri(): Promise<string> {
134
+ try {
135
+ this.callbackServer = new CallbackServer();
136
+ return await this.callbackServer.listen();
137
+ } catch (error: unknown) {
138
+ if (error instanceof Error) {
139
+ throw new Error(`Failed to start callback server: ${error.message}`);
140
+ }
141
+ throw error;
142
+ }
143
+ }
144
+
145
+ async waitForCallback(): Promise<string | null> {
146
+ if (!this.callbackServer) {
147
+ throw new Error("Callback server not initialized");
148
+ }
149
+ return await this.callbackServer.waitForCallback();
150
+ }
151
+
152
+ openLink(url: string): void {
153
+ if (!url) {
154
+ throw new Error("URL is required");
155
+ }
156
+
157
+ console.log(`\n\t Open url to authorize session: ${url}`);
158
+ }
159
+ }
@@ -0,0 +1,4 @@
1
+ export { default } from "./provider";
2
+ export * from "./provider";
3
+ export * from "../errors";
4
+ export * from "../types";
@@ -0,0 +1,178 @@
1
+ import { ec, stark, WalletAccount } from "starknet";
2
+ import { SessionPolicies } from "@cartridge/presets";
3
+ import { AddStarknetChainParameters } from "@starknet-io/types-js";
4
+
5
+ import SessionAccount from "./account";
6
+ import { KEYCHAIN_URL } from "../constants";
7
+ import BaseProvider from "../provider";
8
+ import { toWasmPolicies } from "../utils";
9
+ import { ParsedSessionPolicies } from "../policies";
10
+ import { NodeBackend } from "./backend";
11
+
12
+ export type SessionOptions = {
13
+ rpc: string;
14
+ chainId: string;
15
+ policies: SessionPolicies;
16
+ basePath: string;
17
+ keychainUrl?: string;
18
+ };
19
+
20
+ export default class SessionProvider extends BaseProvider {
21
+ public id = "controller_session";
22
+ public name = "Controller Session";
23
+
24
+ protected _chainId: string;
25
+ protected _rpcUrl: string;
26
+ protected _username?: string;
27
+ protected _policies: ParsedSessionPolicies;
28
+ protected _keychainUrl: string;
29
+ protected _backend: NodeBackend;
30
+
31
+ constructor({
32
+ rpc,
33
+ chainId,
34
+ policies,
35
+ basePath,
36
+ keychainUrl,
37
+ }: SessionOptions) {
38
+ super();
39
+
40
+ this._policies = {
41
+ verified: false,
42
+ contracts: policies.contracts
43
+ ? Object.fromEntries(
44
+ Object.entries(policies.contracts).map(([address, contract]) => [
45
+ address,
46
+ {
47
+ ...contract,
48
+ methods: contract.methods.map((method) => ({
49
+ ...method,
50
+ authorized: true,
51
+ })),
52
+ },
53
+ ]),
54
+ )
55
+ : undefined,
56
+ messages: policies.messages?.map((message) => ({
57
+ ...message,
58
+ authorized: true,
59
+ })),
60
+ };
61
+
62
+ this._rpcUrl = rpc;
63
+ this._chainId = chainId;
64
+ this._keychainUrl = keychainUrl || KEYCHAIN_URL;
65
+ this._backend = new NodeBackend(basePath);
66
+ }
67
+
68
+ async username() {
69
+ const sessionStr = await this._backend.get("session");
70
+ if (sessionStr) {
71
+ const session = JSON.parse(sessionStr);
72
+ return session.username;
73
+ }
74
+ return undefined;
75
+ }
76
+
77
+ async probe(): Promise<WalletAccount | undefined> {
78
+ if (this.account) {
79
+ return this.account;
80
+ }
81
+
82
+ const [sessionStr, signerStr] = await Promise.all([
83
+ this._backend.get("session"),
84
+ this._backend.get("signer"),
85
+ ]);
86
+
87
+ if (!sessionStr || !signerStr) {
88
+ return undefined;
89
+ }
90
+
91
+ const session = JSON.parse(sessionStr);
92
+ const signer = JSON.parse(signerStr);
93
+
94
+ // Check expiration
95
+ const expirationTime = parseInt(session.expiresAt) * 1000;
96
+ if (Date.now() >= expirationTime) {
97
+ await this.disconnect();
98
+ return undefined;
99
+ }
100
+
101
+ this._username = session.username;
102
+ this.account = new SessionAccount(this, {
103
+ rpcUrl: this._rpcUrl,
104
+ privateKey: signer.privKey,
105
+ address: session.address,
106
+ ownerGuid: session.ownerGuid,
107
+ chainId: this._chainId,
108
+ expiresAt: parseInt(session.expiresAt),
109
+ policies: toWasmPolicies(this._policies),
110
+ });
111
+
112
+ return this.account;
113
+ }
114
+
115
+ async connect(): Promise<WalletAccount | undefined> {
116
+ if (this.account) {
117
+ return this.account;
118
+ }
119
+
120
+ const account = await this.probe();
121
+ if (account) {
122
+ return account;
123
+ }
124
+
125
+ const pk = stark.randomAddress();
126
+ const publicKey = ec.starkCurve.getStarkKey(pk);
127
+
128
+ await this._backend.set(
129
+ "signer",
130
+ JSON.stringify({
131
+ privKey: pk,
132
+ pubKey: publicKey,
133
+ }),
134
+ );
135
+
136
+ // Get redirect URI from local server
137
+ const redirectUri = await this._backend.getRedirectUri();
138
+
139
+ const url = `${
140
+ this._keychainUrl
141
+ }/session?public_key=${encodeURIComponent(publicKey)}&redirect_uri=${encodeURIComponent(
142
+ redirectUri,
143
+ )}&redirect_query_name=startapp&policies=${encodeURIComponent(
144
+ JSON.stringify(this._policies),
145
+ )}&rpc_url=${encodeURIComponent(this._rpcUrl)}`;
146
+
147
+ this._backend.openLink(url);
148
+
149
+ // Wait for callback with session data
150
+ const sessionData = await this._backend.waitForCallback();
151
+ if (sessionData) {
152
+ const sessionRegistration = JSON.parse(atob(sessionData));
153
+ // Ensure addresses are properly formatted
154
+ sessionRegistration.address = sessionRegistration.address.toLowerCase();
155
+ sessionRegistration.ownerGuid =
156
+ sessionRegistration.ownerGuid.toLowerCase();
157
+ await this._backend.set("session", JSON.stringify(sessionRegistration));
158
+ return this.probe();
159
+ }
160
+
161
+ return undefined;
162
+ }
163
+
164
+ async disconnect(): Promise<void> {
165
+ await this._backend.delete("signer");
166
+ await this._backend.delete("session");
167
+ this.account = undefined;
168
+ this._username = undefined;
169
+ }
170
+
171
+ switchStarknetChain(_chainId: string): Promise<boolean> {
172
+ throw new Error("switchStarknetChain not implemented");
173
+ }
174
+
175
+ addStarknetChain(_chain: AddStarknetChainParameters): Promise<boolean> {
176
+ throw new Error("addStarknetChain not implemented");
177
+ }
178
+ }
@@ -0,0 +1,89 @@
1
+ import * as http from "http";
2
+ import { AddressInfo } from "net";
3
+
4
+ type ServerResponse = http.ServerResponse<http.IncomingMessage> & {
5
+ req: http.IncomingMessage;
6
+ };
7
+
8
+ export class CallbackServer {
9
+ private server: http.Server;
10
+ private resolveCallback?: (data: string) => void;
11
+ private rejectCallback?: (error: Error) => void;
12
+ private timeoutId?: NodeJS.Timeout;
13
+
14
+ constructor() {
15
+ this.server = http.createServer(this.handleRequest.bind(this));
16
+
17
+ // Handle server errors
18
+ this.server.on("error", (error) => {
19
+ console.error("Server error:", error);
20
+ if (this.rejectCallback) {
21
+ this.rejectCallback(error);
22
+ }
23
+ });
24
+ }
25
+
26
+ private cleanup() {
27
+ if (this.timeoutId) {
28
+ clearTimeout(this.timeoutId);
29
+ }
30
+ this.server.close();
31
+ }
32
+
33
+ private handleRequest(req: http.IncomingMessage, res: ServerResponse) {
34
+ if (!req.url?.startsWith("/callback")) {
35
+ res.writeHead(404);
36
+ res.end();
37
+ return;
38
+ }
39
+
40
+ const params = new URLSearchParams(req.url.split("?")[1]);
41
+ const session = params.get("startapp");
42
+
43
+ if (!session) {
44
+ console.warn("Received callback without session data");
45
+ res.writeHead(400);
46
+ res.end("Missing session data");
47
+ return;
48
+ }
49
+
50
+ if (this.resolveCallback) {
51
+ this.resolveCallback(session);
52
+ }
53
+
54
+ res.writeHead(200, { "Content-Type": "text/html" });
55
+ res.end(
56
+ "<html><body><script>window.close();</script>Session registered successfully. You can close this window.</body></html>",
57
+ );
58
+
59
+ this.cleanup();
60
+ }
61
+
62
+ async listen(): Promise<string> {
63
+ return new Promise((resolve, reject) => {
64
+ this.server.listen(0, "localhost", () => {
65
+ const address = this.server.address() as AddressInfo;
66
+ const url = `http://localhost:${address.port}/callback`;
67
+ resolve(url);
68
+ });
69
+
70
+ this.server.on("error", reject);
71
+ });
72
+ }
73
+
74
+ async waitForCallback(): Promise<string> {
75
+ return new Promise((resolve, reject) => {
76
+ this.resolveCallback = resolve;
77
+ this.rejectCallback = reject;
78
+
79
+ this.timeoutId = setTimeout(
80
+ () => {
81
+ console.warn("Callback timeout reached");
82
+ reject(new Error("Callback timeout after 5 minutes"));
83
+ this.cleanup();
84
+ },
85
+ 5 * 60 * 1000,
86
+ );
87
+ });
88
+ }
89
+ }
@@ -34,7 +34,7 @@ export default class SessionAccount extends WalletAccount {
34
34
  super({ nodeUrl: rpcUrl }, provider);
35
35
 
36
36
  this.address = address;
37
- this.controller = CartridgeSessionAccount.new_as_registered(
37
+ this.controller = CartridgeSessionAccount.newAsRegistered(
38
38
  rpcUrl,
39
39
  privateKey,
40
40
  address,
@@ -219,23 +219,13 @@ export default class SessionProvider extends BaseProvider {
219
219
 
220
220
  // Check expiration
221
221
  const expirationTime = parseInt(sessionRegistration.expiresAt) * 1000;
222
- console.log("Session expiration check:", {
223
- expirationTime,
224
- currentTime: Date.now(),
225
- expired: Date.now() >= expirationTime,
226
- });
227
222
  if (Date.now() >= expirationTime) {
228
- console.log("Session expired, clearing stored session");
229
223
  this.clearStoredSession();
230
224
  return;
231
225
  }
232
226
 
233
227
  // Check stored policies
234
228
  const storedPoliciesStr = localStorage.getItem("sessionPolicies");
235
- console.log("Checking stored policies:", {
236
- storedPoliciesStr,
237
- currentPolicies: this._policies,
238
- });
239
229
  if (storedPoliciesStr) {
240
230
  const storedPolicies = JSON.parse(
241
231
  storedPoliciesStr,
@@ -245,14 +235,8 @@ export default class SessionProvider extends BaseProvider {
245
235
  this._policies,
246
236
  storedPolicies,
247
237
  );
248
- console.log("Policy validation result:", {
249
- isValid,
250
- storedPolicies,
251
- requestedPolicies: this._policies,
252
- });
253
238
 
254
239
  if (!isValid) {
255
- console.log("Policy validation failed, clearing stored session");
256
240
  this.clearStoredSession();
257
241
  return;
258
242
  }