@joeywallet/wallet-sdk 0.2.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/LICENSE +21 -0
- package/README.md +705 -0
- package/dist/client.d.ts +55 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +224 -0
- package/dist/client.js.map +1 -0
- package/dist/detect.d.ts +45 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +238 -0
- package/dist/detect.js.map +1 -0
- package/dist/errors.d.ts +75 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +120 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/mutation.d.ts +46 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +67 -0
- package/dist/mutation.js.map +1 -0
- package/dist/provider.d.ts +159 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +142 -0
- package/dist/provider.js.map +1 -0
- package/dist/react.d.ts +76 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +225 -0
- package/dist/react.js.map +1 -0
- package/dist/types.d.ts +391 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +38 -0
- package/dist/types.js.map +1 -0
- package/dist/vanilla.d.ts +58 -0
- package/dist/vanilla.d.ts.map +1 -0
- package/dist/vanilla.js +161 -0
- package/dist/vanilla.js.map +1 -0
- package/package.json +70 -0
- package/src/client.ts +342 -0
- package/src/detect.ts +278 -0
- package/src/errors.ts +133 -0
- package/src/index.ts +97 -0
- package/src/mutation.ts +109 -0
- package/src/provider.ts +229 -0
- package/src/react.ts +375 -0
- package/src/types.ts +440 -0
- package/src/vanilla.ts +239 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type JoeyInjectedProvider, type JoeyRequestArguments } from './provider.js';
|
|
2
|
+
import { type AnyTransaction, type ConnectParams, type ConnectResult, type JoeyAccount, type JoeyChain, type JoeyEventListener, type JoeyEventName, type JoeyNetwork, type SignAndSubmitTransactionResult, type SignInParams, type SignInResult, type SignTransactionBulkParams, type SignTransactionForParams, type SignTransactionParams, type SignTransactionResult, type TransactionLike } from './types.js';
|
|
3
|
+
export interface Joey {
|
|
4
|
+
/** The raw injected object, for anything this SDK version does not model. */
|
|
5
|
+
readonly provider: JoeyInjectedProvider;
|
|
6
|
+
/** Version of the injected surface, when the provider reports one. */
|
|
7
|
+
readonly version: string | undefined;
|
|
8
|
+
/** Reverse-DNS identity, `xyz.joeywallet`. */
|
|
9
|
+
readonly rdns: string | undefined;
|
|
10
|
+
/** Granted addresses, read synchronously. `[]` until the user connects. */
|
|
11
|
+
readonly accounts: readonly string[];
|
|
12
|
+
/** The chain the wallet is on, or `null` before the first connect. */
|
|
13
|
+
readonly chain: JoeyChain | null;
|
|
14
|
+
/** Synchronous. True once the user has granted this origin an account. */
|
|
15
|
+
isConnected(): boolean;
|
|
16
|
+
connect(params?: ConnectParams): Promise<ConnectResult>;
|
|
17
|
+
disconnect(): Promise<void>;
|
|
18
|
+
/** Granted addresses. `[]` for an origin with no grant — never an error. */
|
|
19
|
+
getAccounts(): Promise<string[]>;
|
|
20
|
+
getNetwork(): Promise<JoeyNetwork>;
|
|
21
|
+
signTransaction<TTx extends TransactionLike = AnyTransaction>(params: SignTransactionParams<TTx>): Promise<SignTransactionResult>;
|
|
22
|
+
signAndSubmitTransaction<TTx extends TransactionLike = AnyTransaction>(params: SignTransactionParams<TTx>): Promise<SignAndSubmitTransactionResult>;
|
|
23
|
+
/** Add one signature to a multisigned transaction. */
|
|
24
|
+
signTransactionFor<TTx extends TransactionLike = AnyTransaction>(params: SignTransactionForParams<TTx>): Promise<SignTransactionResult>;
|
|
25
|
+
/**
|
|
26
|
+
* One approval, up to `MAX_BULK_TRANSACTIONS` transactions, signed in order.
|
|
27
|
+
*
|
|
28
|
+
* Resolves with one entry per transaction, in the order you sent them.
|
|
29
|
+
* `engine_result` is present only when you asked for `submit: true` — with
|
|
30
|
+
* `submit: false` nothing is broadcast, so there is no engine result to give.
|
|
31
|
+
*
|
|
32
|
+
* A batch that fails part way *rejects*, and the error's `data` is a
|
|
33
|
+
* {@link SignTransactionBulkFailure} carrying every signed blob and which
|
|
34
|
+
* index stopped it. Read that rather than re-prompting the user.
|
|
35
|
+
*/
|
|
36
|
+
signTransactionBulk<TTx extends TransactionLike = AnyTransaction>(params: SignTransactionBulkParams<TTx>): Promise<SignAndSubmitTransactionResult[]>;
|
|
37
|
+
signIn(params?: SignInParams): Promise<SignInResult>;
|
|
38
|
+
/** Escape hatch for a method the wallet added after this SDK was published. */
|
|
39
|
+
request<TResult = unknown>(args: JoeyRequestArguments): Promise<TResult>;
|
|
40
|
+
on<K extends JoeyEventName>(event: K, listener: JoeyEventListener<K>): () => void;
|
|
41
|
+
off<K extends JoeyEventName>(event: K, listener: JoeyEventListener<K>): void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Read an account list out of whatever the wallet sent.
|
|
45
|
+
*
|
|
46
|
+
* Accepts a bare array, `{ accounts: [...] }`, and entries that are either
|
|
47
|
+
* address strings or objects — the shapes the provider and the background
|
|
48
|
+
* between them can produce.
|
|
49
|
+
*/
|
|
50
|
+
export declare function readAccounts(value: unknown): JoeyAccount[];
|
|
51
|
+
export declare function readChain(value: unknown): JoeyChain | null;
|
|
52
|
+
export declare function readNetwork(value: unknown): JoeyNetwork | null;
|
|
53
|
+
/** Wrap a raw injected provider in the typed API. */
|
|
54
|
+
export declare function createJoeyClient(provider: JoeyInjectedProvider): Joey;
|
|
55
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typed API a dapp actually calls.
|
|
3
|
+
*
|
|
4
|
+
* Every method resolves a value or rejects with a {@link JoeyRpcError}. There is
|
|
5
|
+
* deliberately no `{ type, result }` envelope: an envelope forces a branch at
|
|
6
|
+
* every call site, and a promise rejection is what a JS developer already writes
|
|
7
|
+
* `try`/`catch` around.
|
|
8
|
+
*
|
|
9
|
+
* Event payloads are normalised here rather than passed through raw. The
|
|
10
|
+
* provider forwards whatever the background sent, which is the right choice for
|
|
11
|
+
* a protocol layer and the wrong one for a dapp — a listener should not have to
|
|
12
|
+
* guess whether `accountsChanged` carried an array, an object with an
|
|
13
|
+
* `accounts` key, or a list of bare address strings.
|
|
14
|
+
*/
|
|
15
|
+
import { JOEY_ERROR_CODES, JoeyRpcError } from './errors.js';
|
|
16
|
+
import { JOEY_RPC_METHODS, invoke, subscribe, } from './provider.js';
|
|
17
|
+
import { isJoeyChain, networkIdForChain, } from './types.js';
|
|
18
|
+
/* --------------------------------------------------------------- normalising */
|
|
19
|
+
function isRecord(value) {
|
|
20
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Read an account list out of whatever the wallet sent.
|
|
24
|
+
*
|
|
25
|
+
* Accepts a bare array, `{ accounts: [...] }`, and entries that are either
|
|
26
|
+
* address strings or objects — the shapes the provider and the background
|
|
27
|
+
* between them can produce.
|
|
28
|
+
*/
|
|
29
|
+
export function readAccounts(value) {
|
|
30
|
+
const source = Array.isArray(value) ? value : isRecord(value) ? value.accounts : undefined;
|
|
31
|
+
if (!Array.isArray(source))
|
|
32
|
+
return [];
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const entry of source) {
|
|
35
|
+
if (typeof entry === 'string') {
|
|
36
|
+
out.push({ address: entry });
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (!isRecord(entry) || typeof entry.address !== 'string')
|
|
40
|
+
continue;
|
|
41
|
+
const account = { address: entry.address };
|
|
42
|
+
if (typeof entry.publicKey === 'string')
|
|
43
|
+
account.publicKey = entry.publicKey;
|
|
44
|
+
if (typeof entry.label === 'string')
|
|
45
|
+
account.label = entry.label;
|
|
46
|
+
out.push(account);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
export function readChain(value) {
|
|
51
|
+
if (isJoeyChain(value))
|
|
52
|
+
return value;
|
|
53
|
+
if (!isRecord(value))
|
|
54
|
+
return null;
|
|
55
|
+
return isJoeyChain(value.chain) ? value.chain : null;
|
|
56
|
+
}
|
|
57
|
+
export function readNetwork(value) {
|
|
58
|
+
const chain = readChain(value);
|
|
59
|
+
if (chain === null)
|
|
60
|
+
return null;
|
|
61
|
+
const record = isRecord(value) ? value : {};
|
|
62
|
+
return {
|
|
63
|
+
chain,
|
|
64
|
+
networkId: typeof record.networkId === 'number' ? record.networkId : (networkIdForChain(chain) ?? 0),
|
|
65
|
+
name: typeof record.name === 'string' ? record.name : chain,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/* -------------------------------------------------------------------- client */
|
|
69
|
+
/** Wrap a raw injected provider in the typed API. */
|
|
70
|
+
export function createJoeyClient(provider) {
|
|
71
|
+
/**
|
|
72
|
+
* Unsubscribe functions, keyed by the exact listener the caller handed us.
|
|
73
|
+
*
|
|
74
|
+
* Needed because the SDK subscribes a *wrapper* that normalises the payload,
|
|
75
|
+
* so the provider never sees the caller's own function.
|
|
76
|
+
*
|
|
77
|
+
* The value is a stack, not a single function, because a listener may be
|
|
78
|
+
* registered more than once and each registration is a separate subscription
|
|
79
|
+
* on the provider. Storing one function per listener silently dropped the
|
|
80
|
+
* earlier registration's unsubscriber: `off()` then removed the newest, the
|
|
81
|
+
* oldest kept firing, and nothing the dapp could call would ever remove it.
|
|
82
|
+
* A React effect that re-subscribes on a dependency change and unsubscribes
|
|
83
|
+
* on cleanup does exactly this, in that order, on every render — so the leak
|
|
84
|
+
* compounds. Each `off()` removes one registration, newest first, which is
|
|
85
|
+
* what `addEventListener`-shaped APIs do.
|
|
86
|
+
*/
|
|
87
|
+
const unsubscribers = new Map();
|
|
88
|
+
const call = async (method, params) => {
|
|
89
|
+
try {
|
|
90
|
+
return await invoke(provider, method, params);
|
|
91
|
+
}
|
|
92
|
+
catch (cause) {
|
|
93
|
+
throw JoeyRpcError.from(cause);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
/** Drop one specific registration, wherever it sits in the stack. */
|
|
97
|
+
const release = (event, listener, unsubscribe) => {
|
|
98
|
+
const forEvent = unsubscribers.get(event);
|
|
99
|
+
const stack = forEvent?.get(listener);
|
|
100
|
+
if (stack === undefined)
|
|
101
|
+
return;
|
|
102
|
+
const at = stack.lastIndexOf(unsubscribe);
|
|
103
|
+
if (at === -1)
|
|
104
|
+
return;
|
|
105
|
+
stack.splice(at, 1);
|
|
106
|
+
if (stack.length === 0)
|
|
107
|
+
forEvent?.delete(listener);
|
|
108
|
+
unsubscribe();
|
|
109
|
+
};
|
|
110
|
+
const normalise = {
|
|
111
|
+
connect: (payload) => ({ accounts: readAccounts(payload), chain: readChain(payload) }),
|
|
112
|
+
disconnect: (payload) => isRecord(payload) && typeof payload.reason === 'string' ? { reason: payload.reason } : {},
|
|
113
|
+
accountsChanged: (payload) => readAccounts(payload),
|
|
114
|
+
networkChanged: (payload) => readNetwork(payload),
|
|
115
|
+
};
|
|
116
|
+
const client = {
|
|
117
|
+
provider,
|
|
118
|
+
version: typeof provider.version === 'string' ? provider.version : undefined,
|
|
119
|
+
rdns: typeof provider.rdns === 'string' ? provider.rdns : undefined,
|
|
120
|
+
get accounts() {
|
|
121
|
+
return provider.accounts ?? [];
|
|
122
|
+
},
|
|
123
|
+
get chain() {
|
|
124
|
+
return provider.chain ?? null;
|
|
125
|
+
},
|
|
126
|
+
isConnected() {
|
|
127
|
+
if (typeof provider.isConnected === 'function')
|
|
128
|
+
return provider.isConnected();
|
|
129
|
+
return (provider.accounts ?? []).length > 0;
|
|
130
|
+
},
|
|
131
|
+
async connect(params) {
|
|
132
|
+
const result = await call(JOEY_RPC_METHODS.connect, params ?? {});
|
|
133
|
+
const record = isRecord(result) ? result : {};
|
|
134
|
+
const chain = readChain(record);
|
|
135
|
+
return {
|
|
136
|
+
accounts: readAccounts(record),
|
|
137
|
+
chain,
|
|
138
|
+
networkId: typeof record.networkId === 'number'
|
|
139
|
+
? record.networkId
|
|
140
|
+
: chain === null
|
|
141
|
+
? null
|
|
142
|
+
: networkIdForChain(chain),
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
async disconnect() {
|
|
146
|
+
await call(JOEY_RPC_METHODS.disconnect, {});
|
|
147
|
+
},
|
|
148
|
+
async getAccounts() {
|
|
149
|
+
const result = await call(JOEY_RPC_METHODS.getAccounts, {});
|
|
150
|
+
// The provider answers with bare addresses; the background may answer with
|
|
151
|
+
// account objects. Both collapse to addresses here.
|
|
152
|
+
return readAccounts(result).map((account) => account.address);
|
|
153
|
+
},
|
|
154
|
+
async getNetwork() {
|
|
155
|
+
const result = await call(JOEY_RPC_METHODS.getNetwork, {});
|
|
156
|
+
const network = readNetwork(result);
|
|
157
|
+
if (network === null) {
|
|
158
|
+
throw new JoeyRpcError(JOEY_ERROR_CODES.UNRECOGNIZED_CHAIN, 'The wallet reported a chain this SDK does not recognise.');
|
|
159
|
+
}
|
|
160
|
+
return network;
|
|
161
|
+
},
|
|
162
|
+
signTransaction(params) {
|
|
163
|
+
return call(JOEY_RPC_METHODS.signTransaction, params);
|
|
164
|
+
},
|
|
165
|
+
signAndSubmitTransaction(params) {
|
|
166
|
+
return call(JOEY_RPC_METHODS.signAndSubmitTransaction, params);
|
|
167
|
+
},
|
|
168
|
+
signTransactionFor(params) {
|
|
169
|
+
return call(JOEY_RPC_METHODS.signTransactionFor, params);
|
|
170
|
+
},
|
|
171
|
+
signTransactionBulk(params) {
|
|
172
|
+
return call(JOEY_RPC_METHODS.signTransactionBulk, params);
|
|
173
|
+
},
|
|
174
|
+
signIn(params) {
|
|
175
|
+
return call(JOEY_RPC_METHODS.signIn, params ?? {});
|
|
176
|
+
},
|
|
177
|
+
async request(args) {
|
|
178
|
+
try {
|
|
179
|
+
return await provider.request(args);
|
|
180
|
+
}
|
|
181
|
+
catch (cause) {
|
|
182
|
+
throw JoeyRpcError.from(cause);
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
on(event, listener) {
|
|
186
|
+
const wrapped = (payload) => {
|
|
187
|
+
;
|
|
188
|
+
listener(normalise[event](payload));
|
|
189
|
+
};
|
|
190
|
+
const unsubscribe = subscribe(provider, event, wrapped);
|
|
191
|
+
let forEvent = unsubscribers.get(event);
|
|
192
|
+
if (forEvent === undefined) {
|
|
193
|
+
forEvent = new Map();
|
|
194
|
+
unsubscribers.set(event, forEvent);
|
|
195
|
+
}
|
|
196
|
+
const stack = forEvent.get(listener);
|
|
197
|
+
if (stack === undefined)
|
|
198
|
+
forEvent.set(listener, [unsubscribe]);
|
|
199
|
+
else
|
|
200
|
+
stack.push(unsubscribe);
|
|
201
|
+
// The returned function removes *this* registration, once. Calling it
|
|
202
|
+
// twice must not take a sibling registration down with it.
|
|
203
|
+
let released = false;
|
|
204
|
+
return () => {
|
|
205
|
+
if (released)
|
|
206
|
+
return;
|
|
207
|
+
released = true;
|
|
208
|
+
release(event, listener, unsubscribe);
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
off(event, listener) {
|
|
212
|
+
const stack = unsubscribers.get(event)?.get(listener);
|
|
213
|
+
const unsubscribe = stack?.pop();
|
|
214
|
+
if (unsubscribe === undefined)
|
|
215
|
+
return;
|
|
216
|
+
unsubscribe();
|
|
217
|
+
if (stack !== undefined && stack.length === 0) {
|
|
218
|
+
unsubscribers.get(event)?.delete(listener);
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
return Object.freeze(client);
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/detect.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding the wallet.
|
|
3
|
+
*
|
|
4
|
+
* This file is load-bearing for adoption, not just for correctness. Every XRPL
|
|
5
|
+
* wallet aggregator gives a wallet about one second to prove it exists, and a
|
|
6
|
+
* detection path that costs a message round trip to a sleeping MV3 service
|
|
7
|
+
* worker will lose that race intermittently — which the aggregator reports to
|
|
8
|
+
* the user as "not installed", the worst possible failure. So detection reads
|
|
9
|
+
* the page globals and returns; it never talks to the extension.
|
|
10
|
+
*/
|
|
11
|
+
import { type Joey } from './client.js';
|
|
12
|
+
/**
|
|
13
|
+
* The Joey client, or `null` when the provider is not on the page.
|
|
14
|
+
*
|
|
15
|
+
* Synchronous by design. It is also safe to `await` — the value is not a
|
|
16
|
+
* promise, so `await getJoey()` costs one microtask and no round trip.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getJoey(): Joey | null;
|
|
19
|
+
/** Synchronous. Never sends a message, never awaits, never throws. */
|
|
20
|
+
export declare function isJoeyAvailable(): boolean;
|
|
21
|
+
/** Like {@link getJoey}, but throws `JoeyRpcError` 4900 instead of returning null. */
|
|
22
|
+
export declare function requireJoey(): Joey;
|
|
23
|
+
export interface WaitForJoeyOptions {
|
|
24
|
+
/** Default 3000. */
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolve once the provider exists.
|
|
30
|
+
*
|
|
31
|
+
* For the case the synchronous path cannot cover: a dapp bundle that executed
|
|
32
|
+
* before the extension's `document_start` content script finished installing
|
|
33
|
+
* the global. Settles on the provider's own announcement events — and, because
|
|
34
|
+
* those may already have fired, asks for them again — with a slow poll as a
|
|
35
|
+
* backstop for a provider that installs the global without announcing at all.
|
|
36
|
+
*/
|
|
37
|
+
export declare function waitForJoey(options?: WaitForJoeyOptions): Promise<Joey>;
|
|
38
|
+
/**
|
|
39
|
+
* Drop the cached client.
|
|
40
|
+
*
|
|
41
|
+
* Only needed by tests and by SPAs that swap the provider at runtime; normal
|
|
42
|
+
* dapps never call it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resetJoeyDetection(): void;
|
|
45
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAoB,KAAK,IAAI,EAAE,MAAM,aAAa,CAAA;AA6CzD;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,IAAI,GAAG,IAAI,CAQrC;AAED,sEAAsE;AACtE,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,sFAAsF;AACtF,wBAAgB,WAAW,IAAI,IAAI,CAIlC;AAED,MAAM,WAAW,kBAAkB;IACjC,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AA8FD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4E3E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC"}
|
package/dist/detect.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding the wallet.
|
|
3
|
+
*
|
|
4
|
+
* This file is load-bearing for adoption, not just for correctness. Every XRPL
|
|
5
|
+
* wallet aggregator gives a wallet about one second to prove it exists, and a
|
|
6
|
+
* detection path that costs a message round trip to a sleeping MV3 service
|
|
7
|
+
* worker will lose that race intermittently — which the aggregator reports to
|
|
8
|
+
* the user as "not installed", the worst possible failure. So detection reads
|
|
9
|
+
* the page globals and returns; it never talks to the extension.
|
|
10
|
+
*/
|
|
11
|
+
import { createJoeyClient } from './client.js';
|
|
12
|
+
import { JOEY_ERROR_CODES, JoeyRpcError, notInstalledError } from './errors.js';
|
|
13
|
+
import { CAIP294_ANNOUNCE_EVENT, CAIP294_PROMPT_EVENT, WALLET_STANDARD_APP_READY_EVENT, WALLET_STANDARD_REGISTER_EVENT, isJoeyInjectedProvider, } from './provider.js';
|
|
14
|
+
/**
|
|
15
|
+
* One client per injected object.
|
|
16
|
+
*
|
|
17
|
+
* React re-renders and aggregator retries both call `getJoey()` repeatedly; a
|
|
18
|
+
* fresh client each time would leak the event subscriptions the previous one
|
|
19
|
+
* registered and break referential equality in hook dependency arrays.
|
|
20
|
+
*/
|
|
21
|
+
let cachedProvider = null;
|
|
22
|
+
let cachedClient = null;
|
|
23
|
+
function globals() {
|
|
24
|
+
// `globalThis` rather than `window` so importing this module in Node (SSR,
|
|
25
|
+
// Next.js, a test runner) is inert instead of a ReferenceError.
|
|
26
|
+
if (typeof globalThis === 'undefined')
|
|
27
|
+
return null;
|
|
28
|
+
return globalThis;
|
|
29
|
+
}
|
|
30
|
+
function readProvider() {
|
|
31
|
+
const scope = globals();
|
|
32
|
+
if (scope === null)
|
|
33
|
+
return null;
|
|
34
|
+
if (isJoeyInjectedProvider(scope.joey))
|
|
35
|
+
return scope.joey;
|
|
36
|
+
// `window.xrpl` is Crossmark's namespace; Joey merges into it without
|
|
37
|
+
// touching anything already there, so this is a legitimate second home.
|
|
38
|
+
const nested = scope.xrpl?.joey;
|
|
39
|
+
if (isJoeyInjectedProvider(nested))
|
|
40
|
+
return nested;
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The Joey client, or `null` when the provider is not on the page.
|
|
45
|
+
*
|
|
46
|
+
* Synchronous by design. It is also safe to `await` — the value is not a
|
|
47
|
+
* promise, so `await getJoey()` costs one microtask and no round trip.
|
|
48
|
+
*/
|
|
49
|
+
export function getJoey() {
|
|
50
|
+
const provider = readProvider();
|
|
51
|
+
if (provider === null)
|
|
52
|
+
return null;
|
|
53
|
+
if (provider !== cachedProvider || cachedClient === null) {
|
|
54
|
+
cachedProvider = provider;
|
|
55
|
+
cachedClient = createJoeyClient(provider);
|
|
56
|
+
}
|
|
57
|
+
return cachedClient;
|
|
58
|
+
}
|
|
59
|
+
/** Synchronous. Never sends a message, never awaits, never throws. */
|
|
60
|
+
export function isJoeyAvailable() {
|
|
61
|
+
return readProvider() !== null;
|
|
62
|
+
}
|
|
63
|
+
/** Like {@link getJoey}, but throws `JoeyRpcError` 4900 instead of returning null. */
|
|
64
|
+
export function requireJoey() {
|
|
65
|
+
const joey = getJoey();
|
|
66
|
+
if (joey === null)
|
|
67
|
+
throw notInstalledError();
|
|
68
|
+
return joey;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Ask any wallet already on the page to announce itself again.
|
|
72
|
+
*
|
|
73
|
+
* Necessary, not merely polite. `waitForJoey` exists for the case where the
|
|
74
|
+
* dapp's bundle ran *after* the extension installed its provider — and in that
|
|
75
|
+
* case both announcements have already been dispatched into a page with no
|
|
76
|
+
* listeners attached. Listening for a second one that will never arrive is how
|
|
77
|
+
* a detection helper times out against a wallet that is sitting right there,
|
|
78
|
+
* and the poll below was quietly carrying the whole feature.
|
|
79
|
+
*
|
|
80
|
+
* Both protocols define the app's half of the handshake and Joey implements
|
|
81
|
+
* both: CAIP-294's `wallet_prompt` makes it re-dispatch `wallet_announce`, and
|
|
82
|
+
* Wallet Standard's `wallet-standard:app-ready` carries a `register` callback
|
|
83
|
+
* that every listening wallet calls synchronously. The callback's argument is
|
|
84
|
+
* discarded — the SDK wants the injected provider global, not a Wallet Standard
|
|
85
|
+
* wallet object — but a wallet that can call it has finished installing, so it
|
|
86
|
+
* is a reliable "look again now" signal.
|
|
87
|
+
*
|
|
88
|
+
* Every step is guarded, but not the way it looks: see {@link dispatchQuietly}
|
|
89
|
+
* for why a `try`/`catch` is the wrong tool for a listener that throws. Failing
|
|
90
|
+
* to prompt costs a poll interval, never the detection.
|
|
91
|
+
*/
|
|
92
|
+
function promptForWallets(target, recheck) {
|
|
93
|
+
dispatchQuietly(target, () => new CustomEvent(CAIP294_PROMPT_EVENT));
|
|
94
|
+
dispatchQuietly(target, () => new CustomEvent(WALLET_STANDARD_APP_READY_EVENT, {
|
|
95
|
+
detail: {
|
|
96
|
+
register: () => {
|
|
97
|
+
recheck();
|
|
98
|
+
return () => undefined;
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Dispatch one prompt event without a page listener's failure landing on
|
|
105
|
+
* anybody else.
|
|
106
|
+
*
|
|
107
|
+
* **`dispatchEvent` does not rethrow what a listener threw.** DOM's "inner
|
|
108
|
+
* invoke" *reports* the exception to the global instead and hands the
|
|
109
|
+
* dispatcher a plain boolean, so the `try`/`catch` that used to sit around
|
|
110
|
+
* these two calls caught nothing it claimed to. The SDK survived — it always
|
|
111
|
+
* would have — while the exception went on to the page's `onerror`, its crash
|
|
112
|
+
* reporter, and (in this repo) the test runner's unhandled-error channel, which
|
|
113
|
+
* failed a green suite with two errors nothing had thrown at it.
|
|
114
|
+
*
|
|
115
|
+
* So what is contained here is the *report*, not a throw. An `error` listener
|
|
116
|
+
* is installed on the global for the synchronous duration of this one dispatch
|
|
117
|
+
* and removed in `finally`. Reporting runs inline inside `dispatchEvent` and
|
|
118
|
+
* there is no `await` and no timer between install and removal, so the only
|
|
119
|
+
* errors it can possibly see are the ones this prompt caused; `preventDefault()`
|
|
120
|
+
* marks them handled, which is what suppresses the console entry and the
|
|
121
|
+
* runner's failure. Everything else the page reports is untouched.
|
|
122
|
+
*
|
|
123
|
+
* Realms differ, and the fallback is the same either way. Where the global
|
|
124
|
+
* reports asynchronously rather than through a cancellable `error` event —
|
|
125
|
+
* a bare Node `EventTarget` defers to `uncaughtException` — the absorber is
|
|
126
|
+
* already gone and the exception surfaces as that realm defines. Nothing about
|
|
127
|
+
* detection changes: the promise is unaffected in every case, because
|
|
128
|
+
* `dispatchEvent` never had the exception to give us.
|
|
129
|
+
*
|
|
130
|
+
* The `try`/`catch` that remains is for what genuinely does throw here: a realm
|
|
131
|
+
* with no `CustomEvent` constructor, or a global that refuses the dispatch.
|
|
132
|
+
*/
|
|
133
|
+
function dispatchQuietly(target, build) {
|
|
134
|
+
const absorb = (event) => {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
};
|
|
137
|
+
let absorbing = false;
|
|
138
|
+
try {
|
|
139
|
+
target.addEventListener('error', absorb, true);
|
|
140
|
+
absorbing = true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// A global that will not take an `error` listener. Nothing to absorb.
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
target.dispatchEvent(build());
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// No `CustomEvent` in this realm, or `dispatchEvent` refused it outright.
|
|
150
|
+
// The poll still covers us.
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
if (absorbing)
|
|
154
|
+
target.removeEventListener('error', absorb, true);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Resolve once the provider exists.
|
|
159
|
+
*
|
|
160
|
+
* For the case the synchronous path cannot cover: a dapp bundle that executed
|
|
161
|
+
* before the extension's `document_start` content script finished installing
|
|
162
|
+
* the global. Settles on the provider's own announcement events — and, because
|
|
163
|
+
* those may already have fired, asks for them again — with a slow poll as a
|
|
164
|
+
* backstop for a provider that installs the global without announcing at all.
|
|
165
|
+
*/
|
|
166
|
+
export function waitForJoey(options = {}) {
|
|
167
|
+
const { timeoutMs = 3000, signal } = options;
|
|
168
|
+
const immediate = getJoey();
|
|
169
|
+
if (immediate !== null)
|
|
170
|
+
return Promise.resolve(immediate);
|
|
171
|
+
const scope = globals();
|
|
172
|
+
if (scope === null || typeof scope.addEventListener !== 'function') {
|
|
173
|
+
return Promise.reject(notInstalledError());
|
|
174
|
+
}
|
|
175
|
+
const target = scope;
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
let settled = false;
|
|
178
|
+
const cleanups = [];
|
|
179
|
+
const finish = (run) => {
|
|
180
|
+
if (settled)
|
|
181
|
+
return;
|
|
182
|
+
settled = true;
|
|
183
|
+
for (const cleanup of cleanups)
|
|
184
|
+
cleanup();
|
|
185
|
+
run();
|
|
186
|
+
};
|
|
187
|
+
const check = () => {
|
|
188
|
+
const joey = getJoey();
|
|
189
|
+
if (joey !== null)
|
|
190
|
+
finish(() => resolve(joey));
|
|
191
|
+
};
|
|
192
|
+
for (const event of [
|
|
193
|
+
CAIP294_ANNOUNCE_EVENT,
|
|
194
|
+
WALLET_STANDARD_REGISTER_EVENT,
|
|
195
|
+
'DOMContentLoaded',
|
|
196
|
+
'load',
|
|
197
|
+
]) {
|
|
198
|
+
target.addEventListener(event, check);
|
|
199
|
+
cleanups.push(() => target.removeEventListener(event, check));
|
|
200
|
+
}
|
|
201
|
+
const poll = setInterval(check, 50);
|
|
202
|
+
cleanups.push(() => clearInterval(poll));
|
|
203
|
+
const timer = setTimeout(() => {
|
|
204
|
+
finish(() => reject(new JoeyRpcError(JOEY_ERROR_CODES.DISCONNECTED, `Joey Wallet did not announce itself within ${timeoutMs}ms. It is probably not installed.`)));
|
|
205
|
+
}, timeoutMs);
|
|
206
|
+
cleanups.push(() => clearTimeout(timer));
|
|
207
|
+
if (signal !== undefined) {
|
|
208
|
+
const onAbort = () => {
|
|
209
|
+
finish(() => reject(new JoeyRpcError(JOEY_ERROR_CODES.INTERNAL, 'Wallet detection was aborted.')));
|
|
210
|
+
};
|
|
211
|
+
if (signal.aborted) {
|
|
212
|
+
onAbort();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
216
|
+
cleanups.push(() => signal.removeEventListener('abort', onAbort));
|
|
217
|
+
}
|
|
218
|
+
// Covers a provider installed between the synchronous check above and the
|
|
219
|
+
// listeners being attached.
|
|
220
|
+
check();
|
|
221
|
+
if (settled)
|
|
222
|
+
return;
|
|
223
|
+
// Now that we are listening, ask the wallets that announced before we
|
|
224
|
+
// existed to say it again.
|
|
225
|
+
promptForWallets(target, check);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Drop the cached client.
|
|
230
|
+
*
|
|
231
|
+
* Only needed by tests and by SPAs that swap the provider at runtime; normal
|
|
232
|
+
* dapps never call it.
|
|
233
|
+
*/
|
|
234
|
+
export function resetJoeyDetection() {
|
|
235
|
+
cachedProvider = null;
|
|
236
|
+
cachedClient = null;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
|