@phantom/embedded-provider-core 1.0.2 → 1.0.4
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/index.d.mts +21 -11
- package/dist/index.d.ts +21 -11
- package/dist/index.js +54 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +55 -67
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -9
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/embedded-provider.ts
|
|
2
2
|
import { base64urlEncode, stringToBase64url } from "@phantom/base64url";
|
|
3
|
-
import { AddressType, PhantomClient, SpendingLimitError } from "@phantom/client";
|
|
3
|
+
import { AddressType, PhantomClient, SpendingLimitError, isAuthenticationError } from "@phantom/client";
|
|
4
4
|
import {
|
|
5
5
|
parseSignMessageResponse,
|
|
6
6
|
parseTransactionResponse,
|
|
@@ -24,21 +24,19 @@ var EmbeddedSolanaChain = class {
|
|
|
24
24
|
constructor(provider) {
|
|
25
25
|
this.provider = provider;
|
|
26
26
|
this.currentNetworkId = NetworkId.SOLANA_MAINNET;
|
|
27
|
-
this._connected = false;
|
|
28
27
|
this._publicKey = null;
|
|
29
28
|
this.eventEmitter = new EventEmitter();
|
|
30
29
|
this.setupEventListeners();
|
|
31
30
|
this.syncInitialState();
|
|
32
31
|
}
|
|
33
|
-
// Wallet adapter compliant properties
|
|
34
|
-
get connected() {
|
|
35
|
-
return this._connected;
|
|
36
|
-
}
|
|
37
32
|
get publicKey() {
|
|
38
33
|
return this._publicKey;
|
|
39
34
|
}
|
|
35
|
+
get isConnected() {
|
|
36
|
+
return this._publicKey !== null;
|
|
37
|
+
}
|
|
40
38
|
ensureConnected() {
|
|
41
|
-
if (!this.
|
|
39
|
+
if (!this.isConnected) {
|
|
42
40
|
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
43
41
|
}
|
|
44
42
|
}
|
|
@@ -96,7 +94,7 @@ var EmbeddedSolanaChain = class {
|
|
|
96
94
|
const solanaAddr = addresses.find((a) => a.addressType === "Solana");
|
|
97
95
|
if (!solanaAddr)
|
|
98
96
|
throw new Error("No Solana address found");
|
|
99
|
-
this.
|
|
97
|
+
this._publicKey = solanaAddr.address;
|
|
100
98
|
return Promise.resolve({ publicKey: solanaAddr.address });
|
|
101
99
|
}
|
|
102
100
|
async disconnect() {
|
|
@@ -106,41 +104,25 @@ var EmbeddedSolanaChain = class {
|
|
|
106
104
|
this.currentNetworkId = network === "mainnet" ? NetworkId.SOLANA_MAINNET : NetworkId.SOLANA_DEVNET;
|
|
107
105
|
return Promise.resolve();
|
|
108
106
|
}
|
|
109
|
-
getPublicKey() {
|
|
110
|
-
if (!this.provider.isConnected())
|
|
111
|
-
return Promise.resolve(null);
|
|
112
|
-
const addresses = this.provider.getAddresses();
|
|
113
|
-
const solanaAddr = addresses.find((a) => a.addressType === "Solana");
|
|
114
|
-
return Promise.resolve(solanaAddr?.address || null);
|
|
115
|
-
}
|
|
116
|
-
isConnected() {
|
|
117
|
-
return this._connected && this.provider.isConnected();
|
|
118
|
-
}
|
|
119
107
|
setupEventListeners() {
|
|
120
108
|
this.provider.on("connect", (data) => {
|
|
121
109
|
const solanaAddress = data.addresses?.find((addr) => addr.addressType === "Solana");
|
|
122
110
|
if (solanaAddress) {
|
|
123
|
-
this.
|
|
111
|
+
this._publicKey = solanaAddress.address;
|
|
124
112
|
this.eventEmitter.emit("connect", solanaAddress.address);
|
|
125
113
|
}
|
|
126
114
|
});
|
|
127
115
|
this.provider.on("disconnect", () => {
|
|
128
|
-
this.
|
|
116
|
+
this._publicKey = null;
|
|
129
117
|
this.eventEmitter.emit("disconnect");
|
|
130
118
|
});
|
|
131
119
|
}
|
|
132
120
|
syncInitialState() {
|
|
133
|
-
if (this.provider.isConnected())
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
updateConnectionState(connected, publicKey) {
|
|
142
|
-
this._connected = connected;
|
|
143
|
-
this._publicKey = publicKey;
|
|
121
|
+
if (!this.provider.isConnected())
|
|
122
|
+
return;
|
|
123
|
+
const addresses = this.provider.getAddresses();
|
|
124
|
+
const solanaAddr = addresses.find((a) => a.addressType === "Solana");
|
|
125
|
+
this._publicKey = solanaAddr?.address || null;
|
|
144
126
|
}
|
|
145
127
|
// Event methods for interface compliance
|
|
146
128
|
on(event, listener) {
|
|
@@ -158,16 +140,11 @@ var EmbeddedEthereumChain = class {
|
|
|
158
140
|
constructor(provider) {
|
|
159
141
|
this.provider = provider;
|
|
160
142
|
this.currentNetworkId = NetworkId2.ETHEREUM_MAINNET;
|
|
161
|
-
this._connected = false;
|
|
162
143
|
this._accounts = [];
|
|
163
144
|
this.eventEmitter = new EventEmitter2();
|
|
164
145
|
this.setupEventListeners();
|
|
165
146
|
this.syncInitialState();
|
|
166
147
|
}
|
|
167
|
-
// EIP-1193 compliant properties
|
|
168
|
-
get connected() {
|
|
169
|
-
return this._connected;
|
|
170
|
-
}
|
|
171
148
|
get chainId() {
|
|
172
149
|
const chainId = networkIdToChainId(this.currentNetworkId) || 1;
|
|
173
150
|
return `0x${chainId.toString(16)}`;
|
|
@@ -191,7 +168,7 @@ var EmbeddedEthereumChain = class {
|
|
|
191
168
|
}
|
|
192
169
|
const addresses = this.provider.getAddresses();
|
|
193
170
|
const ethAddresses = addresses.filter((a) => a.addressType === "Ethereum").map((a) => a.address);
|
|
194
|
-
this.updateConnectionState(
|
|
171
|
+
this.updateConnectionState(ethAddresses);
|
|
195
172
|
return Promise.resolve(ethAddresses);
|
|
196
173
|
}
|
|
197
174
|
async disconnect() {
|
|
@@ -257,19 +234,19 @@ var EmbeddedEthereumChain = class {
|
|
|
257
234
|
return this.request({ method: "eth_accounts" });
|
|
258
235
|
}
|
|
259
236
|
isConnected() {
|
|
260
|
-
return this.
|
|
237
|
+
return this.provider.isConnected() && this._accounts.length > 0;
|
|
261
238
|
}
|
|
262
239
|
setupEventListeners() {
|
|
263
240
|
this.provider.on("connect", (data) => {
|
|
264
241
|
const ethAddresses = data.addresses?.filter((addr) => addr.addressType === "Ethereum")?.map((addr) => addr.address) || [];
|
|
265
242
|
if (ethAddresses.length > 0) {
|
|
266
|
-
this.updateConnectionState(
|
|
243
|
+
this.updateConnectionState(ethAddresses);
|
|
267
244
|
this.eventEmitter.emit("connect", { chainId: this.chainId });
|
|
268
245
|
this.eventEmitter.emit("accountsChanged", ethAddresses);
|
|
269
246
|
}
|
|
270
247
|
});
|
|
271
248
|
this.provider.on("disconnect", () => {
|
|
272
|
-
this.updateConnectionState(
|
|
249
|
+
this.updateConnectionState([]);
|
|
273
250
|
this.eventEmitter.emit("disconnect", { code: 4900, message: "Provider disconnected" });
|
|
274
251
|
this.eventEmitter.emit("accountsChanged", []);
|
|
275
252
|
});
|
|
@@ -279,12 +256,11 @@ var EmbeddedEthereumChain = class {
|
|
|
279
256
|
const addresses = this.provider.getAddresses();
|
|
280
257
|
const ethAddresses = addresses.filter((a) => a.addressType === "Ethereum").map((a) => a.address);
|
|
281
258
|
if (ethAddresses.length > 0) {
|
|
282
|
-
this.updateConnectionState(
|
|
259
|
+
this.updateConnectionState(ethAddresses);
|
|
283
260
|
}
|
|
284
261
|
}
|
|
285
262
|
}
|
|
286
|
-
updateConnectionState(
|
|
287
|
-
this._connected = connected;
|
|
263
|
+
updateConnectionState(accounts) {
|
|
288
264
|
this._accounts = accounts;
|
|
289
265
|
}
|
|
290
266
|
async handleEmbeddedRequest(args) {
|
|
@@ -512,7 +488,8 @@ var EmbeddedProvider = class {
|
|
|
512
488
|
});
|
|
513
489
|
if (session.status !== "completed") {
|
|
514
490
|
const urlSessionId = this.urlParamsAccessor.getParam("session_id");
|
|
515
|
-
|
|
491
|
+
const urlCode = this.urlParamsAccessor.getParam("code");
|
|
492
|
+
if (session.status === "pending" && !urlSessionId && !urlCode) {
|
|
516
493
|
this.logger.warn("EMBEDDED_PROVIDER", "Session mismatch detected - pending session without redirect context", {
|
|
517
494
|
sessionId: session.sessionId,
|
|
518
495
|
status: session.status
|
|
@@ -585,7 +562,7 @@ var EmbeddedProvider = class {
|
|
|
585
562
|
}
|
|
586
563
|
this.logger.log("EMBEDDED_PROVIDER", "No completed session found, checking for redirect resume");
|
|
587
564
|
if (this.authProvider.resumeAuthFromRedirect) {
|
|
588
|
-
const authResult = this.authProvider.resumeAuthFromRedirect(session.authProvider);
|
|
565
|
+
const authResult = await this.authProvider.resumeAuthFromRedirect(session.authProvider);
|
|
589
566
|
if (authResult) {
|
|
590
567
|
this.logger.info("EMBEDDED_PROVIDER", "Resuming from redirect", {
|
|
591
568
|
walletId: authResult.walletId,
|
|
@@ -748,7 +725,7 @@ var EmbeddedProvider = class {
|
|
|
748
725
|
authenticatorName: `auth-${shortPubKey}`,
|
|
749
726
|
authenticatorKind: "keypair",
|
|
750
727
|
publicKey: base64urlPublicKey,
|
|
751
|
-
algorithm:
|
|
728
|
+
algorithm: this.stamper.algorithm,
|
|
752
729
|
expiresInMs
|
|
753
730
|
}
|
|
754
731
|
]
|
|
@@ -864,6 +841,21 @@ var EmbeddedProvider = class {
|
|
|
864
841
|
});
|
|
865
842
|
}
|
|
866
843
|
}
|
|
844
|
+
/**
|
|
845
|
+
* Handles errors from signing operations.
|
|
846
|
+
* Disconnects the user if the server returns a 401/403 (revoked or expired authenticator).
|
|
847
|
+
*/
|
|
848
|
+
async handleSigningError(error) {
|
|
849
|
+
if (isAuthenticationError(error)) {
|
|
850
|
+
this.logger.warn("EMBEDDED_PROVIDER", "Authenticator rejected by server (401/403), disconnecting", { error });
|
|
851
|
+
await this.disconnect(false);
|
|
852
|
+
throw new Error("Authenticator revoked");
|
|
853
|
+
}
|
|
854
|
+
if (error instanceof SpendingLimitError) {
|
|
855
|
+
this.emit("spending_limit_reached", { error });
|
|
856
|
+
}
|
|
857
|
+
throw error;
|
|
858
|
+
}
|
|
867
859
|
async signMessage(params) {
|
|
868
860
|
if (!this.client || !this.walletId) {
|
|
869
861
|
throw new Error("Not connected");
|
|
@@ -880,7 +872,7 @@ var EmbeddedProvider = class {
|
|
|
880
872
|
message: params.message,
|
|
881
873
|
networkId: params.networkId,
|
|
882
874
|
derivationIndex
|
|
883
|
-
});
|
|
875
|
+
}).catch((error) => this.handleSigningError(error));
|
|
884
876
|
this.logger.info("EMBEDDED_PROVIDER", "Message signed successfully", {
|
|
885
877
|
walletId: this.walletId,
|
|
886
878
|
message: params.message
|
|
@@ -913,7 +905,7 @@ var EmbeddedProvider = class {
|
|
|
913
905
|
message: base64UrlMessage,
|
|
914
906
|
networkId: params.networkId,
|
|
915
907
|
derivationIndex
|
|
916
|
-
});
|
|
908
|
+
}).catch((error) => this.handleSigningError(error));
|
|
917
909
|
this.logger.info("EMBEDDED_PROVIDER", "Message signed successfully", {
|
|
918
910
|
walletId: this.walletId,
|
|
919
911
|
message: params.message
|
|
@@ -936,7 +928,7 @@ var EmbeddedProvider = class {
|
|
|
936
928
|
typedData: params.typedData,
|
|
937
929
|
networkId: params.networkId,
|
|
938
930
|
derivationIndex
|
|
939
|
-
});
|
|
931
|
+
}).catch((error) => this.handleSigningError(error));
|
|
940
932
|
this.logger.info("EMBEDDED_PROVIDER", "Typed data signed successfully", {
|
|
941
933
|
walletId: this.walletId
|
|
942
934
|
});
|
|
@@ -973,7 +965,7 @@ var EmbeddedProvider = class {
|
|
|
973
965
|
networkId: params.networkId,
|
|
974
966
|
derivationIndex,
|
|
975
967
|
account
|
|
976
|
-
});
|
|
968
|
+
}).catch((error) => this.handleSigningError(error));
|
|
977
969
|
this.logger.info("EMBEDDED_PROVIDER", "Transaction signed successfully", {
|
|
978
970
|
walletId: this.walletId,
|
|
979
971
|
networkId: params.networkId,
|
|
@@ -1006,21 +998,13 @@ var EmbeddedProvider = class {
|
|
|
1006
998
|
if (!account) {
|
|
1007
999
|
throw new Error(`No address found for network ${params.networkId}`);
|
|
1008
1000
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
account
|
|
1017
|
-
});
|
|
1018
|
-
} catch (error) {
|
|
1019
|
-
if (error instanceof SpendingLimitError) {
|
|
1020
|
-
this.emit("spending_limit_reached", { error });
|
|
1021
|
-
}
|
|
1022
|
-
throw error;
|
|
1023
|
-
}
|
|
1001
|
+
const rawResponse = await this.client.signAndSendTransaction({
|
|
1002
|
+
walletId: this.walletId,
|
|
1003
|
+
transaction: transactionPayload,
|
|
1004
|
+
networkId: params.networkId,
|
|
1005
|
+
derivationIndex,
|
|
1006
|
+
account
|
|
1007
|
+
}).catch((error) => this.handleSigningError(error));
|
|
1024
1008
|
this.logger.info("EMBEDDED_PROVIDER", "Transaction signed and sent successfully", {
|
|
1025
1009
|
walletId: this.walletId,
|
|
1026
1010
|
networkId: params.networkId,
|
|
@@ -1204,8 +1188,9 @@ var EmbeddedProvider = class {
|
|
|
1204
1188
|
// OAuth session management - defaults to allowing refresh unless user explicitly logged out
|
|
1205
1189
|
clearPreviousSession: shouldClearPreviousSession,
|
|
1206
1190
|
// true only after logout
|
|
1207
|
-
allowRefresh: !shouldClearPreviousSession
|
|
1191
|
+
allowRefresh: !shouldClearPreviousSession,
|
|
1208
1192
|
// false only after logout
|
|
1193
|
+
algorithm: this.stamper.algorithm
|
|
1209
1194
|
});
|
|
1210
1195
|
if (authResult && "walletId" in authResult) {
|
|
1211
1196
|
this.logger.info("EMBEDDED_PROVIDER", "Authentication completed after redirect", {
|
|
@@ -1218,6 +1203,7 @@ var EmbeddedProvider = class {
|
|
|
1218
1203
|
tempSession.authProvider = authResult.provider || tempSession.authProvider;
|
|
1219
1204
|
tempSession.accountDerivationIndex = authResult.accountDerivationIndex;
|
|
1220
1205
|
tempSession.authUserId = authResult.authUserId;
|
|
1206
|
+
tempSession.bearerToken = authResult.bearerToken;
|
|
1221
1207
|
tempSession.status = "completed";
|
|
1222
1208
|
tempSession.lastUsed = Date.now();
|
|
1223
1209
|
if (authResult.expiresInMs > 0) {
|
|
@@ -1247,6 +1233,7 @@ var EmbeddedProvider = class {
|
|
|
1247
1233
|
session.organizationId = authResult.organizationId;
|
|
1248
1234
|
session.accountDerivationIndex = authResult.accountDerivationIndex;
|
|
1249
1235
|
session.authUserId = authResult.authUserId;
|
|
1236
|
+
session.bearerToken = authResult.bearerToken;
|
|
1250
1237
|
session.status = "completed";
|
|
1251
1238
|
session.lastUsed = Date.now();
|
|
1252
1239
|
if (authResult.expiresInMs > 0) {
|
|
@@ -1316,7 +1303,8 @@ var EmbeddedProvider = class {
|
|
|
1316
1303
|
organizationId: session.organizationId,
|
|
1317
1304
|
headers: {
|
|
1318
1305
|
...this.platform.analyticsHeaders || {},
|
|
1319
|
-
...session.authUserId ? { "x-auth-user-id": session.authUserId } : {}
|
|
1306
|
+
...session.authUserId ? { "x-auth-user-id": session.authUserId } : {},
|
|
1307
|
+
...session.bearerToken ? { Authorization: session.bearerToken } : {}
|
|
1320
1308
|
}
|
|
1321
1309
|
},
|
|
1322
1310
|
this.stamper
|