@partylayer/adapter-bron 0.6.1 → 0.7.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/README.md +27 -0
- package/dist/index.d.mts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +163 -77
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -78
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -64,6 +64,33 @@ Use PKCE for browser flows and never expose a client secret in frontend code.
|
|
|
64
64
|
Register the callback URL with Bron and follow their onboarding instructions;
|
|
65
65
|
this package does not provision a Bron account or credentials.
|
|
66
66
|
|
|
67
|
+
### Registered callback page
|
|
68
|
+
|
|
69
|
+
For the explicitly configured legacy OAuth contract, the application's registered
|
|
70
|
+
same-origin redirect page relays the authorization response to the popup opener:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { completeBronAuthorization } from '@partylayer/sdk';
|
|
74
|
+
|
|
75
|
+
await completeBronAuthorization('https://your-app.example/oauth/bron/callback');
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Use the exact registered URL. Load this helper only on that dedicated callback
|
|
79
|
+
page; avoid analytics and other third-party scripts there. The opener verifies
|
|
80
|
+
the popup source, origin, redirect path, single-use state and S256 PKCE, then
|
|
81
|
+
exchanges the code. Browser client secrets and non-PKCE browser configuration are
|
|
82
|
+
rejected. Authorization is bounded, tokens remain in memory, and disconnect
|
|
83
|
+
invalidates pending authorization. No new PartyLayer wallet package is required.
|
|
84
|
+
|
|
85
|
+
This compatibility configuration requires a vendor-approved OAuth/signer API
|
|
86
|
+
contract. Bron's current [public API authentication documentation](https://developer.bron.org/api-reference/authentication)
|
|
87
|
+
describes signed API-key JWTs; it does not establish a universal per-dApp OAuth
|
|
88
|
+
client or a delegated submission right on an application's participant. Do not
|
|
89
|
+
put those API private keys in browser configuration or infer a submission route
|
|
90
|
+
from a message-signing capability. The callback helper fixes the local OAuth
|
|
91
|
+
completion path; vendor credentials, endpoint compatibility and live acceptance
|
|
92
|
+
remain independently validated integration requirements.
|
|
93
|
+
|
|
67
94
|
---
|
|
68
95
|
|
|
69
96
|
## Links
|
package/dist/index.d.mts
CHANGED
|
@@ -27,7 +27,7 @@ interface BronAuthConfig {
|
|
|
27
27
|
redirectUri: string;
|
|
28
28
|
/** Scopes */
|
|
29
29
|
scopes?: string[];
|
|
30
|
-
/**
|
|
30
|
+
/** PKCE defaults to true and is required in browsers. */
|
|
31
31
|
usePKCE?: boolean;
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -77,10 +77,12 @@ declare class BronAdapter implements WalletAdapter {
|
|
|
77
77
|
readonly name = "Bron";
|
|
78
78
|
private authClient;
|
|
79
79
|
private apiClient;
|
|
80
|
+
private redirectUri;
|
|
81
|
+
private connecting;
|
|
80
82
|
constructor(config: BronAdapterConfig);
|
|
81
83
|
getCapabilities(): CapabilityKey[];
|
|
82
84
|
detectInstalled(): Promise<AdapterDetectResult>;
|
|
83
|
-
connect(ctx: AdapterContext,
|
|
85
|
+
connect(ctx: AdapterContext, opts?: {
|
|
84
86
|
timeoutMs?: number;
|
|
85
87
|
requiredCapabilities?: CapabilityKey[];
|
|
86
88
|
}): Promise<AdapterConnectResult>;
|
|
@@ -97,4 +99,11 @@ declare class BronAdapter implements WalletAdapter {
|
|
|
97
99
|
ledgerApi(ctx: AdapterContext, session: _partylayer_core.Session, params: LedgerApiParams): Promise<LedgerApiResult>;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Call from the application's registered redirect page. The popup relays only
|
|
104
|
+
* to its own origin; the opener verifies the source, path, state and PKCE.
|
|
105
|
+
* This helper does not register a Bron OAuth client or define vendor endpoints.
|
|
106
|
+
*/
|
|
107
|
+
declare function completeBronAuthorization(redirectUri: string): void;
|
|
108
|
+
|
|
109
|
+
export { BronAdapter, type BronAdapterApiConfig, type BronAdapterConfig, type BronApiConfig, type BronAuthConfig, completeBronAuthorization };
|
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ interface BronAuthConfig {
|
|
|
27
27
|
redirectUri: string;
|
|
28
28
|
/** Scopes */
|
|
29
29
|
scopes?: string[];
|
|
30
|
-
/**
|
|
30
|
+
/** PKCE defaults to true and is required in browsers. */
|
|
31
31
|
usePKCE?: boolean;
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -77,10 +77,12 @@ declare class BronAdapter implements WalletAdapter {
|
|
|
77
77
|
readonly name = "Bron";
|
|
78
78
|
private authClient;
|
|
79
79
|
private apiClient;
|
|
80
|
+
private redirectUri;
|
|
81
|
+
private connecting;
|
|
80
82
|
constructor(config: BronAdapterConfig);
|
|
81
83
|
getCapabilities(): CapabilityKey[];
|
|
82
84
|
detectInstalled(): Promise<AdapterDetectResult>;
|
|
83
|
-
connect(ctx: AdapterContext,
|
|
85
|
+
connect(ctx: AdapterContext, opts?: {
|
|
84
86
|
timeoutMs?: number;
|
|
85
87
|
requiredCapabilities?: CapabilityKey[];
|
|
86
88
|
}): Promise<AdapterConnectResult>;
|
|
@@ -97,4 +99,11 @@ declare class BronAdapter implements WalletAdapter {
|
|
|
97
99
|
ledgerApi(ctx: AdapterContext, session: _partylayer_core.Session, params: LedgerApiParams): Promise<LedgerApiResult>;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Call from the application's registered redirect page. The popup relays only
|
|
104
|
+
* to its own origin; the opener verifies the source, path, state and PKCE.
|
|
105
|
+
* This helper does not register a Bron OAuth client or define vendor endpoints.
|
|
106
|
+
*/
|
|
107
|
+
declare function completeBronAuthorization(redirectUri: string): void;
|
|
108
|
+
|
|
109
|
+
export { BronAdapter, type BronAdapterApiConfig, type BronAdapterConfig, type BronApiConfig, type BronAuthConfig, completeBronAuthorization };
|
package/dist/index.js
CHANGED
|
@@ -10,15 +10,32 @@ var BronAuthClient = class {
|
|
|
10
10
|
storage;
|
|
11
11
|
tokens = null;
|
|
12
12
|
// In-memory by default
|
|
13
|
+
pending = null;
|
|
14
|
+
exchange = null;
|
|
15
|
+
authorization = new AbortController();
|
|
16
|
+
epoch = 0;
|
|
17
|
+
storageWrites = Promise.resolve();
|
|
18
|
+
persist(action) {
|
|
19
|
+
const write = this.storageWrites.catch(() => {
|
|
20
|
+
}).then(action);
|
|
21
|
+
this.storageWrites = write;
|
|
22
|
+
return write;
|
|
23
|
+
}
|
|
13
24
|
constructor(config, storage) {
|
|
14
|
-
|
|
25
|
+
for (const input of [config.authorizationUrl, config.tokenUrl, config.redirectUri]) {
|
|
26
|
+
const url = new URL(input);
|
|
27
|
+
if (url.username || url.password || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) throw new Error("OAuth requires trusted HTTPS URLs");
|
|
28
|
+
}
|
|
29
|
+
if (!config.clientId?.trim()) throw new Error("OAuth clientId is required");
|
|
30
|
+
if (typeof window !== "undefined" && (config.clientSecret || config.usePKCE === false)) throw new Error("Browser OAuth requires PKCE and must not contain a client secret");
|
|
31
|
+
this.config = { ...config, usePKCE: config.usePKCE ?? true };
|
|
15
32
|
this.storage = storage;
|
|
16
33
|
}
|
|
17
34
|
/**
|
|
18
35
|
* Generate PKCE code verifier and challenge
|
|
19
36
|
*/
|
|
20
37
|
async generatePKCE() {
|
|
21
|
-
const verifier = this.generateRandomString(
|
|
38
|
+
const verifier = this.generateRandomString(32);
|
|
22
39
|
const encoder = new TextEncoder();
|
|
23
40
|
const data = encoder.encode(verifier);
|
|
24
41
|
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
@@ -37,6 +54,9 @@ var BronAuthClient = class {
|
|
|
37
54
|
* Start authorization flow
|
|
38
55
|
*/
|
|
39
56
|
async startAuth() {
|
|
57
|
+
this.cancelAuthorization();
|
|
58
|
+
this.authorization = new AbortController();
|
|
59
|
+
const epoch = this.epoch;
|
|
40
60
|
const state = this.generateRandomString(32);
|
|
41
61
|
const params = new URLSearchParams({
|
|
42
62
|
response_type: "code",
|
|
@@ -49,94 +69,108 @@ var BronAuthClient = class {
|
|
|
49
69
|
const pkce = await this.generatePKCE();
|
|
50
70
|
params.set("code_challenge", pkce.challenge);
|
|
51
71
|
params.set("code_challenge_method", "S256");
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
sessionStorage.setItem("bron_auth_state", state);
|
|
55
|
-
}
|
|
72
|
+
if (epoch !== this.epoch) throw new Error("OAuth authorization cancelled");
|
|
73
|
+
this.pending = { state, verifier: pkce.verifier, expiresAt: Date.now() + 3e5 };
|
|
56
74
|
} else {
|
|
57
|
-
|
|
58
|
-
sessionStorage.setItem("bron_auth_state", state);
|
|
59
|
-
}
|
|
75
|
+
this.pending = { state, expiresAt: Date.now() + 3e5 };
|
|
60
76
|
}
|
|
61
|
-
const
|
|
62
|
-
|
|
77
|
+
const url = new URL(this.config.authorizationUrl);
|
|
78
|
+
for (const [key, value] of params) url.searchParams.set(key, value);
|
|
79
|
+
return url.href;
|
|
63
80
|
}
|
|
64
81
|
/**
|
|
65
82
|
* Finish authorization flow with callback URL
|
|
66
83
|
*/
|
|
67
84
|
async finishAuth(callbackUrl) {
|
|
68
85
|
const url = new URL(callbackUrl);
|
|
86
|
+
const redirect = new URL(this.config.redirectUri);
|
|
87
|
+
const pending = this.pending;
|
|
88
|
+
if (url.origin !== redirect.origin || url.pathname !== redirect.pathname || url.hash || url.username || url.password || [...redirect.searchParams].some(([key, value]) => url.searchParams.getAll(key).length !== 1 || url.searchParams.get(key) !== value) || !pending || pending.expiresAt <= Date.now() || url.searchParams.getAll("state").length !== 1 || url.searchParams.get("state") !== pending.state) throw new Error("Invalid or expired OAuth callback state");
|
|
89
|
+
this.pending = null;
|
|
90
|
+
if (url.searchParams.has("error")) throw new Error("OAuth authorization was declined or failed");
|
|
69
91
|
const code = url.searchParams.get("code");
|
|
70
|
-
|
|
71
|
-
const error = url.searchParams.get("error");
|
|
72
|
-
if (error) {
|
|
73
|
-
throw new Error(`OAuth error: ${error}`);
|
|
74
|
-
}
|
|
75
|
-
if (!code) {
|
|
76
|
-
throw new Error("No authorization code in callback");
|
|
77
|
-
}
|
|
78
|
-
if (typeof window !== "undefined") {
|
|
79
|
-
const storedState = sessionStorage.getItem("bron_auth_state");
|
|
80
|
-
if (state !== storedState) {
|
|
81
|
-
throw new Error("State mismatch");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
92
|
+
if (!code || url.searchParams.getAll("code").length !== 1) throw new Error("No unique authorization code in callback");
|
|
84
93
|
const tokenParams = new URLSearchParams({
|
|
85
94
|
grant_type: "authorization_code",
|
|
86
95
|
code,
|
|
87
96
|
redirect_uri: this.config.redirectUri,
|
|
88
97
|
client_id: this.config.clientId
|
|
89
98
|
});
|
|
90
|
-
if (this.config.usePKCE
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
tokenParams.set("code_verifier", verifier);
|
|
94
|
-
sessionStorage.removeItem("bron_pkce_verifier");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (this.config.clientSecret) {
|
|
98
|
-
tokenParams.set("client_secret", this.config.clientSecret);
|
|
99
|
-
}
|
|
100
|
-
const response = await fetch(this.config.tokenUrl, {
|
|
101
|
-
method: "POST",
|
|
102
|
-
headers: {
|
|
103
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
104
|
-
},
|
|
105
|
-
body: tokenParams.toString()
|
|
106
|
-
});
|
|
107
|
-
if (!response.ok) {
|
|
108
|
-
const error2 = await response.text();
|
|
109
|
-
throw new Error(`Token exchange failed: ${error2}`);
|
|
110
|
-
}
|
|
111
|
-
const tokenData = await response.json();
|
|
112
|
-
const tokens = {
|
|
113
|
-
accessToken: tokenData.access_token,
|
|
114
|
-
refreshToken: tokenData.refresh_token,
|
|
115
|
-
expiresAt: Date.now() + tokenData.expires_in * 1e3,
|
|
116
|
-
tokenType: tokenData.token_type || "Bearer"
|
|
117
|
-
};
|
|
118
|
-
this.tokens = tokens;
|
|
119
|
-
if (this.storage) {
|
|
120
|
-
await this.storage.set("bron_tokens", JSON.stringify(tokens));
|
|
99
|
+
if (this.config.usePKCE) {
|
|
100
|
+
if (!pending.verifier) throw new Error("Missing PKCE verifier");
|
|
101
|
+
tokenParams.set("code_verifier", pending.verifier);
|
|
121
102
|
}
|
|
122
|
-
if (
|
|
123
|
-
|
|
103
|
+
if (this.config.clientSecret) tokenParams.set("client_secret", this.config.clientSecret);
|
|
104
|
+
const epoch = this.epoch;
|
|
105
|
+
const controller = new AbortController();
|
|
106
|
+
this.exchange = controller;
|
|
107
|
+
const timer = setTimeout(() => controller.abort(), 15e3);
|
|
108
|
+
try {
|
|
109
|
+
const response = await fetch(this.config.tokenUrl, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" },
|
|
112
|
+
body: tokenParams.toString(),
|
|
113
|
+
credentials: "omit",
|
|
114
|
+
cache: "no-store",
|
|
115
|
+
redirect: "error",
|
|
116
|
+
referrerPolicy: "no-referrer",
|
|
117
|
+
signal: controller.signal
|
|
118
|
+
});
|
|
119
|
+
if (!response.ok) throw new Error("OAuth token exchange failed");
|
|
120
|
+
const raw = await response.text();
|
|
121
|
+
if (raw.length > 256e3) throw new Error("OAuth token response is too large");
|
|
122
|
+
const data = JSON.parse(raw);
|
|
123
|
+
if (!data || typeof data.access_token !== "string" || !data.access_token || data.access_token.length > 64e3 || /[\s\p{Cc}]/u.test(data.access_token) || typeof data.token_type !== "string" || data.token_type.toLowerCase() !== "bearer" || typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in) || data.expires_in <= 0 || data.expires_in > 31536e3 || data.refresh_token !== void 0 && (typeof data.refresh_token !== "string" || !data.refresh_token || /\p{Cc}/u.test(data.refresh_token))) {
|
|
124
|
+
throw new Error("Invalid OAuth token response");
|
|
125
|
+
}
|
|
126
|
+
if (controller.signal.aborted || epoch !== this.epoch) throw new Error("OAuth authorization cancelled");
|
|
127
|
+
const tokens = {
|
|
128
|
+
accessToken: data.access_token,
|
|
129
|
+
expiresAt: Date.now() + data.expires_in * 1e3,
|
|
130
|
+
tokenType: "Bearer",
|
|
131
|
+
...data.refresh_token ? { refreshToken: data.refresh_token } : {}
|
|
132
|
+
};
|
|
133
|
+
this.tokens = tokens;
|
|
134
|
+
if (this.storage) await this.persist(async () => {
|
|
135
|
+
if (epoch === this.epoch) await this.storage.set("bron_tokens", JSON.stringify(tokens));
|
|
136
|
+
});
|
|
137
|
+
if (epoch !== this.epoch) throw new Error("OAuth authorization cancelled");
|
|
138
|
+
return tokens;
|
|
139
|
+
} finally {
|
|
140
|
+
clearTimeout(timer);
|
|
141
|
+
if (this.exchange === controller) this.exchange = null;
|
|
124
142
|
}
|
|
125
|
-
|
|
143
|
+
}
|
|
144
|
+
/** Clear authorization state and abort only the in-flight token exchange. */
|
|
145
|
+
cancelAuthorization() {
|
|
146
|
+
this.authorization.abort();
|
|
147
|
+
this.epoch++;
|
|
148
|
+
this.pending = null;
|
|
149
|
+
this.exchange?.abort();
|
|
150
|
+
this.exchange = null;
|
|
151
|
+
}
|
|
152
|
+
getAuthorizationSignal() {
|
|
153
|
+
return this.authorization.signal;
|
|
126
154
|
}
|
|
127
155
|
/**
|
|
128
156
|
* Get current access token
|
|
129
157
|
*/
|
|
130
158
|
async getAccessToken() {
|
|
159
|
+
const epoch = this.epoch;
|
|
131
160
|
if (this.tokens && Date.now() < this.tokens.expiresAt) {
|
|
132
161
|
return this.tokens.accessToken;
|
|
133
162
|
}
|
|
134
163
|
if (this.storage) {
|
|
135
164
|
const stored = await this.storage.get("bron_tokens");
|
|
165
|
+
if (epoch !== this.epoch) return null;
|
|
136
166
|
if (stored) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
167
|
+
try {
|
|
168
|
+
const tokens = JSON.parse(stored);
|
|
169
|
+
if (typeof tokens.accessToken === "string" && tokens.accessToken && !/[\s\p{Cc}]/u.test(tokens.accessToken) && tokens.tokenType === "Bearer" && Number.isFinite(tokens.expiresAt) && Date.now() < tokens.expiresAt) {
|
|
170
|
+
this.tokens = tokens;
|
|
171
|
+
return tokens.accessToken;
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
140
174
|
}
|
|
141
175
|
}
|
|
142
176
|
}
|
|
@@ -146,9 +180,10 @@ var BronAuthClient = class {
|
|
|
146
180
|
* Logout
|
|
147
181
|
*/
|
|
148
182
|
async logout() {
|
|
183
|
+
this.cancelAuthorization();
|
|
149
184
|
this.tokens = null;
|
|
150
185
|
if (this.storage) {
|
|
151
|
-
await this.storage.remove("bron_tokens");
|
|
186
|
+
await this.persist(() => this.storage.remove("bron_tokens"));
|
|
152
187
|
}
|
|
153
188
|
}
|
|
154
189
|
};
|
|
@@ -270,6 +305,61 @@ var BronApiClient = class {
|
|
|
270
305
|
throw new Error("Polling timeout");
|
|
271
306
|
}
|
|
272
307
|
};
|
|
308
|
+
var CALLBACK = "partylayer:bron:authorization-callback";
|
|
309
|
+
function completeBronAuthorization(redirectUri) {
|
|
310
|
+
if (typeof window === "undefined" || !window.opener) throw new Error("Open this OAuth callback from the connecting application");
|
|
311
|
+
const expected = new URL(redirectUri);
|
|
312
|
+
if (window.location.origin !== expected.origin || window.location.pathname !== expected.pathname) throw new Error("Unexpected OAuth redirect page");
|
|
313
|
+
const callbackUrl = window.location.href;
|
|
314
|
+
window.opener.postMessage({ type: CALLBACK, callbackUrl }, expected.origin);
|
|
315
|
+
window.history.replaceState(null, "", expected.pathname);
|
|
316
|
+
window.close();
|
|
317
|
+
}
|
|
318
|
+
async function authorizeBronPopup(auth, redirectUri, timeoutMs) {
|
|
319
|
+
if (typeof window === "undefined") throw new Error("OAuth flow requires a browser environment");
|
|
320
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 3e5) throw new Error("Invalid OAuth timeout");
|
|
321
|
+
const expected = new URL(redirectUri);
|
|
322
|
+
if (expected.origin !== window.location.origin) throw new Error("Register a same-origin OAuth callback page");
|
|
323
|
+
const url = await auth.startAuth();
|
|
324
|
+
const popup = window.open(url, "partylayer-bron-authorization", "width=500,height=650");
|
|
325
|
+
if (!popup) {
|
|
326
|
+
auth.cancelAuthorization();
|
|
327
|
+
throw new Error("Allow the wallet authorization popup and try again");
|
|
328
|
+
}
|
|
329
|
+
return new Promise((resolve, reject) => {
|
|
330
|
+
const signal = auth.getAuthorizationSignal();
|
|
331
|
+
let callbackReceived = false;
|
|
332
|
+
let finished = false;
|
|
333
|
+
const finish = (error) => {
|
|
334
|
+
if (finished) return;
|
|
335
|
+
finished = true;
|
|
336
|
+
clearTimeout(timer);
|
|
337
|
+
clearInterval(closed);
|
|
338
|
+
window.removeEventListener("message", receive);
|
|
339
|
+
signal.removeEventListener("abort", cancel);
|
|
340
|
+
if (error) auth.cancelAuthorization();
|
|
341
|
+
try {
|
|
342
|
+
popup.close();
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
if (error) reject(error);
|
|
346
|
+
else resolve();
|
|
347
|
+
};
|
|
348
|
+
const receive = (event) => {
|
|
349
|
+
if (finished || callbackReceived || event.source !== popup || event.origin !== expected.origin || !event.data || event.data.type !== CALLBACK || typeof event.data.callbackUrl !== "string") return;
|
|
350
|
+
callbackReceived = true;
|
|
351
|
+
void auth.finishAuth(event.data.callbackUrl).then(() => finish(), (error) => finish(error));
|
|
352
|
+
};
|
|
353
|
+
const cancel = () => finish(new Error("Wallet authorization cancelled"));
|
|
354
|
+
const timer = setTimeout(() => finish(new Error("Wallet authorization timed out")), timeoutMs);
|
|
355
|
+
const closed = setInterval(() => {
|
|
356
|
+
if (!callbackReceived && popup.closed) finish(new core.UserRejectedError("Wallet authorization was closed"));
|
|
357
|
+
}, 250);
|
|
358
|
+
window.addEventListener("message", receive);
|
|
359
|
+
signal.addEventListener("abort", cancel, { once: true });
|
|
360
|
+
if (signal.aborted) cancel();
|
|
361
|
+
});
|
|
362
|
+
}
|
|
273
363
|
|
|
274
364
|
// src/bron-adapter.ts
|
|
275
365
|
var BronAdapter = class {
|
|
@@ -277,8 +367,11 @@ var BronAdapter = class {
|
|
|
277
367
|
name = "Bron";
|
|
278
368
|
authClient;
|
|
279
369
|
apiClient;
|
|
370
|
+
redirectUri;
|
|
371
|
+
connecting = false;
|
|
280
372
|
constructor(config) {
|
|
281
373
|
this.authClient = new BronAuthClient(config.auth);
|
|
374
|
+
this.redirectUri = config.auth.redirectUri;
|
|
282
375
|
this.apiClient = new BronApiClient({
|
|
283
376
|
baseUrl: config.api.baseUrl,
|
|
284
377
|
getAccessToken: async () => {
|
|
@@ -308,23 +401,13 @@ var BronAdapter = class {
|
|
|
308
401
|
reason: "Bron is a remote signer service"
|
|
309
402
|
});
|
|
310
403
|
}
|
|
311
|
-
async connect(ctx,
|
|
404
|
+
async connect(ctx, opts) {
|
|
405
|
+
if (this.connecting) throw new Error("A Bron connection is already pending");
|
|
406
|
+
this.connecting = true;
|
|
312
407
|
try {
|
|
313
408
|
const accessToken = await this.authClient.getAccessToken();
|
|
314
409
|
if (!accessToken) {
|
|
315
|
-
|
|
316
|
-
throw new Error("OAuth flow requires browser environment");
|
|
317
|
-
}
|
|
318
|
-
const authUrl = await this.authClient.startAuth();
|
|
319
|
-
const popup = window.open(
|
|
320
|
-
authUrl,
|
|
321
|
-
"Bron Auth",
|
|
322
|
-
"width=500,height=600"
|
|
323
|
-
);
|
|
324
|
-
if (!popup) {
|
|
325
|
-
throw new Error("Failed to open auth popup");
|
|
326
|
-
}
|
|
327
|
-
throw new Error("OAuth callback not implemented in adapter - handle in app");
|
|
410
|
+
await authorizeBronPopup(this.authClient, this.redirectUri, opts?.timeoutMs ?? 12e4);
|
|
328
411
|
}
|
|
329
412
|
const session = await this.apiClient.createSession();
|
|
330
413
|
return {
|
|
@@ -350,6 +433,8 @@ var BronAdapter = class {
|
|
|
350
433
|
phase: "connect",
|
|
351
434
|
transport: "remote"
|
|
352
435
|
});
|
|
436
|
+
} finally {
|
|
437
|
+
this.connecting = false;
|
|
353
438
|
}
|
|
354
439
|
}
|
|
355
440
|
async disconnect(_ctx, _session) {
|
|
@@ -497,5 +582,6 @@ var BronAdapter = class {
|
|
|
497
582
|
};
|
|
498
583
|
|
|
499
584
|
exports.BronAdapter = BronAdapter;
|
|
585
|
+
exports.completeBronAuthorization = completeBronAuthorization;
|
|
500
586
|
//# sourceMappingURL=index.js.map
|
|
501
587
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.ts","../src/api.ts","../src/bron-adapter.ts"],"names":["error","toPartyId","toWalletId","mapUnknownErrorToPartyLayerError","UserRejectedError","toSignature","signedTx","toTransactionHash","normalizeLedgerMethodUpper","ledgerApiBodyToString"],"mappings":";;;;;;;AA6CO,IAAM,iBAAN,MAAqB;AAAA,EAClB,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA,GAA4B,IAAA;AAAA;AAAA,EAEpC,WAAA,CAAY,QAAwB,OAAA,EAA0B;AAC5D,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YAAA,GAAiE;AAC7E,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,oBAAA,CAAqB,GAAG,CAAA;AAC9C,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAChC,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,MAAA,CAAO,QAAQ,CAAA;AACpC,IAAA,MAAM,SAAS,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,WAAW,IAAI,CAAA;AACzD,IAAA,MAAM,SAAA,GAAY,KAAK,MAAA,CAAO,YAAA,CAAa,GAAG,IAAI,UAAA,CAAW,MAAM,CAAC,CAAC,EAClE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAClB,OAAA,CAAQ,OAAO,GAAG,CAAA,CAClB,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA;AAEnB,IAAA,OAAO,EAAE,UAAU,SAAA,EAAU;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,MAAA,EAAwB;AACnD,IAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAM,CAAA;AACnC,IAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAA,EAAO,CAAC,SAAS,IAAA,CAAK,QAAA,CAAS,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAA,GAA6B;AACjC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,oBAAA,CAAqB,EAAE,CAAA;AAC1C,IAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB;AAAA,MACjC,aAAA,EAAe,MAAA;AAAA,MACf,SAAA,EAAW,KAAK,MAAA,CAAO,QAAA;AAAA,MACvB,YAAA,EAAc,KAAK,MAAA,CAAO,WAAA;AAAA,MAC1B,KAAA;AAAA,MACA,KAAA,EAAA,CAAQ,KAAK,MAAA,CAAO,MAAA,IAAU,CAAC,QAAA,EAAU,SAAS,CAAA,EAAG,IAAA,CAAK,GAAG;AAAA,KAC9D,CAAA;AAGD,IAAA,IAAI,IAAA,CAAK,OAAO,OAAA,EAAS;AACvB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,YAAA,EAAa;AACrC,MAAA,MAAA,CAAO,GAAA,CAAI,gBAAA,EAAkB,IAAA,CAAK,SAAS,CAAA;AAC3C,MAAA,MAAA,CAAO,GAAA,CAAI,yBAAyB,MAAM,CAAA;AAG1C,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,cAAA,CAAe,OAAA,CAAQ,oBAAA,EAAsB,IAAA,CAAK,QAAQ,CAAA;AAC1D,QAAA,cAAA,CAAe,OAAA,CAAQ,mBAAmB,KAAK,CAAA;AAAA,MACjD;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,cAAA,CAAe,OAAA,CAAQ,mBAAmB,KAAK,CAAA;AAAA,MACjD;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAU,GAAG,IAAA,CAAK,MAAA,CAAO,gBAAgB,CAAA,CAAA,EAAI,MAAA,CAAO,UAAU,CAAA,CAAA;AACpE,IAAA,OAAO,OAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,WAAA,EAA0C;AACzD,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,WAAW,CAAA;AAC/B,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACxC,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AAC1C,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AAE1C,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,aAAA,EAAgB,KAAK,CAAA,CAAE,CAAA;AAAA,IACzC;AAEA,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,MAAM,IAAI,MAAM,mCAAmC,CAAA;AAAA,IACrD;AAGA,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,MAAM,WAAA,GAAc,cAAA,CAAe,OAAA,CAAQ,iBAAiB,CAAA;AAC5D,MAAA,IAAI,UAAU,WAAA,EAAa;AACzB,QAAA,MAAM,IAAI,MAAM,gBAAgB,CAAA;AAAA,MAClC;AAAA,IACF;AAGA,IAAA,MAAM,WAAA,GAAc,IAAI,eAAA,CAAgB;AAAA,MACtC,UAAA,EAAY,oBAAA;AAAA,MACZ,IAAA;AAAA,MACA,YAAA,EAAc,KAAK,MAAA,CAAO,WAAA;AAAA,MAC1B,SAAA,EAAW,KAAK,MAAA,CAAO;AAAA,KACxB,CAAA;AAGD,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,OAAO,WAAW,WAAA,EAAa;AACxD,MAAA,MAAM,QAAA,GAAW,cAAA,CAAe,OAAA,CAAQ,oBAAoB,CAAA;AAC5D,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,WAAA,CAAY,GAAA,CAAI,iBAAiB,QAAQ,CAAA;AACzC,QAAA,cAAA,CAAe,WAAW,oBAAoB,CAAA;AAAA,MAChD;AAAA,IACF;AAGA,IAAA,IAAI,IAAA,CAAK,OAAO,YAAA,EAAc;AAC5B,MAAA,WAAA,CAAY,GAAA,CAAI,eAAA,EAAiB,IAAA,CAAK,MAAA,CAAO,YAAY,CAAA;AAAA,IAC3D;AAGA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,IAAA,CAAK,OAAO,QAAA,EAAU;AAAA,MACjD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,IAAA,EAAM,YAAY,QAAA;AAAS,KAC5B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAMA,MAAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0BA,MAAK,CAAA,CAAE,CAAA;AAAA,IACnD;AAEA,IAAA,MAAM,SAAA,GAAa,MAAM,QAAA,CAAS,IAAA,EAAK;AAOvC,IAAA,MAAM,MAAA,GAAqB;AAAA,MACzB,aAAa,SAAA,CAAU,YAAA;AAAA,MACvB,cAAc,SAAA,CAAU,aAAA;AAAA,MACxB,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,UAAU,UAAA,GAAa,GAAA;AAAA,MAC/C,SAAA,EAAW,UAAU,UAAA,IAAc;AAAA,KACrC;AAGA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAI,KAAK,OAAA,EAAS;AAEhB,MAAA,MAAM,KAAK,OAAA,CAAQ,GAAA,CAAI,eAAe,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA;AAAA,IAC9D;AAGA,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,cAAA,CAAe,WAAW,iBAAiB,CAAA;AAAA,IAC7C;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAA,GAAyC;AAE7C,IAAA,IAAI,KAAK,MAAA,IAAU,IAAA,CAAK,KAAI,GAAI,IAAA,CAAK,OAAO,SAAA,EAAW;AACrD,MAAA,OAAO,KAAK,MAAA,CAAO,WAAA;AAAA,IACrB;AAGA,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAI,aAAa,CAAA;AACnD,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAC/B,QAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,IAAA,CAAK,OAAO,SAAA,EAAW;AACtC,UAAA,OAAO,KAAK,MAAA,CAAO,WAAA;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,GAAwB;AAC5B,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,aAAa,CAAA;AAAA,IACzC;AAAA,EACF;AACF,CAAA;AC1KO,IAAM,gBAAN,MAAoB;AAAA,EACjB,MAAA;AAAA,EAER,YAAY,MAAA,EAAuB;AACjC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,UAAA,GAAmC;AAC/C,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,MAAA,CAAO,cAAA,EAAe;AAC/C,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAAA,IAC7C;AAEA,IAAA,OAAO;AAAA,MACL,eAAA,EAAiB,UAAU,KAAK,CAAA,CAAA;AAAA,MAChC,cAAA,EAAgB;AAAA,KAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAA,GAAsC;AAC1C,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,SAAA,CAAA,EAAa;AAAA,MAC9D,MAAA,EAAQ,MAAA;AAAA,MACR;AAAA,KACD,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,KAAK,CAAA,CAAE,CAAA;AAAA,IACtD;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAMlC,IAAA,OAAO;AAAA,MACL,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,OAAA,EAASC,cAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AAAA,MAC/B,WAAW,IAAA,CAAK;AAAA,KAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,OAAA,EAAqD;AAC1E,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,WAAA,CAAA,EAAe;AAAA,MAChE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC7B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,KAAK,CAAA,CAAE,CAAA;AAAA,IACzD;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAOlC,IAAA,OAAO;AAAA,MACL,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,iBAAiB,IAAA,CAAK;AAAA,KACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,SAAA,EAA+C;AACpE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,MAAA,CAAO,OAAO,CAAA,YAAA,EAAe,SAAS,CAAA,CAAA,EAAI;AAAA,MAC7E,MAAA,EAAQ,KAAA;AAAA,MACR;AAAA,KACD,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8BAAA,EAAiC,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1D;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAWlC,IAAA,OAAO;AAAA,MACL,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,iBAAiB,IAAA,CAAK,eAAA;AAAA,MACtB,OAAO,IAAA,CAAK;AAAA,KACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,eAAe,OAAA,EAKa;AAChC,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,aAAA,CAAA,EAAiB;AAAA,MAClE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC7B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,KAAK,CAAA,CAAE,CAAA;AAAA,IACrD;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,IAAA,OAAO,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAS;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAA,CACJ,SAAA,EACA,SAAA,GAAoB,GAAA,EACpB,aAAqB,GAAA,EACO;AAC5B,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,SAAA,EAAW;AACzC,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,gBAAA,CAAiB,SAAS,CAAA;AAEpD,MAAA,IAAI,MAAA,CAAO,WAAW,UAAA,IAAc,MAAA,CAAO,WAAW,QAAA,IAAY,MAAA,CAAO,WAAW,SAAA,EAAW;AAC7F,QAAA,OAAO,MAAA;AAAA,MACT;AAGA,MAAA,MAAM,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,UAAU,CAAC,CAAA;AAAA,IAChE;AAEA,IAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AAAA,EACnC;AACF,CAAA;;;AC9KO,IAAM,cAAN,MAA2C;AAAA,EACvC,QAAA,GAAWC,gBAAW,MAAM,CAAA;AAAA,EAC5B,IAAA,GAAO,MAAA;AAAA,EAER,UAAA;AAAA,EACA,SAAA;AAAA,EAER,YAAY,MAAA,EAA2B;AAIrC,IAAA,IAAA,CAAK,UAAA,GAAa,IAAI,cAAA,CAAe,MAAA,CAAO,IAAI,CAAA;AAKhD,IAAA,IAAA,CAAK,SAAA,GAAY,IAAI,aAAA,CAAc;AAAA,MACjC,OAAA,EAAS,OAAO,GAAA,CAAI,OAAA;AAAA,MACpB,gBAAgB,YAAY;AAC1B,QAAA,OAAO,MAAM,IAAA,CAAK,UAAA,CAAW,cAAA,EAAe;AAAA,MAC9C;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,eAAA,GAAmC;AACjC,IAAA,OAAO;AAAA,MACL,SAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,cAAA;AAAA,MACA,aAAA;AAAA,MACA,iBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA,EAEA,eAAA,GAAgD;AAO9C,IAAA,OAAO,QAAQ,OAAA,CAAQ;AAAA,MACrB,SAAA,EAAW,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKX,YAAA,EAAc,EAAE,IAAA,EAAM,kBAAA,EAAmB;AAAA,MACzC,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,OAAA,CACJ,GAAA,EACA,KAAA,EAI+B;AAC/B,IAAA,IAAI;AAEF,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,UAAA,CAAW,cAAA,EAAe;AAGzD,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,UAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,QAC3D;AAEA,QAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,CAAW,SAAA,EAAU;AAGhD,QAAA,MAAM,QAAQ,MAAA,CAAO,IAAA;AAAA,UACnB,OAAA;AAAA,UACA,WAAA;AAAA,UACA;AAAA,SACF;AAEA,QAAA,IAAI,CAAC,KAAA,EAAO;AACV,UAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAAA,QAC7C;AAKA,QAAA,MAAM,IAAI,MAAM,2DAA2D,CAAA;AAAA,MAC7E;AAGA,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,aAAA,EAAc;AAEnD,MAAA,OAAO;AAAA,QACL,SAAS,OAAA,CAAQ,OAAA;AAAA,QACjB,OAAA,EAAS;AAAA,UACP,UAAU,IAAA,CAAK,QAAA;AAAA;AAAA;AAAA;AAAA,UAIf,SAAS,GAAA,CAAI,OAAA;AAAA,UACb,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,UACpB,WAAW,OAAA,CAAQ,SAAA;AAAA,UACnB,oBAAA,EAAsB,CAAC,SAAA,EAAW,aAAA,EAAe,mBAAmB,cAAc,CAAA;AAAA,UAClF,QAAA,EAAU;AAAA,YACR,WAAW,OAAA,CAAQ;AAAA;AACrB,SACF;AAAA,QACA,YAAA,EAAc,CAAC,SAAA,EAAW,aAAA,EAAe,mBAAmB,cAAc;AAAA,OAC5E;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMC,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,SAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,UAAA,CACJ,IAAA,EACA,QAAA,EACe;AACf,IAAA,MAAM,IAAA,CAAK,WAAW,MAAA,EAAO;AAAA,EAC/B;AAAA,EAEA,MAAM,OAAA,CACJ,IAAA,EACA,SAAA,EACoD;AAEpD,IAAA,MAAM,SAAA,GAAY,UAAU,QAAA,EAAU,SAAA;AACtC,IAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,UAAA,CAAW,cAAA,EAAe;AACzD,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,IAAI,UAAU,SAAA,IAAa,IAAA,CAAK,GAAA,EAAI,IAAK,UAAU,SAAA,EAAW;AAC5D,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,OAAO;AAAA,MACL,GAAG,SAAA;AAAA,MACH,UAAU,IAAA,CAAK;AAAA,KACjB;AAAA,EACF;AAAA,EAEA,MAAM,WAAA,CACJ,IAAA,EACA,OAAA,EACA,MAAA,EACmD;AACnD,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,EAAU,SAAA;AACpC,MAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,QAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,MACjC;AAGA,MAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,SAAA,CAAU,gBAAA,CAAiB;AAAA,QACzD,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB;AAAA,OACD,CAAA;AAGD,MAAA,IAAI,YAAA,CAAa,WAAW,SAAA,EAAW;AACrC,QAAA,MAAM,SAAS,MAAM,IAAA,CAAK,SAAA,CAAU,iBAAA,CAAkB,aAAa,SAAS,CAAA;AAE5E,QAAA,IAAI,MAAA,CAAO,WAAW,QAAA,EAAU;AAC9B,UAAA,MAAM,IAAIC,uBAAkB,0BAA0B,CAAA;AAAA,QACxD;AAEA,QAAA,IAAI,MAAA,CAAO,MAAA,KAAW,UAAA,IAAc,MAAA,CAAO,SAAA,EAAW;AACpD,UAAA,OAAO;AAAA,YACL,SAAS,MAAA,CAAO,OAAA;AAAA,YAChB,SAAA,EAAWC,gBAAA,CAAY,MAAA,CAAO,SAAS,CAAA;AAAA,YACvC,SAAS,OAAA,CAAQ;AAAA,WACnB;AAAA,QACF;AAEA,QAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,MAC5C;AAEA,MAAA,IAAI,YAAA,CAAa,WAAW,QAAA,EAAU;AACpC,QAAA,MAAM,IAAID,uBAAkB,0BAA0B,CAAA;AAAA,MACxD;AAEA,MAAA,IAAI,CAAC,aAAa,SAAA,EAAW;AAC3B,QAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,MAC5C;AAEA,MAAA,OAAO;AAAA,QACL,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,SAAA,EAAWC,gBAAA,CAAY,YAAA,CAAa,SAAS,CAAA;AAAA,QAC7C,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMF,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,aAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,eAAA,CACJ,IAAA,EACA,OAAA,EACA,MAAA,EACuD;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,EAAU,SAAA;AACpC,MAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,QAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,MACjC;AAGA,MAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,SAAA,CAAU,gBAAA,CAAiB;AAAA,QACzD,aAAa,MAAA,CAAO,EAAA;AAAA,QACpB;AAAA,OACD,CAAA;AAGD,MAAA,IAAI,YAAA,CAAa,WAAW,SAAA,EAAW;AACrC,QAAA,MAAM,SAAS,MAAM,IAAA,CAAK,SAAA,CAAU,iBAAA,CAAkB,aAAa,SAAS,CAAA;AAE5E,QAAA,IAAI,MAAA,CAAO,WAAW,QAAA,EAAU;AAC9B,UAAA,MAAM,IAAIC,uBAAkB,4BAA4B,CAAA;AAAA,QAC1D;AAEA,QAAA,IAAI,MAAA,CAAO,MAAA,KAAW,UAAA,IAAc,MAAA,CAAO,SAAA,EAAW;AACpD,UAAA,MAAME,SAAAA,GAAW,OAAO,MAAA,CAAO,EAAA,KAAO,YAAY,MAAA,CAAO,EAAA,KAAO,IAAA,GAC5D,EAAE,GAAG,MAAA,CAAO,IAA+B,SAAA,EAAW,MAAA,CAAO,WAAU,GACvE,EAAE,IAAI,MAAA,CAAO,EAAA,EAAI,SAAA,EAAW,MAAA,CAAO,SAAA,EAAU;AACjD,UAAA,OAAO;AAAA,YACL,QAAA,EAAAA,SAAAA;AAAA;AAAA;AAAA,YAGA,GAAI,MAAA,CAAO,eAAA,GACP,EAAE,eAAA,EAAiBC,uBAAkB,MAAA,CAAO,eAAe,CAAA,EAAE,GAC7D,EAAC;AAAA,YACL,SAAS,OAAA,CAAQ;AAAA,WACnB;AAAA,QACF;AAEA,QAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,MAC9C;AAEA,MAAA,IAAI,YAAA,CAAa,WAAW,QAAA,EAAU;AACpC,QAAA,MAAM,IAAIH,uBAAkB,4BAA4B,CAAA;AAAA,MAC1D;AAEA,MAAA,IAAI,CAAC,aAAa,SAAA,EAAW;AAC3B,QAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,MAC5C;AAEA,MAAA,MAAM,QAAA,GAAW,OAAO,MAAA,CAAO,EAAA,KAAO,YAAY,MAAA,CAAO,EAAA,KAAO,IAAA,GAC5D,EAAE,GAAG,MAAA,CAAO,IAA+B,SAAA,EAAW,YAAA,CAAa,WAAU,GAC7E,EAAE,IAAI,MAAA,CAAO,EAAA,EAAI,SAAA,EAAW,YAAA,CAAa,SAAA,EAAU;AACvD,MAAA,OAAO;AAAA,QACL,QAAA;AAAA,QACA,GAAI,YAAA,CAAa,eAAA,GACb,EAAE,eAAA,EAAiBG,uBAAkB,YAAA,CAAa,eAAe,CAAA,EAAE,GACnE,EAAC;AAAA,QACL,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMJ,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,iBAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAA,CACJ,GAAA,EACA,OAAA,EACA,MAAA,EAC0B;AAC1B,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,EAAU,SAAA;AACpC,MAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,QAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,MACjC;AAEA,MAAA,GAAA,CAAI,MAAA,CAAO,MAAM,sCAAA,EAAwC;AAAA,QACvD,SAAA;AAAA,QACA,eAAe,MAAA,CAAO,aAAA;AAAA,QACtB,UAAU,MAAA,CAAO;AAAA,OAClB,CAAA;AAED,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,cAAA,CAAe;AAAA,QACjD,aAAA,EAAeK,+BAAA,CAA2B,MAAA,CAAO,aAAa,CAAA;AAAA,QAC9D,UAAU,MAAA,CAAO,QAAA;AAAA,QACjB,IAAA,EAAMC,0BAAA,CAAsB,MAAA,CAAO,IAAI,CAAA;AAAA,QACvC;AAAA,OACD,CAAA;AAED,MAAA,OAAO,EAAE,QAAA,EAAU,MAAA,CAAO,QAAA,EAAS;AAAA,IACrC,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMN,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,WAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAAA,EACF;AACF","file":"index.js","sourcesContent":["/**\n * Bron OAuth2 Authentication Client\n * \n * Handles OAuth2 flows for Bron enterprise wallet.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n */\n\nimport type { StorageAdapter } from '@partylayer/core';\n\n/**\n * OAuth2 configuration\n */\nexport interface BronAuthConfig {\n /** Authorization server URL */\n authorizationUrl: string;\n /** Token endpoint URL */\n tokenUrl: string;\n /** Client ID */\n clientId: string;\n /** Client secret (for server-side flows) */\n clientSecret?: string;\n /** Redirect URI */\n redirectUri: string;\n /** Scopes */\n scopes?: string[];\n /** Use PKCE (recommended for browser) */\n usePKCE?: boolean;\n}\n\n/**\n * OAuth2 tokens\n */\nexport interface BronTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number;\n tokenType: string;\n}\n\n/**\n * Bron OAuth2 client\n */\nexport class BronAuthClient {\n private config: BronAuthConfig;\n private storage?: StorageAdapter;\n private tokens: BronTokens | null = null; // In-memory by default\n\n constructor(config: BronAuthConfig, storage?: StorageAdapter) {\n this.config = config;\n this.storage = storage;\n }\n\n /**\n * Generate PKCE code verifier and challenge\n */\n private async generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n const verifier = this.generateRandomString(128);\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const challenge = btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n\n return { verifier, challenge };\n }\n\n /**\n * Generate random string\n */\n private generateRandomString(length: number): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Start authorization flow\n */\n async startAuth(): Promise<string> {\n const state = this.generateRandomString(32);\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n state,\n scope: (this.config.scopes || ['openid', 'profile']).join(' '),\n });\n\n // Add PKCE if enabled\n if (this.config.usePKCE) {\n const pkce = await this.generatePKCE();\n params.set('code_challenge', pkce.challenge);\n params.set('code_challenge_method', 'S256');\n \n // Store verifier temporarily (in sessionStorage)\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('bron_pkce_verifier', pkce.verifier);\n sessionStorage.setItem('bron_auth_state', state);\n }\n } else {\n // Store state\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('bron_auth_state', state);\n }\n }\n\n const authUrl = `${this.config.authorizationUrl}?${params.toString()}`;\n return authUrl;\n }\n\n /**\n * Finish authorization flow with callback URL\n */\n async finishAuth(callbackUrl: string): Promise<BronTokens> {\n const url = new URL(callbackUrl);\n const code = url.searchParams.get('code');\n const state = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n\n if (error) {\n throw new Error(`OAuth error: ${error}`);\n }\n\n if (!code) {\n throw new Error('No authorization code in callback');\n }\n\n // Validate state\n if (typeof window !== 'undefined') {\n const storedState = sessionStorage.getItem('bron_auth_state');\n if (state !== storedState) {\n throw new Error('State mismatch');\n }\n }\n\n // Exchange code for tokens\n const tokenParams = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: this.config.redirectUri,\n client_id: this.config.clientId,\n });\n\n // Add PKCE verifier if used\n if (this.config.usePKCE && typeof window !== 'undefined') {\n const verifier = sessionStorage.getItem('bron_pkce_verifier');\n if (verifier) {\n tokenParams.set('code_verifier', verifier);\n sessionStorage.removeItem('bron_pkce_verifier');\n }\n }\n\n // Add client secret for server-side flow\n if (this.config.clientSecret) {\n tokenParams.set('client_secret', this.config.clientSecret);\n }\n\n // Request tokens\n const response = await fetch(this.config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: tokenParams.toString(),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token exchange failed: ${error}`);\n }\n\n const tokenData = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n };\n\n const tokens: BronTokens = {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token,\n expiresAt: Date.now() + tokenData.expires_in * 1000,\n tokenType: tokenData.token_type || 'Bearer',\n };\n\n // Store tokens (in memory by default, or encrypted storage if configured)\n this.tokens = tokens;\n if (this.storage) {\n // Store encrypted (implementation depends on storage adapter)\n await this.storage.set('bron_tokens', JSON.stringify(tokens));\n }\n\n // Clean up session storage\n if (typeof window !== 'undefined') {\n sessionStorage.removeItem('bron_auth_state');\n }\n\n return tokens;\n }\n\n /**\n * Get current access token\n */\n async getAccessToken(): Promise<string | null> {\n // Check if token exists and is not expired\n if (this.tokens && Date.now() < this.tokens.expiresAt) {\n return this.tokens.accessToken;\n }\n\n // Try to load from storage\n if (this.storage) {\n const stored = await this.storage.get('bron_tokens');\n if (stored) {\n this.tokens = JSON.parse(stored) as BronTokens;\n if (Date.now() < this.tokens.expiresAt) {\n return this.tokens.accessToken;\n }\n }\n }\n\n return null;\n }\n\n /**\n * Logout\n */\n async logout(): Promise<void> {\n this.tokens = null;\n if (this.storage) {\n await this.storage.remove('bron_tokens');\n }\n }\n}\n","/**\n * Bron API Client\n * \n * Typed client for Bron enterprise wallet API endpoints.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n */\n\nimport type { PartyId } from '@partylayer/core';\nimport { toPartyId } from '@partylayer/core';\n\n/**\n * Bron API configuration\n */\nexport interface BronApiConfig {\n /** Base API URL */\n baseUrl: string;\n /** Access token getter */\n getAccessToken: () => Promise<string | null>;\n}\n\n/**\n * Session/Party mapping\n */\nexport interface BronSession {\n sessionId: string;\n partyId: PartyId;\n expiresAt?: number;\n}\n\n/**\n * Signature request\n */\nexport interface BronSignRequest {\n message?: string;\n transaction?: unknown;\n sessionId: string;\n}\n\n/**\n * Signature response\n */\nexport interface BronSignResponse {\n requestId: string;\n status: 'pending' | 'approved' | 'denied';\n signature?: string;\n transactionHash?: string;\n}\n\n/**\n * Request status\n */\nexport interface BronRequestStatus {\n requestId: string;\n status: 'pending' | 'approved' | 'denied' | 'expired';\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Bron API client\n */\nexport class BronApiClient {\n private config: BronApiConfig;\n\n constructor(config: BronApiConfig) {\n this.config = config;\n }\n\n /**\n * Create authenticated request headers\n */\n private async getHeaders(): Promise<HeadersInit> {\n const token = await this.config.getAccessToken();\n if (!token) {\n throw new Error('No access token available');\n }\n\n return {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n };\n }\n\n /**\n * Create session / get party mapping\n */\n async createSession(): Promise<BronSession> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/sessions`, {\n method: 'POST',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to create session: ${error}`);\n }\n\n const data = (await response.json()) as {\n sessionId: string;\n partyId: string;\n expiresAt?: number;\n };\n\n return {\n sessionId: data.sessionId,\n partyId: toPartyId(data.partyId),\n expiresAt: data.expiresAt,\n };\n }\n\n /**\n * Request signature\n */\n async requestSignature(request: BronSignRequest): Promise<BronSignResponse> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to request signature: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied',\n signature: data.signature,\n transactionHash: data.transactionHash,\n };\n }\n\n /**\n * Get request status\n */\n async getRequestStatus(requestId: string): Promise<BronRequestStatus> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures/${requestId}`, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to get request status: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied' | 'expired',\n signature: data.signature,\n transactionHash: data.transactionHash,\n error: data.error,\n };\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron remote signer.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API on behalf of the connected party and returns\n * the raw JSON response.\n */\n async proxyLedgerApi(request: {\n requestMethod: string;\n resource: string;\n body?: string;\n sessionId: string;\n }): Promise<{ response: string }> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/ledger-proxy`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Ledger API proxy failed: ${error}`);\n }\n\n const data = (await response.json()) as { response: string };\n return { response: data.response };\n }\n\n /**\n * Poll request status until complete\n */\n async pollRequestStatus(\n requestId: string,\n timeoutMs: number = 60000,\n intervalMs: number = 2000\n ): Promise<BronRequestStatus> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const status = await this.getRequestStatus(requestId);\n\n if (status.status === 'approved' || status.status === 'denied' || status.status === 'expired') {\n return status;\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n throw new Error('Polling timeout');\n }\n}\n","/**\n * Bron Wallet Adapter\n * \n * Enterprise remote signer adapter using OAuth2 + API client.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n * - Wallet Integration Guide: https://docs.digitalasset.com/integrate/devnet/index.html\n */\n\nimport type {\n WalletAdapter,\n AdapterContext,\n AdapterDetectResult,\n AdapterConnectResult,\n SignMessageParams,\n SignTransactionParams,\n LedgerApiParams,\n LedgerApiResult,\n} from '@partylayer/core';\nimport { normalizeLedgerMethodUpper, ledgerApiBodyToString } from '@partylayer/core';\nimport {\n toWalletId,\n toSignature,\n toTransactionHash,\n UserRejectedError,\n mapUnknownErrorToPartyLayerError,\n type CapabilityKey,\n} from '@partylayer/core';\nimport { BronAuthClient, type BronAuthConfig } from './auth';\nimport { BronApiClient } from './api';\n\n// Re-export types for convenience\nexport type { BronAuthConfig } from './auth';\nexport type { BronApiConfig } from './api';\n\n/**\n * API configuration for the Bron adapter. Only `baseUrl` is needed: the adapter\n * supplies its own access-token getter, wired to its OAuth client, so a caller\n * neither provides nor overrides one. This is deliberately narrower than the\n * internal BronApiConfig (which the API client uses and does carry a token getter).\n */\nexport interface BronAdapterApiConfig {\n /** Base URL of the Bron signer API. */\n baseUrl: string;\n}\n\n/**\n * Bron adapter configuration\n */\nexport interface BronAdapterConfig {\n /** OAuth2 configuration */\n auth: BronAuthConfig;\n /** API configuration */\n api: BronAdapterApiConfig;\n}\n\n/**\n * Bron Wallet Adapter\n */\nexport class BronAdapter implements WalletAdapter {\n readonly walletId = toWalletId('bron');\n readonly name = 'Bron';\n\n private authClient: BronAuthClient;\n private apiClient: BronApiClient;\n\n constructor(config: BronAdapterConfig) {\n // Initialize auth client\n // Tokens stored in memory by default (secure)\n // Can optionally use encrypted storage if provided\n this.authClient = new BronAuthClient(config.auth);\n\n // Initialize the real API client. There is no URL- or environment-inferred\n // mock: a mock, if wanted for a test, must be constructed explicitly by the\n // test, never triggered by a substring in a URL or by NODE_ENV.\n this.apiClient = new BronApiClient({\n baseUrl: config.api.baseUrl,\n getAccessToken: async () => {\n return await this.authClient.getAccessToken();\n },\n });\n }\n\n getCapabilities(): CapabilityKey[] {\n return [\n 'connect',\n 'disconnect',\n 'restore',\n 'remoteSigner',\n 'signMessage',\n 'signTransaction',\n 'ledgerApi',\n ];\n }\n\n detectInstalled(): Promise<AdapterDetectResult> {\n // Bron is an enterprise remote signer - no \"installation\" required\n // Availability depends on OAuth2 configuration\n // Bron is an enterprise remote signer: no local install, and unusable\n // without OAuth credentials the app supplies. `needs-config` lets the picker\n // hide it rather than show a tile whose click dead-ends at an OAuth error —\n // which is the behaviour the SDK already had, now stated in the data.\n return Promise.resolve({\n installed: false,\n // BronAdapterConfig requires `auth`, so an instance cannot exist without\n // credentials; the unconfigured case is handled a level up by not\n // registering the adapter, which is why Bron is absent from the picker\n // rather than present and broken.\n availability: { kind: 'no-local-install' },\n reason: 'Bron is a remote signer service',\n });\n }\n\n async connect(\n ctx: AdapterContext,\n _opts?: {\n timeoutMs?: number;\n requiredCapabilities?: CapabilityKey[];\n }\n ): Promise<AdapterConnectResult> {\n try {\n // Check if we have an access token\n const accessToken = await this.authClient.getAccessToken();\n\n // If no token, start OAuth flow\n if (!accessToken) {\n if (typeof window === 'undefined') {\n throw new Error('OAuth flow requires browser environment');\n }\n\n const authUrl = await this.authClient.startAuth();\n \n // Open auth URL (popup or redirect)\n const popup = window.open(\n authUrl,\n 'Bron Auth',\n 'width=500,height=600'\n );\n\n if (!popup) {\n throw new Error('Failed to open auth popup');\n }\n\n // The OAuth callback (finishAuth with the returned code) must be handled\n // by the app; the adapter has no redirect handler of its own. Fail loudly\n // rather than fabricating a token — there is no dev/mock shortcut.\n throw new Error('OAuth callback not implemented in adapter - handle in app');\n }\n\n // Create session with Bron API\n const session = await this.apiClient.createSession();\n\n return {\n partyId: session.partyId,\n session: {\n walletId: this.walletId,\n // Bron's API session does not report the connected network → not\n // wallet-reported, so network-mismatch detection is limited for this\n // adapter (echoes the requested ctx.network).\n network: ctx.network,\n createdAt: Date.now(),\n expiresAt: session.expiresAt,\n capabilitiesSnapshot: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n metadata: {\n sessionId: session.sessionId,\n },\n },\n capabilities: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'connect',\n transport: 'remote',\n });\n }\n }\n\n async disconnect(\n _ctx: AdapterContext,\n _session: import('@partylayer/core').Session\n ): Promise<void> {\n await this.authClient.logout();\n }\n\n async restore(\n _ctx: AdapterContext,\n persisted: import('@partylayer/core').PersistedSession\n ): Promise<import('@partylayer/core').Session | null> {\n // Check if we have a session ID and access token\n const sessionId = persisted.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n return null;\n }\n\n const accessToken = await this.authClient.getAccessToken();\n if (!accessToken) {\n return null; // No token to restore\n }\n\n // Check expiration\n if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {\n return null;\n }\n\n // Restore session\n return {\n ...persisted,\n walletId: this.walletId,\n };\n }\n\n async signMessage(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignMessageParams\n ): Promise<import('@partylayer/core').SignedMessage> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n message: params.message,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n return {\n message: params.message,\n signature: toSignature(status.signature),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Signature request failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n return {\n message: params.message,\n signature: toSignature(signResponse.signature),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signMessage',\n transport: 'remote',\n });\n }\n }\n\n async signTransaction(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignTransactionParams\n ): Promise<import('@partylayer/core').SignedTransaction> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n transaction: params.tx,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: status.signature }\n : { tx: params.tx, signature: status.signature };\n return {\n signedTx,\n // Was `toTransactionHash('pending')` when Bron reported no hash.\n // The field is optional now, so nothing is what gets reported.\n ...(status.transactionHash\n ? { transactionHash: toTransactionHash(status.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Transaction signing failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: signResponse.signature }\n : { tx: params.tx, signature: signResponse.signature };\n return {\n signedTx,\n ...(signResponse.transactionHash\n ? { transactionHash: toTransactionHash(signResponse.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signTransaction',\n transport: 'remote',\n });\n }\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron enterprise API.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API using the enterprise session credentials.\n */\n async ledgerApi(\n ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: LedgerApiParams,\n ): Promise<LedgerApiResult> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n ctx.logger.debug('Proxying ledger API request via Bron', {\n sessionId,\n requestMethod: params.requestMethod,\n resource: params.resource,\n });\n\n const result = await this.apiClient.proxyLedgerApi({\n requestMethod: normalizeLedgerMethodUpper(params.requestMethod),\n resource: params.resource,\n body: ledgerApiBodyToString(params.body),\n sessionId,\n });\n\n return { response: result.response };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'ledgerApi',\n transport: 'remote',\n });\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts","../src/api.ts","../src/authorization.ts","../src/bron-adapter.ts"],"names":["toPartyId","UserRejectedError","toWalletId","mapUnknownErrorToPartyLayerError","toSignature","signedTx","toTransactionHash","normalizeLedgerMethodUpper","ledgerApiBodyToString"],"mappings":";;;;;;;AA6CO,IAAM,iBAAN,MAAqB;AAAA,EAClB,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA,GAA4B,IAAA;AAAA;AAAA,EAC5B,OAAA,GAA0E,IAAA;AAAA,EAC1E,QAAA,GAAmC,IAAA;AAAA,EACnC,aAAA,GAAgB,IAAI,eAAA,EAAgB;AAAA,EACpC,KAAA,GAAQ,CAAA;AAAA,EACR,aAAA,GAA+B,QAAQ,OAAA,EAAQ;AAAA,EAE/C,QAAQ,MAAA,EAA4C;AAC1D,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,aAAA,CAAc,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA,CAAE,IAAA,CAAK,MAAM,CAAA;AAC5D,IAAA,IAAA,CAAK,aAAA,GAAgB,KAAA;AACrB,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,WAAA,CAAY,QAAwB,OAAA,EAA0B;AAC5D,IAAA,KAAA,MAAW,KAAA,IAAS,CAAC,MAAA,CAAO,gBAAA,EAAkB,OAAO,QAAA,EAAU,MAAA,CAAO,WAAW,CAAA,EAAG;AAClF,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,KAAK,CAAA;AACzB,MAAA,IAAI,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,QAAS,GAAA,CAAI,QAAA,KAAa,QAAA,IAChE,EAAE,GAAA,CAAI,QAAA,KAAa,WAAW,CAAC,WAAA,EAAa,WAAA,EAAa,OAAO,CAAA,CAAE,QAAA,CAAS,GAAA,CAAI,QAAQ,CAAA,CAAA,EAAK,MAAM,IAAI,KAAA,CAAM,mCAAmC,CAAA;AAAA,IACnJ;AACA,IAAA,IAAI,CAAC,OAAO,QAAA,EAAU,IAAA,IAAQ,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAC1E,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,KAAgB,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,OAAA,KAAY,KAAA,CAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,kEAAkE,CAAA;AAC1K,IAAA,IAAA,CAAK,SAAS,EAAE,GAAG,QAAQ,OAAA,EAAS,MAAA,CAAO,WAAW,IAAA,EAAK;AAC3D,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YAAA,GAAiE;AAE7E,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,oBAAA,CAAqB,EAAE,CAAA;AAC7C,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAChC,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,MAAA,CAAO,QAAQ,CAAA;AACpC,IAAA,MAAM,SAAS,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,WAAW,IAAI,CAAA;AACzD,IAAA,MAAM,SAAA,GAAY,KAAK,MAAA,CAAO,YAAA,CAAa,GAAG,IAAI,UAAA,CAAW,MAAM,CAAC,CAAC,EAClE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAClB,OAAA,CAAQ,OAAO,GAAG,CAAA,CAClB,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA;AAEnB,IAAA,OAAO,EAAE,UAAU,SAAA,EAAU;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,MAAA,EAAwB;AACnD,IAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAM,CAAA;AACnC,IAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAA,EAAO,CAAC,SAAS,IAAA,CAAK,QAAA,CAAS,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAA,GAA6B;AACjC,IAAA,IAAA,CAAK,mBAAA,EAAoB;AACzB,IAAA,IAAA,CAAK,aAAA,GAAgB,IAAI,eAAA,EAAgB;AACzC,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,oBAAA,CAAqB,EAAE,CAAA;AAC1C,IAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB;AAAA,MACjC,aAAA,EAAe,MAAA;AAAA,MACf,SAAA,EAAW,KAAK,MAAA,CAAO,QAAA;AAAA,MACvB,YAAA,EAAc,KAAK,MAAA,CAAO,WAAA;AAAA,MAC1B,KAAA;AAAA,MACA,KAAA,EAAA,CAAQ,KAAK,MAAA,CAAO,MAAA,IAAU,CAAC,QAAA,EAAU,SAAS,CAAA,EAAG,IAAA,CAAK,GAAG;AAAA,KAC9D,CAAA;AAGD,IAAA,IAAI,IAAA,CAAK,OAAO,OAAA,EAAS;AACvB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,YAAA,EAAa;AACrC,MAAA,MAAA,CAAO,GAAA,CAAI,gBAAA,EAAkB,IAAA,CAAK,SAAS,CAAA;AAC3C,MAAA,MAAA,CAAO,GAAA,CAAI,yBAAyB,MAAM,CAAA;AAE1C,MAAA,IAAI,UAAU,IAAA,CAAK,KAAA,EAAO,MAAM,IAAI,MAAM,+BAA+B,CAAA;AACzE,MAAA,IAAA,CAAK,OAAA,GAAU,EAAE,KAAA,EAAO,QAAA,EAAU,IAAA,CAAK,UAAU,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA,EAAQ;AAAA,IACnF,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,UAAU,EAAE,KAAA,EAAO,WAAW,IAAA,CAAK,GAAA,KAAQ,GAAA,EAAQ;AAAA,IAC1D;AAEA,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAA,CAAK,OAAO,gBAAgB,CAAA;AAChD,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,QAAQ,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAClE,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,WAAA,EAA0C;AACzD,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,WAAW,CAAA;AAC/B,IAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,IAAA,CAAK,OAAO,WAAW,CAAA;AAChD,IAAA,MAAM,UAAU,IAAA,CAAK,OAAA;AACrB,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,QAAA,CAAS,MAAA,IAAU,GAAA,CAAI,QAAA,KAAa,QAAA,CAAS,QAAA,IAAY,GAAA,CAAI,IAAA,IAAQ,GAAA,CAAI,QAAA,IAAY,GAAA,CAAI,QAAA,IAC1G,CAAC,GAAG,QAAA,CAAS,YAAY,CAAA,CAAE,IAAA,CAAK,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM,GAAA,CAAI,YAAA,CAAa,MAAA,CAAO,GAAG,CAAA,CAAE,MAAA,KAAW,CAAA,IAAK,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,GAAG,CAAA,KAAM,KAAK,CAAA,IAClI,CAAC,OAAA,IAAW,OAAA,CAAQ,SAAA,IAAa,IAAA,CAAK,GAAA,MAAS,GAAA,CAAI,YAAA,CAAa,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,KAAW,CAAA,IAC3F,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA,KAAM,OAAA,CAAQ,KAAA,EAAO,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAE5G,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAI,GAAA,CAAI,aAAa,GAAA,CAAI,OAAO,GAAG,MAAM,IAAI,MAAM,4CAA4C,CAAA;AAC/F,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACxC,IAAA,IAAI,CAAC,IAAA,IAAQ,GAAA,CAAI,YAAA,CAAa,MAAA,CAAO,MAAM,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,0CAA0C,CAAA;AACrH,IAAA,MAAM,WAAA,GAAc,IAAI,eAAA,CAAgB;AAAA,MAAE,UAAA,EAAY,oBAAA;AAAA,MAAsB,IAAA;AAAA,MAC1E,YAAA,EAAc,KAAK,MAAA,CAAO,WAAA;AAAA,MAAa,SAAA,EAAW,KAAK,MAAA,CAAO;AAAA,KAAU,CAAA;AAC1E,IAAA,IAAI,IAAA,CAAK,OAAO,OAAA,EAAS;AACvB,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,EAAU,MAAM,IAAI,MAAM,uBAAuB,CAAA;AAC9D,MAAA,WAAA,CAAY,GAAA,CAAI,eAAA,EAAiB,OAAA,CAAQ,QAAQ,CAAA;AAAA,IACnD;AACA,IAAA,IAAI,IAAA,CAAK,OAAO,YAAA,EAAc,WAAA,CAAY,IAAI,eAAA,EAAiB,IAAA,CAAK,OAAO,YAAY,CAAA;AACvF,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AAAG,IAAA,IAAA,CAAK,QAAA,GAAW,UAAA;AAC1D,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,IAAM,CAAA;AACzD,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,IAAA,CAAK,OAAO,QAAA,EAAU;AAAA,QACjD,MAAA,EAAQ,MAAA;AAAA,QAAQ,OAAA,EAAS,EAAE,cAAA,EAAgB,mCAAA,EAAqC,QAAQ,kBAAA,EAAmB;AAAA,QAC3G,IAAA,EAAM,YAAY,QAAA,EAAS;AAAA,QAAG,WAAA,EAAa,MAAA;AAAA,QAAQ,KAAA,EAAO,UAAA;AAAA,QAAY,QAAA,EAAU,OAAA;AAAA,QAChF,cAAA,EAAgB,aAAA;AAAA,QAAe,QAAQ,UAAA,CAAW;AAAA,OACnD,CAAA;AACD,MAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,MAAM,IAAI,MAAM,6BAA6B,CAAA;AAC/D,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,CAAS,IAAA,EAAK;AAChC,MAAA,IAAI,IAAI,MAAA,GAAS,KAAA,EAAS,MAAM,IAAI,MAAM,mCAAmC,CAAA;AAC7E,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC3B,MAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,CAAK,YAAA,KAAiB,QAAA,IAAY,CAAC,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,YAAA,CAAa,MAAA,GAAS,IAAA,IACrG,cAAc,IAAA,CAAK,IAAA,CAAK,YAAY,CAAA,IAAK,OAAO,IAAA,CAAK,UAAA,KAAe,QAAA,IAAY,IAAA,CAAK,UAAA,CAAW,WAAA,EAAY,KAAM,QAAA,IAClH,OAAO,KAAK,UAAA,KAAe,QAAA,IAAY,CAAC,MAAA,CAAO,QAAA,CAAS,IAAA,CAAK,UAAU,CAAA,IAAK,IAAA,CAAK,UAAA,IAAc,CAAA,IAAK,IAAA,CAAK,UAAA,GAAa,OAAA,IACrH,IAAA,CAAK,aAAA,KAAkB,KAAA,CAAA,KAAc,OAAO,IAAA,CAAK,aAAA,KAAkB,QAAA,IAAY,CAAC,IAAA,CAAK,aAAA,IAAiB,SAAA,CAAU,IAAA,CAAK,IAAA,CAAK,aAAa,CAAA,CAAA,EAAK;AAC7I,QAAA,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAAA,MAChD;AACA,MAAA,IAAI,UAAA,CAAW,OAAO,OAAA,IAAW,KAAA,KAAU,KAAK,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,+BAA+B,CAAA;AACtG,MAAA,MAAM,MAAA,GAAqB;AAAA,QAAE,aAAa,IAAA,CAAK,YAAA;AAAA,QAAc,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,KAAK,UAAA,GAAa,GAAA;AAAA,QACrG,SAAA,EAAW,QAAA;AAAA,QAAU,GAAI,KAAK,aAAA,GAAgB,EAAE,cAAc,IAAA,CAAK,aAAA,KAAkB;AAAC,OAAG;AAC3F,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,MAAA,IAAI,IAAA,CAAK,OAAA,EAAS,MAAM,IAAA,CAAK,QAAQ,YAAY;AAC/C,QAAA,IAAI,KAAA,KAAU,IAAA,CAAK,KAAA,EAAO,MAAM,IAAA,CAAK,OAAA,CAAS,GAAA,CAAI,aAAA,EAAe,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA;AAAA,MACzF,CAAC,CAAA;AACD,MAAA,IAAI,UAAU,IAAA,CAAK,KAAA,EAAO,MAAM,IAAI,MAAM,+BAA+B,CAAA;AACzE,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,KAAK,CAAA;AAAG,MAAA,IAAI,IAAA,CAAK,QAAA,KAAa,UAAA,EAAY,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,IACzE;AAAA,EACF;AAAA;AAAA,EAGA,mBAAA,GAA4B;AAC1B,IAAA,IAAA,CAAK,cAAc,KAAA,EAAM;AACzB,IAAA,IAAA,CAAK,KAAA,EAAA;AAAS,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAAM,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AAAG,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,EAC7E;AAAA,EAEA,sBAAA,GAAsC;AAAE,IAAA,OAAO,KAAK,aAAA,CAAc,MAAA;AAAA,EAAQ;AAAA;AAAA;AAAA;AAAA,EAK1E,MAAM,cAAA,GAAyC;AAC7C,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AAEnB,IAAA,IAAI,KAAK,MAAA,IAAU,IAAA,CAAK,KAAI,GAAI,IAAA,CAAK,OAAO,SAAA,EAAW;AACrD,MAAA,OAAO,KAAK,MAAA,CAAO,WAAA;AAAA,IACrB;AAGA,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAI,aAAa,CAAA;AACnD,MAAA,IAAI,KAAA,KAAU,IAAA,CAAK,KAAA,EAAO,OAAO,IAAA;AACjC,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAChC,UAAA,IAAI,OAAO,MAAA,CAAO,WAAA,KAAgB,QAAA,IAAY,MAAA,CAAO,eAAe,CAAC,aAAA,CAAc,IAAA,CAAK,MAAA,CAAO,WAAW,CAAA,IACxG,OAAO,SAAA,KAAc,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,SAAS,KAAK,IAAA,CAAK,GAAA,EAAI,GAAI,MAAA,CAAO,SAAA,EAAW;AACrG,YAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAQ,YAAA,OAAO,MAAA,CAAO,WAAA;AAAA,UACtC;AAAA,QACF,CAAA,CAAA,MAAQ;AAAA,QAA2E;AAAA,MACrF;AAAA,IACF;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,GAAwB;AAC5B,IAAA,IAAA,CAAK,mBAAA,EAAoB;AACzB,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAI,KAAK,OAAA,EAAS;AAChB,MAAA,MAAM,KAAK,OAAA,CAAQ,MAAM,KAAK,OAAA,CAAS,MAAA,CAAO,aAAa,CAAC,CAAA;AAAA,IAC9D;AAAA,EACF;AACF,CAAA;ACxKO,IAAM,gBAAN,MAAoB;AAAA,EACjB,MAAA;AAAA,EAER,YAAY,MAAA,EAAuB;AACjC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,UAAA,GAAmC;AAC/C,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,MAAA,CAAO,cAAA,EAAe;AAC/C,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAAA,IAC7C;AAEA,IAAA,OAAO;AAAA,MACL,eAAA,EAAiB,UAAU,KAAK,CAAA,CAAA;AAAA,MAChC,cAAA,EAAgB;AAAA,KAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAA,GAAsC;AAC1C,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,SAAA,CAAA,EAAa;AAAA,MAC9D,MAAA,EAAQ,MAAA;AAAA,MACR;AAAA,KACD,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,KAAK,CAAA,CAAE,CAAA;AAAA,IACtD;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAMlC,IAAA,OAAO;AAAA,MACL,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,OAAA,EAASA,cAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AAAA,MAC/B,WAAW,IAAA,CAAK;AAAA,KAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,OAAA,EAAqD;AAC1E,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,WAAA,CAAA,EAAe;AAAA,MAChE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC7B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,KAAK,CAAA,CAAE,CAAA;AAAA,IACzD;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAOlC,IAAA,OAAO;AAAA,MACL,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,iBAAiB,IAAA,CAAK;AAAA,KACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,SAAA,EAA+C;AACpE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,KAAK,MAAA,CAAO,OAAO,CAAA,YAAA,EAAe,SAAS,CAAA,CAAA,EAAI;AAAA,MAC7E,MAAA,EAAQ,KAAA;AAAA,MACR;AAAA,KACD,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8BAAA,EAAiC,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1D;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAWlC,IAAA,OAAO;AAAA,MACL,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,iBAAiB,IAAA,CAAK,eAAA;AAAA,MACtB,OAAO,IAAA,CAAK;AAAA,KACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,eAAe,OAAA,EAKa;AAChC,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,UAAA,EAAW;AACtC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,aAAA,CAAA,EAAiB;AAAA,MAClE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC7B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,KAAK,CAAA,CAAE,CAAA;AAAA,IACrD;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAClC,IAAA,OAAO,EAAE,QAAA,EAAU,IAAA,CAAK,QAAA,EAAS;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAA,CACJ,SAAA,EACA,SAAA,GAAoB,GAAA,EACpB,aAAqB,GAAA,EACO;AAC5B,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,IAAA,OAAO,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,GAAY,SAAA,EAAW;AACzC,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,gBAAA,CAAiB,SAAS,CAAA;AAEpD,MAAA,IAAI,MAAA,CAAO,WAAW,UAAA,IAAc,MAAA,CAAO,WAAW,QAAA,IAAY,MAAA,CAAO,WAAW,SAAA,EAAW;AAC7F,QAAA,OAAO,MAAA;AAAA,MACT;AAGA,MAAA,MAAM,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,UAAU,CAAC,CAAA;AAAA,IAChE;AAEA,IAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AAAA,EACnC;AACF,CAAA;ACxOA,IAAM,QAAA,GAAW,wCAAA;AAOV,SAAS,0BAA0B,WAAA,EAA2B;AACnE,EAAA,IAAI,OAAO,WAAW,WAAA,IAAe,CAAC,OAAO,MAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,0DAA0D,CAAA;AAC/H,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,WAAW,CAAA;AACpC,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,MAAA,KAAW,QAAA,CAAS,MAAA,IAAU,MAAA,CAAO,QAAA,CAAS,QAAA,KAAa,QAAA,CAAS,QAAA,EAAU,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAClJ,EAAA,MAAM,WAAA,GAAc,OAAO,QAAA,CAAS,IAAA;AACpC,EAAA,MAAA,CAAO,MAAA,CAAO,YAAY,EAAE,IAAA,EAAM,UAAU,WAAA,EAAY,EAAG,SAAS,MAAM,CAAA;AAE1E,EAAA,MAAA,CAAO,OAAA,CAAQ,YAAA,CAAa,IAAA,EAAM,EAAA,EAAI,SAAS,QAAQ,CAAA;AACvD,EAAA,MAAA,CAAO,KAAA,EAAM;AACf;AAGA,eAAsB,kBAAA,CAAmB,IAAA,EAAsB,WAAA,EAAqB,SAAA,EAAkC;AACpH,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAC9F,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,SAAS,CAAA,IAAK,SAAA,GAAY,CAAA,IAAK,SAAA,GAAY,GAAA,EAAS,MAAM,IAAI,KAAA,CAAM,uBAAuB,CAAA;AACjH,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,WAAW,CAAA;AACpC,EAAA,IAAI,QAAA,CAAS,WAAW,MAAA,CAAO,QAAA,CAAS,QAAQ,MAAM,IAAI,MAAM,4CAA4C,CAAA;AAC5G,EAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,EAAU;AACjC,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,GAAA,EAAK,iCAAiC,sBAAsB,CAAA;AACtF,EAAA,IAAI,CAAC,KAAA,EAAO;AAAE,IAAA,IAAA,CAAK,mBAAA,EAAoB;AAAG,IAAA,MAAM,IAAI,MAAM,oDAAoD,CAAA;AAAA,EAAG;AACjH,EAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,IAAA,MAAM,MAAA,GAAS,KAAK,sBAAA,EAAuB;AAC3C,IAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,IAAA,IAAI,QAAA,GAAW,KAAA;AACf,IAAA,MAAM,MAAA,GAAS,CAAC,KAAA,KAAoB;AAClC,MAAA,IAAI,QAAA,EAAU;AACd,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,YAAA,CAAa,KAAK,CAAA;AAAG,MAAA,aAAA,CAAc,MAAM,CAAA;AACzC,MAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,OAAO,CAAA;AAC7C,MAAA,MAAA,CAAO,mBAAA,CAAoB,SAAS,MAAM,CAAA;AAC1C,MAAA,IAAI,KAAA,OAAY,mBAAA,EAAoB;AACpC,MAAA,IAAI;AAAE,QAAA,KAAA,CAAM,KAAA,EAAM;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAA2D;AACxF,MAAA,IAAI,KAAA,SAAc,KAAK,CAAA;AAAA,WAAQ,OAAA,EAAQ;AAAA,IACzC,CAAA;AACA,IAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAAwB;AACvC,MAAA,IAAI,QAAA,IAAY,oBAAoB,KAAA,CAAM,MAAA,KAAW,SAAS,KAAA,CAAM,MAAA,KAAW,SAAS,MAAA,IACtF,CAAC,MAAM,IAAA,IAAQ,KAAA,CAAM,KAAK,IAAA,KAAS,QAAA,IAAY,OAAO,KAAA,CAAM,IAAA,CAAK,gBAAgB,QAAA,EAAU;AAC7F,MAAA,gBAAA,GAAmB,IAAA;AACnB,MAAA,KAAK,IAAA,CAAK,UAAA,CAAW,KAAA,CAAM,IAAA,CAAK,WAAW,CAAA,CAAE,IAAA,CAAK,MAAM,MAAA,EAAO,EAAG,CAAA,KAAA,KAAS,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IAC1F,CAAA;AACA,IAAA,MAAM,SAAS,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,gCAAgC,CAAC,CAAA;AACvE,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,gCAAgC,CAAC,CAAA,EAAG,SAAS,CAAA;AAC7F,IAAA,MAAM,MAAA,GAAS,YAAY,MAAM;AAC/B,MAAA,IAAI,CAAC,oBAAoB,KAAA,CAAM,MAAA,SAAe,IAAIC,sBAAA,CAAkB,iCAAiC,CAAC,CAAA;AAAA,IACxG,GAAG,GAAG,CAAA;AACN,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,OAAO,CAAA;AAC1C,IAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,MAAA,EAAQ,EAAE,IAAA,EAAM,MAAM,CAAA;AACvD,IAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAO;AAAA,EAC7B,CAAC,CAAA;AACH;;;ACGO,IAAM,cAAN,MAA2C;AAAA,EACvC,QAAA,GAAWC,gBAAW,MAAM,CAAA;AAAA,EAC5B,IAAA,GAAO,MAAA;AAAA,EAER,UAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,GAAa,KAAA;AAAA,EAErB,YAAY,MAAA,EAA2B;AAIrC,IAAA,IAAA,CAAK,UAAA,GAAa,IAAI,cAAA,CAAe,MAAA,CAAO,IAAI,CAAA;AAChD,IAAA,IAAA,CAAK,WAAA,GAAc,OAAO,IAAA,CAAK,WAAA;AAK/B,IAAA,IAAA,CAAK,SAAA,GAAY,IAAI,aAAA,CAAc;AAAA,MACjC,OAAA,EAAS,OAAO,GAAA,CAAI,OAAA;AAAA,MACpB,gBAAgB,YAAY;AAC1B,QAAA,OAAO,MAAM,IAAA,CAAK,UAAA,CAAW,cAAA,EAAe;AAAA,MAC9C;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,eAAA,GAAmC;AACjC,IAAA,OAAO;AAAA,MACL,SAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,cAAA;AAAA,MACA,aAAA;AAAA,MACA,iBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA,EAEA,eAAA,GAAgD;AAO9C,IAAA,OAAO,QAAQ,OAAA,CAAQ;AAAA,MACrB,SAAA,EAAW,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKX,YAAA,EAAc,EAAE,IAAA,EAAM,kBAAA,EAAmB;AAAA,MACzC,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,OAAA,CACJ,GAAA,EACA,IAAA,EAI+B;AAC/B,IAAA,IAAI,IAAA,CAAK,UAAA,EAAY,MAAM,IAAI,MAAM,sCAAsC,CAAA;AAC3E,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,IAAI;AAEF,MAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,UAAA,CAAW,cAAA,EAAe;AAGzD,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,MAAM,mBAAmB,IAAA,CAAK,UAAA,EAAY,KAAK,WAAA,EAAa,IAAA,EAAM,aAAa,IAAO,CAAA;AAAA,MACxF;AAGA,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,aAAA,EAAc;AAEnD,MAAA,OAAO;AAAA,QACL,SAAS,OAAA,CAAQ,OAAA;AAAA,QACjB,OAAA,EAAS;AAAA,UACP,UAAU,IAAA,CAAK,QAAA;AAAA;AAAA;AAAA;AAAA,UAIf,SAAS,GAAA,CAAI,OAAA;AAAA,UACb,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,UACpB,WAAW,OAAA,CAAQ,SAAA;AAAA,UACnB,oBAAA,EAAsB,CAAC,SAAA,EAAW,aAAA,EAAe,mBAAmB,cAAc,CAAA;AAAA,UAClF,QAAA,EAAU;AAAA,YACR,WAAW,OAAA,CAAQ;AAAA;AACrB,SACF;AAAA,QACA,YAAA,EAAc,CAAC,SAAA,EAAW,aAAA,EAAe,mBAAmB,cAAc;AAAA,OAC5E;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMC,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,SAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,UAAA,CACJ,IAAA,EACA,QAAA,EACe;AACf,IAAA,MAAM,IAAA,CAAK,WAAW,MAAA,EAAO;AAAA,EAC/B;AAAA,EAEA,MAAM,OAAA,CACJ,IAAA,EACA,SAAA,EACoD;AAEpD,IAAA,MAAM,SAAA,GAAY,UAAU,QAAA,EAAU,SAAA;AACtC,IAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,UAAA,CAAW,cAAA,EAAe;AACzD,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,IAAI,UAAU,SAAA,IAAa,IAAA,CAAK,GAAA,EAAI,IAAK,UAAU,SAAA,EAAW;AAC5D,MAAA,OAAO,IAAA;AAAA,IACT;AAGA,IAAA,OAAO;AAAA,MACL,GAAG,SAAA;AAAA,MACH,UAAU,IAAA,CAAK;AAAA,KACjB;AAAA,EACF;AAAA,EAEA,MAAM,WAAA,CACJ,IAAA,EACA,OAAA,EACA,MAAA,EACmD;AACnD,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,EAAU,SAAA;AACpC,MAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,QAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,MACjC;AAGA,MAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,SAAA,CAAU,gBAAA,CAAiB;AAAA,QACzD,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB;AAAA,OACD,CAAA;AAGD,MAAA,IAAI,YAAA,CAAa,WAAW,SAAA,EAAW;AACrC,QAAA,MAAM,SAAS,MAAM,IAAA,CAAK,SAAA,CAAU,iBAAA,CAAkB,aAAa,SAAS,CAAA;AAE5E,QAAA,IAAI,MAAA,CAAO,WAAW,QAAA,EAAU;AAC9B,UAAA,MAAM,IAAIF,uBAAkB,0BAA0B,CAAA;AAAA,QACxD;AAEA,QAAA,IAAI,MAAA,CAAO,MAAA,KAAW,UAAA,IAAc,MAAA,CAAO,SAAA,EAAW;AACpD,UAAA,OAAO;AAAA,YACL,SAAS,MAAA,CAAO,OAAA;AAAA,YAChB,SAAA,EAAWG,gBAAA,CAAY,MAAA,CAAO,SAAS,CAAA;AAAA,YACvC,SAAS,OAAA,CAAQ;AAAA,WACnB;AAAA,QACF;AAEA,QAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,MAC5C;AAEA,MAAA,IAAI,YAAA,CAAa,WAAW,QAAA,EAAU;AACpC,QAAA,MAAM,IAAIH,uBAAkB,0BAA0B,CAAA;AAAA,MACxD;AAEA,MAAA,IAAI,CAAC,aAAa,SAAA,EAAW;AAC3B,QAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,MAC5C;AAEA,MAAA,OAAO;AAAA,QACL,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,SAAA,EAAWG,gBAAA,CAAY,YAAA,CAAa,SAAS,CAAA;AAAA,QAC7C,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMD,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,aAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,eAAA,CACJ,IAAA,EACA,OAAA,EACA,MAAA,EACuD;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,EAAU,SAAA;AACpC,MAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,QAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,MACjC;AAGA,MAAA,MAAM,YAAA,GAAe,MAAM,IAAA,CAAK,SAAA,CAAU,gBAAA,CAAiB;AAAA,QACzD,aAAa,MAAA,CAAO,EAAA;AAAA,QACpB;AAAA,OACD,CAAA;AAGD,MAAA,IAAI,YAAA,CAAa,WAAW,SAAA,EAAW;AACrC,QAAA,MAAM,SAAS,MAAM,IAAA,CAAK,SAAA,CAAU,iBAAA,CAAkB,aAAa,SAAS,CAAA;AAE5E,QAAA,IAAI,MAAA,CAAO,WAAW,QAAA,EAAU;AAC9B,UAAA,MAAM,IAAIF,uBAAkB,4BAA4B,CAAA;AAAA,QAC1D;AAEA,QAAA,IAAI,MAAA,CAAO,MAAA,KAAW,UAAA,IAAc,MAAA,CAAO,SAAA,EAAW;AACpD,UAAA,MAAMI,SAAAA,GAAW,OAAO,MAAA,CAAO,EAAA,KAAO,YAAY,MAAA,CAAO,EAAA,KAAO,IAAA,GAC5D,EAAE,GAAG,MAAA,CAAO,IAA+B,SAAA,EAAW,MAAA,CAAO,WAAU,GACvE,EAAE,IAAI,MAAA,CAAO,EAAA,EAAI,SAAA,EAAW,MAAA,CAAO,SAAA,EAAU;AACjD,UAAA,OAAO;AAAA,YACL,QAAA,EAAAA,SAAAA;AAAA;AAAA;AAAA,YAGA,GAAI,MAAA,CAAO,eAAA,GACP,EAAE,eAAA,EAAiBC,uBAAkB,MAAA,CAAO,eAAe,CAAA,EAAE,GAC7D,EAAC;AAAA,YACL,SAAS,OAAA,CAAQ;AAAA,WACnB;AAAA,QACF;AAEA,QAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,MAC9C;AAEA,MAAA,IAAI,YAAA,CAAa,WAAW,QAAA,EAAU;AACpC,QAAA,MAAM,IAAIL,uBAAkB,4BAA4B,CAAA;AAAA,MAC1D;AAEA,MAAA,IAAI,CAAC,aAAa,SAAA,EAAW;AAC3B,QAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,MAC5C;AAEA,MAAA,MAAM,QAAA,GAAW,OAAO,MAAA,CAAO,EAAA,KAAO,YAAY,MAAA,CAAO,EAAA,KAAO,IAAA,GAC5D,EAAE,GAAG,MAAA,CAAO,IAA+B,SAAA,EAAW,YAAA,CAAa,WAAU,GAC7E,EAAE,IAAI,MAAA,CAAO,EAAA,EAAI,SAAA,EAAW,YAAA,CAAa,SAAA,EAAU;AACvD,MAAA,OAAO;AAAA,QACL,QAAA;AAAA,QACA,GAAI,YAAA,CAAa,eAAA,GACb,EAAE,eAAA,EAAiBK,uBAAkB,YAAA,CAAa,eAAe,CAAA,EAAE,GACnE,EAAC;AAAA,QACL,SAAS,OAAA,CAAQ;AAAA,OACnB;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,MAAMH,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,iBAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAA,CACJ,GAAA,EACA,OAAA,EACA,MAAA,EAC0B;AAC1B,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,EAAU,SAAA;AACpC,MAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,QAAA,MAAM,IAAI,MAAM,eAAe,CAAA;AAAA,MACjC;AAEA,MAAA,GAAA,CAAI,MAAA,CAAO,MAAM,sCAAA,EAAwC;AAAA,QACvD,SAAA;AAAA,QACA,eAAe,MAAA,CAAO,aAAA;AAAA,QACtB,UAAU,MAAA,CAAO;AAAA,OAClB,CAAA;AAED,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,cAAA,CAAe;AAAA,QACjD,aAAA,EAAeI,+BAAA,CAA2B,MAAA,CAAO,aAAa,CAAA;AAAA,QAC9D,UAAU,MAAA,CAAO,QAAA;AAAA,QACjB,IAAA,EAAMC,0BAAA,CAAsB,MAAA,CAAO,IAAI,CAAA;AAAA,QACvC;AAAA,OACD,CAAA;AAED,MAAA,OAAO,EAAE,QAAA,EAAU,MAAA,CAAO,QAAA,EAAS;AAAA,IACrC,SAAS,GAAA,EAAK;AACZ,MAAA,MAAML,sCAAiC,GAAA,EAAK;AAAA,QAC1C,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,KAAA,EAAO,WAAA;AAAA,QACP,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAAA,EACF;AACF","file":"index.js","sourcesContent":["/**\n * Bron OAuth2 Authentication Client\n * \n * Handles OAuth2 flows for Bron enterprise wallet.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n */\n\nimport type { StorageAdapter } from '@partylayer/core';\n\n/**\n * OAuth2 configuration\n */\nexport interface BronAuthConfig {\n /** Authorization server URL */\n authorizationUrl: string;\n /** Token endpoint URL */\n tokenUrl: string;\n /** Client ID */\n clientId: string;\n /** Client secret (for server-side flows) */\n clientSecret?: string;\n /** Redirect URI */\n redirectUri: string;\n /** Scopes */\n scopes?: string[];\n /** PKCE defaults to true and is required in browsers. */\n usePKCE?: boolean;\n}\n\n/**\n * OAuth2 tokens\n */\nexport interface BronTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number;\n tokenType: string;\n}\n\n/**\n * Bron OAuth2 client\n */\nexport class BronAuthClient {\n private config: BronAuthConfig;\n private storage?: StorageAdapter;\n private tokens: BronTokens | null = null; // In-memory by default\n private pending: { state: string; verifier?: string; expiresAt: number } | null = null;\n private exchange: AbortController | null = null;\n private authorization = new AbortController();\n private epoch = 0;\n private storageWrites: Promise<void> = Promise.resolve();\n\n private persist(action: () => Promise<void>): Promise<void> {\n const write = this.storageWrites.catch(() => {}).then(action);\n this.storageWrites = write;\n return write;\n }\n\n constructor(config: BronAuthConfig, storage?: StorageAdapter) {\n for (const input of [config.authorizationUrl, config.tokenUrl, config.redirectUri]) {\n const url = new URL(input);\n if (url.username || url.password || url.hash || (url.protocol !== 'https:' &&\n !(url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)))) throw new Error('OAuth requires trusted HTTPS URLs');\n }\n if (!config.clientId?.trim()) throw new Error('OAuth clientId is required');\n if (typeof window !== 'undefined' && (config.clientSecret || config.usePKCE === false)) throw new Error('Browser OAuth requires PKCE and must not contain a client secret');\n this.config = { ...config, usePKCE: config.usePKCE ?? true };\n this.storage = storage;\n }\n\n /**\n * Generate PKCE code verifier and challenge\n */\n private async generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n // 32 random bytes produce a 64-character RFC 7636 verifier (43–128 chars).\n const verifier = this.generateRandomString(32);\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const challenge = btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n\n return { verifier, challenge };\n }\n\n /**\n * Generate random string\n */\n private generateRandomString(length: number): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Start authorization flow\n */\n async startAuth(): Promise<string> {\n this.cancelAuthorization();\n this.authorization = new AbortController();\n const epoch = this.epoch;\n const state = this.generateRandomString(32);\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n state,\n scope: (this.config.scopes || ['openid', 'profile']).join(' '),\n });\n\n // Add PKCE if enabled\n if (this.config.usePKCE) {\n const pkce = await this.generatePKCE();\n params.set('code_challenge', pkce.challenge);\n params.set('code_challenge_method', 'S256');\n \n if (epoch !== this.epoch) throw new Error('OAuth authorization cancelled');\n this.pending = { state, verifier: pkce.verifier, expiresAt: Date.now() + 300_000 };\n } else {\n this.pending = { state, expiresAt: Date.now() + 300_000 };\n }\n\n const url = new URL(this.config.authorizationUrl);\n for (const [key, value] of params) url.searchParams.set(key, value);\n return url.href;\n }\n\n /**\n * Finish authorization flow with callback URL\n */\n async finishAuth(callbackUrl: string): Promise<BronTokens> {\n const url = new URL(callbackUrl);\n const redirect = new URL(this.config.redirectUri);\n const pending = this.pending;\n if (url.origin !== redirect.origin || url.pathname !== redirect.pathname || url.hash || url.username || url.password ||\n [...redirect.searchParams].some(([key, value]) => url.searchParams.getAll(key).length !== 1 || url.searchParams.get(key) !== value) ||\n !pending || pending.expiresAt <= Date.now() || url.searchParams.getAll('state').length !== 1 ||\n url.searchParams.get('state') !== pending.state) throw new Error('Invalid or expired OAuth callback state');\n // Consume before the asynchronous token request, including provider errors.\n this.pending = null;\n if (url.searchParams.has('error')) throw new Error('OAuth authorization was declined or failed');\n const code = url.searchParams.get('code');\n if (!code || url.searchParams.getAll('code').length !== 1) throw new Error('No unique authorization code in callback');\n const tokenParams = new URLSearchParams({ grant_type: 'authorization_code', code,\n redirect_uri: this.config.redirectUri, client_id: this.config.clientId });\n if (this.config.usePKCE) {\n if (!pending.verifier) throw new Error('Missing PKCE verifier');\n tokenParams.set('code_verifier', pending.verifier);\n }\n if (this.config.clientSecret) tokenParams.set('client_secret', this.config.clientSecret);\n const epoch = this.epoch;\n const controller = new AbortController(); this.exchange = controller;\n const timer = setTimeout(() => controller.abort(), 15_000);\n try {\n const response = await fetch(this.config.tokenUrl, {\n method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },\n body: tokenParams.toString(), credentials: 'omit', cache: 'no-store', redirect: 'error',\n referrerPolicy: 'no-referrer', signal: controller.signal,\n });\n if (!response.ok) throw new Error('OAuth token exchange failed');\n const raw = await response.text();\n if (raw.length > 256_000) throw new Error('OAuth token response is too large');\n const data = JSON.parse(raw);\n if (!data || typeof data.access_token !== 'string' || !data.access_token || data.access_token.length > 64_000 ||\n /[\\s\\p{Cc}]/u.test(data.access_token) || typeof data.token_type !== 'string' || data.token_type.toLowerCase() !== 'bearer' ||\n typeof data.expires_in !== 'number' || !Number.isFinite(data.expires_in) || data.expires_in <= 0 || data.expires_in > 31_536_000 ||\n (data.refresh_token !== undefined && (typeof data.refresh_token !== 'string' || !data.refresh_token || /\\p{Cc}/u.test(data.refresh_token)))) {\n throw new Error('Invalid OAuth token response');\n }\n if (controller.signal.aborted || epoch !== this.epoch) throw new Error('OAuth authorization cancelled');\n const tokens: BronTokens = { accessToken: data.access_token, expiresAt: Date.now() + data.expires_in * 1000,\n tokenType: 'Bearer', ...(data.refresh_token ? { refreshToken: data.refresh_token } : {}) };\n this.tokens = tokens;\n // A custom storage adapter is app-owned; it is not encrypted by this class.\n if (this.storage) await this.persist(async () => {\n if (epoch === this.epoch) await this.storage!.set('bron_tokens', JSON.stringify(tokens));\n });\n if (epoch !== this.epoch) throw new Error('OAuth authorization cancelled');\n return tokens;\n } finally {\n clearTimeout(timer); if (this.exchange === controller) this.exchange = null;\n }\n }\n\n /** Clear authorization state and abort only the in-flight token exchange. */\n cancelAuthorization(): void {\n this.authorization.abort();\n this.epoch++; this.pending = null; this.exchange?.abort(); this.exchange = null;\n }\n\n getAuthorizationSignal(): AbortSignal { return this.authorization.signal; }\n\n /**\n * Get current access token\n */\n async getAccessToken(): Promise<string | null> {\n const epoch = this.epoch;\n // Check if token exists and is not expired\n if (this.tokens && Date.now() < this.tokens.expiresAt) {\n return this.tokens.accessToken;\n }\n\n // Try to load from storage\n if (this.storage) {\n const stored = await this.storage.get('bron_tokens');\n if (epoch !== this.epoch) return null;\n if (stored) {\n try {\n const tokens = JSON.parse(stored) as BronTokens;\n if (typeof tokens.accessToken === 'string' && tokens.accessToken && !/[\\s\\p{Cc}]/u.test(tokens.accessToken) &&\n tokens.tokenType === 'Bearer' && Number.isFinite(tokens.expiresAt) && Date.now() < tokens.expiresAt) {\n this.tokens = tokens; return tokens.accessToken;\n }\n } catch { /* Invalid persisted data never establishes an authenticated session. */ }\n }\n }\n\n return null;\n }\n\n /**\n * Logout\n */\n async logout(): Promise<void> {\n this.cancelAuthorization();\n this.tokens = null;\n if (this.storage) {\n await this.persist(() => this.storage!.remove('bron_tokens'));\n }\n }\n}\n","/**\n * Bron API Client\n * \n * Typed client for Bron enterprise wallet API endpoints.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n */\n\nimport type { PartyId } from '@partylayer/core';\nimport { toPartyId } from '@partylayer/core';\n\n/**\n * Bron API configuration\n */\nexport interface BronApiConfig {\n /** Base API URL */\n baseUrl: string;\n /** Access token getter */\n getAccessToken: () => Promise<string | null>;\n}\n\n/**\n * Session/Party mapping\n */\nexport interface BronSession {\n sessionId: string;\n partyId: PartyId;\n expiresAt?: number;\n}\n\n/**\n * Signature request\n */\nexport interface BronSignRequest {\n message?: string;\n transaction?: unknown;\n sessionId: string;\n}\n\n/**\n * Signature response\n */\nexport interface BronSignResponse {\n requestId: string;\n status: 'pending' | 'approved' | 'denied';\n signature?: string;\n transactionHash?: string;\n}\n\n/**\n * Request status\n */\nexport interface BronRequestStatus {\n requestId: string;\n status: 'pending' | 'approved' | 'denied' | 'expired';\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Bron API client\n */\nexport class BronApiClient {\n private config: BronApiConfig;\n\n constructor(config: BronApiConfig) {\n this.config = config;\n }\n\n /**\n * Create authenticated request headers\n */\n private async getHeaders(): Promise<HeadersInit> {\n const token = await this.config.getAccessToken();\n if (!token) {\n throw new Error('No access token available');\n }\n\n return {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n };\n }\n\n /**\n * Create session / get party mapping\n */\n async createSession(): Promise<BronSession> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/sessions`, {\n method: 'POST',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to create session: ${error}`);\n }\n\n const data = (await response.json()) as {\n sessionId: string;\n partyId: string;\n expiresAt?: number;\n };\n\n return {\n sessionId: data.sessionId,\n partyId: toPartyId(data.partyId),\n expiresAt: data.expiresAt,\n };\n }\n\n /**\n * Request signature\n */\n async requestSignature(request: BronSignRequest): Promise<BronSignResponse> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to request signature: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied',\n signature: data.signature,\n transactionHash: data.transactionHash,\n };\n }\n\n /**\n * Get request status\n */\n async getRequestStatus(requestId: string): Promise<BronRequestStatus> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures/${requestId}`, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to get request status: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied' | 'expired',\n signature: data.signature,\n transactionHash: data.transactionHash,\n error: data.error,\n };\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron remote signer.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API on behalf of the connected party and returns\n * the raw JSON response.\n */\n async proxyLedgerApi(request: {\n requestMethod: string;\n resource: string;\n body?: string;\n sessionId: string;\n }): Promise<{ response: string }> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/ledger-proxy`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Ledger API proxy failed: ${error}`);\n }\n\n const data = (await response.json()) as { response: string };\n return { response: data.response };\n }\n\n /**\n * Poll request status until complete\n */\n async pollRequestStatus(\n requestId: string,\n timeoutMs: number = 60000,\n intervalMs: number = 2000\n ): Promise<BronRequestStatus> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const status = await this.getRequestStatus(requestId);\n\n if (status.status === 'approved' || status.status === 'denied' || status.status === 'expired') {\n return status;\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n throw new Error('Polling timeout');\n }\n}\n","import { UserRejectedError } from '@partylayer/core';\nimport type { BronAuthClient } from './auth';\n\nconst CALLBACK = 'partylayer:bron:authorization-callback';\n\n/**\n * Call from the application's registered redirect page. The popup relays only\n * to its own origin; the opener verifies the source, path, state and PKCE.\n * This helper does not register a Bron OAuth client or define vendor endpoints.\n */\nexport function completeBronAuthorization(redirectUri: string): void {\n if (typeof window === 'undefined' || !window.opener) throw new Error('Open this OAuth callback from the connecting application');\n const expected = new URL(redirectUri);\n if (window.location.origin !== expected.origin || window.location.pathname !== expected.pathname) throw new Error('Unexpected OAuth redirect page');\n const callbackUrl = window.location.href;\n window.opener.postMessage({ type: CALLBACK, callbackUrl }, expected.origin);\n // Clear authorization codes from this page's address/history after relaying.\n window.history.replaceState(null, '', expected.pathname);\n window.close();\n}\n\n/** Internal bounded popup bridge for the legacy, explicitly configured OAuth integration. */\nexport async function authorizeBronPopup(auth: BronAuthClient, redirectUri: string, timeoutMs: number): Promise<void> {\n if (typeof window === 'undefined') throw new Error('OAuth flow requires a browser environment');\n if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 300_000) throw new Error('Invalid OAuth timeout');\n const expected = new URL(redirectUri);\n if (expected.origin !== window.location.origin) throw new Error('Register a same-origin OAuth callback page');\n const url = await auth.startAuth();\n const popup = window.open(url, 'partylayer-bron-authorization', 'width=500,height=650');\n if (!popup) { auth.cancelAuthorization(); throw new Error('Allow the wallet authorization popup and try again'); }\n return new Promise<void>((resolve, reject) => {\n const signal = auth.getAuthorizationSignal();\n let callbackReceived = false;\n let finished = false;\n const finish = (error?: unknown) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer); clearInterval(closed);\n window.removeEventListener('message', receive);\n signal.removeEventListener('abort', cancel);\n if (error) auth.cancelAuthorization();\n try { popup.close(); } catch { /* Window closure does not determine the auth result. */ }\n if (error) reject(error); else resolve();\n };\n const receive = (event: MessageEvent) => {\n if (finished || callbackReceived || event.source !== popup || event.origin !== expected.origin ||\n !event.data || event.data.type !== CALLBACK || typeof event.data.callbackUrl !== 'string') return;\n callbackReceived = true;\n void auth.finishAuth(event.data.callbackUrl).then(() => finish(), error => finish(error));\n };\n const cancel = () => finish(new Error('Wallet authorization cancelled'));\n const timer = setTimeout(() => finish(new Error('Wallet authorization timed out')), timeoutMs);\n const closed = setInterval(() => {\n if (!callbackReceived && popup.closed) finish(new UserRejectedError('Wallet authorization was closed'));\n }, 250);\n window.addEventListener('message', receive);\n signal.addEventListener('abort', cancel, { once: true });\n if (signal.aborted) cancel();\n });\n}\n","/**\n * Bron Wallet Adapter\n * \n * Enterprise remote signer adapter using OAuth2 + API client.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n * - Wallet Integration Guide: https://docs.digitalasset.com/integrate/devnet/index.html\n */\n\nimport type {\n WalletAdapter,\n AdapterContext,\n AdapterDetectResult,\n AdapterConnectResult,\n SignMessageParams,\n SignTransactionParams,\n LedgerApiParams,\n LedgerApiResult,\n} from '@partylayer/core';\nimport { normalizeLedgerMethodUpper, ledgerApiBodyToString } from '@partylayer/core';\nimport {\n toWalletId,\n toSignature,\n toTransactionHash,\n UserRejectedError,\n mapUnknownErrorToPartyLayerError,\n type CapabilityKey,\n} from '@partylayer/core';\nimport { BronAuthClient, type BronAuthConfig } from './auth';\nimport { BronApiClient } from './api';\nimport { authorizeBronPopup } from './authorization';\n\n// Re-export types for convenience\nexport type { BronAuthConfig } from './auth';\nexport type { BronApiConfig } from './api';\n\n/**\n * API configuration for the Bron adapter. Only `baseUrl` is needed: the adapter\n * supplies its own access-token getter, wired to its OAuth client, so a caller\n * neither provides nor overrides one. This is deliberately narrower than the\n * internal BronApiConfig (which the API client uses and does carry a token getter).\n */\nexport interface BronAdapterApiConfig {\n /** Base URL of the Bron signer API. */\n baseUrl: string;\n}\n\n/**\n * Bron adapter configuration\n */\nexport interface BronAdapterConfig {\n /** OAuth2 configuration */\n auth: BronAuthConfig;\n /** API configuration */\n api: BronAdapterApiConfig;\n}\n\n/**\n * Bron Wallet Adapter\n */\nexport class BronAdapter implements WalletAdapter {\n readonly walletId = toWalletId('bron');\n readonly name = 'Bron';\n\n private authClient: BronAuthClient;\n private apiClient: BronApiClient;\n private redirectUri: string;\n private connecting = false;\n\n constructor(config: BronAdapterConfig) {\n // Initialize auth client\n // Tokens stored in memory by default (secure)\n // Can optionally use encrypted storage if provided\n this.authClient = new BronAuthClient(config.auth);\n this.redirectUri = config.auth.redirectUri;\n\n // Initialize the real API client. There is no URL- or environment-inferred\n // mock: a mock, if wanted for a test, must be constructed explicitly by the\n // test, never triggered by a substring in a URL or by NODE_ENV.\n this.apiClient = new BronApiClient({\n baseUrl: config.api.baseUrl,\n getAccessToken: async () => {\n return await this.authClient.getAccessToken();\n },\n });\n }\n\n getCapabilities(): CapabilityKey[] {\n return [\n 'connect',\n 'disconnect',\n 'restore',\n 'remoteSigner',\n 'signMessage',\n 'signTransaction',\n 'ledgerApi',\n ];\n }\n\n detectInstalled(): Promise<AdapterDetectResult> {\n // Bron is an enterprise remote signer - no \"installation\" required\n // Availability depends on OAuth2 configuration\n // Bron is an enterprise remote signer: no local install, and unusable\n // without OAuth credentials the app supplies. `needs-config` lets the picker\n // hide it rather than show a tile whose click dead-ends at an OAuth error —\n // which is the behaviour the SDK already had, now stated in the data.\n return Promise.resolve({\n installed: false,\n // BronAdapterConfig requires `auth`, so an instance cannot exist without\n // credentials; the unconfigured case is handled a level up by not\n // registering the adapter, which is why Bron is absent from the picker\n // rather than present and broken.\n availability: { kind: 'no-local-install' },\n reason: 'Bron is a remote signer service',\n });\n }\n\n async connect(\n ctx: AdapterContext,\n opts?: {\n timeoutMs?: number;\n requiredCapabilities?: CapabilityKey[];\n }\n ): Promise<AdapterConnectResult> {\n if (this.connecting) throw new Error('A Bron connection is already pending');\n this.connecting = true;\n try {\n // Check if we have an access token\n const accessToken = await this.authClient.getAccessToken();\n\n // If no token, start OAuth flow\n if (!accessToken) {\n await authorizeBronPopup(this.authClient, this.redirectUri, opts?.timeoutMs ?? 120_000);\n }\n\n // Create session with Bron API\n const session = await this.apiClient.createSession();\n\n return {\n partyId: session.partyId,\n session: {\n walletId: this.walletId,\n // Bron's API session does not report the connected network → not\n // wallet-reported, so network-mismatch detection is limited for this\n // adapter (echoes the requested ctx.network).\n network: ctx.network,\n createdAt: Date.now(),\n expiresAt: session.expiresAt,\n capabilitiesSnapshot: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n metadata: {\n sessionId: session.sessionId,\n },\n },\n capabilities: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'connect',\n transport: 'remote',\n });\n } finally {\n this.connecting = false;\n }\n }\n\n async disconnect(\n _ctx: AdapterContext,\n _session: import('@partylayer/core').Session\n ): Promise<void> {\n await this.authClient.logout();\n }\n\n async restore(\n _ctx: AdapterContext,\n persisted: import('@partylayer/core').PersistedSession\n ): Promise<import('@partylayer/core').Session | null> {\n // Check if we have a session ID and access token\n const sessionId = persisted.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n return null;\n }\n\n const accessToken = await this.authClient.getAccessToken();\n if (!accessToken) {\n return null; // No token to restore\n }\n\n // Check expiration\n if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {\n return null;\n }\n\n // Restore session\n return {\n ...persisted,\n walletId: this.walletId,\n };\n }\n\n async signMessage(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignMessageParams\n ): Promise<import('@partylayer/core').SignedMessage> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n message: params.message,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n return {\n message: params.message,\n signature: toSignature(status.signature),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Signature request failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n return {\n message: params.message,\n signature: toSignature(signResponse.signature),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signMessage',\n transport: 'remote',\n });\n }\n }\n\n async signTransaction(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignTransactionParams\n ): Promise<import('@partylayer/core').SignedTransaction> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n transaction: params.tx,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: status.signature }\n : { tx: params.tx, signature: status.signature };\n return {\n signedTx,\n // Was `toTransactionHash('pending')` when Bron reported no hash.\n // The field is optional now, so nothing is what gets reported.\n ...(status.transactionHash\n ? { transactionHash: toTransactionHash(status.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Transaction signing failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: signResponse.signature }\n : { tx: params.tx, signature: signResponse.signature };\n return {\n signedTx,\n ...(signResponse.transactionHash\n ? { transactionHash: toTransactionHash(signResponse.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signTransaction',\n transport: 'remote',\n });\n }\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron enterprise API.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API using the enterprise session credentials.\n */\n async ledgerApi(\n ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: LedgerApiParams,\n ): Promise<LedgerApiResult> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n ctx.logger.debug('Proxying ledger API request via Bron', {\n sessionId,\n requestMethod: params.requestMethod,\n resource: params.resource,\n });\n\n const result = await this.apiClient.proxyLedgerApi({\n requestMethod: normalizeLedgerMethodUpper(params.requestMethod),\n resource: params.resource,\n body: ledgerApiBodyToString(params.body),\n sessionId,\n });\n\n return { response: result.response };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'ledgerApi',\n transport: 'remote',\n });\n }\n }\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -8,15 +8,32 @@ var BronAuthClient = class {
|
|
|
8
8
|
storage;
|
|
9
9
|
tokens = null;
|
|
10
10
|
// In-memory by default
|
|
11
|
+
pending = null;
|
|
12
|
+
exchange = null;
|
|
13
|
+
authorization = new AbortController();
|
|
14
|
+
epoch = 0;
|
|
15
|
+
storageWrites = Promise.resolve();
|
|
16
|
+
persist(action) {
|
|
17
|
+
const write = this.storageWrites.catch(() => {
|
|
18
|
+
}).then(action);
|
|
19
|
+
this.storageWrites = write;
|
|
20
|
+
return write;
|
|
21
|
+
}
|
|
11
22
|
constructor(config, storage) {
|
|
12
|
-
|
|
23
|
+
for (const input of [config.authorizationUrl, config.tokenUrl, config.redirectUri]) {
|
|
24
|
+
const url = new URL(input);
|
|
25
|
+
if (url.username || url.password || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) throw new Error("OAuth requires trusted HTTPS URLs");
|
|
26
|
+
}
|
|
27
|
+
if (!config.clientId?.trim()) throw new Error("OAuth clientId is required");
|
|
28
|
+
if (typeof window !== "undefined" && (config.clientSecret || config.usePKCE === false)) throw new Error("Browser OAuth requires PKCE and must not contain a client secret");
|
|
29
|
+
this.config = { ...config, usePKCE: config.usePKCE ?? true };
|
|
13
30
|
this.storage = storage;
|
|
14
31
|
}
|
|
15
32
|
/**
|
|
16
33
|
* Generate PKCE code verifier and challenge
|
|
17
34
|
*/
|
|
18
35
|
async generatePKCE() {
|
|
19
|
-
const verifier = this.generateRandomString(
|
|
36
|
+
const verifier = this.generateRandomString(32);
|
|
20
37
|
const encoder = new TextEncoder();
|
|
21
38
|
const data = encoder.encode(verifier);
|
|
22
39
|
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
@@ -35,6 +52,9 @@ var BronAuthClient = class {
|
|
|
35
52
|
* Start authorization flow
|
|
36
53
|
*/
|
|
37
54
|
async startAuth() {
|
|
55
|
+
this.cancelAuthorization();
|
|
56
|
+
this.authorization = new AbortController();
|
|
57
|
+
const epoch = this.epoch;
|
|
38
58
|
const state = this.generateRandomString(32);
|
|
39
59
|
const params = new URLSearchParams({
|
|
40
60
|
response_type: "code",
|
|
@@ -47,94 +67,108 @@ var BronAuthClient = class {
|
|
|
47
67
|
const pkce = await this.generatePKCE();
|
|
48
68
|
params.set("code_challenge", pkce.challenge);
|
|
49
69
|
params.set("code_challenge_method", "S256");
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
sessionStorage.setItem("bron_auth_state", state);
|
|
53
|
-
}
|
|
70
|
+
if (epoch !== this.epoch) throw new Error("OAuth authorization cancelled");
|
|
71
|
+
this.pending = { state, verifier: pkce.verifier, expiresAt: Date.now() + 3e5 };
|
|
54
72
|
} else {
|
|
55
|
-
|
|
56
|
-
sessionStorage.setItem("bron_auth_state", state);
|
|
57
|
-
}
|
|
73
|
+
this.pending = { state, expiresAt: Date.now() + 3e5 };
|
|
58
74
|
}
|
|
59
|
-
const
|
|
60
|
-
|
|
75
|
+
const url = new URL(this.config.authorizationUrl);
|
|
76
|
+
for (const [key, value] of params) url.searchParams.set(key, value);
|
|
77
|
+
return url.href;
|
|
61
78
|
}
|
|
62
79
|
/**
|
|
63
80
|
* Finish authorization flow with callback URL
|
|
64
81
|
*/
|
|
65
82
|
async finishAuth(callbackUrl) {
|
|
66
83
|
const url = new URL(callbackUrl);
|
|
84
|
+
const redirect = new URL(this.config.redirectUri);
|
|
85
|
+
const pending = this.pending;
|
|
86
|
+
if (url.origin !== redirect.origin || url.pathname !== redirect.pathname || url.hash || url.username || url.password || [...redirect.searchParams].some(([key, value]) => url.searchParams.getAll(key).length !== 1 || url.searchParams.get(key) !== value) || !pending || pending.expiresAt <= Date.now() || url.searchParams.getAll("state").length !== 1 || url.searchParams.get("state") !== pending.state) throw new Error("Invalid or expired OAuth callback state");
|
|
87
|
+
this.pending = null;
|
|
88
|
+
if (url.searchParams.has("error")) throw new Error("OAuth authorization was declined or failed");
|
|
67
89
|
const code = url.searchParams.get("code");
|
|
68
|
-
|
|
69
|
-
const error = url.searchParams.get("error");
|
|
70
|
-
if (error) {
|
|
71
|
-
throw new Error(`OAuth error: ${error}`);
|
|
72
|
-
}
|
|
73
|
-
if (!code) {
|
|
74
|
-
throw new Error("No authorization code in callback");
|
|
75
|
-
}
|
|
76
|
-
if (typeof window !== "undefined") {
|
|
77
|
-
const storedState = sessionStorage.getItem("bron_auth_state");
|
|
78
|
-
if (state !== storedState) {
|
|
79
|
-
throw new Error("State mismatch");
|
|
80
|
-
}
|
|
81
|
-
}
|
|
90
|
+
if (!code || url.searchParams.getAll("code").length !== 1) throw new Error("No unique authorization code in callback");
|
|
82
91
|
const tokenParams = new URLSearchParams({
|
|
83
92
|
grant_type: "authorization_code",
|
|
84
93
|
code,
|
|
85
94
|
redirect_uri: this.config.redirectUri,
|
|
86
95
|
client_id: this.config.clientId
|
|
87
96
|
});
|
|
88
|
-
if (this.config.usePKCE
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
tokenParams.set("code_verifier", verifier);
|
|
92
|
-
sessionStorage.removeItem("bron_pkce_verifier");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (this.config.clientSecret) {
|
|
96
|
-
tokenParams.set("client_secret", this.config.clientSecret);
|
|
97
|
-
}
|
|
98
|
-
const response = await fetch(this.config.tokenUrl, {
|
|
99
|
-
method: "POST",
|
|
100
|
-
headers: {
|
|
101
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
102
|
-
},
|
|
103
|
-
body: tokenParams.toString()
|
|
104
|
-
});
|
|
105
|
-
if (!response.ok) {
|
|
106
|
-
const error2 = await response.text();
|
|
107
|
-
throw new Error(`Token exchange failed: ${error2}`);
|
|
108
|
-
}
|
|
109
|
-
const tokenData = await response.json();
|
|
110
|
-
const tokens = {
|
|
111
|
-
accessToken: tokenData.access_token,
|
|
112
|
-
refreshToken: tokenData.refresh_token,
|
|
113
|
-
expiresAt: Date.now() + tokenData.expires_in * 1e3,
|
|
114
|
-
tokenType: tokenData.token_type || "Bearer"
|
|
115
|
-
};
|
|
116
|
-
this.tokens = tokens;
|
|
117
|
-
if (this.storage) {
|
|
118
|
-
await this.storage.set("bron_tokens", JSON.stringify(tokens));
|
|
97
|
+
if (this.config.usePKCE) {
|
|
98
|
+
if (!pending.verifier) throw new Error("Missing PKCE verifier");
|
|
99
|
+
tokenParams.set("code_verifier", pending.verifier);
|
|
119
100
|
}
|
|
120
|
-
if (
|
|
121
|
-
|
|
101
|
+
if (this.config.clientSecret) tokenParams.set("client_secret", this.config.clientSecret);
|
|
102
|
+
const epoch = this.epoch;
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
this.exchange = controller;
|
|
105
|
+
const timer = setTimeout(() => controller.abort(), 15e3);
|
|
106
|
+
try {
|
|
107
|
+
const response = await fetch(this.config.tokenUrl, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" },
|
|
110
|
+
body: tokenParams.toString(),
|
|
111
|
+
credentials: "omit",
|
|
112
|
+
cache: "no-store",
|
|
113
|
+
redirect: "error",
|
|
114
|
+
referrerPolicy: "no-referrer",
|
|
115
|
+
signal: controller.signal
|
|
116
|
+
});
|
|
117
|
+
if (!response.ok) throw new Error("OAuth token exchange failed");
|
|
118
|
+
const raw = await response.text();
|
|
119
|
+
if (raw.length > 256e3) throw new Error("OAuth token response is too large");
|
|
120
|
+
const data = JSON.parse(raw);
|
|
121
|
+
if (!data || typeof data.access_token !== "string" || !data.access_token || data.access_token.length > 64e3 || /[\s\p{Cc}]/u.test(data.access_token) || typeof data.token_type !== "string" || data.token_type.toLowerCase() !== "bearer" || typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in) || data.expires_in <= 0 || data.expires_in > 31536e3 || data.refresh_token !== void 0 && (typeof data.refresh_token !== "string" || !data.refresh_token || /\p{Cc}/u.test(data.refresh_token))) {
|
|
122
|
+
throw new Error("Invalid OAuth token response");
|
|
123
|
+
}
|
|
124
|
+
if (controller.signal.aborted || epoch !== this.epoch) throw new Error("OAuth authorization cancelled");
|
|
125
|
+
const tokens = {
|
|
126
|
+
accessToken: data.access_token,
|
|
127
|
+
expiresAt: Date.now() + data.expires_in * 1e3,
|
|
128
|
+
tokenType: "Bearer",
|
|
129
|
+
...data.refresh_token ? { refreshToken: data.refresh_token } : {}
|
|
130
|
+
};
|
|
131
|
+
this.tokens = tokens;
|
|
132
|
+
if (this.storage) await this.persist(async () => {
|
|
133
|
+
if (epoch === this.epoch) await this.storage.set("bron_tokens", JSON.stringify(tokens));
|
|
134
|
+
});
|
|
135
|
+
if (epoch !== this.epoch) throw new Error("OAuth authorization cancelled");
|
|
136
|
+
return tokens;
|
|
137
|
+
} finally {
|
|
138
|
+
clearTimeout(timer);
|
|
139
|
+
if (this.exchange === controller) this.exchange = null;
|
|
122
140
|
}
|
|
123
|
-
|
|
141
|
+
}
|
|
142
|
+
/** Clear authorization state and abort only the in-flight token exchange. */
|
|
143
|
+
cancelAuthorization() {
|
|
144
|
+
this.authorization.abort();
|
|
145
|
+
this.epoch++;
|
|
146
|
+
this.pending = null;
|
|
147
|
+
this.exchange?.abort();
|
|
148
|
+
this.exchange = null;
|
|
149
|
+
}
|
|
150
|
+
getAuthorizationSignal() {
|
|
151
|
+
return this.authorization.signal;
|
|
124
152
|
}
|
|
125
153
|
/**
|
|
126
154
|
* Get current access token
|
|
127
155
|
*/
|
|
128
156
|
async getAccessToken() {
|
|
157
|
+
const epoch = this.epoch;
|
|
129
158
|
if (this.tokens && Date.now() < this.tokens.expiresAt) {
|
|
130
159
|
return this.tokens.accessToken;
|
|
131
160
|
}
|
|
132
161
|
if (this.storage) {
|
|
133
162
|
const stored = await this.storage.get("bron_tokens");
|
|
163
|
+
if (epoch !== this.epoch) return null;
|
|
134
164
|
if (stored) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
165
|
+
try {
|
|
166
|
+
const tokens = JSON.parse(stored);
|
|
167
|
+
if (typeof tokens.accessToken === "string" && tokens.accessToken && !/[\s\p{Cc}]/u.test(tokens.accessToken) && tokens.tokenType === "Bearer" && Number.isFinite(tokens.expiresAt) && Date.now() < tokens.expiresAt) {
|
|
168
|
+
this.tokens = tokens;
|
|
169
|
+
return tokens.accessToken;
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
138
172
|
}
|
|
139
173
|
}
|
|
140
174
|
}
|
|
@@ -144,9 +178,10 @@ var BronAuthClient = class {
|
|
|
144
178
|
* Logout
|
|
145
179
|
*/
|
|
146
180
|
async logout() {
|
|
181
|
+
this.cancelAuthorization();
|
|
147
182
|
this.tokens = null;
|
|
148
183
|
if (this.storage) {
|
|
149
|
-
await this.storage.remove("bron_tokens");
|
|
184
|
+
await this.persist(() => this.storage.remove("bron_tokens"));
|
|
150
185
|
}
|
|
151
186
|
}
|
|
152
187
|
};
|
|
@@ -268,6 +303,61 @@ var BronApiClient = class {
|
|
|
268
303
|
throw new Error("Polling timeout");
|
|
269
304
|
}
|
|
270
305
|
};
|
|
306
|
+
var CALLBACK = "partylayer:bron:authorization-callback";
|
|
307
|
+
function completeBronAuthorization(redirectUri) {
|
|
308
|
+
if (typeof window === "undefined" || !window.opener) throw new Error("Open this OAuth callback from the connecting application");
|
|
309
|
+
const expected = new URL(redirectUri);
|
|
310
|
+
if (window.location.origin !== expected.origin || window.location.pathname !== expected.pathname) throw new Error("Unexpected OAuth redirect page");
|
|
311
|
+
const callbackUrl = window.location.href;
|
|
312
|
+
window.opener.postMessage({ type: CALLBACK, callbackUrl }, expected.origin);
|
|
313
|
+
window.history.replaceState(null, "", expected.pathname);
|
|
314
|
+
window.close();
|
|
315
|
+
}
|
|
316
|
+
async function authorizeBronPopup(auth, redirectUri, timeoutMs) {
|
|
317
|
+
if (typeof window === "undefined") throw new Error("OAuth flow requires a browser environment");
|
|
318
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 3e5) throw new Error("Invalid OAuth timeout");
|
|
319
|
+
const expected = new URL(redirectUri);
|
|
320
|
+
if (expected.origin !== window.location.origin) throw new Error("Register a same-origin OAuth callback page");
|
|
321
|
+
const url = await auth.startAuth();
|
|
322
|
+
const popup = window.open(url, "partylayer-bron-authorization", "width=500,height=650");
|
|
323
|
+
if (!popup) {
|
|
324
|
+
auth.cancelAuthorization();
|
|
325
|
+
throw new Error("Allow the wallet authorization popup and try again");
|
|
326
|
+
}
|
|
327
|
+
return new Promise((resolve, reject) => {
|
|
328
|
+
const signal = auth.getAuthorizationSignal();
|
|
329
|
+
let callbackReceived = false;
|
|
330
|
+
let finished = false;
|
|
331
|
+
const finish = (error) => {
|
|
332
|
+
if (finished) return;
|
|
333
|
+
finished = true;
|
|
334
|
+
clearTimeout(timer);
|
|
335
|
+
clearInterval(closed);
|
|
336
|
+
window.removeEventListener("message", receive);
|
|
337
|
+
signal.removeEventListener("abort", cancel);
|
|
338
|
+
if (error) auth.cancelAuthorization();
|
|
339
|
+
try {
|
|
340
|
+
popup.close();
|
|
341
|
+
} catch {
|
|
342
|
+
}
|
|
343
|
+
if (error) reject(error);
|
|
344
|
+
else resolve();
|
|
345
|
+
};
|
|
346
|
+
const receive = (event) => {
|
|
347
|
+
if (finished || callbackReceived || event.source !== popup || event.origin !== expected.origin || !event.data || event.data.type !== CALLBACK || typeof event.data.callbackUrl !== "string") return;
|
|
348
|
+
callbackReceived = true;
|
|
349
|
+
void auth.finishAuth(event.data.callbackUrl).then(() => finish(), (error) => finish(error));
|
|
350
|
+
};
|
|
351
|
+
const cancel = () => finish(new Error("Wallet authorization cancelled"));
|
|
352
|
+
const timer = setTimeout(() => finish(new Error("Wallet authorization timed out")), timeoutMs);
|
|
353
|
+
const closed = setInterval(() => {
|
|
354
|
+
if (!callbackReceived && popup.closed) finish(new UserRejectedError("Wallet authorization was closed"));
|
|
355
|
+
}, 250);
|
|
356
|
+
window.addEventListener("message", receive);
|
|
357
|
+
signal.addEventListener("abort", cancel, { once: true });
|
|
358
|
+
if (signal.aborted) cancel();
|
|
359
|
+
});
|
|
360
|
+
}
|
|
271
361
|
|
|
272
362
|
// src/bron-adapter.ts
|
|
273
363
|
var BronAdapter = class {
|
|
@@ -275,8 +365,11 @@ var BronAdapter = class {
|
|
|
275
365
|
name = "Bron";
|
|
276
366
|
authClient;
|
|
277
367
|
apiClient;
|
|
368
|
+
redirectUri;
|
|
369
|
+
connecting = false;
|
|
278
370
|
constructor(config) {
|
|
279
371
|
this.authClient = new BronAuthClient(config.auth);
|
|
372
|
+
this.redirectUri = config.auth.redirectUri;
|
|
280
373
|
this.apiClient = new BronApiClient({
|
|
281
374
|
baseUrl: config.api.baseUrl,
|
|
282
375
|
getAccessToken: async () => {
|
|
@@ -306,23 +399,13 @@ var BronAdapter = class {
|
|
|
306
399
|
reason: "Bron is a remote signer service"
|
|
307
400
|
});
|
|
308
401
|
}
|
|
309
|
-
async connect(ctx,
|
|
402
|
+
async connect(ctx, opts) {
|
|
403
|
+
if (this.connecting) throw new Error("A Bron connection is already pending");
|
|
404
|
+
this.connecting = true;
|
|
310
405
|
try {
|
|
311
406
|
const accessToken = await this.authClient.getAccessToken();
|
|
312
407
|
if (!accessToken) {
|
|
313
|
-
|
|
314
|
-
throw new Error("OAuth flow requires browser environment");
|
|
315
|
-
}
|
|
316
|
-
const authUrl = await this.authClient.startAuth();
|
|
317
|
-
const popup = window.open(
|
|
318
|
-
authUrl,
|
|
319
|
-
"Bron Auth",
|
|
320
|
-
"width=500,height=600"
|
|
321
|
-
);
|
|
322
|
-
if (!popup) {
|
|
323
|
-
throw new Error("Failed to open auth popup");
|
|
324
|
-
}
|
|
325
|
-
throw new Error("OAuth callback not implemented in adapter - handle in app");
|
|
408
|
+
await authorizeBronPopup(this.authClient, this.redirectUri, opts?.timeoutMs ?? 12e4);
|
|
326
409
|
}
|
|
327
410
|
const session = await this.apiClient.createSession();
|
|
328
411
|
return {
|
|
@@ -348,6 +431,8 @@ var BronAdapter = class {
|
|
|
348
431
|
phase: "connect",
|
|
349
432
|
transport: "remote"
|
|
350
433
|
});
|
|
434
|
+
} finally {
|
|
435
|
+
this.connecting = false;
|
|
351
436
|
}
|
|
352
437
|
}
|
|
353
438
|
async disconnect(_ctx, _session) {
|
|
@@ -494,6 +579,6 @@ var BronAdapter = class {
|
|
|
494
579
|
}
|
|
495
580
|
};
|
|
496
581
|
|
|
497
|
-
export { BronAdapter };
|
|
582
|
+
export { BronAdapter, completeBronAuthorization };
|
|
498
583
|
//# sourceMappingURL=index.mjs.map
|
|
499
584
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.ts","../src/api.ts","../src/bron-adapter.ts"],"names":["error","signedTx"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Bron OAuth2 Authentication Client\n * \n * Handles OAuth2 flows for Bron enterprise wallet.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n */\n\nimport type { StorageAdapter } from '@partylayer/core';\n\n/**\n * OAuth2 configuration\n */\nexport interface BronAuthConfig {\n /** Authorization server URL */\n authorizationUrl: string;\n /** Token endpoint URL */\n tokenUrl: string;\n /** Client ID */\n clientId: string;\n /** Client secret (for server-side flows) */\n clientSecret?: string;\n /** Redirect URI */\n redirectUri: string;\n /** Scopes */\n scopes?: string[];\n /** Use PKCE (recommended for browser) */\n usePKCE?: boolean;\n}\n\n/**\n * OAuth2 tokens\n */\nexport interface BronTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number;\n tokenType: string;\n}\n\n/**\n * Bron OAuth2 client\n */\nexport class BronAuthClient {\n private config: BronAuthConfig;\n private storage?: StorageAdapter;\n private tokens: BronTokens | null = null; // In-memory by default\n\n constructor(config: BronAuthConfig, storage?: StorageAdapter) {\n this.config = config;\n this.storage = storage;\n }\n\n /**\n * Generate PKCE code verifier and challenge\n */\n private async generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n const verifier = this.generateRandomString(128);\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const challenge = btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n\n return { verifier, challenge };\n }\n\n /**\n * Generate random string\n */\n private generateRandomString(length: number): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Start authorization flow\n */\n async startAuth(): Promise<string> {\n const state = this.generateRandomString(32);\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n state,\n scope: (this.config.scopes || ['openid', 'profile']).join(' '),\n });\n\n // Add PKCE if enabled\n if (this.config.usePKCE) {\n const pkce = await this.generatePKCE();\n params.set('code_challenge', pkce.challenge);\n params.set('code_challenge_method', 'S256');\n \n // Store verifier temporarily (in sessionStorage)\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('bron_pkce_verifier', pkce.verifier);\n sessionStorage.setItem('bron_auth_state', state);\n }\n } else {\n // Store state\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('bron_auth_state', state);\n }\n }\n\n const authUrl = `${this.config.authorizationUrl}?${params.toString()}`;\n return authUrl;\n }\n\n /**\n * Finish authorization flow with callback URL\n */\n async finishAuth(callbackUrl: string): Promise<BronTokens> {\n const url = new URL(callbackUrl);\n const code = url.searchParams.get('code');\n const state = url.searchParams.get('state');\n const error = url.searchParams.get('error');\n\n if (error) {\n throw new Error(`OAuth error: ${error}`);\n }\n\n if (!code) {\n throw new Error('No authorization code in callback');\n }\n\n // Validate state\n if (typeof window !== 'undefined') {\n const storedState = sessionStorage.getItem('bron_auth_state');\n if (state !== storedState) {\n throw new Error('State mismatch');\n }\n }\n\n // Exchange code for tokens\n const tokenParams = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: this.config.redirectUri,\n client_id: this.config.clientId,\n });\n\n // Add PKCE verifier if used\n if (this.config.usePKCE && typeof window !== 'undefined') {\n const verifier = sessionStorage.getItem('bron_pkce_verifier');\n if (verifier) {\n tokenParams.set('code_verifier', verifier);\n sessionStorage.removeItem('bron_pkce_verifier');\n }\n }\n\n // Add client secret for server-side flow\n if (this.config.clientSecret) {\n tokenParams.set('client_secret', this.config.clientSecret);\n }\n\n // Request tokens\n const response = await fetch(this.config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: tokenParams.toString(),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Token exchange failed: ${error}`);\n }\n\n const tokenData = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n token_type: string;\n };\n\n const tokens: BronTokens = {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token,\n expiresAt: Date.now() + tokenData.expires_in * 1000,\n tokenType: tokenData.token_type || 'Bearer',\n };\n\n // Store tokens (in memory by default, or encrypted storage if configured)\n this.tokens = tokens;\n if (this.storage) {\n // Store encrypted (implementation depends on storage adapter)\n await this.storage.set('bron_tokens', JSON.stringify(tokens));\n }\n\n // Clean up session storage\n if (typeof window !== 'undefined') {\n sessionStorage.removeItem('bron_auth_state');\n }\n\n return tokens;\n }\n\n /**\n * Get current access token\n */\n async getAccessToken(): Promise<string | null> {\n // Check if token exists and is not expired\n if (this.tokens && Date.now() < this.tokens.expiresAt) {\n return this.tokens.accessToken;\n }\n\n // Try to load from storage\n if (this.storage) {\n const stored = await this.storage.get('bron_tokens');\n if (stored) {\n this.tokens = JSON.parse(stored) as BronTokens;\n if (Date.now() < this.tokens.expiresAt) {\n return this.tokens.accessToken;\n }\n }\n }\n\n return null;\n }\n\n /**\n * Logout\n */\n async logout(): Promise<void> {\n this.tokens = null;\n if (this.storage) {\n await this.storage.remove('bron_tokens');\n }\n }\n}\n","/**\n * Bron API Client\n * \n * Typed client for Bron enterprise wallet API endpoints.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n */\n\nimport type { PartyId } from '@partylayer/core';\nimport { toPartyId } from '@partylayer/core';\n\n/**\n * Bron API configuration\n */\nexport interface BronApiConfig {\n /** Base API URL */\n baseUrl: string;\n /** Access token getter */\n getAccessToken: () => Promise<string | null>;\n}\n\n/**\n * Session/Party mapping\n */\nexport interface BronSession {\n sessionId: string;\n partyId: PartyId;\n expiresAt?: number;\n}\n\n/**\n * Signature request\n */\nexport interface BronSignRequest {\n message?: string;\n transaction?: unknown;\n sessionId: string;\n}\n\n/**\n * Signature response\n */\nexport interface BronSignResponse {\n requestId: string;\n status: 'pending' | 'approved' | 'denied';\n signature?: string;\n transactionHash?: string;\n}\n\n/**\n * Request status\n */\nexport interface BronRequestStatus {\n requestId: string;\n status: 'pending' | 'approved' | 'denied' | 'expired';\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Bron API client\n */\nexport class BronApiClient {\n private config: BronApiConfig;\n\n constructor(config: BronApiConfig) {\n this.config = config;\n }\n\n /**\n * Create authenticated request headers\n */\n private async getHeaders(): Promise<HeadersInit> {\n const token = await this.config.getAccessToken();\n if (!token) {\n throw new Error('No access token available');\n }\n\n return {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n };\n }\n\n /**\n * Create session / get party mapping\n */\n async createSession(): Promise<BronSession> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/sessions`, {\n method: 'POST',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to create session: ${error}`);\n }\n\n const data = (await response.json()) as {\n sessionId: string;\n partyId: string;\n expiresAt?: number;\n };\n\n return {\n sessionId: data.sessionId,\n partyId: toPartyId(data.partyId),\n expiresAt: data.expiresAt,\n };\n }\n\n /**\n * Request signature\n */\n async requestSignature(request: BronSignRequest): Promise<BronSignResponse> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to request signature: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied',\n signature: data.signature,\n transactionHash: data.transactionHash,\n };\n }\n\n /**\n * Get request status\n */\n async getRequestStatus(requestId: string): Promise<BronRequestStatus> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures/${requestId}`, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to get request status: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied' | 'expired',\n signature: data.signature,\n transactionHash: data.transactionHash,\n error: data.error,\n };\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron remote signer.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API on behalf of the connected party and returns\n * the raw JSON response.\n */\n async proxyLedgerApi(request: {\n requestMethod: string;\n resource: string;\n body?: string;\n sessionId: string;\n }): Promise<{ response: string }> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/ledger-proxy`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Ledger API proxy failed: ${error}`);\n }\n\n const data = (await response.json()) as { response: string };\n return { response: data.response };\n }\n\n /**\n * Poll request status until complete\n */\n async pollRequestStatus(\n requestId: string,\n timeoutMs: number = 60000,\n intervalMs: number = 2000\n ): Promise<BronRequestStatus> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const status = await this.getRequestStatus(requestId);\n\n if (status.status === 'approved' || status.status === 'denied' || status.status === 'expired') {\n return status;\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n throw new Error('Polling timeout');\n }\n}\n","/**\n * Bron Wallet Adapter\n * \n * Enterprise remote signer adapter using OAuth2 + API client.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n * - Wallet Integration Guide: https://docs.digitalasset.com/integrate/devnet/index.html\n */\n\nimport type {\n WalletAdapter,\n AdapterContext,\n AdapterDetectResult,\n AdapterConnectResult,\n SignMessageParams,\n SignTransactionParams,\n LedgerApiParams,\n LedgerApiResult,\n} from '@partylayer/core';\nimport { normalizeLedgerMethodUpper, ledgerApiBodyToString } from '@partylayer/core';\nimport {\n toWalletId,\n toSignature,\n toTransactionHash,\n UserRejectedError,\n mapUnknownErrorToPartyLayerError,\n type CapabilityKey,\n} from '@partylayer/core';\nimport { BronAuthClient, type BronAuthConfig } from './auth';\nimport { BronApiClient } from './api';\n\n// Re-export types for convenience\nexport type { BronAuthConfig } from './auth';\nexport type { BronApiConfig } from './api';\n\n/**\n * API configuration for the Bron adapter. Only `baseUrl` is needed: the adapter\n * supplies its own access-token getter, wired to its OAuth client, so a caller\n * neither provides nor overrides one. This is deliberately narrower than the\n * internal BronApiConfig (which the API client uses and does carry a token getter).\n */\nexport interface BronAdapterApiConfig {\n /** Base URL of the Bron signer API. */\n baseUrl: string;\n}\n\n/**\n * Bron adapter configuration\n */\nexport interface BronAdapterConfig {\n /** OAuth2 configuration */\n auth: BronAuthConfig;\n /** API configuration */\n api: BronAdapterApiConfig;\n}\n\n/**\n * Bron Wallet Adapter\n */\nexport class BronAdapter implements WalletAdapter {\n readonly walletId = toWalletId('bron');\n readonly name = 'Bron';\n\n private authClient: BronAuthClient;\n private apiClient: BronApiClient;\n\n constructor(config: BronAdapterConfig) {\n // Initialize auth client\n // Tokens stored in memory by default (secure)\n // Can optionally use encrypted storage if provided\n this.authClient = new BronAuthClient(config.auth);\n\n // Initialize the real API client. There is no URL- or environment-inferred\n // mock: a mock, if wanted for a test, must be constructed explicitly by the\n // test, never triggered by a substring in a URL or by NODE_ENV.\n this.apiClient = new BronApiClient({\n baseUrl: config.api.baseUrl,\n getAccessToken: async () => {\n return await this.authClient.getAccessToken();\n },\n });\n }\n\n getCapabilities(): CapabilityKey[] {\n return [\n 'connect',\n 'disconnect',\n 'restore',\n 'remoteSigner',\n 'signMessage',\n 'signTransaction',\n 'ledgerApi',\n ];\n }\n\n detectInstalled(): Promise<AdapterDetectResult> {\n // Bron is an enterprise remote signer - no \"installation\" required\n // Availability depends on OAuth2 configuration\n // Bron is an enterprise remote signer: no local install, and unusable\n // without OAuth credentials the app supplies. `needs-config` lets the picker\n // hide it rather than show a tile whose click dead-ends at an OAuth error —\n // which is the behaviour the SDK already had, now stated in the data.\n return Promise.resolve({\n installed: false,\n // BronAdapterConfig requires `auth`, so an instance cannot exist without\n // credentials; the unconfigured case is handled a level up by not\n // registering the adapter, which is why Bron is absent from the picker\n // rather than present and broken.\n availability: { kind: 'no-local-install' },\n reason: 'Bron is a remote signer service',\n });\n }\n\n async connect(\n ctx: AdapterContext,\n _opts?: {\n timeoutMs?: number;\n requiredCapabilities?: CapabilityKey[];\n }\n ): Promise<AdapterConnectResult> {\n try {\n // Check if we have an access token\n const accessToken = await this.authClient.getAccessToken();\n\n // If no token, start OAuth flow\n if (!accessToken) {\n if (typeof window === 'undefined') {\n throw new Error('OAuth flow requires browser environment');\n }\n\n const authUrl = await this.authClient.startAuth();\n \n // Open auth URL (popup or redirect)\n const popup = window.open(\n authUrl,\n 'Bron Auth',\n 'width=500,height=600'\n );\n\n if (!popup) {\n throw new Error('Failed to open auth popup');\n }\n\n // The OAuth callback (finishAuth with the returned code) must be handled\n // by the app; the adapter has no redirect handler of its own. Fail loudly\n // rather than fabricating a token — there is no dev/mock shortcut.\n throw new Error('OAuth callback not implemented in adapter - handle in app');\n }\n\n // Create session with Bron API\n const session = await this.apiClient.createSession();\n\n return {\n partyId: session.partyId,\n session: {\n walletId: this.walletId,\n // Bron's API session does not report the connected network → not\n // wallet-reported, so network-mismatch detection is limited for this\n // adapter (echoes the requested ctx.network).\n network: ctx.network,\n createdAt: Date.now(),\n expiresAt: session.expiresAt,\n capabilitiesSnapshot: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n metadata: {\n sessionId: session.sessionId,\n },\n },\n capabilities: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'connect',\n transport: 'remote',\n });\n }\n }\n\n async disconnect(\n _ctx: AdapterContext,\n _session: import('@partylayer/core').Session\n ): Promise<void> {\n await this.authClient.logout();\n }\n\n async restore(\n _ctx: AdapterContext,\n persisted: import('@partylayer/core').PersistedSession\n ): Promise<import('@partylayer/core').Session | null> {\n // Check if we have a session ID and access token\n const sessionId = persisted.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n return null;\n }\n\n const accessToken = await this.authClient.getAccessToken();\n if (!accessToken) {\n return null; // No token to restore\n }\n\n // Check expiration\n if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {\n return null;\n }\n\n // Restore session\n return {\n ...persisted,\n walletId: this.walletId,\n };\n }\n\n async signMessage(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignMessageParams\n ): Promise<import('@partylayer/core').SignedMessage> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n message: params.message,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n return {\n message: params.message,\n signature: toSignature(status.signature),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Signature request failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n return {\n message: params.message,\n signature: toSignature(signResponse.signature),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signMessage',\n transport: 'remote',\n });\n }\n }\n\n async signTransaction(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignTransactionParams\n ): Promise<import('@partylayer/core').SignedTransaction> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n transaction: params.tx,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: status.signature }\n : { tx: params.tx, signature: status.signature };\n return {\n signedTx,\n // Was `toTransactionHash('pending')` when Bron reported no hash.\n // The field is optional now, so nothing is what gets reported.\n ...(status.transactionHash\n ? { transactionHash: toTransactionHash(status.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Transaction signing failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: signResponse.signature }\n : { tx: params.tx, signature: signResponse.signature };\n return {\n signedTx,\n ...(signResponse.transactionHash\n ? { transactionHash: toTransactionHash(signResponse.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signTransaction',\n transport: 'remote',\n });\n }\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron enterprise API.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API using the enterprise session credentials.\n */\n async ledgerApi(\n ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: LedgerApiParams,\n ): Promise<LedgerApiResult> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n ctx.logger.debug('Proxying ledger API request via Bron', {\n sessionId,\n requestMethod: params.requestMethod,\n resource: params.resource,\n });\n\n const result = await this.apiClient.proxyLedgerApi({\n requestMethod: normalizeLedgerMethodUpper(params.requestMethod),\n resource: params.resource,\n body: ledgerApiBodyToString(params.body),\n sessionId,\n });\n\n return { response: result.response };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'ledgerApi',\n transport: 'remote',\n });\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts","../src/api.ts","../src/authorization.ts","../src/bron-adapter.ts"],"names":["UserRejectedError","signedTx"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Bron OAuth2 Authentication Client\n * \n * Handles OAuth2 flows for Bron enterprise wallet.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n */\n\nimport type { StorageAdapter } from '@partylayer/core';\n\n/**\n * OAuth2 configuration\n */\nexport interface BronAuthConfig {\n /** Authorization server URL */\n authorizationUrl: string;\n /** Token endpoint URL */\n tokenUrl: string;\n /** Client ID */\n clientId: string;\n /** Client secret (for server-side flows) */\n clientSecret?: string;\n /** Redirect URI */\n redirectUri: string;\n /** Scopes */\n scopes?: string[];\n /** PKCE defaults to true and is required in browsers. */\n usePKCE?: boolean;\n}\n\n/**\n * OAuth2 tokens\n */\nexport interface BronTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number;\n tokenType: string;\n}\n\n/**\n * Bron OAuth2 client\n */\nexport class BronAuthClient {\n private config: BronAuthConfig;\n private storage?: StorageAdapter;\n private tokens: BronTokens | null = null; // In-memory by default\n private pending: { state: string; verifier?: string; expiresAt: number } | null = null;\n private exchange: AbortController | null = null;\n private authorization = new AbortController();\n private epoch = 0;\n private storageWrites: Promise<void> = Promise.resolve();\n\n private persist(action: () => Promise<void>): Promise<void> {\n const write = this.storageWrites.catch(() => {}).then(action);\n this.storageWrites = write;\n return write;\n }\n\n constructor(config: BronAuthConfig, storage?: StorageAdapter) {\n for (const input of [config.authorizationUrl, config.tokenUrl, config.redirectUri]) {\n const url = new URL(input);\n if (url.username || url.password || url.hash || (url.protocol !== 'https:' &&\n !(url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)))) throw new Error('OAuth requires trusted HTTPS URLs');\n }\n if (!config.clientId?.trim()) throw new Error('OAuth clientId is required');\n if (typeof window !== 'undefined' && (config.clientSecret || config.usePKCE === false)) throw new Error('Browser OAuth requires PKCE and must not contain a client secret');\n this.config = { ...config, usePKCE: config.usePKCE ?? true };\n this.storage = storage;\n }\n\n /**\n * Generate PKCE code verifier and challenge\n */\n private async generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n // 32 random bytes produce a 64-character RFC 7636 verifier (43–128 chars).\n const verifier = this.generateRandomString(32);\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const digest = await crypto.subtle.digest('SHA-256', data);\n const challenge = btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n\n return { verifier, challenge };\n }\n\n /**\n * Generate random string\n */\n private generateRandomString(length: number): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Start authorization flow\n */\n async startAuth(): Promise<string> {\n this.cancelAuthorization();\n this.authorization = new AbortController();\n const epoch = this.epoch;\n const state = this.generateRandomString(32);\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n state,\n scope: (this.config.scopes || ['openid', 'profile']).join(' '),\n });\n\n // Add PKCE if enabled\n if (this.config.usePKCE) {\n const pkce = await this.generatePKCE();\n params.set('code_challenge', pkce.challenge);\n params.set('code_challenge_method', 'S256');\n \n if (epoch !== this.epoch) throw new Error('OAuth authorization cancelled');\n this.pending = { state, verifier: pkce.verifier, expiresAt: Date.now() + 300_000 };\n } else {\n this.pending = { state, expiresAt: Date.now() + 300_000 };\n }\n\n const url = new URL(this.config.authorizationUrl);\n for (const [key, value] of params) url.searchParams.set(key, value);\n return url.href;\n }\n\n /**\n * Finish authorization flow with callback URL\n */\n async finishAuth(callbackUrl: string): Promise<BronTokens> {\n const url = new URL(callbackUrl);\n const redirect = new URL(this.config.redirectUri);\n const pending = this.pending;\n if (url.origin !== redirect.origin || url.pathname !== redirect.pathname || url.hash || url.username || url.password ||\n [...redirect.searchParams].some(([key, value]) => url.searchParams.getAll(key).length !== 1 || url.searchParams.get(key) !== value) ||\n !pending || pending.expiresAt <= Date.now() || url.searchParams.getAll('state').length !== 1 ||\n url.searchParams.get('state') !== pending.state) throw new Error('Invalid or expired OAuth callback state');\n // Consume before the asynchronous token request, including provider errors.\n this.pending = null;\n if (url.searchParams.has('error')) throw new Error('OAuth authorization was declined or failed');\n const code = url.searchParams.get('code');\n if (!code || url.searchParams.getAll('code').length !== 1) throw new Error('No unique authorization code in callback');\n const tokenParams = new URLSearchParams({ grant_type: 'authorization_code', code,\n redirect_uri: this.config.redirectUri, client_id: this.config.clientId });\n if (this.config.usePKCE) {\n if (!pending.verifier) throw new Error('Missing PKCE verifier');\n tokenParams.set('code_verifier', pending.verifier);\n }\n if (this.config.clientSecret) tokenParams.set('client_secret', this.config.clientSecret);\n const epoch = this.epoch;\n const controller = new AbortController(); this.exchange = controller;\n const timer = setTimeout(() => controller.abort(), 15_000);\n try {\n const response = await fetch(this.config.tokenUrl, {\n method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },\n body: tokenParams.toString(), credentials: 'omit', cache: 'no-store', redirect: 'error',\n referrerPolicy: 'no-referrer', signal: controller.signal,\n });\n if (!response.ok) throw new Error('OAuth token exchange failed');\n const raw = await response.text();\n if (raw.length > 256_000) throw new Error('OAuth token response is too large');\n const data = JSON.parse(raw);\n if (!data || typeof data.access_token !== 'string' || !data.access_token || data.access_token.length > 64_000 ||\n /[\\s\\p{Cc}]/u.test(data.access_token) || typeof data.token_type !== 'string' || data.token_type.toLowerCase() !== 'bearer' ||\n typeof data.expires_in !== 'number' || !Number.isFinite(data.expires_in) || data.expires_in <= 0 || data.expires_in > 31_536_000 ||\n (data.refresh_token !== undefined && (typeof data.refresh_token !== 'string' || !data.refresh_token || /\\p{Cc}/u.test(data.refresh_token)))) {\n throw new Error('Invalid OAuth token response');\n }\n if (controller.signal.aborted || epoch !== this.epoch) throw new Error('OAuth authorization cancelled');\n const tokens: BronTokens = { accessToken: data.access_token, expiresAt: Date.now() + data.expires_in * 1000,\n tokenType: 'Bearer', ...(data.refresh_token ? { refreshToken: data.refresh_token } : {}) };\n this.tokens = tokens;\n // A custom storage adapter is app-owned; it is not encrypted by this class.\n if (this.storage) await this.persist(async () => {\n if (epoch === this.epoch) await this.storage!.set('bron_tokens', JSON.stringify(tokens));\n });\n if (epoch !== this.epoch) throw new Error('OAuth authorization cancelled');\n return tokens;\n } finally {\n clearTimeout(timer); if (this.exchange === controller) this.exchange = null;\n }\n }\n\n /** Clear authorization state and abort only the in-flight token exchange. */\n cancelAuthorization(): void {\n this.authorization.abort();\n this.epoch++; this.pending = null; this.exchange?.abort(); this.exchange = null;\n }\n\n getAuthorizationSignal(): AbortSignal { return this.authorization.signal; }\n\n /**\n * Get current access token\n */\n async getAccessToken(): Promise<string | null> {\n const epoch = this.epoch;\n // Check if token exists and is not expired\n if (this.tokens && Date.now() < this.tokens.expiresAt) {\n return this.tokens.accessToken;\n }\n\n // Try to load from storage\n if (this.storage) {\n const stored = await this.storage.get('bron_tokens');\n if (epoch !== this.epoch) return null;\n if (stored) {\n try {\n const tokens = JSON.parse(stored) as BronTokens;\n if (typeof tokens.accessToken === 'string' && tokens.accessToken && !/[\\s\\p{Cc}]/u.test(tokens.accessToken) &&\n tokens.tokenType === 'Bearer' && Number.isFinite(tokens.expiresAt) && Date.now() < tokens.expiresAt) {\n this.tokens = tokens; return tokens.accessToken;\n }\n } catch { /* Invalid persisted data never establishes an authenticated session. */ }\n }\n }\n\n return null;\n }\n\n /**\n * Logout\n */\n async logout(): Promise<void> {\n this.cancelAuthorization();\n this.tokens = null;\n if (this.storage) {\n await this.persist(() => this.storage!.remove('bron_tokens'));\n }\n }\n}\n","/**\n * Bron API Client\n * \n * Typed client for Bron enterprise wallet API endpoints.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n */\n\nimport type { PartyId } from '@partylayer/core';\nimport { toPartyId } from '@partylayer/core';\n\n/**\n * Bron API configuration\n */\nexport interface BronApiConfig {\n /** Base API URL */\n baseUrl: string;\n /** Access token getter */\n getAccessToken: () => Promise<string | null>;\n}\n\n/**\n * Session/Party mapping\n */\nexport interface BronSession {\n sessionId: string;\n partyId: PartyId;\n expiresAt?: number;\n}\n\n/**\n * Signature request\n */\nexport interface BronSignRequest {\n message?: string;\n transaction?: unknown;\n sessionId: string;\n}\n\n/**\n * Signature response\n */\nexport interface BronSignResponse {\n requestId: string;\n status: 'pending' | 'approved' | 'denied';\n signature?: string;\n transactionHash?: string;\n}\n\n/**\n * Request status\n */\nexport interface BronRequestStatus {\n requestId: string;\n status: 'pending' | 'approved' | 'denied' | 'expired';\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Bron API client\n */\nexport class BronApiClient {\n private config: BronApiConfig;\n\n constructor(config: BronApiConfig) {\n this.config = config;\n }\n\n /**\n * Create authenticated request headers\n */\n private async getHeaders(): Promise<HeadersInit> {\n const token = await this.config.getAccessToken();\n if (!token) {\n throw new Error('No access token available');\n }\n\n return {\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n };\n }\n\n /**\n * Create session / get party mapping\n */\n async createSession(): Promise<BronSession> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/sessions`, {\n method: 'POST',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to create session: ${error}`);\n }\n\n const data = (await response.json()) as {\n sessionId: string;\n partyId: string;\n expiresAt?: number;\n };\n\n return {\n sessionId: data.sessionId,\n partyId: toPartyId(data.partyId),\n expiresAt: data.expiresAt,\n };\n }\n\n /**\n * Request signature\n */\n async requestSignature(request: BronSignRequest): Promise<BronSignResponse> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to request signature: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied',\n signature: data.signature,\n transactionHash: data.transactionHash,\n };\n }\n\n /**\n * Get request status\n */\n async getRequestStatus(requestId: string): Promise<BronRequestStatus> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/signatures/${requestId}`, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to get request status: ${error}`);\n }\n\n const data = (await response.json()) as {\n requestId: string;\n status: string;\n signature?: string;\n transactionHash?: string;\n error?: {\n code: string;\n message: string;\n };\n };\n\n return {\n requestId: data.requestId,\n status: data.status as 'pending' | 'approved' | 'denied' | 'expired',\n signature: data.signature,\n transactionHash: data.transactionHash,\n error: data.error,\n };\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron remote signer.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API on behalf of the connected party and returns\n * the raw JSON response.\n */\n async proxyLedgerApi(request: {\n requestMethod: string;\n resource: string;\n body?: string;\n sessionId: string;\n }): Promise<{ response: string }> {\n const headers = await this.getHeaders();\n const response = await fetch(`${this.config.baseUrl}/ledger-proxy`, {\n method: 'POST',\n headers,\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Ledger API proxy failed: ${error}`);\n }\n\n const data = (await response.json()) as { response: string };\n return { response: data.response };\n }\n\n /**\n * Poll request status until complete\n */\n async pollRequestStatus(\n requestId: string,\n timeoutMs: number = 60000,\n intervalMs: number = 2000\n ): Promise<BronRequestStatus> {\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const status = await this.getRequestStatus(requestId);\n\n if (status.status === 'approved' || status.status === 'denied' || status.status === 'expired') {\n return status;\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n throw new Error('Polling timeout');\n }\n}\n","import { UserRejectedError } from '@partylayer/core';\nimport type { BronAuthClient } from './auth';\n\nconst CALLBACK = 'partylayer:bron:authorization-callback';\n\n/**\n * Call from the application's registered redirect page. The popup relays only\n * to its own origin; the opener verifies the source, path, state and PKCE.\n * This helper does not register a Bron OAuth client or define vendor endpoints.\n */\nexport function completeBronAuthorization(redirectUri: string): void {\n if (typeof window === 'undefined' || !window.opener) throw new Error('Open this OAuth callback from the connecting application');\n const expected = new URL(redirectUri);\n if (window.location.origin !== expected.origin || window.location.pathname !== expected.pathname) throw new Error('Unexpected OAuth redirect page');\n const callbackUrl = window.location.href;\n window.opener.postMessage({ type: CALLBACK, callbackUrl }, expected.origin);\n // Clear authorization codes from this page's address/history after relaying.\n window.history.replaceState(null, '', expected.pathname);\n window.close();\n}\n\n/** Internal bounded popup bridge for the legacy, explicitly configured OAuth integration. */\nexport async function authorizeBronPopup(auth: BronAuthClient, redirectUri: string, timeoutMs: number): Promise<void> {\n if (typeof window === 'undefined') throw new Error('OAuth flow requires a browser environment');\n if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 300_000) throw new Error('Invalid OAuth timeout');\n const expected = new URL(redirectUri);\n if (expected.origin !== window.location.origin) throw new Error('Register a same-origin OAuth callback page');\n const url = await auth.startAuth();\n const popup = window.open(url, 'partylayer-bron-authorization', 'width=500,height=650');\n if (!popup) { auth.cancelAuthorization(); throw new Error('Allow the wallet authorization popup and try again'); }\n return new Promise<void>((resolve, reject) => {\n const signal = auth.getAuthorizationSignal();\n let callbackReceived = false;\n let finished = false;\n const finish = (error?: unknown) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer); clearInterval(closed);\n window.removeEventListener('message', receive);\n signal.removeEventListener('abort', cancel);\n if (error) auth.cancelAuthorization();\n try { popup.close(); } catch { /* Window closure does not determine the auth result. */ }\n if (error) reject(error); else resolve();\n };\n const receive = (event: MessageEvent) => {\n if (finished || callbackReceived || event.source !== popup || event.origin !== expected.origin ||\n !event.data || event.data.type !== CALLBACK || typeof event.data.callbackUrl !== 'string') return;\n callbackReceived = true;\n void auth.finishAuth(event.data.callbackUrl).then(() => finish(), error => finish(error));\n };\n const cancel = () => finish(new Error('Wallet authorization cancelled'));\n const timer = setTimeout(() => finish(new Error('Wallet authorization timed out')), timeoutMs);\n const closed = setInterval(() => {\n if (!callbackReceived && popup.closed) finish(new UserRejectedError('Wallet authorization was closed'));\n }, 250);\n window.addEventListener('message', receive);\n signal.addEventListener('abort', cancel, { once: true });\n if (signal.aborted) cancel();\n });\n}\n","/**\n * Bron Wallet Adapter\n * \n * Enterprise remote signer adapter using OAuth2 + API client.\n * \n * References:\n * - Bron developer portal: https://developer.bron.org/\n * - Bron ecosystem: https://www.canton.network/ecosystem/bron-wallet\n * - Wallet Integration Guide: https://docs.digitalasset.com/integrate/devnet/index.html\n */\n\nimport type {\n WalletAdapter,\n AdapterContext,\n AdapterDetectResult,\n AdapterConnectResult,\n SignMessageParams,\n SignTransactionParams,\n LedgerApiParams,\n LedgerApiResult,\n} from '@partylayer/core';\nimport { normalizeLedgerMethodUpper, ledgerApiBodyToString } from '@partylayer/core';\nimport {\n toWalletId,\n toSignature,\n toTransactionHash,\n UserRejectedError,\n mapUnknownErrorToPartyLayerError,\n type CapabilityKey,\n} from '@partylayer/core';\nimport { BronAuthClient, type BronAuthConfig } from './auth';\nimport { BronApiClient } from './api';\nimport { authorizeBronPopup } from './authorization';\n\n// Re-export types for convenience\nexport type { BronAuthConfig } from './auth';\nexport type { BronApiConfig } from './api';\n\n/**\n * API configuration for the Bron adapter. Only `baseUrl` is needed: the adapter\n * supplies its own access-token getter, wired to its OAuth client, so a caller\n * neither provides nor overrides one. This is deliberately narrower than the\n * internal BronApiConfig (which the API client uses and does carry a token getter).\n */\nexport interface BronAdapterApiConfig {\n /** Base URL of the Bron signer API. */\n baseUrl: string;\n}\n\n/**\n * Bron adapter configuration\n */\nexport interface BronAdapterConfig {\n /** OAuth2 configuration */\n auth: BronAuthConfig;\n /** API configuration */\n api: BronAdapterApiConfig;\n}\n\n/**\n * Bron Wallet Adapter\n */\nexport class BronAdapter implements WalletAdapter {\n readonly walletId = toWalletId('bron');\n readonly name = 'Bron';\n\n private authClient: BronAuthClient;\n private apiClient: BronApiClient;\n private redirectUri: string;\n private connecting = false;\n\n constructor(config: BronAdapterConfig) {\n // Initialize auth client\n // Tokens stored in memory by default (secure)\n // Can optionally use encrypted storage if provided\n this.authClient = new BronAuthClient(config.auth);\n this.redirectUri = config.auth.redirectUri;\n\n // Initialize the real API client. There is no URL- or environment-inferred\n // mock: a mock, if wanted for a test, must be constructed explicitly by the\n // test, never triggered by a substring in a URL or by NODE_ENV.\n this.apiClient = new BronApiClient({\n baseUrl: config.api.baseUrl,\n getAccessToken: async () => {\n return await this.authClient.getAccessToken();\n },\n });\n }\n\n getCapabilities(): CapabilityKey[] {\n return [\n 'connect',\n 'disconnect',\n 'restore',\n 'remoteSigner',\n 'signMessage',\n 'signTransaction',\n 'ledgerApi',\n ];\n }\n\n detectInstalled(): Promise<AdapterDetectResult> {\n // Bron is an enterprise remote signer - no \"installation\" required\n // Availability depends on OAuth2 configuration\n // Bron is an enterprise remote signer: no local install, and unusable\n // without OAuth credentials the app supplies. `needs-config` lets the picker\n // hide it rather than show a tile whose click dead-ends at an OAuth error —\n // which is the behaviour the SDK already had, now stated in the data.\n return Promise.resolve({\n installed: false,\n // BronAdapterConfig requires `auth`, so an instance cannot exist without\n // credentials; the unconfigured case is handled a level up by not\n // registering the adapter, which is why Bron is absent from the picker\n // rather than present and broken.\n availability: { kind: 'no-local-install' },\n reason: 'Bron is a remote signer service',\n });\n }\n\n async connect(\n ctx: AdapterContext,\n opts?: {\n timeoutMs?: number;\n requiredCapabilities?: CapabilityKey[];\n }\n ): Promise<AdapterConnectResult> {\n if (this.connecting) throw new Error('A Bron connection is already pending');\n this.connecting = true;\n try {\n // Check if we have an access token\n const accessToken = await this.authClient.getAccessToken();\n\n // If no token, start OAuth flow\n if (!accessToken) {\n await authorizeBronPopup(this.authClient, this.redirectUri, opts?.timeoutMs ?? 120_000);\n }\n\n // Create session with Bron API\n const session = await this.apiClient.createSession();\n\n return {\n partyId: session.partyId,\n session: {\n walletId: this.walletId,\n // Bron's API session does not report the connected network → not\n // wallet-reported, so network-mismatch detection is limited for this\n // adapter (echoes the requested ctx.network).\n network: ctx.network,\n createdAt: Date.now(),\n expiresAt: session.expiresAt,\n capabilitiesSnapshot: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n metadata: {\n sessionId: session.sessionId,\n },\n },\n capabilities: ['connect', 'signMessage', 'signTransaction', 'remoteSigner'],\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'connect',\n transport: 'remote',\n });\n } finally {\n this.connecting = false;\n }\n }\n\n async disconnect(\n _ctx: AdapterContext,\n _session: import('@partylayer/core').Session\n ): Promise<void> {\n await this.authClient.logout();\n }\n\n async restore(\n _ctx: AdapterContext,\n persisted: import('@partylayer/core').PersistedSession\n ): Promise<import('@partylayer/core').Session | null> {\n // Check if we have a session ID and access token\n const sessionId = persisted.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n return null;\n }\n\n const accessToken = await this.authClient.getAccessToken();\n if (!accessToken) {\n return null; // No token to restore\n }\n\n // Check expiration\n if (persisted.expiresAt && Date.now() >= persisted.expiresAt) {\n return null;\n }\n\n // Restore session\n return {\n ...persisted,\n walletId: this.walletId,\n };\n }\n\n async signMessage(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignMessageParams\n ): Promise<import('@partylayer/core').SignedMessage> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n message: params.message,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n return {\n message: params.message,\n signature: toSignature(status.signature),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Signature request failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Signature request denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n return {\n message: params.message,\n signature: toSignature(signResponse.signature),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signMessage',\n transport: 'remote',\n });\n }\n }\n\n async signTransaction(\n _ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: SignTransactionParams\n ): Promise<import('@partylayer/core').SignedTransaction> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n // Request signature\n const signResponse = await this.apiClient.requestSignature({\n transaction: params.tx,\n sessionId,\n });\n\n // If pending, poll for status\n if (signResponse.status === 'pending') {\n const status = await this.apiClient.pollRequestStatus(signResponse.requestId);\n \n if (status.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (status.status === 'approved' && status.signature) {\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: status.signature }\n : { tx: params.tx, signature: status.signature };\n return {\n signedTx,\n // Was `toTransactionHash('pending')` when Bron reported no hash.\n // The field is optional now, so nothing is what gets reported.\n ...(status.transactionHash\n ? { transactionHash: toTransactionHash(status.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n }\n\n throw new Error('Transaction signing failed');\n }\n\n if (signResponse.status === 'denied') {\n throw new UserRejectedError('Transaction signing denied');\n }\n\n if (!signResponse.signature) {\n throw new Error('No signature in response');\n }\n\n const signedTx = typeof params.tx === 'object' && params.tx !== null\n ? { ...params.tx as Record<string, unknown>, signature: signResponse.signature }\n : { tx: params.tx, signature: signResponse.signature };\n return {\n signedTx,\n ...(signResponse.transactionHash\n ? { transactionHash: toTransactionHash(signResponse.transactionHash) }\n : {}),\n partyId: session.partyId,\n };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'signTransaction',\n transport: 'remote',\n });\n }\n }\n\n /**\n * Proxy a Canton Ledger API request through the Bron enterprise API.\n *\n * Bron acts as an authenticated HTTP proxy — it forwards the request\n * to the Canton Ledger API using the enterprise session credentials.\n */\n async ledgerApi(\n ctx: AdapterContext,\n session: import('@partylayer/core').Session,\n params: LedgerApiParams,\n ): Promise<LedgerApiResult> {\n try {\n const sessionId = session.metadata?.sessionId;\n if (typeof sessionId !== 'string') {\n throw new Error('No session ID');\n }\n\n ctx.logger.debug('Proxying ledger API request via Bron', {\n sessionId,\n requestMethod: params.requestMethod,\n resource: params.resource,\n });\n\n const result = await this.apiClient.proxyLedgerApi({\n requestMethod: normalizeLedgerMethodUpper(params.requestMethod),\n resource: params.resource,\n body: ledgerApiBodyToString(params.body),\n sessionId,\n });\n\n return { response: result.response };\n } catch (err) {\n throw mapUnknownErrorToPartyLayerError(err, {\n walletId: this.walletId,\n phase: 'ledgerApi',\n transport: 'remote',\n });\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@partylayer/adapter-bron",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"description": "Bron Wallet adapter for PartyLayer",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"url": "https://github.com/PartyLayer/PartyLayer/issues"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@partylayer/core": "^0.
|
|
36
|
+
"@partylayer/core": "^0.16.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^20.11.0",
|