decane-connect-kit 2.29.1 → 2.30.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.
package/dist/index.cjs CHANGED
@@ -42,6 +42,7 @@ __export(errors_exports, {
42
42
  InvalidApiKeyError: () => InvalidApiKeyError,
43
43
  InvalidPinError: () => InvalidPinError,
44
44
  InvalidRecoveryFileError: () => InvalidRecoveryFileError,
45
+ LoginInUseError: () => LoginInUseError,
45
46
  NetworkError: () => NetworkError,
46
47
  NewDeviceError: () => NewDeviceError,
47
48
  OriginNotAllowedError: () => OriginNotAllowedError,
@@ -64,7 +65,7 @@ __export(errors_exports, {
64
65
  WrongPasswordError: () => WrongPasswordError,
65
66
  WrongUnlockPasswordError: () => WrongUnlockPasswordError
66
67
  });
67
- var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError, WalletExistsError, WalletEnrolmentError, ProvisioningRateLimitedError, EnclaveHttpError;
68
+ var DecaneConnectError, InvalidApiKeyError, OriginNotAllowedError, SessionExpiredError, UnlockRequiredError, ReconnectRequiredError, UserCancelledError, WebAuthnNotSupportedError, InvalidPinError, CallSequenceError, NetworkError, ShareCorruptedError, ProvisioningTimeoutError, NewDeviceError, StaleDeviceShareError, PromptPinNotConfiguredError, PromptPasswordNotConfiguredError, WrongUnlockPasswordError, InvalidAccessTokenError, UnlockTokenRejectedError, AttestationError, RecoveryFailedError, InvalidRecoveryFileError, WrongPasswordError, RecoveryWalletMismatchError, ExportNotAuthorizedError, LoginInUseError, WalletExistsError, WalletEnrolmentError, ProvisioningRateLimitedError, EnclaveHttpError;
68
69
  var init_errors = __esm({
69
70
  "src/social/errors.ts"() {
70
71
  "use strict";
@@ -213,6 +214,11 @@ var init_errors = __esm({
213
214
  super("EXPORT_NOT_AUTHORIZED", "Export requires a fresh security check", true);
214
215
  }
215
216
  };
217
+ LoginInUseError = class extends DecaneConnectError {
218
+ constructor(message = "That login already opens another account. It was not linked.") {
219
+ super("LOGIN_IN_USE", message);
220
+ }
221
+ };
216
222
  WalletExistsError = class extends DecaneConnectError {
217
223
  constructor() {
218
224
  super("WALLET_EXISTS", "This account already has a wallet; opening it instead.", true);
@@ -266,6 +272,7 @@ __export(index_exports, {
266
272
  InvalidApiKeyError: () => InvalidApiKeyError,
267
273
  InvalidPinError: () => InvalidPinError,
268
274
  InvalidRecoveryFileError: () => InvalidRecoveryFileError,
275
+ LoginInUseError: () => LoginInUseError,
269
276
  MIN_PASSWORD_LENGTH: () => MIN_PASSWORD_LENGTH,
270
277
  NetworkError: () => NetworkError,
271
278
  NewDeviceError: () => NewDeviceError,
@@ -2118,7 +2125,9 @@ var ERROR_MAP = {
2118
2125
  // generic failure message.
2119
2126
  UNAUTHORIZED: ReconnectRequiredError,
2120
2127
  // A restorable wallet already exists: the client provisions instead of creating.
2121
- WALLET_EXISTS: WalletExistsError
2128
+ WALLET_EXISTS: WalletExistsError,
2129
+ // linkWithToken(): the login already opens another account.
2130
+ LOGIN_IN_USE: LoginInUseError
2122
2131
  };
2123
2132
  var REQUEST_TIMEOUT_MS = 3e4;
2124
2133
  var ApiClient = class {
@@ -2287,6 +2296,23 @@ var ApiClient = class {
2287
2296
  body: JSON.stringify(providerId ? { token, providerId } : { token })
2288
2297
  });
2289
2298
  }
2299
+ /** Attach a login from the project's own provider to the signed-in account. */
2300
+ async linkExternal(jwt, token, providerId) {
2301
+ return this._request("/auth/link/external", {
2302
+ method: "POST",
2303
+ headers: { Authorization: `Bearer ${jwt}` },
2304
+ body: JSON.stringify(providerId ? { token, providerId } : { token })
2305
+ });
2306
+ }
2307
+ async listLinkedLogins(jwt) {
2308
+ return this._request("/auth/link/external", { method: "GET", headers: { Authorization: `Bearer ${jwt}` } });
2309
+ }
2310
+ async unlinkLogin(jwt, id) {
2311
+ await this._request(`/auth/link/external/${encodeURIComponent(id)}`, {
2312
+ method: "DELETE",
2313
+ headers: { Authorization: `Bearer ${jwt}` }
2314
+ });
2315
+ }
2290
2316
  /**
2291
2317
  * Returns null when this user has no server-registered passkey, which is the
2292
2318
  * expected answer for wallets created before passkey sign-in existed or for
@@ -3910,7 +3936,7 @@ async function buildPortableBackup(deviceShare, recoveryShare, password, address
3910
3936
  // src/social/client.ts
3911
3937
  var DEFAULT_API_BASE = "https://backend.decane.app";
3912
3938
  var DEFAULT_TEE_URL = "https://4405742df08d19abc549a05ade2a7154d98bd87f-8443.dstack-pha-prod9.phala.network";
3913
- var DEFAULT_SESSION_MINUTES = 120;
3939
+ var DEFAULT_SESSION_MINUTES = 480;
3914
3940
  function makePersistKey(apiKey) {
3915
3941
  return `decane:social:${apiKey.slice(0, 20)}`;
3916
3942
  }
@@ -4954,6 +4980,20 @@ async function createDecaneConnect(config) {
4954
4980
  const result = await api.authExternal(token, opts?.providerId);
4955
4981
  return handleAuthResult(result);
4956
4982
  },
4983
+ async linkWithToken(token, opts) {
4984
+ if (!token) throw new CallSequenceError("linkWithToken requires a token");
4985
+ if (!auth) throw new ReconnectRequiredError();
4986
+ const result = await api.linkExternal(auth.jwt, token, opts?.providerId);
4987
+ return result.id ? { alreadyLinked: result.alreadyLinked, id: result.id } : { alreadyLinked: result.alreadyLinked };
4988
+ },
4989
+ async listLinkedLogins() {
4990
+ if (!auth) throw new ReconnectRequiredError();
4991
+ return (await api.listLinkedLogins(auth.jwt)).logins;
4992
+ },
4993
+ async unlinkLogin(id) {
4994
+ if (!auth) throw new ReconnectRequiredError();
4995
+ await api.unlinkLogin(auth.jwt, id);
4996
+ },
4957
4997
  async connectWithAccessToken(token) {
4958
4998
  const claims = decodeAccessToken(token);
4959
4999
  if (!claims) throw new InvalidAccessTokenError("not a Decane access token");
@@ -6887,6 +6927,7 @@ function DecaneKit({ config, children }) {
6887
6927
  protection,
6888
6928
  deferDeviceProtection,
6889
6929
  resumeSessionAcrossTabs,
6930
+ sessionDurationMinutes,
6890
6931
  // Recovery callbacks. Forwarding these is what makes recovery
6891
6932
  // configurable at all from <DecaneKit>; before, they were silently
6892
6933
  // dropped and the headless client was constructed without them.
@@ -6910,6 +6951,7 @@ function DecaneKit({ config, children }) {
6910
6951
  protection,
6911
6952
  deferDeviceProtection,
6912
6953
  resumeSessionAcrossTabs,
6954
+ sessionDurationMinutes,
6913
6955
  offerRecoveryAtSignup,
6914
6956
  onRecoveryShareOffer,
6915
6957
  onRecoveryFileReady,
@@ -7033,6 +7075,21 @@ function DecaneKit({ config, children }) {
7033
7075
  throw e;
7034
7076
  }
7035
7077
  }, [clearPhase]);
7078
+ const linkWithToken = (0, import_react5.useCallback)(async (token, opts) => {
7079
+ const sdk = socialRef.current;
7080
+ if (!sdk) throw new Error("Social sign-in not configured");
7081
+ return sdk.linkWithToken(token, opts);
7082
+ }, []);
7083
+ const listLinkedLogins = (0, import_react5.useCallback)(async () => {
7084
+ const sdk = socialRef.current;
7085
+ if (!sdk) throw new Error("Social sign-in not configured");
7086
+ return sdk.listLinkedLogins();
7087
+ }, []);
7088
+ const unlinkLogin = (0, import_react5.useCallback)(async (id) => {
7089
+ const sdk = socialRef.current;
7090
+ if (!sdk) throw new Error("Social sign-in not configured");
7091
+ await sdk.unlinkLogin(id);
7092
+ }, []);
7036
7093
  const connectWithToken = (0, import_react5.useCallback)(async (token, opts) => {
7037
7094
  const sdk = socialRef.current;
7038
7095
  if (!sdk) throw new Error("Social sign-in not configured");
@@ -7250,6 +7307,9 @@ function DecaneKit({ config, children }) {
7250
7307
  verifyPhoneCode: verifyPhoneCode2,
7251
7308
  connectWithToken,
7252
7309
  connectWithAccessToken,
7310
+ linkWithToken,
7311
+ listLinkedLogins,
7312
+ unlinkLogin,
7253
7313
  customAuthLabel: customAuthConfig?.label,
7254
7314
  connectWithCustomAuth: customAuthConfig ? connectWithCustomAuth : void 0,
7255
7315
  socialUnlock,
@@ -7366,6 +7426,9 @@ function useSocialAuth() {
7366
7426
  verifyPhoneCode: verifyPhoneCode2,
7367
7427
  connectWithToken,
7368
7428
  connectWithAccessToken,
7429
+ linkWithToken,
7430
+ listLinkedLogins,
7431
+ unlinkLogin,
7369
7432
  customAuthLabel,
7370
7433
  connectWithCustomAuth,
7371
7434
  signInWithPasskey: ctxSignInWithPasskey,
@@ -7569,6 +7632,11 @@ function useSocialAuth() {
7569
7632
  confirmPhoneCode,
7570
7633
  signInWithToken,
7571
7634
  signInWithAccessToken,
7635
+ // Linked logins: while signed in, attach a login from your own auth (a
7636
+ // phone number your backend verified, say) so it opens this same wallet.
7637
+ linkWithToken,
7638
+ listLinkedLogins,
7639
+ unlinkLogin,
7572
7640
  signInWithCustomAuth: connectWithCustomAuth ? signInWithCustomAuth : void 0,
7573
7641
  signInWithPasskey,
7574
7642
  unlock,
@@ -8123,6 +8191,7 @@ function useSignTypedData() {
8123
8191
  InvalidApiKeyError,
8124
8192
  InvalidPinError,
8125
8193
  InvalidRecoveryFileError,
8194
+ LoginInUseError,
8126
8195
  MIN_PASSWORD_LENGTH,
8127
8196
  NetworkError,
8128
8197
  NewDeviceError,