@gvnrdao/dh-sdk 0.0.311 → 0.0.312
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/browser/dist/browser.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +88 -1
- package/dist/index.mjs +84 -1
- package/dist/interfaces/chunks/config.i.d.ts +13 -0
- package/dist/modules/diamond-hands-sdk.d.ts +23 -0
- package/dist/utils/server-session.d.ts +30 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export type { BitcoinOperationsConfig, BitcoinNetwork, EnrichedBitcoinBalance, }
|
|
|
35
35
|
export type { SupportedStablecoinData } from './graphs/diamond-hands';
|
|
36
36
|
export { validateSDKConfig, validateServiceModeConfig, validateStandaloneModeConfig, isServiceModeConfig, isStandaloneModeConfig, } from './interfaces/chunks/config.i';
|
|
37
37
|
export { assertSafeServiceEndpoint } from './utils/service-endpoint-policy';
|
|
38
|
+
export { buildLoginDomain, buildSignedLoginPayload, LOGIN_TYPES, LOGIN_TYPES_WITH_AUDIENCE, } from './utils/eip712-login';
|
|
39
|
+
export type { DhServerLoginMessage, DhServerLoginPayload, } from './utils/eip712-login';
|
|
38
40
|
export { DEFAULT_LIT_NETWORK, VALID_LIT_NETWORKS, SDK_DEFAULTS, } from './constants/chunks/sdk-config';
|
|
39
41
|
export { ALL_CONTRACTS, ALL_DEPLOYMENTS, getContractsByNetwork, getDeploymentByNetwork, LOCALHOST_CONTRACTS, SEPOLIA_CONTRACTS, } from './constants/chunks/deployment-addresses';
|
|
40
42
|
export type { DeploymentContracts, DeploymentData, DeploymentLatestEnv, } from './constants/chunks/deployment-addresses';
|
package/dist/index.js
CHANGED
|
@@ -5574,6 +5574,8 @@ __export(src_exports, {
|
|
|
5574
5574
|
ErrorSeverity: () => ErrorSeverity,
|
|
5575
5575
|
EventHelpers: () => EventHelpers,
|
|
5576
5576
|
LOCALHOST_CONTRACTS: () => LOCALHOST_CONTRACTS,
|
|
5577
|
+
LOGIN_TYPES: () => LOGIN_TYPES,
|
|
5578
|
+
LOGIN_TYPES_WITH_AUDIENCE: () => LOGIN_TYPES_WITH_AUDIENCE,
|
|
5577
5579
|
LRUCache: () => LRUCache,
|
|
5578
5580
|
LoanCreator: () => LoanCreator,
|
|
5579
5581
|
LoanQuery: () => LoanQuery,
|
|
@@ -5596,6 +5598,8 @@ __export(src_exports, {
|
|
|
5596
5598
|
buildBtcExecuteEnvelope: () => buildBtcExecuteEnvelope,
|
|
5597
5599
|
buildInvalidateMessageHash: () => buildInvalidateMessageHash,
|
|
5598
5600
|
buildInvalidateStaleSpendEnvelope: () => buildInvalidateStaleSpendEnvelope,
|
|
5601
|
+
buildLoginDomain: () => buildLoginDomain,
|
|
5602
|
+
buildSignedLoginPayload: () => buildSignedLoginPayload,
|
|
5599
5603
|
collectFailures: () => collectFailures,
|
|
5600
5604
|
collectSuccesses: () => collectSuccesses,
|
|
5601
5605
|
combine: () => combine,
|
|
@@ -6700,6 +6704,7 @@ function isLoginRejection(error) {
|
|
|
6700
6704
|
var ServerSession = class {
|
|
6701
6705
|
signer;
|
|
6702
6706
|
serviceEndpoint;
|
|
6707
|
+
loginAudience;
|
|
6703
6708
|
chainId;
|
|
6704
6709
|
store;
|
|
6705
6710
|
onSignaturePrompt;
|
|
@@ -6730,6 +6735,10 @@ var ServerSession = class {
|
|
|
6730
6735
|
assertSafeServiceEndpoint(opts.serviceEndpoint);
|
|
6731
6736
|
this.signer = opts.signer;
|
|
6732
6737
|
this.serviceEndpoint = opts.serviceEndpoint.replace(/\/+$/, "");
|
|
6738
|
+
this.loginAudience = (opts.loginAudience ?? this.serviceEndpoint).replace(
|
|
6739
|
+
/\/+$/,
|
|
6740
|
+
""
|
|
6741
|
+
);
|
|
6733
6742
|
this.chainId = opts.chainId;
|
|
6734
6743
|
this.store = opts.persistSession === false ? null : opts.sessionStore ?? createDefaultSessionStore();
|
|
6735
6744
|
this.onSignaturePrompt = opts.onSignaturePrompt;
|
|
@@ -6829,6 +6838,53 @@ var ServerSession = class {
|
|
|
6829
6838
|
);
|
|
6830
6839
|
}
|
|
6831
6840
|
}
|
|
6841
|
+
/**
|
|
6842
|
+
* Adopt a login envelope signed ELSEWHERE and exchange it for a session now.
|
|
6843
|
+
*
|
|
6844
|
+
* The browser frontend collects one wallet signature and spends it at both the
|
|
6845
|
+
* api and this service, so the envelope is minted outside the SDK. Without this
|
|
6846
|
+
* seam the SDK would mint its own — a second wallet prompt, which for a
|
|
6847
|
+
* multi-sig Safe is another full propose-and-confirm ceremony across owners.
|
|
6848
|
+
*
|
|
6849
|
+
* Must be called PROMPTLY after signing. Each server pins the nonce on FIRST
|
|
6850
|
+
* use and requires that first use to be fresh (±120s EOA, ±600s contract
|
|
6851
|
+
* wallet); the stores are independent, so a late hand-off is rejected as
|
|
6852
|
+
* `stale_first_use` even though the other service already accepted it. After a
|
|
6853
|
+
* successful first use, silent re-mint covers the next 24h.
|
|
6854
|
+
*
|
|
6855
|
+
* No-ops the prompt path entirely: on success the session is cached and
|
|
6856
|
+
* persisted exactly as a self-minted login would be.
|
|
6857
|
+
*/
|
|
6858
|
+
adoptLoginPayload(payload) {
|
|
6859
|
+
const gen = this.generation;
|
|
6860
|
+
const notCleared = () => gen === this.generation;
|
|
6861
|
+
const attempt = (async () => {
|
|
6862
|
+
if (payload?.chainId !== this.chainId) {
|
|
6863
|
+
throw new Error(
|
|
6864
|
+
`ServerSession: cannot adopt a login for chain ${payload?.chainId} \u2014 this session is on ${this.chainId}`
|
|
6865
|
+
);
|
|
6866
|
+
}
|
|
6867
|
+
const payloadAddress = payload.message?.address?.toLowerCase();
|
|
6868
|
+
const signerAddress = (await this.signer.getAddress()).toLowerCase();
|
|
6869
|
+
if (!payloadAddress || payloadAddress !== signerAddress) {
|
|
6870
|
+
throw new Error(
|
|
6871
|
+
"ServerSession: cannot adopt a login signed by a different address"
|
|
6872
|
+
);
|
|
6873
|
+
}
|
|
6874
|
+
const session = await this.login(payload);
|
|
6875
|
+
if (notCleared()) {
|
|
6876
|
+
this.persist(payload, session);
|
|
6877
|
+
this.cached = session;
|
|
6878
|
+
this.promptBackoff = null;
|
|
6879
|
+
}
|
|
6880
|
+
return session;
|
|
6881
|
+
})();
|
|
6882
|
+
this.inFlight = attempt;
|
|
6883
|
+
return attempt.then(() => void 0).finally(() => {
|
|
6884
|
+
if (notCleared())
|
|
6885
|
+
this.inFlight = null;
|
|
6886
|
+
});
|
|
6887
|
+
}
|
|
6832
6888
|
/**
|
|
6833
6889
|
* Resolve a session WITHOUT ever prompting for a wallet signature: a live
|
|
6834
6890
|
* cached token, else the persisted JWT (adopted if still fresh, otherwise
|
|
@@ -6901,7 +6957,7 @@ var ServerSession = class {
|
|
|
6901
6957
|
const payload = await buildSignedLoginPayload(
|
|
6902
6958
|
this.signer,
|
|
6903
6959
|
this.chainId,
|
|
6904
|
-
this.
|
|
6960
|
+
this.loginAudience,
|
|
6905
6961
|
reuse
|
|
6906
6962
|
);
|
|
6907
6963
|
if (storeKey && !reuse) {
|
|
@@ -16545,6 +16601,32 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
16545
16601
|
await this.serverSession.clearPersisted();
|
|
16546
16602
|
}
|
|
16547
16603
|
}
|
|
16604
|
+
/**
|
|
16605
|
+
* Establish the lit-ops-server session from a login envelope the CALLER already
|
|
16606
|
+
* had signed, instead of prompting the wallet for one.
|
|
16607
|
+
*
|
|
16608
|
+
* For a host that authenticates several services from one wallet signature (the
|
|
16609
|
+
* browser frontend signs once and spends the same envelope at the api and here),
|
|
16610
|
+
* this is what turns two wallet prompts into one — and for a multi-sig Safe each
|
|
16611
|
+
* prompt saved is a whole propose-and-confirm ceremony across owners.
|
|
16612
|
+
*
|
|
16613
|
+
* Call it PROMPTLY after signing: each server pins the nonce on first use and
|
|
16614
|
+
* requires that first use to be fresh (±120s EOA, ±600s contract wallet), and
|
|
16615
|
+
* the two servers' replay stores are independent, so a late hand-off is rejected
|
|
16616
|
+
* as stale even though the other service already accepted the same envelope.
|
|
16617
|
+
* Once accepted, silent re-mint covers the next 24h with no further prompts.
|
|
16618
|
+
*
|
|
16619
|
+
* Requires `loginAudience` to be configured to a value BOTH servers accept —
|
|
16620
|
+
* otherwise this service rejects the envelope as `audience_mismatch`.
|
|
16621
|
+
*
|
|
16622
|
+
* Throws if the exchange fails, so a caller can fall back to the prompt path.
|
|
16623
|
+
* No-op in standalone mode (no server session to prime).
|
|
16624
|
+
*/
|
|
16625
|
+
async primeServerSession(payload) {
|
|
16626
|
+
if (!this.serverSession)
|
|
16627
|
+
return;
|
|
16628
|
+
await this.serverSession.adoptLoginPayload(payload);
|
|
16629
|
+
}
|
|
16548
16630
|
/**
|
|
16549
16631
|
* Audit H-9: invalidate the LoanQuery cache so subsequent reads return
|
|
16550
16632
|
* the post-write state. We clear the entire loan-query cache (not just
|
|
@@ -16656,6 +16738,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
16656
16738
|
this.serverSession = new ServerSession({
|
|
16657
16739
|
signer: config.authSigner ?? config.contractSigner,
|
|
16658
16740
|
serviceEndpoint: config.serviceEndpoint,
|
|
16741
|
+
loginAudience: config.loginAudience,
|
|
16659
16742
|
chainId: config.chainId,
|
|
16660
16743
|
persistSession: config.sessionPersistence?.enabled,
|
|
16661
16744
|
sessionStore: config.sessionPersistence?.store,
|
|
@@ -23866,6 +23949,8 @@ async function getPositionDelegate(positionId, provider, registryAddress) {
|
|
|
23866
23949
|
ErrorSeverity,
|
|
23867
23950
|
EventHelpers,
|
|
23868
23951
|
LOCALHOST_CONTRACTS,
|
|
23952
|
+
LOGIN_TYPES,
|
|
23953
|
+
LOGIN_TYPES_WITH_AUDIENCE,
|
|
23869
23954
|
LRUCache,
|
|
23870
23955
|
LoanCreator,
|
|
23871
23956
|
LoanQuery,
|
|
@@ -23888,6 +23973,8 @@ async function getPositionDelegate(positionId, provider, registryAddress) {
|
|
|
23888
23973
|
buildBtcExecuteEnvelope,
|
|
23889
23974
|
buildInvalidateMessageHash,
|
|
23890
23975
|
buildInvalidateStaleSpendEnvelope,
|
|
23976
|
+
buildLoginDomain,
|
|
23977
|
+
buildSignedLoginPayload,
|
|
23891
23978
|
collectFailures,
|
|
23892
23979
|
collectSuccesses,
|
|
23893
23980
|
combine,
|
package/dist/index.mjs
CHANGED
|
@@ -6619,6 +6619,7 @@ function isLoginRejection(error) {
|
|
|
6619
6619
|
var ServerSession = class {
|
|
6620
6620
|
signer;
|
|
6621
6621
|
serviceEndpoint;
|
|
6622
|
+
loginAudience;
|
|
6622
6623
|
chainId;
|
|
6623
6624
|
store;
|
|
6624
6625
|
onSignaturePrompt;
|
|
@@ -6649,6 +6650,10 @@ var ServerSession = class {
|
|
|
6649
6650
|
assertSafeServiceEndpoint(opts.serviceEndpoint);
|
|
6650
6651
|
this.signer = opts.signer;
|
|
6651
6652
|
this.serviceEndpoint = opts.serviceEndpoint.replace(/\/+$/, "");
|
|
6653
|
+
this.loginAudience = (opts.loginAudience ?? this.serviceEndpoint).replace(
|
|
6654
|
+
/\/+$/,
|
|
6655
|
+
""
|
|
6656
|
+
);
|
|
6652
6657
|
this.chainId = opts.chainId;
|
|
6653
6658
|
this.store = opts.persistSession === false ? null : opts.sessionStore ?? createDefaultSessionStore();
|
|
6654
6659
|
this.onSignaturePrompt = opts.onSignaturePrompt;
|
|
@@ -6748,6 +6753,53 @@ var ServerSession = class {
|
|
|
6748
6753
|
);
|
|
6749
6754
|
}
|
|
6750
6755
|
}
|
|
6756
|
+
/**
|
|
6757
|
+
* Adopt a login envelope signed ELSEWHERE and exchange it for a session now.
|
|
6758
|
+
*
|
|
6759
|
+
* The browser frontend collects one wallet signature and spends it at both the
|
|
6760
|
+
* api and this service, so the envelope is minted outside the SDK. Without this
|
|
6761
|
+
* seam the SDK would mint its own — a second wallet prompt, which for a
|
|
6762
|
+
* multi-sig Safe is another full propose-and-confirm ceremony across owners.
|
|
6763
|
+
*
|
|
6764
|
+
* Must be called PROMPTLY after signing. Each server pins the nonce on FIRST
|
|
6765
|
+
* use and requires that first use to be fresh (±120s EOA, ±600s contract
|
|
6766
|
+
* wallet); the stores are independent, so a late hand-off is rejected as
|
|
6767
|
+
* `stale_first_use` even though the other service already accepted it. After a
|
|
6768
|
+
* successful first use, silent re-mint covers the next 24h.
|
|
6769
|
+
*
|
|
6770
|
+
* No-ops the prompt path entirely: on success the session is cached and
|
|
6771
|
+
* persisted exactly as a self-minted login would be.
|
|
6772
|
+
*/
|
|
6773
|
+
adoptLoginPayload(payload) {
|
|
6774
|
+
const gen = this.generation;
|
|
6775
|
+
const notCleared = () => gen === this.generation;
|
|
6776
|
+
const attempt = (async () => {
|
|
6777
|
+
if (payload?.chainId !== this.chainId) {
|
|
6778
|
+
throw new Error(
|
|
6779
|
+
`ServerSession: cannot adopt a login for chain ${payload?.chainId} \u2014 this session is on ${this.chainId}`
|
|
6780
|
+
);
|
|
6781
|
+
}
|
|
6782
|
+
const payloadAddress = payload.message?.address?.toLowerCase();
|
|
6783
|
+
const signerAddress = (await this.signer.getAddress()).toLowerCase();
|
|
6784
|
+
if (!payloadAddress || payloadAddress !== signerAddress) {
|
|
6785
|
+
throw new Error(
|
|
6786
|
+
"ServerSession: cannot adopt a login signed by a different address"
|
|
6787
|
+
);
|
|
6788
|
+
}
|
|
6789
|
+
const session = await this.login(payload);
|
|
6790
|
+
if (notCleared()) {
|
|
6791
|
+
this.persist(payload, session);
|
|
6792
|
+
this.cached = session;
|
|
6793
|
+
this.promptBackoff = null;
|
|
6794
|
+
}
|
|
6795
|
+
return session;
|
|
6796
|
+
})();
|
|
6797
|
+
this.inFlight = attempt;
|
|
6798
|
+
return attempt.then(() => void 0).finally(() => {
|
|
6799
|
+
if (notCleared())
|
|
6800
|
+
this.inFlight = null;
|
|
6801
|
+
});
|
|
6802
|
+
}
|
|
6751
6803
|
/**
|
|
6752
6804
|
* Resolve a session WITHOUT ever prompting for a wallet signature: a live
|
|
6753
6805
|
* cached token, else the persisted JWT (adopted if still fresh, otherwise
|
|
@@ -6820,7 +6872,7 @@ var ServerSession = class {
|
|
|
6820
6872
|
const payload = await buildSignedLoginPayload(
|
|
6821
6873
|
this.signer,
|
|
6822
6874
|
this.chainId,
|
|
6823
|
-
this.
|
|
6875
|
+
this.loginAudience,
|
|
6824
6876
|
reuse
|
|
6825
6877
|
);
|
|
6826
6878
|
if (storeKey && !reuse) {
|
|
@@ -16474,6 +16526,32 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
16474
16526
|
await this.serverSession.clearPersisted();
|
|
16475
16527
|
}
|
|
16476
16528
|
}
|
|
16529
|
+
/**
|
|
16530
|
+
* Establish the lit-ops-server session from a login envelope the CALLER already
|
|
16531
|
+
* had signed, instead of prompting the wallet for one.
|
|
16532
|
+
*
|
|
16533
|
+
* For a host that authenticates several services from one wallet signature (the
|
|
16534
|
+
* browser frontend signs once and spends the same envelope at the api and here),
|
|
16535
|
+
* this is what turns two wallet prompts into one — and for a multi-sig Safe each
|
|
16536
|
+
* prompt saved is a whole propose-and-confirm ceremony across owners.
|
|
16537
|
+
*
|
|
16538
|
+
* Call it PROMPTLY after signing: each server pins the nonce on first use and
|
|
16539
|
+
* requires that first use to be fresh (±120s EOA, ±600s contract wallet), and
|
|
16540
|
+
* the two servers' replay stores are independent, so a late hand-off is rejected
|
|
16541
|
+
* as stale even though the other service already accepted the same envelope.
|
|
16542
|
+
* Once accepted, silent re-mint covers the next 24h with no further prompts.
|
|
16543
|
+
*
|
|
16544
|
+
* Requires `loginAudience` to be configured to a value BOTH servers accept —
|
|
16545
|
+
* otherwise this service rejects the envelope as `audience_mismatch`.
|
|
16546
|
+
*
|
|
16547
|
+
* Throws if the exchange fails, so a caller can fall back to the prompt path.
|
|
16548
|
+
* No-op in standalone mode (no server session to prime).
|
|
16549
|
+
*/
|
|
16550
|
+
async primeServerSession(payload) {
|
|
16551
|
+
if (!this.serverSession)
|
|
16552
|
+
return;
|
|
16553
|
+
await this.serverSession.adoptLoginPayload(payload);
|
|
16554
|
+
}
|
|
16477
16555
|
/**
|
|
16478
16556
|
* Audit H-9: invalidate the LoanQuery cache so subsequent reads return
|
|
16479
16557
|
* the post-write state. We clear the entire loan-query cache (not just
|
|
@@ -16585,6 +16663,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
16585
16663
|
this.serverSession = new ServerSession({
|
|
16586
16664
|
signer: config.authSigner ?? config.contractSigner,
|
|
16587
16665
|
serviceEndpoint: config.serviceEndpoint,
|
|
16666
|
+
loginAudience: config.loginAudience,
|
|
16588
16667
|
chainId: config.chainId,
|
|
16589
16668
|
persistSession: config.sessionPersistence?.enabled,
|
|
16590
16669
|
sessionStore: config.sessionPersistence?.store,
|
|
@@ -23794,6 +23873,8 @@ export {
|
|
|
23794
23873
|
ErrorSeverity,
|
|
23795
23874
|
EventHelpers,
|
|
23796
23875
|
LOCALHOST_CONTRACTS,
|
|
23876
|
+
LOGIN_TYPES,
|
|
23877
|
+
LOGIN_TYPES_WITH_AUDIENCE,
|
|
23797
23878
|
LRUCache,
|
|
23798
23879
|
LoanCreator,
|
|
23799
23880
|
LoanQuery,
|
|
@@ -23816,6 +23897,8 @@ export {
|
|
|
23816
23897
|
buildBtcExecuteEnvelope,
|
|
23817
23898
|
buildInvalidateMessageHash,
|
|
23818
23899
|
buildInvalidateStaleSpendEnvelope,
|
|
23900
|
+
buildLoginDomain,
|
|
23901
|
+
buildSignedLoginPayload,
|
|
23819
23902
|
collectFailures,
|
|
23820
23903
|
collectSuccesses,
|
|
23821
23904
|
combine,
|
|
@@ -71,6 +71,19 @@ interface BaseSDKConfig {
|
|
|
71
71
|
/** Custom store (e.g. a file-backed store for CLI daemons). */
|
|
72
72
|
store?: ServerSessionStore;
|
|
73
73
|
};
|
|
74
|
+
/**
|
|
75
|
+
* Audit M-8 audience the server-session login binds to. Defaults to
|
|
76
|
+
* `serviceEndpoint`.
|
|
77
|
+
*
|
|
78
|
+
* Set this only when ONE signature must authenticate several services — the
|
|
79
|
+
* browser frontend signs a single envelope and spends it at both
|
|
80
|
+
* lit-ops-server and the api, and a per-endpoint audience cannot name two
|
|
81
|
+
* endpoints. Every server the envelope is presented to must list this value as
|
|
82
|
+
* an accepted audience, so changing it requires a server-side config change
|
|
83
|
+
* FIRST. Node callers (CLI, MCP, cr-monitor) omit it and keep binding to the
|
|
84
|
+
* endpoint they call.
|
|
85
|
+
*/
|
|
86
|
+
loginAudience?: string;
|
|
74
87
|
/**
|
|
75
88
|
* Fires immediately before the server-session login requests a wallet
|
|
76
89
|
* signature — never on the silent re-mint paths. Lets UIs show a
|
|
@@ -18,6 +18,7 @@ import { SDKError } from "../utils/error-handler";
|
|
|
18
18
|
import type { CreateLoanRequest, CreateLoanResult, LoanDataDetail, UCDMintRequest, UCDMintResult, PartialPaymentRequest, PartialPaymentResult, BTCWithdrawalResult, RenewPositionRequest, RenewPositionResult, LiquidationRequest, LiquidationResult, ConfirmBalanceRequest, ConfirmBalanceResult, TermsWithFeesResult } from "../interfaces/chunks/loan-operations.i";
|
|
19
19
|
import type { DiamondHandsSDKConfig } from "../interfaces/chunks/config.i";
|
|
20
20
|
import type { PKPData } from "../interfaces/chunks/pkp-integration.i";
|
|
21
|
+
import type { DhServerLoginPayload } from "../utils/eip712-login";
|
|
21
22
|
import { type ReconciledWithdrawal } from "../utils/withdrawal-reconciliation.utils";
|
|
22
23
|
import { ContractManager } from "./contract/contract-manager.module";
|
|
23
24
|
import { WithdrawalAddressModule } from "./withdrawal-address/withdrawal-address.module";
|
|
@@ -125,6 +126,28 @@ export declare class DiamondHandsSDK {
|
|
|
125
126
|
* and never prompts the wallet.
|
|
126
127
|
*/
|
|
127
128
|
clearServerSession(): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Establish the lit-ops-server session from a login envelope the CALLER already
|
|
131
|
+
* had signed, instead of prompting the wallet for one.
|
|
132
|
+
*
|
|
133
|
+
* For a host that authenticates several services from one wallet signature (the
|
|
134
|
+
* browser frontend signs once and spends the same envelope at the api and here),
|
|
135
|
+
* this is what turns two wallet prompts into one — and for a multi-sig Safe each
|
|
136
|
+
* prompt saved is a whole propose-and-confirm ceremony across owners.
|
|
137
|
+
*
|
|
138
|
+
* Call it PROMPTLY after signing: each server pins the nonce on first use and
|
|
139
|
+
* requires that first use to be fresh (±120s EOA, ±600s contract wallet), and
|
|
140
|
+
* the two servers' replay stores are independent, so a late hand-off is rejected
|
|
141
|
+
* as stale even though the other service already accepted the same envelope.
|
|
142
|
+
* Once accepted, silent re-mint covers the next 24h with no further prompts.
|
|
143
|
+
*
|
|
144
|
+
* Requires `loginAudience` to be configured to a value BOTH servers accept —
|
|
145
|
+
* otherwise this service rejects the envelope as `audience_mismatch`.
|
|
146
|
+
*
|
|
147
|
+
* Throws if the exchange fails, so a caller can fall back to the prompt path.
|
|
148
|
+
* No-op in standalone mode (no server session to prime).
|
|
149
|
+
*/
|
|
150
|
+
primeServerSession(payload: DhServerLoginPayload): Promise<void>;
|
|
128
151
|
/**
|
|
129
152
|
* Audit H-9: invalidate the LoanQuery cache so subsequent reads return
|
|
130
153
|
* the post-write state. We clear the entire loan-query cache (not just
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* `~/.diamond-hands/session.json` for cross-invocation reuse.
|
|
23
23
|
*/
|
|
24
24
|
import type { Signer } from "ethers";
|
|
25
|
+
import { type DhServerLoginPayload } from "./eip712-login";
|
|
25
26
|
import { type ServerSessionStore } from "./server-session-store";
|
|
26
27
|
export interface ServerSessionOptions {
|
|
27
28
|
signer: Signer;
|
|
@@ -34,6 +35,16 @@ export interface ServerSessionOptions {
|
|
|
34
35
|
sessionStore?: ServerSessionStore;
|
|
35
36
|
/** Set false to disable persistence entirely (fresh signature per instance + expiry). */
|
|
36
37
|
persistSession?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Audit M-8 audience to bind the login to. Defaults to `serviceEndpoint`.
|
|
40
|
+
*
|
|
41
|
+
* A caller that shares ONE signature across several services (the browser
|
|
42
|
+
* frontend, which authenticates both lit-ops-server and the api from a single
|
|
43
|
+
* wallet prompt) cannot bind to a single endpoint, so it passes the app audience
|
|
44
|
+
* instead — and every server it talks to must accept that value. Node callers
|
|
45
|
+
* (CLI, MCP, cr-monitor) omit it and keep the endpoint binding unchanged.
|
|
46
|
+
*/
|
|
47
|
+
loginAudience?: string;
|
|
37
48
|
/**
|
|
38
49
|
* Fires immediately before a wallet signature is requested — i.e. only when
|
|
39
50
|
* neither the cached JWT nor the persisted envelope could renew the session,
|
|
@@ -59,6 +70,7 @@ export declare class ServerLoginError extends Error {
|
|
|
59
70
|
export declare class ServerSession {
|
|
60
71
|
private readonly signer;
|
|
61
72
|
private readonly serviceEndpoint;
|
|
73
|
+
private readonly loginAudience;
|
|
62
74
|
private readonly chainId;
|
|
63
75
|
private readonly store;
|
|
64
76
|
private readonly onSignaturePrompt?;
|
|
@@ -118,6 +130,24 @@ export declare class ServerSession {
|
|
|
118
130
|
* of server response so the client stops presenting the token.
|
|
119
131
|
*/
|
|
120
132
|
logout(): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Adopt a login envelope signed ELSEWHERE and exchange it for a session now.
|
|
135
|
+
*
|
|
136
|
+
* The browser frontend collects one wallet signature and spends it at both the
|
|
137
|
+
* api and this service, so the envelope is minted outside the SDK. Without this
|
|
138
|
+
* seam the SDK would mint its own — a second wallet prompt, which for a
|
|
139
|
+
* multi-sig Safe is another full propose-and-confirm ceremony across owners.
|
|
140
|
+
*
|
|
141
|
+
* Must be called PROMPTLY after signing. Each server pins the nonce on FIRST
|
|
142
|
+
* use and requires that first use to be fresh (±120s EOA, ±600s contract
|
|
143
|
+
* wallet); the stores are independent, so a late hand-off is rejected as
|
|
144
|
+
* `stale_first_use` even though the other service already accepted it. After a
|
|
145
|
+
* successful first use, silent re-mint covers the next 24h.
|
|
146
|
+
*
|
|
147
|
+
* No-ops the prompt path entirely: on success the session is cached and
|
|
148
|
+
* persisted exactly as a self-minted login would be.
|
|
149
|
+
*/
|
|
150
|
+
adoptLoginPayload(payload: DhServerLoginPayload): Promise<void>;
|
|
121
151
|
/**
|
|
122
152
|
* Resolve a session WITHOUT ever prompting for a wallet signature: a live
|
|
123
153
|
* cached token, else the persisted JWT (adopted if still fresh, otherwise
|
package/package.json
CHANGED