@phantom/embedded-provider-core 1.0.0-beta.21 → 1.0.0-beta.24
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/README.md +3 -3
- package/dist/index.d.mts +56 -69
- package/dist/index.d.ts +56 -69
- package/dist/index.js +37 -159
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +36 -158
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -9
package/dist/index.mjs
CHANGED
|
@@ -13,91 +13,7 @@ import bs582 from "bs58";
|
|
|
13
13
|
// src/constants.ts
|
|
14
14
|
var AUTHENTICATOR_EXPIRATION_TIME_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
15
15
|
var AUTHENTICATOR_RENEWAL_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
|
|
16
|
-
|
|
17
|
-
// src/auth/jwt-auth.ts
|
|
18
|
-
var JWTAuth = class {
|
|
19
|
-
async authenticate(options) {
|
|
20
|
-
if (!options.jwtToken || typeof options.jwtToken !== "string") {
|
|
21
|
-
throw new Error("Invalid JWT token: token must be a non-empty string");
|
|
22
|
-
}
|
|
23
|
-
const jwtParts = options.jwtToken.split(".");
|
|
24
|
-
if (jwtParts.length !== 3) {
|
|
25
|
-
throw new Error("Invalid JWT token format: token must have 3 parts separated by dots");
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
const response = await fetch("/api/auth/jwt", {
|
|
29
|
-
method: "POST",
|
|
30
|
-
headers: {
|
|
31
|
-
"Content-Type": "application/json",
|
|
32
|
-
Authorization: `Bearer ${options.jwtToken}`,
|
|
33
|
-
"X-PHANTOM-APPID": options.appId
|
|
34
|
-
},
|
|
35
|
-
body: JSON.stringify({
|
|
36
|
-
appId: options.appId,
|
|
37
|
-
publicKey: options.publicKey
|
|
38
|
-
})
|
|
39
|
-
});
|
|
40
|
-
if (!response.ok) {
|
|
41
|
-
let errorMessage = `HTTP ${response.status}`;
|
|
42
|
-
try {
|
|
43
|
-
const errorData = await response.json();
|
|
44
|
-
errorMessage = errorData.message || errorData.error || errorMessage;
|
|
45
|
-
} catch {
|
|
46
|
-
errorMessage = response.statusText || errorMessage;
|
|
47
|
-
}
|
|
48
|
-
switch (response.status) {
|
|
49
|
-
case 400:
|
|
50
|
-
throw new Error(`Invalid JWT authentication request: ${errorMessage}`);
|
|
51
|
-
case 401:
|
|
52
|
-
throw new Error(`JWT token is invalid or expired: ${errorMessage}`);
|
|
53
|
-
case 403:
|
|
54
|
-
throw new Error(`JWT authentication forbidden: ${errorMessage}`);
|
|
55
|
-
case 404:
|
|
56
|
-
throw new Error(`JWT authentication endpoint not found: ${errorMessage}`);
|
|
57
|
-
case 429:
|
|
58
|
-
throw new Error(`Too many JWT authentication requests: ${errorMessage}`);
|
|
59
|
-
case 500:
|
|
60
|
-
case 502:
|
|
61
|
-
case 503:
|
|
62
|
-
case 504:
|
|
63
|
-
throw new Error(`JWT authentication server error: ${errorMessage}`);
|
|
64
|
-
default:
|
|
65
|
-
throw new Error(`JWT authentication failed: ${errorMessage}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
let result;
|
|
69
|
-
try {
|
|
70
|
-
result = await response.json();
|
|
71
|
-
} catch (parseError) {
|
|
72
|
-
throw new Error("Invalid response from JWT authentication server: response is not valid JSON");
|
|
73
|
-
}
|
|
74
|
-
if (!result.walletId) {
|
|
75
|
-
throw new Error("Invalid JWT authentication response: missing walletId");
|
|
76
|
-
}
|
|
77
|
-
if (!result.organizationId) {
|
|
78
|
-
throw new Error("Invalid JWT authentication response: missing organizationId");
|
|
79
|
-
}
|
|
80
|
-
if (!result.expiresInMs) {
|
|
81
|
-
throw new Error("Invalid JWT authentication response: missing expiresInMs");
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
walletId: result.walletId,
|
|
85
|
-
organizationId: result.organizationId,
|
|
86
|
-
provider: "jwt",
|
|
87
|
-
expiresInMs: result.expiresInMs,
|
|
88
|
-
accountDerivationIndex: result.accountDerivationIndex || 0
|
|
89
|
-
};
|
|
90
|
-
} catch (error) {
|
|
91
|
-
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
92
|
-
throw new Error("JWT authentication failed: network error or invalid endpoint");
|
|
93
|
-
}
|
|
94
|
-
if (error instanceof Error) {
|
|
95
|
-
throw error;
|
|
96
|
-
}
|
|
97
|
-
throw new Error(`JWT authentication error: ${String(error)}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
16
|
+
var EMBEDDED_PROVIDER_AUTH_TYPES = ["google", "apple", "x", "phantom", "tiktok"];
|
|
101
17
|
|
|
102
18
|
// src/chains/SolanaChain.ts
|
|
103
19
|
import { EventEmitter } from "eventemitter3";
|
|
@@ -497,7 +413,6 @@ var EmbeddedProvider = class {
|
|
|
497
413
|
this.phantomAppProvider = platform.phantomAppProvider;
|
|
498
414
|
this.urlParamsAccessor = platform.urlParamsAccessor;
|
|
499
415
|
this.stamper = platform.stamper;
|
|
500
|
-
this.jwtAuth = new JWTAuth();
|
|
501
416
|
this.solana = new EmbeddedSolanaChain(this);
|
|
502
417
|
this.ethereum = new EmbeddedEthereumChain(this);
|
|
503
418
|
this.logger.info("EMBEDDED_PROVIDER", "EmbeddedProvider initialized");
|
|
@@ -638,7 +553,11 @@ var EmbeddedProvider = class {
|
|
|
638
553
|
this.logger.log("EMBEDDED_PROVIDER", "Getting existing session");
|
|
639
554
|
let session = await this.storage.getSession();
|
|
640
555
|
session = await this.validateAndCleanSession(session);
|
|
641
|
-
if (session
|
|
556
|
+
if (!session) {
|
|
557
|
+
this.logger.log("EMBEDDED_PROVIDER", "No existing session found");
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
if (session.status === "completed") {
|
|
642
561
|
this.logger.info("EMBEDDED_PROVIDER", "Using existing completed session", {
|
|
643
562
|
sessionId: session.sessionId,
|
|
644
563
|
walletId: session.walletId
|
|
@@ -655,8 +574,8 @@ var EmbeddedProvider = class {
|
|
|
655
574
|
walletId: this.walletId,
|
|
656
575
|
addresses: this.addresses,
|
|
657
576
|
status: "completed",
|
|
658
|
-
|
|
659
|
-
|
|
577
|
+
authUserId: session.authUserId,
|
|
578
|
+
authProvider: session.authProvider
|
|
660
579
|
};
|
|
661
580
|
this.emit("connect", {
|
|
662
581
|
...result,
|
|
@@ -666,7 +585,7 @@ var EmbeddedProvider = class {
|
|
|
666
585
|
}
|
|
667
586
|
this.logger.log("EMBEDDED_PROVIDER", "No completed session found, checking for redirect resume");
|
|
668
587
|
if (this.authProvider.resumeAuthFromRedirect) {
|
|
669
|
-
const authResult = this.authProvider.resumeAuthFromRedirect();
|
|
588
|
+
const authResult = this.authProvider.resumeAuthFromRedirect(session.authProvider);
|
|
670
589
|
if (authResult) {
|
|
671
590
|
this.logger.info("EMBEDDED_PROVIDER", "Resuming from redirect", {
|
|
672
591
|
walletId: authResult.walletId,
|
|
@@ -698,11 +617,10 @@ var EmbeddedProvider = class {
|
|
|
698
617
|
* This ensures only supported auth providers are used and required tokens are present.
|
|
699
618
|
*/
|
|
700
619
|
validateAuthOptions(authOptions) {
|
|
701
|
-
if (!
|
|
702
|
-
throw new Error(
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
throw new Error("JWT token is required when using JWT authentication");
|
|
620
|
+
if (!EMBEDDED_PROVIDER_AUTH_TYPES.includes(authOptions.provider)) {
|
|
621
|
+
throw new Error(
|
|
622
|
+
`Invalid auth provider: ${authOptions.provider}. Must be "google", "apple", "phantom", "tiktok", or "x"`
|
|
623
|
+
);
|
|
706
624
|
}
|
|
707
625
|
}
|
|
708
626
|
/*
|
|
@@ -842,8 +760,7 @@ var EmbeddedProvider = class {
|
|
|
842
760
|
try {
|
|
843
761
|
this.logger.info("EMBEDDED_PROVIDER", "Starting embedded provider connect", {
|
|
844
762
|
authOptions: {
|
|
845
|
-
provider: authOptions.provider
|
|
846
|
-
hasJwtToken: !!authOptions.jwtToken
|
|
763
|
+
provider: authOptions.provider
|
|
847
764
|
}
|
|
848
765
|
});
|
|
849
766
|
this.emit("connect_start", {
|
|
@@ -873,10 +790,10 @@ var EmbeddedProvider = class {
|
|
|
873
790
|
return {
|
|
874
791
|
addresses: [],
|
|
875
792
|
status: "pending",
|
|
876
|
-
|
|
793
|
+
authProvider: authOptions.provider
|
|
877
794
|
};
|
|
878
795
|
}
|
|
879
|
-
if (
|
|
796
|
+
if (this.config.embeddedWalletType === "app-wallet") {
|
|
880
797
|
session.lastUsed = Date.now();
|
|
881
798
|
await this.storage.saveSession(session);
|
|
882
799
|
}
|
|
@@ -886,8 +803,8 @@ var EmbeddedProvider = class {
|
|
|
886
803
|
walletId: this.walletId,
|
|
887
804
|
addresses: this.addresses,
|
|
888
805
|
status: "completed",
|
|
889
|
-
|
|
890
|
-
|
|
806
|
+
authUserId: session?.authUserId,
|
|
807
|
+
authProvider: session?.authProvider
|
|
891
808
|
};
|
|
892
809
|
this.emit("connect", {
|
|
893
810
|
...result,
|
|
@@ -955,12 +872,11 @@ var EmbeddedProvider = class {
|
|
|
955
872
|
walletId: this.walletId,
|
|
956
873
|
message: params.message
|
|
957
874
|
});
|
|
958
|
-
const base64UrlMessage = stringToBase64url(params.message);
|
|
959
875
|
const session = await this.storage.getSession();
|
|
960
876
|
const derivationIndex = session?.accountDerivationIndex ?? 0;
|
|
961
|
-
const rawResponse = await this.client.
|
|
877
|
+
const rawResponse = await this.client.signUtf8Message({
|
|
962
878
|
walletId: this.walletId,
|
|
963
|
-
message:
|
|
879
|
+
message: params.message,
|
|
964
880
|
networkId: params.networkId,
|
|
965
881
|
derivationIndex
|
|
966
882
|
});
|
|
@@ -1046,12 +962,16 @@ var EmbeddedProvider = class {
|
|
|
1046
962
|
if (!transactionPayload) {
|
|
1047
963
|
throw new Error("Failed to parse transaction: no valid encoding found");
|
|
1048
964
|
}
|
|
965
|
+
const account = this.getAddressForNetwork(params.networkId);
|
|
966
|
+
if (!account) {
|
|
967
|
+
throw new Error(`No address found for network ${params.networkId}`);
|
|
968
|
+
}
|
|
1049
969
|
const rawResponse = await this.client.signTransaction({
|
|
1050
970
|
walletId: this.walletId,
|
|
1051
971
|
transaction: transactionPayload,
|
|
1052
972
|
networkId: params.networkId,
|
|
1053
973
|
derivationIndex,
|
|
1054
|
-
account
|
|
974
|
+
account
|
|
1055
975
|
});
|
|
1056
976
|
this.logger.info("EMBEDDED_PROVIDER", "Transaction signed successfully", {
|
|
1057
977
|
walletId: this.walletId,
|
|
@@ -1081,12 +1001,16 @@ var EmbeddedProvider = class {
|
|
|
1081
1001
|
if (!transactionPayload) {
|
|
1082
1002
|
throw new Error("Failed to parse transaction: no valid encoding found");
|
|
1083
1003
|
}
|
|
1004
|
+
const account = this.getAddressForNetwork(params.networkId);
|
|
1005
|
+
if (!account) {
|
|
1006
|
+
throw new Error(`No address found for network ${params.networkId}`);
|
|
1007
|
+
}
|
|
1084
1008
|
const rawResponse = await this.client.signAndSendTransaction({
|
|
1085
1009
|
walletId: this.walletId,
|
|
1086
1010
|
transaction: transactionPayload,
|
|
1087
1011
|
networkId: params.networkId,
|
|
1088
1012
|
derivationIndex,
|
|
1089
|
-
account
|
|
1013
|
+
account
|
|
1090
1014
|
});
|
|
1091
1015
|
this.logger.info("EMBEDDED_PROVIDER", "Transaction signed and sent successfully", {
|
|
1092
1016
|
walletId: this.walletId,
|
|
@@ -1112,9 +1036,7 @@ var EmbeddedProvider = class {
|
|
|
1112
1036
|
this.logger.info("EMBEDDED_PROVIDER", "Creating user-wallet, routing authentication", {
|
|
1113
1037
|
authProvider: authOptions.provider
|
|
1114
1038
|
});
|
|
1115
|
-
if (authOptions.provider === "
|
|
1116
|
-
return await this.handleJWTAuth(publicKey, stamperInfo, authOptions, expiresInMs);
|
|
1117
|
-
} else if (authOptions.provider === "phantom") {
|
|
1039
|
+
if (authOptions.provider === "phantom") {
|
|
1118
1040
|
return await this.handlePhantomAuth(publicKey, stamperInfo, expiresInMs);
|
|
1119
1041
|
} else {
|
|
1120
1042
|
this.logger.info("EMBEDDED_PROVIDER", "Starting redirect-based authentication flow", {
|
|
@@ -1147,7 +1069,8 @@ var EmbeddedProvider = class {
|
|
|
1147
1069
|
organizationId,
|
|
1148
1070
|
appId: this.config.appId,
|
|
1149
1071
|
stamperInfo,
|
|
1150
|
-
authProvider: "
|
|
1072
|
+
authProvider: "device",
|
|
1073
|
+
// For now app wallets have no auth provider.
|
|
1151
1074
|
accountDerivationIndex: 0,
|
|
1152
1075
|
// App wallets default to index 0
|
|
1153
1076
|
status: "completed",
|
|
@@ -1162,51 +1085,6 @@ var EmbeddedProvider = class {
|
|
|
1162
1085
|
return session;
|
|
1163
1086
|
}
|
|
1164
1087
|
}
|
|
1165
|
-
/*
|
|
1166
|
-
* We use this method to handle JWT-based authentication for user-wallets.
|
|
1167
|
-
* It authenticates using the provided JWT token and creates a completed session.
|
|
1168
|
-
*/
|
|
1169
|
-
async handleJWTAuth(publicKey, stamperInfo, authOptions, localExpiresInMs) {
|
|
1170
|
-
this.logger.info("EMBEDDED_PROVIDER", "Using JWT authentication flow");
|
|
1171
|
-
if (!authOptions.jwtToken) {
|
|
1172
|
-
this.logger.error("EMBEDDED_PROVIDER", "JWT token missing for JWT authentication");
|
|
1173
|
-
throw new Error("JWT token is required for JWT authentication");
|
|
1174
|
-
}
|
|
1175
|
-
this.logger.log("EMBEDDED_PROVIDER", "Starting JWT authentication");
|
|
1176
|
-
const authResult = await this.jwtAuth.authenticate({
|
|
1177
|
-
publicKey,
|
|
1178
|
-
appId: this.config.appId,
|
|
1179
|
-
jwtToken: authOptions.jwtToken
|
|
1180
|
-
});
|
|
1181
|
-
const walletId = authResult.walletId;
|
|
1182
|
-
const organizationId = authResult.organizationId;
|
|
1183
|
-
const expiresInMs = authResult.expiresInMs > 0 ? authResult.expiresInMs : localExpiresInMs;
|
|
1184
|
-
this.logger.info("EMBEDDED_PROVIDER", "JWT authentication completed", {
|
|
1185
|
-
walletId,
|
|
1186
|
-
organizationId,
|
|
1187
|
-
expiresInMs,
|
|
1188
|
-
source: authResult.expiresInMs ? "server" : "local"
|
|
1189
|
-
});
|
|
1190
|
-
const now = Date.now();
|
|
1191
|
-
const session = {
|
|
1192
|
-
sessionId: generateSessionId(),
|
|
1193
|
-
walletId,
|
|
1194
|
-
organizationId,
|
|
1195
|
-
appId: this.config.appId,
|
|
1196
|
-
stamperInfo,
|
|
1197
|
-
authProvider: authResult.provider,
|
|
1198
|
-
accountDerivationIndex: authResult.accountDerivationIndex,
|
|
1199
|
-
status: "completed",
|
|
1200
|
-
createdAt: now,
|
|
1201
|
-
lastUsed: now,
|
|
1202
|
-
authenticatorCreatedAt: now,
|
|
1203
|
-
authenticatorExpiresAt: Date.now() + expiresInMs,
|
|
1204
|
-
lastRenewalAttempt: void 0
|
|
1205
|
-
};
|
|
1206
|
-
this.logger.log("EMBEDDED_PROVIDER", "Saving JWT session");
|
|
1207
|
-
await this.storage.saveSession(session);
|
|
1208
|
-
return session;
|
|
1209
|
-
}
|
|
1210
1088
|
/*
|
|
1211
1089
|
* We use this method to handle Phantom app-based authentication for user-wallets.
|
|
1212
1090
|
* This method uses the PhantomAppProvider to authenticate via the browser extension or mobile app.
|
|
@@ -1380,8 +1258,8 @@ var EmbeddedProvider = class {
|
|
|
1380
1258
|
walletId: this.walletId,
|
|
1381
1259
|
addresses: this.addresses,
|
|
1382
1260
|
status: "completed",
|
|
1383
|
-
|
|
1384
|
-
|
|
1261
|
+
authUserId: session.authUserId,
|
|
1262
|
+
authProvider: session.authProvider
|
|
1385
1263
|
};
|
|
1386
1264
|
}
|
|
1387
1265
|
/*
|
|
@@ -1440,10 +1318,10 @@ var EmbeddedProvider = class {
|
|
|
1440
1318
|
export {
|
|
1441
1319
|
AUTHENTICATOR_EXPIRATION_TIME_MS,
|
|
1442
1320
|
AUTHENTICATOR_RENEWAL_WINDOW_MS,
|
|
1321
|
+
EMBEDDED_PROVIDER_AUTH_TYPES,
|
|
1443
1322
|
EmbeddedEthereumChain,
|
|
1444
1323
|
EmbeddedProvider,
|
|
1445
1324
|
EmbeddedSolanaChain,
|
|
1446
|
-
JWTAuth,
|
|
1447
1325
|
generateSessionId,
|
|
1448
1326
|
retryWithBackoff
|
|
1449
1327
|
};
|